Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sql.json(null) should produce 'null'::jsonb instead of null #317

Closed
thecodeboss opened this issue Dec 9, 2021 · 2 comments
Closed

sql.json(null) should produce 'null'::jsonb instead of null #317

thecodeboss opened this issue Dec 9, 2021 · 2 comments

Comments

@thecodeboss
Copy link
Contributor

Expected Behavior

The query

sql`
  SELECT ${sql.json(null)}
`;

should result in the SQL

SELECT 'null'::jsonb

Current Behavior

The above query actually gets translated to

SELECT NULL

NULL and 'null'::jsonb are different, and this can have a bad side effect such as when using jsonb_set. In the following example, we have a jsonb {"key": "value"}, and try to set the value to null, which should result in a new jsonb {"key": null}

sql`
  SELECT jsonb_set('{"key": "value"}'::jsonb, '{key}', ${sql.json(null)})
`

However, it actually results in NULL instead of {"key": null} since Slonik passes in NULL instead of 'null'::jsonb. Note that you could also simply pass in the string 'null' and it would be implicitly casted to jsonb here.

Possible Solution

I haven't followed the code path for how sql.json gets translated, but I did find a test case that is specifically checking null but expecting what I consider an incorrect result.
The test is:

test('passes null unstringified', (t) => {
  const query = sql`SELECT ${sql.json(null)}`;

  t.deepEqual(query, {
    sql: 'SELECT $1',
    type: SqlToken,
    values: [
      null,
    ],
  });
});

but I believe it should be:

test('passes null unstringified', (t) => {
  const query = sql`SELECT ${sql.json(null)}`;

  t.deepEqual(query, {
    sql: 'SELECT $1',
    type: SqlToken,
    values: [
      'null',
    ],
  });
});

Workaround

I ran into this issue when trying to do something like

sql`SELECT jsonb_set(data, path, ${sql.join(value)}`

where value can sometimes be null. Instead I've rewritten this as:

sql`SELECT jsonb_set(data, path, ${value === null ? sql`'null'::jsonb` : sql.json(value)})`

The ternary works, but it would be simpler if sql.json handled null differently.

@gajus
Copy link
Owner

gajus commented Mar 26, 2022

@thecodeboss Please review #333

@gajus gajus closed this as completed in 476a856 Mar 27, 2022
@gajus
Copy link
Owner

gajus commented Mar 27, 2022

🎉 This issue has been resolved in version 28.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@gajus gajus added the released label Mar 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants