diff --git a/.changeset/calm-parrots-shave.md b/.changeset/calm-parrots-shave.md new file mode 100644 index 000000000..6dbf33778 --- /dev/null +++ b/.changeset/calm-parrots-shave.md @@ -0,0 +1,5 @@ +--- +'@electric-sql/pglite': patch +--- + +Allow parsing of nulls in arrays #997 diff --git a/packages/pglite/src/types.ts b/packages/pglite/src/types.ts index dec8a9388..8f02fb110 100644 --- a/packages/pglite/src/types.ts +++ b/packages/pglite/src/types.ts @@ -310,13 +310,24 @@ function arrayParserLoop( s.last = ++s.i xs.push(arrayParserLoop(s, x, parser, typarray)) } else if (s.char === '}') { + if (s.last < s.i) { + const el = x.slice(s.last, s.i) + if (el === 'NULL' && !s.quoted) { + xs.push(null) + } else { + xs.push(parser ? parser(el) : el) + } + } s.quoted = false - s.last < s.i && - xs.push(parser ? parser(x.slice(s.last, s.i)) : x.slice(s.last, s.i)) s.last = s.i + 1 break } else if (s.char === delimiter && s.p !== '}' && s.p !== '"') { - xs.push(parser ? parser(x.slice(s.last, s.i)) : x.slice(s.last, s.i)) + const el = x.slice(s.last, s.i) + if (el === 'NULL' && !s.quoted) { + xs.push(null) + } else { + xs.push(parser ? parser(el) : el) + } s.last = s.i + 1 } s.p = s.char diff --git a/packages/pglite/tests/basic.test.ts b/packages/pglite/tests/basic.test.ts index b845b4f1f..3c28d5382 100644 --- a/packages/pglite/tests/basic.test.ts +++ b/packages/pglite/tests/basic.test.ts @@ -715,5 +715,40 @@ await testEsmCjsAndDTC(async (importType) => { expect(process.exitCode).toEqual(origExitCode) }) + + it("arrays with NULL elements should return null, not string 'NULL'", async () => { + const pg = await PGlite.create() + + await pg.exec('CREATE TEMP TABLE t (str_val text, arr_val text[])') + + await pg.query('INSERT INTO t (str_val, arr_val) VALUES ($1, $2)', [ + null, + [null, 'hello', 'NULL'], + ]) + await pg.query('INSERT INTO t (str_val, arr_val) VALUES ($1, $2)', [ + null, + ['NULL', null, 'NULL'], + ]) + await pg.query('INSERT INTO t (str_val, arr_val) VALUES ($1, $2)', [ + null, + ['NULL', 'hello', null], + ]) + await pg.query('INSERT INTO t (str_val, arr_val) VALUES ($1, $2)', [ + null, + [null, null, null], + ]) + + const res = await pg.query('SELECT str_val, arr_val FROM t') + expect(res.rows[0].str_val).toEqual(null) + expect(res.rows[0].arr_val).toEqual([null, 'hello', 'NULL']) + expect(res.rows[1].arr_val).toEqual(['NULL', null, 'NULL']) + expect(res.rows[2].arr_val).toEqual(['NULL', 'hello', null]) + expect(res.rows[3].arr_val).toEqual([null, null, null]) + + await pg.exec('CREATE TEMP TABLE v (arr_int int[])') + await pg.query('INSERT INTO v (arr_int) VALUES ($1)', [[null, 123, 0]]) + const resInt = await pg.query('SELECT arr_int FROM v') + expect(resInt.rows[0].arr_int).toEqual([null, 123, 0]) + }) }) })