deserializeRawResults.ts•2.45 kB
import type { QueryIntrospectionBuiltinType } from '@prisma/generator'
import Decimal from 'decimal.js'
export type RawResponse = {
  columns: string[]
  types: QueryIntrospectionBuiltinType[]
  rows: unknown[][]
}
function deserializeValue(type: QueryIntrospectionBuiltinType, value: unknown): unknown {
  if (value === null) {
    return value
  }
  switch (type) {
    case 'bigint':
      return BigInt(value as string)
    case 'bytes': {
      const { buffer, byteOffset, byteLength } = Buffer.from(value as string, 'base64')
      return new Uint8Array(buffer, byteOffset, byteLength)
    }
    case 'decimal':
      return new Decimal(value as string)
    case 'datetime':
    case 'date':
      return new Date(value as string)
    case 'time':
      return new Date(`1970-01-01T${value}Z`)
    case 'bigint-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('bigint', v))
    case 'bytes-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('bytes', v))
    case 'decimal-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('decimal', v))
    case 'datetime-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('datetime', v))
    case 'date-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('date', v))
    case 'time-array':
      return (value as unknown[]).map((v: unknown) => deserializeValue('time', v))
    default:
      return value
  }
}
type DeserializedResponse = Array<Record<string, unknown>>
export function deserializeRawResult(response: RawResponse): DeserializedResponse {
  const deserializedResponse: DeserializedResponse = []
  // Performance optimization. See https://github.com/brianc/node-postgres/issues/3042
  const prebuiltEmptyObject = createPrebuiltEmptyResultObject(response)
  for (let i = 0; i < response.rows.length; i++) {
    const row = response.rows[i]
    const mappedRow = { ...prebuiltEmptyObject } as Record<string, unknown>
    for (let j = 0; j < row.length; j++) {
      mappedRow[response.columns[j]] = deserializeValue(response.types[j], row[j])
    }
    deserializedResponse.push(mappedRow)
  }
  return deserializedResponse
}
function createPrebuiltEmptyResultObject(response: RawResponse): Record<string, null> {
  const row = {}
  for (let i = 0; i < response.columns.length; i++) {
    row[response.columns[i]] = null
  }
  return row
}