@graffy/pg 0.15.25-alpha.4 → 0.15.25-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs +171 -110
- package/index.mjs +63 -1
- package/package.json +2 -3
package/index.cjs
CHANGED
|
@@ -2,12 +2,73 @@
|
|
|
2
2
|
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
|
|
3
3
|
const common = require("@graffy/common");
|
|
4
4
|
const pg$1 = require("pg");
|
|
5
|
-
const sql = require("sql-template-tag");
|
|
6
5
|
const debug = require("debug");
|
|
7
6
|
const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
|
|
8
7
|
const pg__default = /* @__PURE__ */ _interopDefaultLegacy(pg$1);
|
|
9
|
-
const sql__default = /* @__PURE__ */ _interopDefaultLegacy(sql);
|
|
10
8
|
const debug__default = /* @__PURE__ */ _interopDefaultLegacy(debug);
|
|
9
|
+
class Sql {
|
|
10
|
+
constructor(rawStrings, rawValues) {
|
|
11
|
+
if (rawStrings.length - 1 !== rawValues.length) {
|
|
12
|
+
if (rawStrings.length === 0) {
|
|
13
|
+
throw new TypeError("Expected at least 1 string");
|
|
14
|
+
}
|
|
15
|
+
throw new TypeError(`Expected ${rawStrings.length} strings to have ${rawStrings.length - 1} values`);
|
|
16
|
+
}
|
|
17
|
+
const valuesLength = rawValues.reduce((len, value) => len + (value instanceof Sql ? value.values.length : 1), 0);
|
|
18
|
+
this.values = new Array(valuesLength);
|
|
19
|
+
this.strings = new Array(valuesLength + 1);
|
|
20
|
+
this.strings[0] = rawStrings[0];
|
|
21
|
+
let i = 0, pos = 0;
|
|
22
|
+
while (i < rawValues.length) {
|
|
23
|
+
const child = rawValues[i++];
|
|
24
|
+
const rawString = rawStrings[i];
|
|
25
|
+
if (child instanceof Sql) {
|
|
26
|
+
this.strings[pos] += child.strings[0];
|
|
27
|
+
let childIndex = 0;
|
|
28
|
+
while (childIndex < child.values.length) {
|
|
29
|
+
this.values[pos++] = child.values[childIndex++];
|
|
30
|
+
this.strings[pos] = child.strings[childIndex];
|
|
31
|
+
}
|
|
32
|
+
this.strings[pos] += rawString;
|
|
33
|
+
} else {
|
|
34
|
+
this.values[pos++] = child;
|
|
35
|
+
this.strings[pos] = rawString;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
get text() {
|
|
40
|
+
let i = 1, value = this.strings[0];
|
|
41
|
+
while (i < this.strings.length)
|
|
42
|
+
value += `$${i}${this.strings[i++]}`;
|
|
43
|
+
return value;
|
|
44
|
+
}
|
|
45
|
+
get sql() {
|
|
46
|
+
let i = 1, value = this.strings[0];
|
|
47
|
+
while (i < this.strings.length)
|
|
48
|
+
value += `?${this.strings[i++]}`;
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
inspect() {
|
|
52
|
+
return {
|
|
53
|
+
text: this.text,
|
|
54
|
+
sql: this.sql,
|
|
55
|
+
values: this.values
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function join(values, separator = ",", prefix = "", suffix = "") {
|
|
60
|
+
if (values.length === 0) {
|
|
61
|
+
throw new TypeError("Expected `join([])` to be called with an array of multiple elements, but got an empty array");
|
|
62
|
+
}
|
|
63
|
+
return new Sql([prefix, ...Array(values.length - 1).fill(separator), suffix], values);
|
|
64
|
+
}
|
|
65
|
+
function raw(value) {
|
|
66
|
+
return new Sql([value], []);
|
|
67
|
+
}
|
|
68
|
+
const empty = raw("");
|
|
69
|
+
function sql(strings, ...values) {
|
|
70
|
+
return new Sql(strings, values);
|
|
71
|
+
}
|
|
11
72
|
const valid = {
|
|
12
73
|
$eq: true,
|
|
13
74
|
$lt: true,
|
|
@@ -134,60 +195,60 @@ function simplify(node) {
|
|
|
134
195
|
return node;
|
|
135
196
|
}
|
|
136
197
|
const getJsonBuildTrusted = (variadic) => {
|
|
137
|
-
const args =
|
|
198
|
+
const args = join(
|
|
138
199
|
Object.entries(variadic).map(([name, value]) => {
|
|
139
|
-
return
|
|
200
|
+
return sql`'${raw(name)}', ${getJsonBuildValue(value)}`;
|
|
140
201
|
})
|
|
141
202
|
);
|
|
142
|
-
return
|
|
203
|
+
return sql`jsonb_build_object(${args})`;
|
|
143
204
|
};
|
|
144
205
|
const getJsonBuildValue = (value) => {
|
|
145
|
-
if (value instanceof
|
|
206
|
+
if (value instanceof Sql)
|
|
146
207
|
return value;
|
|
147
208
|
if (typeof value === "string")
|
|
148
|
-
return
|
|
149
|
-
return
|
|
209
|
+
return sql`${value}::text`;
|
|
210
|
+
return sql`${JSON.stringify(stripAttributes(value))}::jsonb`;
|
|
150
211
|
};
|
|
151
212
|
const lookup = (prop) => {
|
|
152
213
|
const [prefix, ...suffix] = common.encodePath(prop);
|
|
153
|
-
return suffix.length ?
|
|
214
|
+
return suffix.length ? sql`"${raw(prefix)}" #> ${suffix}` : sql`"${raw(prefix)}"`;
|
|
154
215
|
};
|
|
155
216
|
const lookupNumeric = (prop) => {
|
|
156
217
|
const [prefix, ...suffix] = common.encodePath(prop);
|
|
157
|
-
return suffix.length ?
|
|
218
|
+
return suffix.length ? sql`CASE WHEN "${raw(prefix)}" #> ${suffix} = 'null'::jsonb THEN 0 ELSE ("${raw(
|
|
158
219
|
prefix
|
|
159
|
-
)}" #> ${suffix})::numeric END` :
|
|
220
|
+
)}" #> ${suffix})::numeric END` : sql`"${raw(prefix)}"`;
|
|
160
221
|
};
|
|
161
222
|
const aggSql = {
|
|
162
|
-
$sum: (prop) =>
|
|
163
|
-
$card: (prop) =>
|
|
164
|
-
$avg: (prop) =>
|
|
165
|
-
$max: (prop) =>
|
|
166
|
-
$min: (prop) =>
|
|
223
|
+
$sum: (prop) => sql`sum((${lookupNumeric(prop)})::numeric)`,
|
|
224
|
+
$card: (prop) => sql`count(distinct(${lookup(prop)}))`,
|
|
225
|
+
$avg: (prop) => sql`avg((${lookupNumeric(prop)})::numeric)`,
|
|
226
|
+
$max: (prop) => sql`max((${lookupNumeric(prop)})::numeric)`,
|
|
227
|
+
$min: (prop) => sql`min((${lookupNumeric(prop)})::numeric)`
|
|
167
228
|
};
|
|
168
229
|
const getSelectCols = (table, projection = null) => {
|
|
169
230
|
if (!projection)
|
|
170
|
-
return
|
|
231
|
+
return sql`*`;
|
|
171
232
|
const sqls = [];
|
|
172
233
|
for (const key in projection) {
|
|
173
234
|
if (key === "$count") {
|
|
174
|
-
sqls.push(
|
|
235
|
+
sqls.push(sql`count(*) AS "$count"`);
|
|
175
236
|
} else if (aggSql[key]) {
|
|
176
237
|
const subSqls = [];
|
|
177
238
|
for (const prop in projection[key]) {
|
|
178
|
-
subSqls.push(
|
|
239
|
+
subSqls.push(sql`${prop}::text, ${aggSql[key](prop)}`);
|
|
179
240
|
}
|
|
180
241
|
sqls.push(
|
|
181
|
-
|
|
242
|
+
sql`jsonb_build_object(${join(subSqls, ", ")}) AS "${raw(key)}"`
|
|
182
243
|
);
|
|
183
244
|
} else {
|
|
184
|
-
sqls.push(
|
|
245
|
+
sqls.push(sql`"${raw(key)}"`);
|
|
185
246
|
}
|
|
186
247
|
}
|
|
187
|
-
return
|
|
248
|
+
return join(sqls, ", ");
|
|
188
249
|
};
|
|
189
250
|
function vertexSql(array, nullValue) {
|
|
190
|
-
return
|
|
251
|
+
return sql`array[${join(
|
|
191
252
|
array.map((num) => num === null ? nullValue : num)
|
|
192
253
|
)}]::float8[]`;
|
|
193
254
|
}
|
|
@@ -195,20 +256,20 @@ function cubeLiteralSql(value) {
|
|
|
195
256
|
if (!Array.isArray(value) || !value.length || Array.isArray(value[0]) && value.length !== 2) {
|
|
196
257
|
throw Error("pg.castValue_bad_cube" + JSON.stringify(value));
|
|
197
258
|
}
|
|
198
|
-
return Array.isArray(value[0]) ?
|
|
259
|
+
return Array.isArray(value[0]) ? sql`cube(${vertexSql(value[0], sql`'-Infinity'`)}, ${vertexSql(
|
|
199
260
|
value[1],
|
|
200
|
-
|
|
201
|
-
)})` :
|
|
261
|
+
sql`'Infinity'`
|
|
262
|
+
)})` : sql`cube(${vertexSql(value, 0)})`;
|
|
202
263
|
}
|
|
203
264
|
function castValue(value, type, name, isPut) {
|
|
204
265
|
if (!type)
|
|
205
266
|
throw Error("pg.write_no_column " + name);
|
|
206
|
-
if (value instanceof
|
|
267
|
+
if (value instanceof Sql)
|
|
207
268
|
return value;
|
|
208
269
|
if (value === null)
|
|
209
|
-
return
|
|
270
|
+
return sql`NULL`;
|
|
210
271
|
if (type === "jsonb") {
|
|
211
|
-
return isPut ? JSON.stringify(stripAttributes(value)) :
|
|
272
|
+
return isPut ? JSON.stringify(stripAttributes(value)) : sql`jsonb_strip_nulls(${getJsonUpdate(value, name, [])})`;
|
|
212
273
|
}
|
|
213
274
|
if (type === "cube")
|
|
214
275
|
return cubeLiteralSql(value);
|
|
@@ -217,22 +278,22 @@ function castValue(value, type, name, isPut) {
|
|
|
217
278
|
const getInsert = (row, options) => {
|
|
218
279
|
const cols = [];
|
|
219
280
|
const vals = [];
|
|
220
|
-
Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol,
|
|
221
|
-
cols.push(
|
|
281
|
+
Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol, sql`default`]]).forEach(([col, val]) => {
|
|
282
|
+
cols.push(sql`"${raw(col)}"`);
|
|
222
283
|
vals.push(castValue(val, options.schema.types[col], col, row.$put));
|
|
223
284
|
});
|
|
224
|
-
return { cols:
|
|
285
|
+
return { cols: join(cols, ", "), vals: join(vals, ", ") };
|
|
225
286
|
};
|
|
226
287
|
const getUpdates = (row, options) => {
|
|
227
|
-
return
|
|
288
|
+
return join(
|
|
228
289
|
Object.entries(row).filter(([col]) => col !== options.idCol && col[0] !== "$").map(
|
|
229
|
-
([col, val]) =>
|
|
290
|
+
([col, val]) => sql`"${raw(col)}" = ${castValue(
|
|
230
291
|
val,
|
|
231
292
|
options.schema.types[col],
|
|
232
293
|
col,
|
|
233
294
|
row.$put
|
|
234
295
|
)}`
|
|
235
|
-
).concat(
|
|
296
|
+
).concat(sql`"${raw(options.verCol)}" = default`),
|
|
236
297
|
", "
|
|
237
298
|
);
|
|
238
299
|
};
|
|
@@ -240,15 +301,15 @@ function getJsonUpdate(object, col, path) {
|
|
|
240
301
|
if (!object || typeof object !== "object" || Array.isArray(object) || object.$put) {
|
|
241
302
|
return getJsonBuildValue(object);
|
|
242
303
|
}
|
|
243
|
-
const curr =
|
|
304
|
+
const curr = sql`"${raw(col)}"${path.length ? sql`#>${path}` : empty}`;
|
|
244
305
|
if (common.isEmpty(object))
|
|
245
306
|
return curr;
|
|
246
|
-
return
|
|
307
|
+
return sql`(case jsonb_typeof(${curr})
|
|
247
308
|
when 'object' then ${curr}
|
|
248
309
|
else '{}'::jsonb
|
|
249
|
-
end) || jsonb_build_object(${
|
|
310
|
+
end) || jsonb_build_object(${join(
|
|
250
311
|
Object.entries(object).map(
|
|
251
|
-
([key, value]) =>
|
|
312
|
+
([key, value]) => sql`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`
|
|
252
313
|
),
|
|
253
314
|
", "
|
|
254
315
|
)})`;
|
|
@@ -269,50 +330,50 @@ function stripAttributes(object) {
|
|
|
269
330
|
const opSql = {
|
|
270
331
|
$and: `AND`,
|
|
271
332
|
$or: `OR`,
|
|
272
|
-
$not:
|
|
273
|
-
$eq:
|
|
274
|
-
$neq:
|
|
275
|
-
$in:
|
|
276
|
-
$nin:
|
|
277
|
-
$lt:
|
|
278
|
-
$lte:
|
|
279
|
-
$gt:
|
|
280
|
-
$gte:
|
|
281
|
-
$re:
|
|
282
|
-
$ire:
|
|
283
|
-
$cts:
|
|
284
|
-
$ctd:
|
|
333
|
+
$not: sql`NOT`,
|
|
334
|
+
$eq: sql`=`,
|
|
335
|
+
$neq: sql`<>`,
|
|
336
|
+
$in: sql`IN`,
|
|
337
|
+
$nin: sql`NOT IN`,
|
|
338
|
+
$lt: sql`<`,
|
|
339
|
+
$lte: sql`<=`,
|
|
340
|
+
$gt: sql`>`,
|
|
341
|
+
$gte: sql`>=`,
|
|
342
|
+
$re: sql`~`,
|
|
343
|
+
$ire: sql`~*`,
|
|
344
|
+
$cts: sql`@>`,
|
|
345
|
+
$ctd: sql`<@`
|
|
285
346
|
};
|
|
286
347
|
function getBinarySql(lhs, type, op, value, textLhs) {
|
|
287
348
|
if (value === null && op === "$eq")
|
|
288
|
-
return
|
|
349
|
+
return sql`${lhs} IS NULL`;
|
|
289
350
|
if (value === null && op === "$neq")
|
|
290
|
-
return
|
|
351
|
+
return sql`${lhs} IS NOT NULL`;
|
|
291
352
|
const sqlOp = opSql[op];
|
|
292
353
|
if (!sqlOp)
|
|
293
354
|
throw Error("pg.getSql_unknown_operator " + op);
|
|
294
355
|
if (op === "$in" || op === "$nin") {
|
|
295
356
|
if (type === "jsonb" && typeof value[0] === "string")
|
|
296
357
|
lhs = textLhs;
|
|
297
|
-
return
|
|
358
|
+
return sql`${lhs} ${sqlOp} (${join(value)})`;
|
|
298
359
|
}
|
|
299
360
|
if (op === "$re" || op === "$ire") {
|
|
300
361
|
if (type === "jsonb") {
|
|
301
362
|
lhs = textLhs;
|
|
302
363
|
} else if (type !== "text") {
|
|
303
|
-
lhs =
|
|
364
|
+
lhs = sql`(${lhs})::text`;
|
|
304
365
|
}
|
|
305
|
-
return
|
|
366
|
+
return sql`${lhs} ${sqlOp} ${String(value)}`;
|
|
306
367
|
}
|
|
307
368
|
if (type === "jsonb") {
|
|
308
369
|
if (typeof value === "string") {
|
|
309
|
-
return
|
|
370
|
+
return sql`${textLhs} ${sqlOp} ${value}`;
|
|
310
371
|
}
|
|
311
|
-
return
|
|
372
|
+
return sql`${lhs} ${sqlOp} ${JSON.stringify(value)}::jsonb`;
|
|
312
373
|
}
|
|
313
374
|
if (type === "cube")
|
|
314
|
-
return
|
|
315
|
-
return
|
|
375
|
+
return sql`${lhs} ${sqlOp} ${cubeLiteralSql(value)}`;
|
|
376
|
+
return sql`${lhs} ${sqlOp} ${value}`;
|
|
316
377
|
}
|
|
317
378
|
function getSql(filter, options) {
|
|
318
379
|
function getNodeSql(ast) {
|
|
@@ -320,12 +381,12 @@ function getSql(filter, options) {
|
|
|
320
381
|
return ast;
|
|
321
382
|
const op = ast[0];
|
|
322
383
|
if (op === "$and" || op === "$or") {
|
|
323
|
-
return
|
|
384
|
+
return sql`(${join(
|
|
324
385
|
ast[1].map((node) => getNodeSql(node)),
|
|
325
386
|
`) ${opSql[op]} (`
|
|
326
387
|
)})`;
|
|
327
388
|
} else if (op === "$not") {
|
|
328
|
-
return
|
|
389
|
+
return sql`${opSql[op]} (${getNodeSql(ast[1])})`;
|
|
329
390
|
}
|
|
330
391
|
const [prefix, ...suffix] = common.encodePath(ast[1]);
|
|
331
392
|
const { types: types2 } = options.schema;
|
|
@@ -333,28 +394,28 @@ function getSql(filter, options) {
|
|
|
333
394
|
throw Error("pg.no_column " + prefix);
|
|
334
395
|
if (types2[prefix] === "jsonb") {
|
|
335
396
|
const [lhs, textLhs] = suffix.length ? [
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
] : [
|
|
397
|
+
sql`"${raw(prefix)}" #> ${suffix}`,
|
|
398
|
+
sql`"${raw(prefix)}" #>> ${suffix}`
|
|
399
|
+
] : [sql`"${raw(prefix)}"`, sql`"${raw(prefix)}" #>> '{}'`];
|
|
339
400
|
return getBinarySql(lhs, "jsonb", op, ast[2], textLhs);
|
|
340
401
|
} else {
|
|
341
402
|
if (suffix.length)
|
|
342
403
|
throw Error("pg.lookup_not_jsonb " + prefix);
|
|
343
|
-
return getBinarySql(
|
|
404
|
+
return getBinarySql(sql`"${raw(prefix)}"`, types2[prefix], op, ast[2]);
|
|
344
405
|
}
|
|
345
406
|
}
|
|
346
407
|
return getNodeSql(getAst(filter));
|
|
347
408
|
}
|
|
348
|
-
const getIdMeta = ({ idCol, verDefault }) =>
|
|
349
|
-
const getArgMeta = (key, { prefix, idCol, verDefault }) =>
|
|
409
|
+
const getIdMeta = ({ idCol, verDefault }) => sql`"${raw(idCol)}" AS "$key", ${raw(verDefault)} AS "$ver"`;
|
|
410
|
+
const getArgMeta = (key, { prefix, idCol, verDefault }) => sql`
|
|
350
411
|
${key} AS "$key",
|
|
351
|
-
${
|
|
412
|
+
${raw(verDefault)} AS "$ver",
|
|
352
413
|
array[
|
|
353
|
-
${
|
|
354
|
-
"${
|
|
414
|
+
${join(prefix.map((k) => sql`${k}::text`))},
|
|
415
|
+
"${raw(idCol)}"
|
|
355
416
|
]::text[] AS "$ref"
|
|
356
417
|
`;
|
|
357
|
-
const getAggMeta = (key, { verDefault }) =>
|
|
418
|
+
const getAggMeta = (key, { verDefault }) => sql`${key} AS "$key", ${raw(verDefault)} AS "$ver"`;
|
|
358
419
|
function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $cursor: _, ...rest }, options) {
|
|
359
420
|
const { $order, $group, ...filter } = rest;
|
|
360
421
|
const { prefix, idCol } = options;
|
|
@@ -366,16 +427,16 @@ function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $curs
|
|
|
366
427
|
if (($order || $group && $group !== true) && !hasRangeArg) {
|
|
367
428
|
throw Error("pg_arg.range_arg_expected in " + prefix);
|
|
368
429
|
}
|
|
369
|
-
const baseKey =
|
|
430
|
+
const baseKey = sql`${JSON.stringify(rest)}::jsonb`;
|
|
370
431
|
const where = [];
|
|
371
432
|
if (!common.isEmpty(filter))
|
|
372
433
|
where.push(getSql(filter, options));
|
|
373
434
|
if (!hasRangeArg)
|
|
374
435
|
return { meta: meta(baseKey), where, limit: 1 };
|
|
375
436
|
const groupCols = Array.isArray($group) && $group.length && $group.map(lookup);
|
|
376
|
-
const group = groupCols ?
|
|
437
|
+
const group = groupCols ? join(groupCols, ", ") : void 0;
|
|
377
438
|
const orderCols = ($order || [idCol]).map(
|
|
378
|
-
(orderItem) => orderItem[0] === "!" ?
|
|
439
|
+
(orderItem) => orderItem[0] === "!" ? sql`-(${lookup(orderItem.slice(1))})::float8` : lookup(orderItem)
|
|
379
440
|
);
|
|
380
441
|
Object.entries({ $after, $before, $since, $until }).forEach(
|
|
381
442
|
([name, value]) => {
|
|
@@ -383,16 +444,16 @@ function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $curs
|
|
|
383
444
|
where.push(getBoundCond(orderCols, value, name));
|
|
384
445
|
}
|
|
385
446
|
);
|
|
386
|
-
const order = !$group &&
|
|
447
|
+
const order = !$group && join(
|
|
387
448
|
($order || [idCol]).map(
|
|
388
|
-
(orderItem) => orderItem[0] === "!" ?
|
|
449
|
+
(orderItem) => orderItem[0] === "!" ? sql`${lookup(orderItem.slice(1))} ${$last ? sql`ASC` : sql`DESC`}` : sql`${lookup(orderItem)} ${$last ? sql`DESC` : sql`ASC`}`
|
|
389
450
|
),
|
|
390
451
|
`, `
|
|
391
452
|
);
|
|
392
453
|
const cursorKey = getJsonBuildTrusted({
|
|
393
|
-
$cursor: $group === true ?
|
|
454
|
+
$cursor: $group === true ? sql`''` : sql`jsonb_build_array(${join(groupCols || orderCols)})`
|
|
394
455
|
});
|
|
395
|
-
const key =
|
|
456
|
+
const key = sql`(${baseKey} || ${cursorKey})`;
|
|
396
457
|
return {
|
|
397
458
|
meta: meta(key),
|
|
398
459
|
where,
|
|
@@ -412,21 +473,21 @@ function getBoundCond(orderCols, bound, kind) {
|
|
|
412
473
|
switch (kind) {
|
|
413
474
|
case "$after":
|
|
414
475
|
case "$since":
|
|
415
|
-
return
|
|
476
|
+
return sql`${lhs} > ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
|
|
416
477
|
case "$before":
|
|
417
478
|
case "$until":
|
|
418
|
-
return
|
|
479
|
+
return sql`${lhs} < ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
|
|
419
480
|
}
|
|
420
481
|
} else {
|
|
421
482
|
switch (kind) {
|
|
422
483
|
case "$after":
|
|
423
|
-
return
|
|
484
|
+
return sql`${lhs} > ${rhs}`;
|
|
424
485
|
case "$since":
|
|
425
|
-
return
|
|
486
|
+
return sql`${lhs} >= ${rhs}`;
|
|
426
487
|
case "$before":
|
|
427
|
-
return
|
|
488
|
+
return sql`${lhs} < ${rhs}`;
|
|
428
489
|
case "$until":
|
|
429
|
-
return
|
|
490
|
+
return sql`${lhs} <= ${rhs}`;
|
|
430
491
|
}
|
|
431
492
|
}
|
|
432
493
|
}
|
|
@@ -435,30 +496,30 @@ function selectByArgs(args, projection, options) {
|
|
|
435
496
|
const { table } = options;
|
|
436
497
|
const { where, order, group, limit, meta } = getArgSql(args, options);
|
|
437
498
|
const clampedLimit = Math.min(MAX_LIMIT, limit || MAX_LIMIT);
|
|
438
|
-
return
|
|
499
|
+
return sql`
|
|
439
500
|
SELECT
|
|
440
501
|
${getSelectCols(table, projection)}, ${meta}
|
|
441
|
-
FROM "${
|
|
442
|
-
${where.length ?
|
|
443
|
-
${group ?
|
|
444
|
-
${order ?
|
|
502
|
+
FROM "${raw(table)}"
|
|
503
|
+
${where.length ? sql`WHERE ${join(where, ` AND `)}` : empty}
|
|
504
|
+
${group ? sql`GROUP BY ${group}` : empty}
|
|
505
|
+
${order ? sql`ORDER BY ${order}` : empty}
|
|
445
506
|
LIMIT ${clampedLimit}
|
|
446
507
|
`;
|
|
447
508
|
}
|
|
448
509
|
function selectByIds(ids, projection, options) {
|
|
449
510
|
const { table, idCol } = options;
|
|
450
|
-
return
|
|
511
|
+
return sql`
|
|
451
512
|
SELECT
|
|
452
513
|
${getSelectCols(table, projection)}, ${getIdMeta(options)}
|
|
453
|
-
FROM "${
|
|
454
|
-
WHERE "${
|
|
514
|
+
FROM "${raw(table)}"
|
|
515
|
+
WHERE "${raw(idCol)}" IN (${join(ids)})
|
|
455
516
|
`;
|
|
456
517
|
}
|
|
457
518
|
function getSingleSql(arg, options) {
|
|
458
519
|
const { table, idCol } = options;
|
|
459
520
|
if (!common.isPlainObject(arg)) {
|
|
460
521
|
return {
|
|
461
|
-
where:
|
|
522
|
+
where: sql`"${raw(idCol)}" = ${arg}`,
|
|
462
523
|
meta: getIdMeta(options)
|
|
463
524
|
};
|
|
464
525
|
}
|
|
@@ -466,10 +527,10 @@ function getSingleSql(arg, options) {
|
|
|
466
527
|
if (!where || !where.length)
|
|
467
528
|
throw Error("pg_write.no_condition");
|
|
468
529
|
return {
|
|
469
|
-
where:
|
|
470
|
-
SELECT "${
|
|
471
|
-
FROM "${
|
|
472
|
-
WHERE ${
|
|
530
|
+
where: sql`"${raw(idCol)}" = (
|
|
531
|
+
SELECT "${raw(idCol)}"
|
|
532
|
+
FROM "${raw(table)}"
|
|
533
|
+
WHERE ${join(where, ` AND `)}
|
|
473
534
|
LIMIT 1
|
|
474
535
|
)`,
|
|
475
536
|
meta
|
|
@@ -479,8 +540,8 @@ function patch(object, arg, options) {
|
|
|
479
540
|
const { table } = options;
|
|
480
541
|
const { where, meta } = getSingleSql(arg, options);
|
|
481
542
|
const row = object;
|
|
482
|
-
return
|
|
483
|
-
UPDATE "${
|
|
543
|
+
return sql`
|
|
544
|
+
UPDATE "${raw(table)}" SET ${getUpdates(row, options)}
|
|
484
545
|
WHERE ${where}
|
|
485
546
|
RETURNING ${getSelectCols()}, ${meta}`;
|
|
486
547
|
}
|
|
@@ -490,22 +551,22 @@ function put(object, arg, options) {
|
|
|
490
551
|
let meta, conflictTarget;
|
|
491
552
|
if (common.isPlainObject(arg)) {
|
|
492
553
|
({ meta } = getArgSql(arg, options));
|
|
493
|
-
conflictTarget =
|
|
554
|
+
conflictTarget = join(Object.keys(arg).map((col) => sql`"${raw(col)}"`));
|
|
494
555
|
} else {
|
|
495
556
|
meta = getIdMeta(options);
|
|
496
|
-
conflictTarget =
|
|
557
|
+
conflictTarget = sql`"${raw(idCol)}"`;
|
|
497
558
|
}
|
|
498
559
|
const { cols, vals } = getInsert(row, options);
|
|
499
|
-
return
|
|
500
|
-
INSERT INTO "${
|
|
560
|
+
return sql`
|
|
561
|
+
INSERT INTO "${raw(table)}" (${cols}) VALUES (${vals})
|
|
501
562
|
ON CONFLICT (${conflictTarget}) DO UPDATE SET (${cols}) = (${vals})
|
|
502
563
|
RETURNING ${getSelectCols()}, ${meta}`;
|
|
503
564
|
}
|
|
504
565
|
function del(arg, options) {
|
|
505
566
|
const { table } = options;
|
|
506
567
|
const { where } = getSingleSql(arg, options);
|
|
507
|
-
return
|
|
508
|
-
DELETE FROM "${
|
|
568
|
+
return sql`
|
|
569
|
+
DELETE FROM "${raw(table)}"
|
|
509
570
|
WHERE ${where}
|
|
510
571
|
RETURNING ${arg} "$key"`;
|
|
511
572
|
}
|
|
@@ -560,13 +621,13 @@ class Db {
|
|
|
560
621
|
if (tableOptions.schema)
|
|
561
622
|
return;
|
|
562
623
|
const { table, verCol } = tableOptions;
|
|
563
|
-
const tableSchema = (await this.query(
|
|
624
|
+
const tableSchema = (await this.query(sql`
|
|
564
625
|
SELECT table_schema
|
|
565
626
|
FROM information_schema.tables
|
|
566
627
|
WHERE table_name = ${table}
|
|
567
628
|
ORDER BY array_position(current_schemas(false)::text[], table_schema::text) ASC
|
|
568
629
|
LIMIT 1`)).rows[0].table_schema;
|
|
569
|
-
const types2 = (await this.query(
|
|
630
|
+
const types2 = (await this.query(sql`
|
|
570
631
|
SELECT jsonb_object_agg(column_name, udt_name) AS column_types
|
|
571
632
|
FROM information_schema.columns
|
|
572
633
|
WHERE
|
|
@@ -574,7 +635,7 @@ class Db {
|
|
|
574
635
|
table_schema = ${tableSchema}`)).rows[0].column_types;
|
|
575
636
|
if (!types2)
|
|
576
637
|
throw Error(`pg.missing_table ${table}`);
|
|
577
|
-
const verDefault = (await this.query(
|
|
638
|
+
const verDefault = (await this.query(sql`
|
|
578
639
|
SELECT column_default
|
|
579
640
|
FROM information_schema.columns
|
|
580
641
|
WHERE
|
package/index.mjs
CHANGED
|
@@ -1,7 +1,69 @@
|
|
|
1
1
|
import { encodePath, isEmpty, isPlainObject, unwrap, decodeArgs, decodeQuery, finalize, wrap, isRange, decodeGraph, mergeObject, merge, encodeGraph, wrapObject, remove } from "@graffy/common";
|
|
2
2
|
import pg$1 from "pg";
|
|
3
|
-
import sql, { join, raw, Sql, empty } from "sql-template-tag";
|
|
4
3
|
import debug from "debug";
|
|
4
|
+
class Sql {
|
|
5
|
+
constructor(rawStrings, rawValues) {
|
|
6
|
+
if (rawStrings.length - 1 !== rawValues.length) {
|
|
7
|
+
if (rawStrings.length === 0) {
|
|
8
|
+
throw new TypeError("Expected at least 1 string");
|
|
9
|
+
}
|
|
10
|
+
throw new TypeError(`Expected ${rawStrings.length} strings to have ${rawStrings.length - 1} values`);
|
|
11
|
+
}
|
|
12
|
+
const valuesLength = rawValues.reduce((len, value) => len + (value instanceof Sql ? value.values.length : 1), 0);
|
|
13
|
+
this.values = new Array(valuesLength);
|
|
14
|
+
this.strings = new Array(valuesLength + 1);
|
|
15
|
+
this.strings[0] = rawStrings[0];
|
|
16
|
+
let i = 0, pos = 0;
|
|
17
|
+
while (i < rawValues.length) {
|
|
18
|
+
const child = rawValues[i++];
|
|
19
|
+
const rawString = rawStrings[i];
|
|
20
|
+
if (child instanceof Sql) {
|
|
21
|
+
this.strings[pos] += child.strings[0];
|
|
22
|
+
let childIndex = 0;
|
|
23
|
+
while (childIndex < child.values.length) {
|
|
24
|
+
this.values[pos++] = child.values[childIndex++];
|
|
25
|
+
this.strings[pos] = child.strings[childIndex];
|
|
26
|
+
}
|
|
27
|
+
this.strings[pos] += rawString;
|
|
28
|
+
} else {
|
|
29
|
+
this.values[pos++] = child;
|
|
30
|
+
this.strings[pos] = rawString;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
get text() {
|
|
35
|
+
let i = 1, value = this.strings[0];
|
|
36
|
+
while (i < this.strings.length)
|
|
37
|
+
value += `$${i}${this.strings[i++]}`;
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
40
|
+
get sql() {
|
|
41
|
+
let i = 1, value = this.strings[0];
|
|
42
|
+
while (i < this.strings.length)
|
|
43
|
+
value += `?${this.strings[i++]}`;
|
|
44
|
+
return value;
|
|
45
|
+
}
|
|
46
|
+
inspect() {
|
|
47
|
+
return {
|
|
48
|
+
text: this.text,
|
|
49
|
+
sql: this.sql,
|
|
50
|
+
values: this.values
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function join(values, separator = ",", prefix = "", suffix = "") {
|
|
55
|
+
if (values.length === 0) {
|
|
56
|
+
throw new TypeError("Expected `join([])` to be called with an array of multiple elements, but got an empty array");
|
|
57
|
+
}
|
|
58
|
+
return new Sql([prefix, ...Array(values.length - 1).fill(separator), suffix], values);
|
|
59
|
+
}
|
|
60
|
+
function raw(value) {
|
|
61
|
+
return new Sql([value], []);
|
|
62
|
+
}
|
|
63
|
+
const empty = raw("");
|
|
64
|
+
function sql(strings, ...values) {
|
|
65
|
+
return new Sql(strings, values);
|
|
66
|
+
}
|
|
5
67
|
const valid = {
|
|
6
68
|
$eq: true,
|
|
7
69
|
$lt: true,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graffy/pg",
|
|
3
3
|
"description": "The standard Postgres module for Graffy. Each instance this module mounts a Postgres table as a Graffy subtree.",
|
|
4
4
|
"author": "aravind (https://github.com/aravindet)",
|
|
5
|
-
"version": "0.15.25-alpha.
|
|
5
|
+
"version": "0.15.25-alpha.6",
|
|
6
6
|
"main": "./index.cjs",
|
|
7
7
|
"exports": {
|
|
8
8
|
"import": "./index.mjs",
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"license": "Apache-2.0",
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@graffy/common": "0.15.25-alpha.
|
|
20
|
-
"sql-template-tag": "^5.0.3",
|
|
19
|
+
"@graffy/common": "0.15.25-alpha.6",
|
|
21
20
|
"debug": "^4.3.3"
|
|
22
21
|
},
|
|
23
22
|
"peerDependencies": {
|