|
| 1 | +import pgClient from 'postgres'; |
| 2 | +import { expect, test } from 'vitest'; |
| 3 | +import { makePgArray } from '~/pg-core'; |
| 4 | +import { PostgresType } from '~/pg-core/codecs'; |
| 5 | + |
| 6 | +const db = pgClient('postgres://postgres:postgres@localhost:55433/drizzle'); |
| 7 | + |
| 8 | +export type NormalizeCodec = (value: any) => any; |
| 9 | +export type NormalizeArrayCodec = (value: any, arrayDimensions: number) => any; |
| 10 | +export type CastCodec = (name: string) => string; |
| 11 | +export type CastArrayCodec = (name: string, arrayDimensions: number) => string; |
| 12 | +export type CastParamCodec = (name: string) => string; |
| 13 | +export type CastArrayParamCodec = (name: string, arrayDimensions: number) => string; |
| 14 | + |
| 15 | +export type Codec = { |
| 16 | + cast: CastCodec; |
| 17 | + castArray: CastArrayCodec; |
| 18 | + castInJson: CastCodec; |
| 19 | + castArrayInJson: CastArrayCodec; |
| 20 | + |
| 21 | + castParam: CastParamCodec; |
| 22 | + castArrayParam: CastArrayParamCodec; |
| 23 | + |
| 24 | + normalize?: NormalizeCodec | undefined; |
| 25 | + normalizeArray?: NormalizeArrayCodec | undefined; |
| 26 | + normalizeInJson?: NormalizeCodec | undefined; |
| 27 | + normalizeArrayInJson?: NormalizeArrayCodec | undefined; |
| 28 | + |
| 29 | + normalizeParam?: NormalizeCodec | undefined; |
| 30 | + normalizeParamArray?: NormalizeArrayCodec | undefined; |
| 31 | +}; |
| 32 | + |
| 33 | +export const jsonColumnCodec: Codec = { |
| 34 | + cast: (v) => v, |
| 35 | + castArray: (v) => v, |
| 36 | + castArrayInJson: (v) => v, |
| 37 | + castArrayParam: (v) => v, |
| 38 | + castInJson: (v) => v, |
| 39 | + castParam: (v) => v, |
| 40 | + normalizeParam: (v) => JSON.stringify(v), |
| 41 | + normalizeParamArray: (v, _dimensions) => makePgArray(v.map((e: any) => JSON.stringify(e))), |
| 42 | + normalize: (v) => JSON.parse(v), |
| 43 | + normalizeInJson: (v) => JSON.parse(v), |
| 44 | +}; |
| 45 | + |
| 46 | +export const someDriverCodecs: Partial<Record<PostgresType, Codec>> = { |
| 47 | + json: jsonColumnCodec, |
| 48 | + jsonb: jsonColumnCodec, |
| 49 | +}; |
| 50 | + |
| 51 | +await db.unsafe('DROP TABLE IF EXISTS test CASCADE;'); |
| 52 | + |
| 53 | +test('all', async () => { |
| 54 | + await db.unsafe(`CREATE TABLE test ( |
| 55 | + subject JSON, |
| 56 | + subject_arr JSON[] |
| 57 | + );`); |
| 58 | + |
| 59 | + const subjectValue = { string: 'value', number: 1, null: null }; |
| 60 | + const subjectArrayValue = [{ string: 'value', number: 1, null: null }, { value: 2 }, ['nestedArr']]; |
| 61 | + |
| 62 | + const input = [ |
| 63 | + jsonColumnCodec.normalizeParam!(subjectValue), |
| 64 | + jsonColumnCodec.normalizeParamArray!(subjectArrayValue, 1), |
| 65 | + ]; |
| 66 | + |
| 67 | + await db.unsafe( |
| 68 | + `INSERT INTO test(subject, subject_arr) VALUES (${jsonColumnCodec.castParam('$1')}, ${ |
| 69 | + jsonColumnCodec.castParam('$2') |
| 70 | + })`, |
| 71 | + input, |
| 72 | + ); |
| 73 | + |
| 74 | + const res = await db.unsafe( |
| 75 | + `SELECT ${jsonColumnCodec.cast('subject')}, ${jsonColumnCodec.cast('subject_arr')} FROM test;`, |
| 76 | + ) |
| 77 | + .values(); |
| 78 | + |
| 79 | + const [[subject, subjectArr]] = res as any; |
| 80 | + const mappedSubject = jsonColumnCodec.normalize ? jsonColumnCodec.normalize(subject) : subject; |
| 81 | + const mappedSubjectArr = jsonColumnCodec.normalizeArray |
| 82 | + ? jsonColumnCodec.normalizeArray(subjectArr, 1) |
| 83 | + : subjectArr; |
| 84 | + |
| 85 | + expect(mappedSubject).toStrictEqual(subjectValue); |
| 86 | + expect(mappedSubjectArr).toStrictEqual(subjectArrayValue); |
| 87 | + |
| 88 | + const jsonRes = await db.unsafe( |
| 89 | + `SELECT row_to_json(r.*) FROM (SELECT ${jsonColumnCodec.castArrayInJson('subject', 1)} as "jsonSubject", ${ |
| 90 | + jsonColumnCodec.castArrayInJson('subject_arr', 1) |
| 91 | + } as "jsonSubjectArr" FROM test ) r;`, |
| 92 | + ) as any; |
| 93 | + |
| 94 | + const { jsonSubject, jsonSubjectArr } = jsonRes[0].row_to_json; |
| 95 | + |
| 96 | + const mappedJsonSubject = jsonColumnCodec.normalizeInJson |
| 97 | + ? jsonColumnCodec.normalizeInJson(jsonSubject) |
| 98 | + : jsonSubject; |
| 99 | + const mappedJsonSubjectArr = jsonColumnCodec.normalizeArrayInJson |
| 100 | + ? jsonColumnCodec.normalizeArrayInJson(jsonSubjectArr, 1) |
| 101 | + : jsonSubjectArr; |
| 102 | + |
| 103 | + expect(mappedJsonSubject).toStrictEqual(subjectValue); |
| 104 | + expect(mappedJsonSubjectArr).toStrictEqual(subjectArrayValue); |
| 105 | +}); |
0 commit comments