Skip to content

Commit

Permalink
db-util: use sql.*() instead of slonik-sql-tag-raw (#1240)
Browse files Browse the repository at this point in the history
  • Loading branch information
alxndrsn authored Oct 30, 2024
1 parent 8b9db34 commit 42a50ad
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 25 deletions.
4 changes: 2 additions & 2 deletions lib/model/query/submissions.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,9 @@ const _exportUnjoiner = unjoiner(Submission, Submission.Def, Submission.Xml, Sub
// we just use the terrible hack.
const { raw } = require('slonik-sql-tag-raw');
const _exportFields = raw(_exportUnjoiner.fields.sql
.replace(',submissions."userAgent" as "submissions!userAgent"', '')
.replace(',"submissions"."userAgent" as "submissions!userAgent"', '')
.replace(
'submission_defs."xml" as "submission_defs!xml"',
'"submission_defs"."xml" as "submission_defs!xml"',
'(case when submission_defs."localKey" is null then submission_defs.xml end) as "submission_defs!xml"'
));

Expand Down
19 changes: 9 additions & 10 deletions lib/util/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
const { inspect } = require('util');
const { mergeRight, pick, always, without, remove, indexOf } = require('ramda');
const { sql } = require('slonik');
const { raw } = require('slonik-sql-tag-raw');
const { reject } = require('./promise');
const Problem = require('./problem');
const Option = require('./option');
Expand Down Expand Up @@ -87,9 +86,9 @@ const unjoiner = (...frames) => {
const isOption = MaybeInstance instanceof Option;
const Instance = isOption ? MaybeInstance.get() : MaybeInstance;
for (const field of Instance.fields) {
const fullname = (Instance.from == null) ? `"${field}"` : `${Instance.from}."${field}"`;
const fullname = (Instance.from == null) ? sql.identifier([field]) : sql.identifier([Instance.from, field]);
const sqlname = (Instance.from == null) ? field : `${Instance.from}!${field}`;
fields.push(`${fullname} as "${sqlname}"`);
fields.push(sql`${fullname} as ${sql.identifier([sqlname])}`);
unmap[sqlname] = Instance.to;
unprefix[sqlname] = field;
constructors[Instance.to] = isOption ? maybeConstruct(Instance) : construct(Instance);
Expand All @@ -112,7 +111,7 @@ const unjoiner = (...frames) => {
return new frames[0](primary, bag);
};

unjoin.fields = raw(fields.join(','));
unjoin.fields = sql`${sql.join(fields, sql`,`)}`; // FIXME remove wrapping sql``
return unjoin;
};

Expand Down Expand Up @@ -147,7 +146,7 @@ const insert = (obj) => {
if (obj.constructor.hasCreatedAt) keys.push('createdAt');
const fieldlist = sql.join(keys.map((k) => sql.identifier([ k ])), sql`,`);
return sql`
insert into ${raw(obj.constructor.table)} (${fieldlist})
insert into ${sql.identifier([obj.constructor.table])} (${fieldlist})
values (${sql.join(keys.map(_assign(obj)), sql`,`)})
returning *`;
};
Expand All @@ -167,7 +166,7 @@ const insertMany = (objs) => {
// we need to set clock_timestamp if there's createdAt column
// Slonik doesn't support setting sql identitfier for sql.unnest yet
if (Type.hasCreatedAt) {
columns = sql`"createdAt", ${raw(without(['createdAt'], Type.insertfields).map((s) => `"${s}"`).join(','))}`;
columns = sql`"createdAt", ${sql.join(without(['createdAt'], Type.insertfields).map(f => sql.identifier([f])), sql`,`)}`;
rows = objs.map(obj => without(['createdAt'], Type.insertfields).map(_assign(obj)));
columnTypes = remove(indexOf('createdAt', Type.insertfields), 1, Type.insertFieldTypes);
selectExp = sql`clock_timestamp(), *`;
Expand All @@ -179,7 +178,7 @@ const insertMany = (objs) => {
}

return sql`
INSERT INTO ${raw(Type.table)} (${columns})
INSERT INTO ${sql.identifier([Type.table])} (${columns})
SELECT ${selectExp} FROM ${sql.unnest(rows, columnTypes)} AS t`;
};

Expand All @@ -190,7 +189,7 @@ const updater = (obj, data, whereKey = 'id') => {
if (keys.length === 0) return sql`select true`;
const assigner = _assign(data);
return sql`
update ${raw(obj.constructor.table)}
update ${sql.identifier([obj.constructor.table])}
set ${sql.join(keys.map((k) => sql`${sql.identifier([ k ])}=${assigner(k)}`), sql`,`)}
${(obj.constructor.hasUpdatedAt && !keys.includes('updatedAt')) ? sql`,"updatedAt"=clock_timestamp()` : nothing}
where ${sql.identifier([ whereKey ])}=${obj[whereKey]}
Expand All @@ -199,10 +198,10 @@ returning *`;

// generic del utility
const markDeleted = (obj) =>
sql`update ${raw(obj.constructor.table)} set "deletedAt"=now() where id=${obj.id}`;
sql`update ${sql.identifier([obj.constructor.table])} set "deletedAt"=now() where id=${obj.id}`;

const markUndeleted = (obj) =>
sql`update ${raw(obj.constructor.table)} set "deletedAt"=null where id=${obj.id}`;
sql`update ${sql.identifier([obj.constructor.table])} set "deletedAt"=null where id=${obj.id}`;


////////////////////////////////////////
Expand Down
26 changes: 13 additions & 13 deletions test/unit/util/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ describe('util/db', () => {
const U = Frame.define(into('extra'), 'z');
it('should generate fields', () => {
unjoiner(T, U)
.fields.should.eql(sql`frames."x" as "frames!x",frames."y" as "frames!y","z" as "z"`);
.fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`);
});

it('should unjoin data', () => {
Expand All @@ -219,7 +219,7 @@ describe('util/db', () => {

it('should optionally unjoin optional data', () => {
const unjoin = unjoiner(T, Option.of(U));
unjoin.fields.should.eql(sql`frames."x" as "frames!x",frames."y" as "frames!y","z" as "z"`);
unjoin.fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`);
unjoin({ 'frames!x': 3, 'frames!y': 4, z: 5 })
.should.eql(new T({ x: 3, y: 4 }, { extra: Option.of(new U({ z: 5 })) }));
unjoin({ 'frames!x': 3, 'frames!y': 4 })
Expand All @@ -239,7 +239,7 @@ describe('util/db', () => {
it('should provide the appropriate arguments when not extended', () => {
let run = false;
extender(T)(U)((fields, extend, options, x, y, z) => {
fields.should.eql(sql`frames."x" as "frames!x",frames."y" as "frames!y"`);
fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y"`);
(sql`${extend|| true}`).should.eql(sql``);
x.should.equal(2);
y.should.equal(3);
Expand All @@ -252,7 +252,7 @@ describe('util/db', () => {
it('should provide the appropriate arguments when extended', () => {
let run = false;
extender(T)(U)((fields, extend, options, x, y, z) => {
fields.should.eql(sql`frames."x" as "frames!x",frames."y" as "frames!y","a" as "a","b" as "b"`);
fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","a" as "a","b" as "b"`);
(sql`${extend|| true}`).should.eql(sql`${true}`);
x.should.equal(2);
y.should.equal(3);
Expand Down Expand Up @@ -285,23 +285,23 @@ describe('util/db', () => {

it('should formulate a basic response based on data', () => {
insert(new T({ x: 2, y: 3 })).should.eql(sql`
insert into frames ("x","y")
insert into "frames" ("x","y")
values (${2},${3})
returning *`);
});

it('should deal with strange data input types', () => {
insert(new T({ x: { test: true }, y: undefined, z: new Date('2000-01-01'), w: Object.assign(Object.create(null), { foo: 'bar' }) }))
.should.eql(sql`
insert into frames ("x","y","z","w")
insert into "frames" ("x","y","z","w")
values (${'{"test":true}'},${null},${'2000-01-01T00:00:00.000Z'},${'{"foo":"bar"}'})
returning *`);
});

it('should automatically insert into createdAt if expected', () => {
const U = Frame.define(table('cats'), 'createdAt', 'updatedAt');
insert(new U()).should.eql(sql`
insert into cats ("createdAt")
insert into "cats" ("createdAt")
values (${sql`clock_timestamp()`})
returning *`);
});
Expand All @@ -318,7 +318,7 @@ returning *`);
it('should insert all data', () => {
const query = insertMany([ new T({ x: 2 }), new T({ y: 3 }) ]);
query.sql.should.be.eql(`
INSERT INTO dogs ("x","y")
INSERT INTO "dogs" ("x","y")
SELECT * FROM unnest($1::"text"[], $2::"text"[]) AS t`);
query.values.should.be.eql([
[2, null],
Expand All @@ -330,7 +330,7 @@ returning *`);
const U = Frame.define(table('dogs'), 'x', 'createdAt', fieldTypes(['timestamptz', 'timestamptz']));
const query = insertMany([ new U({ x: new Date('2000-01-01') }), new U() ]);
query.sql.should.be.eql(`
INSERT INTO dogs ("createdAt", "x")
INSERT INTO "dogs" ("createdAt", "x")
SELECT clock_timestamp(), * FROM unnest($1::"timestamptz"[]) AS t`);
query.values.should.be.eql([
['2000-01-01T00:00:00.000Z', null]
Expand All @@ -341,7 +341,7 @@ returning *`);
const U = Frame.define(table('dogs'), 'x', 'createdAt', 'age', fieldTypes(['timestamptz', 'timestamptz', 'int4']));
const query = insertMany([ new U({ x: new Date('2000-01-01'), age: 14 }), new U({ age: 8 }), new U() ]);
query.sql.should.be.eql(`
INSERT INTO dogs ("createdAt", "x","age")
INSERT INTO "dogs" ("createdAt", "x","age")
SELECT clock_timestamp(), * FROM unnest($1::"timestamptz"[], $2::"int4"[]) AS t`);
query.values.should.be.eql([
['2000-01-01T00:00:00.000Z', null, null],
Expand All @@ -362,7 +362,7 @@ returning *`);

it('should update the given data', () => {
updater(new T({ id: 1, x: 2 }), new T({ y: 3 })).should.eql(sql`
update rabbits
update "rabbits"
set "y"=${3}
where ${sql.identifier([ 'id' ])}=${1}
Expand All @@ -372,7 +372,7 @@ returning *`);
it('should set updatedAt if present', () => {
const U = Frame.define(table('rabbits'), 'createdAt', 'updatedAt');
updater(new U({ id: 1, x: 2 }), new U({ y: 3 })).should.eql(sql`
update rabbits
update "rabbits"
set "y"=${3}
,"updatedAt"=clock_timestamp()
where "id"=${1}
Expand All @@ -381,7 +381,7 @@ returning *`);

it('should use a different id key if given', () => {
updater(new T({ otherId: 0, x: 2 }), new T({ y: 3 }), 'otherId').should.eql(sql`
update rabbits
update "rabbits"
set "y"=${3}
where "otherId"=${0}
Expand Down

0 comments on commit 42a50ad

Please sign in to comment.