@graffy/pg 0.15.24-alpha.1 → 0.15.25-alpha.2

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 CHANGED
@@ -1,43 +1,13 @@
1
1
  "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
6
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
- var __spreadValues = (a, b) => {
8
- for (var prop in b || (b = {}))
9
- if (__hasOwnProp.call(b, prop))
10
- __defNormalProp(a, prop, b[prop]);
11
- if (__getOwnPropSymbols)
12
- for (var prop of __getOwnPropSymbols(b)) {
13
- if (__propIsEnum.call(b, prop))
14
- __defNormalProp(a, prop, b[prop]);
15
- }
16
- return a;
17
- };
18
- var __objRest = (source, exclude) => {
19
- var target = {};
20
- for (var prop in source)
21
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
22
- target[prop] = source[prop];
23
- if (source != null && __getOwnPropSymbols)
24
- for (var prop of __getOwnPropSymbols(source)) {
25
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
26
- target[prop] = source[prop];
27
- }
28
- return target;
29
- };
30
- Object.defineProperty(exports, "__esModule", { value: true });
31
- exports[Symbol.toStringTag] = "Module";
32
- var common = require("@graffy/common");
33
- var pg$1 = require("pg");
34
- var sql = require("sql-template-tag");
35
- var debug = require("debug");
36
- function _interopDefaultLegacy(e) {
37
- return e && typeof e === "object" && "default" in e ? e : { "default": e };
38
- }
39
- var sql__default = /* @__PURE__ */ _interopDefaultLegacy(sql);
40
- var debug__default = /* @__PURE__ */ _interopDefaultLegacy(debug);
2
+ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
+ const common = require("@graffy/common");
4
+ const pg$1 = require("pg");
5
+ const sql = require("sql-template-tag");
6
+ const debug = require("debug");
7
+ const _interopDefaultLegacy = (e) => e && typeof e === "object" && "default" in e ? e : { default: e };
8
+ const pg__default = /* @__PURE__ */ _interopDefaultLegacy(pg$1);
9
+ const sql__default = /* @__PURE__ */ _interopDefaultLegacy(sql);
10
+ const debug__default = /* @__PURE__ */ _interopDefaultLegacy(debug);
41
11
  const valid = {
42
12
  $eq: true,
43
13
  $lt: true,
@@ -129,22 +99,27 @@ function simplify(node) {
129
99
  return !node[1];
130
100
  }
131
101
  if (op === "$or") {
132
- const { eqmap, noneq, change } = node[1].reduce((acc, item) => {
133
- if (item[0] !== "$eq") {
134
- acc.noneq.push(item);
135
- } else if (acc.eqmap[item[1]]) {
136
- acc.change = true;
137
- acc.eqmap[item[1]].push(item[2]);
102
+ const { eqmap, noneq, change } = node[1].reduce(
103
+ (acc, item) => {
104
+ if (item[0] !== "$eq") {
105
+ acc.noneq.push(item);
106
+ } else if (acc.eqmap[item[1]]) {
107
+ acc.change = true;
108
+ acc.eqmap[item[1]].push(item[2]);
109
+ return acc;
110
+ } else {
111
+ acc.eqmap[item[1]] = [item[2]];
112
+ }
138
113
  return acc;
139
- } else {
140
- acc.eqmap[item[1]] = [item[2]];
141
- }
142
- return acc;
143
- }, { eqmap: {}, noneq: [], change: false });
114
+ },
115
+ { eqmap: {}, noneq: [], change: false }
116
+ );
144
117
  if (change) {
145
118
  node[1] = [
146
119
  ...noneq,
147
- ...Object.entries(eqmap).map(([prop, val]) => val.length > 1 ? ["$in", prop, val] : ["$eq", prop, val[0]])
120
+ ...Object.entries(eqmap).map(
121
+ ([prop, val]) => val.length > 1 ? ["$in", prop, val] : ["$eq", prop, val[0]]
122
+ )
148
123
  ];
149
124
  }
150
125
  }
@@ -159,56 +134,71 @@ function simplify(node) {
159
134
  return node;
160
135
  }
161
136
  const getJsonBuildTrusted = (variadic) => {
162
- const args = sql.join(Object.entries(variadic).map(([name, value]) => {
163
- return sql__default["default"]`'${sql.raw(name)}', ${getJsonBuildValue(value)}`;
164
- }));
165
- return sql__default["default"]`jsonb_build_object(${args})`;
137
+ const args = sql.join(
138
+ Object.entries(variadic).map(([name, value]) => {
139
+ return sql__default.default`'${sql.raw(name)}', ${getJsonBuildValue(value)}`;
140
+ })
141
+ );
142
+ return sql__default.default`jsonb_build_object(${args})`;
166
143
  };
167
144
  const getJsonBuildValue = (value) => {
168
145
  if (value instanceof sql.Sql)
169
146
  return value;
170
147
  if (typeof value === "string")
171
- return sql__default["default"]`${value}::text`;
172
- return sql__default["default"]`${JSON.stringify(stripAttributes(value))}::jsonb`;
148
+ return sql__default.default`${value}::text`;
149
+ return sql__default.default`${JSON.stringify(stripAttributes(value))}::jsonb`;
173
150
  };
174
151
  const lookup = (prop) => {
175
152
  const [prefix, ...suffix] = common.encodePath(prop);
176
- return suffix.length ? sql__default["default"]`"${sql.raw(prefix)}" #> ${suffix}` : sql__default["default"]`"${sql.raw(prefix)}"`;
153
+ return suffix.length ? sql__default.default`"${sql.raw(prefix)}" #> ${suffix}` : sql__default.default`"${sql.raw(prefix)}"`;
154
+ };
155
+ const lookupNumeric = (prop) => {
156
+ const [prefix, ...suffix] = common.encodePath(prop);
157
+ return suffix.length ? sql__default.default`CASE WHEN "${sql.raw(prefix)}" #> ${suffix} = 'null'::jsonb THEN 0 ELSE ("${sql.raw(
158
+ prefix
159
+ )}" #> ${suffix})::numeric END` : sql__default.default`"${sql.raw(prefix)}"`;
177
160
  };
178
161
  const aggSql = {
179
- $sum: (prop) => sql__default["default"]`sum((${lookup(prop)})::numeric)`,
180
- $card: (prop) => sql__default["default"]`count(distinct(${lookup(prop)}))`,
181
- $avg: (prop) => sql__default["default"]`avg((${lookup(prop)})::numeric)`,
182
- $max: (prop) => sql__default["default"]`max((${lookup(prop)})::numeric)`,
183
- $min: (prop) => sql__default["default"]`min((${lookup(prop)})::numeric)`
162
+ $sum: (prop) => sql__default.default`sum((${lookupNumeric(prop)})::numeric)`,
163
+ $card: (prop) => sql__default.default`count(distinct(${lookup(prop)}))`,
164
+ $avg: (prop) => sql__default.default`avg((${lookupNumeric(prop)})::numeric)`,
165
+ $max: (prop) => sql__default.default`max((${lookupNumeric(prop)})::numeric)`,
166
+ $min: (prop) => sql__default.default`min((${lookupNumeric(prop)})::numeric)`
184
167
  };
185
168
  const getSelectCols = (table, projection = null) => {
186
169
  if (!projection)
187
- return sql__default["default"]`to_jsonb("${sql.raw(table)}")`;
170
+ return sql__default.default`*`;
188
171
  const sqls = [];
189
172
  for (const key in projection) {
190
173
  if (key === "$count") {
191
- sqls.push(sql__default["default"]`'$count', count(*)`);
174
+ sqls.push(sql__default.default`count(*) AS "$count"`);
192
175
  } else if (aggSql[key]) {
193
176
  const subSqls = [];
194
177
  for (const prop in projection[key]) {
195
- subSqls.push(sql__default["default"]`${prop}::text, ${aggSql[key](prop)}`);
178
+ subSqls.push(sql__default.default`${prop}::text, ${aggSql[key](prop)}`);
196
179
  }
197
- sqls.push(sql__default["default"]`${key}::text, jsonb_build_object(${sql.join(subSqls, ", ")})`);
180
+ sqls.push(
181
+ sql__default.default`jsonb_build_object(${sql.join(subSqls, ", ")}) AS "${sql.raw(key)}"`
182
+ );
198
183
  } else {
199
- sqls.push(sql__default["default"]`${key}::text, "${sql.raw(key)}"`);
184
+ sqls.push(sql__default.default`"${sql.raw(key)}"`);
200
185
  }
201
186
  }
202
- return sql__default["default"]`jsonb_build_object(${sql.join(sqls, ", ")})`;
187
+ return sql.join(sqls, ", ");
203
188
  };
204
189
  function vertexSql(array, nullValue) {
205
- return sql__default["default"]`array[${sql.join(array.map((num) => num === null ? nullValue : num))}]::float8[]`;
190
+ return sql__default.default`array[${sql.join(
191
+ array.map((num) => num === null ? nullValue : num)
192
+ )}]::float8[]`;
206
193
  }
207
194
  function cubeLiteralSql(value) {
208
195
  if (!Array.isArray(value) || !value.length || Array.isArray(value[0]) && value.length !== 2) {
209
196
  throw Error("pg.castValue_bad_cube" + JSON.stringify(value));
210
197
  }
211
- return Array.isArray(value[0]) ? sql__default["default"]`cube(${vertexSql(value[0], sql__default["default"]`'-Infinity'`)}, ${vertexSql(value[1], sql__default["default"]`'Infinity'`)})` : sql__default["default"]`cube(${vertexSql(value, 0)})`;
198
+ return Array.isArray(value[0]) ? sql__default.default`cube(${vertexSql(value[0], sql__default.default`'-Infinity'`)}, ${vertexSql(
199
+ value[1],
200
+ sql__default.default`'Infinity'`
201
+ )})` : sql__default.default`cube(${vertexSql(value, 0)})`;
212
202
  }
213
203
  function castValue(value, type, name, isPut) {
214
204
  if (!type)
@@ -216,9 +206,9 @@ function castValue(value, type, name, isPut) {
216
206
  if (value instanceof sql.Sql)
217
207
  return value;
218
208
  if (value === null)
219
- return sql__default["default"]`NULL`;
209
+ return sql__default.default`NULL`;
220
210
  if (type === "jsonb") {
221
- return isPut ? JSON.stringify(stripAttributes(value)) : sql__default["default"]`jsonb_strip_nulls(${getJsonUpdate(value, name, [])})`;
211
+ return isPut ? JSON.stringify(stripAttributes(value)) : sql__default.default`jsonb_strip_nulls(${getJsonUpdate(value, name, [])})`;
222
212
  }
223
213
  if (type === "cube")
224
214
  return cubeLiteralSql(value);
@@ -227,26 +217,41 @@ function castValue(value, type, name, isPut) {
227
217
  const getInsert = (row, options) => {
228
218
  const cols = [];
229
219
  const vals = [];
230
- Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol, sql__default["default"]`default`]]).forEach(([col, val]) => {
231
- cols.push(sql__default["default"]`"${sql.raw(col)}"`);
220
+ Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol, sql__default.default`default`]]).forEach(([col, val]) => {
221
+ cols.push(sql__default.default`"${sql.raw(col)}"`);
232
222
  vals.push(castValue(val, options.schema.types[col], col, row.$put));
233
223
  });
234
224
  return { cols: sql.join(cols, ", "), vals: sql.join(vals, ", ") };
235
225
  };
236
226
  const getUpdates = (row, options) => {
237
- return sql.join(Object.entries(row).filter(([col]) => col !== options.idCol && col[0] !== "$").map(([col, val]) => sql__default["default"]`"${sql.raw(col)}" = ${castValue(val, options.schema.types[col], col, row.$put)}`).concat(sql__default["default"]`"${sql.raw(options.verCol)}" = default`), ", ");
227
+ return sql.join(
228
+ Object.entries(row).filter(([col]) => col !== options.idCol && col[0] !== "$").map(
229
+ ([col, val]) => sql__default.default`"${sql.raw(col)}" = ${castValue(
230
+ val,
231
+ options.schema.types[col],
232
+ col,
233
+ row.$put
234
+ )}`
235
+ ).concat(sql__default.default`"${sql.raw(options.verCol)}" = default`),
236
+ ", "
237
+ );
238
238
  };
239
239
  function getJsonUpdate(object, col, path) {
240
240
  if (!object || typeof object !== "object" || Array.isArray(object) || object.$put) {
241
241
  return getJsonBuildValue(object);
242
242
  }
243
- const curr = sql__default["default"]`"${sql.raw(col)}"${path.length ? sql__default["default"]`#>${path}` : sql.empty}`;
243
+ const curr = sql__default.default`"${sql.raw(col)}"${path.length ? sql__default.default`#>${path}` : sql.empty}`;
244
244
  if (common.isEmpty(object))
245
245
  return curr;
246
- return sql__default["default"]`(case jsonb_typeof(${curr})
246
+ return sql__default.default`(case jsonb_typeof(${curr})
247
247
  when 'object' then ${curr}
248
248
  else '{}'::jsonb
249
- end) || jsonb_build_object(${sql.join(Object.entries(object).map(([key, value]) => sql__default["default"]`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`), ", ")})`;
249
+ end) || jsonb_build_object(${sql.join(
250
+ Object.entries(object).map(
251
+ ([key, value]) => sql__default.default`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`
252
+ ),
253
+ ", "
254
+ )})`;
250
255
  }
251
256
  function stripAttributes(object) {
252
257
  if (typeof object !== "object" || !object)
@@ -264,50 +269,50 @@ function stripAttributes(object) {
264
269
  const opSql = {
265
270
  $and: `AND`,
266
271
  $or: `OR`,
267
- $not: sql__default["default"]`NOT`,
268
- $eq: sql__default["default"]`=`,
269
- $neq: sql__default["default"]`<>`,
270
- $in: sql__default["default"]`IN`,
271
- $nin: sql__default["default"]`NOT IN`,
272
- $lt: sql__default["default"]`<`,
273
- $lte: sql__default["default"]`<=`,
274
- $gt: sql__default["default"]`>`,
275
- $gte: sql__default["default"]`>=`,
276
- $re: sql__default["default"]`~`,
277
- $ire: sql__default["default"]`~*`,
278
- $cts: sql__default["default"]`@>`,
279
- $ctd: sql__default["default"]`<@`
272
+ $not: sql__default.default`NOT`,
273
+ $eq: sql__default.default`=`,
274
+ $neq: sql__default.default`<>`,
275
+ $in: sql__default.default`IN`,
276
+ $nin: sql__default.default`NOT IN`,
277
+ $lt: sql__default.default`<`,
278
+ $lte: sql__default.default`<=`,
279
+ $gt: sql__default.default`>`,
280
+ $gte: sql__default.default`>=`,
281
+ $re: sql__default.default`~`,
282
+ $ire: sql__default.default`~*`,
283
+ $cts: sql__default.default`@>`,
284
+ $ctd: sql__default.default`<@`
280
285
  };
281
286
  function getBinarySql(lhs, type, op, value, textLhs) {
282
287
  if (value === null && op === "$eq")
283
- return sql__default["default"]`${lhs} IS NULL`;
288
+ return sql__default.default`${lhs} IS NULL`;
284
289
  if (value === null && op === "$neq")
285
- return sql__default["default"]`${lhs} IS NOT NULL`;
290
+ return sql__default.default`${lhs} IS NOT NULL`;
286
291
  const sqlOp = opSql[op];
287
292
  if (!sqlOp)
288
293
  throw Error("pg.getSql_unknown_operator " + op);
289
294
  if (op === "$in" || op === "$nin") {
290
295
  if (type === "jsonb" && typeof value[0] === "string")
291
296
  lhs = textLhs;
292
- return sql__default["default"]`${lhs} ${sqlOp} (${sql.join(value)})`;
297
+ return sql__default.default`${lhs} ${sqlOp} (${sql.join(value)})`;
293
298
  }
294
299
  if (op === "$re" || op === "$ire") {
295
300
  if (type === "jsonb") {
296
301
  lhs = textLhs;
297
302
  } else if (type !== "text") {
298
- lhs = sql__default["default"]`(${lhs})::text`;
303
+ lhs = sql__default.default`(${lhs})::text`;
299
304
  }
300
- return sql__default["default"]`${lhs} ${sqlOp} ${String(value)}`;
305
+ return sql__default.default`${lhs} ${sqlOp} ${String(value)}`;
301
306
  }
302
307
  if (type === "jsonb") {
303
308
  if (typeof value === "string") {
304
- return sql__default["default"]`${textLhs} ${sqlOp} ${value}`;
309
+ return sql__default.default`${textLhs} ${sqlOp} ${value}`;
305
310
  }
306
- return sql__default["default"]`${lhs} ${sqlOp} ${JSON.stringify(value)}::jsonb`;
311
+ return sql__default.default`${lhs} ${sqlOp} ${JSON.stringify(value)}::jsonb`;
307
312
  }
308
313
  if (type === "cube")
309
- return sql__default["default"]`${lhs} ${sqlOp} ${cubeLiteralSql(value)}`;
310
- return sql__default["default"]`${lhs} ${sqlOp} ${value}`;
314
+ return sql__default.default`${lhs} ${sqlOp} ${cubeLiteralSql(value)}`;
315
+ return sql__default.default`${lhs} ${sqlOp} ${value}`;
311
316
  }
312
317
  function getSql(filter, options) {
313
318
  function getNodeSql(ast) {
@@ -315,75 +320,79 @@ function getSql(filter, options) {
315
320
  return ast;
316
321
  const op = ast[0];
317
322
  if (op === "$and" || op === "$or") {
318
- return sql__default["default"]`(${sql.join(ast[1].map((node) => getNodeSql(node)), `) ${opSql[op]} (`)})`;
323
+ return sql__default.default`(${sql.join(
324
+ ast[1].map((node) => getNodeSql(node)),
325
+ `) ${opSql[op]} (`
326
+ )})`;
319
327
  } else if (op === "$not") {
320
- return sql__default["default"]`${opSql[op]} (${getNodeSql(ast[1])})`;
328
+ return sql__default.default`${opSql[op]} (${getNodeSql(ast[1])})`;
321
329
  }
322
330
  const [prefix, ...suffix] = common.encodePath(ast[1]);
323
- const { types } = options.schema;
324
- if (!types[prefix])
331
+ const { types: types2 } = options.schema;
332
+ if (!types2[prefix])
325
333
  throw Error("pg.no_column " + prefix);
326
- if (types[prefix] === "jsonb") {
334
+ if (types2[prefix] === "jsonb") {
327
335
  const [lhs, textLhs] = suffix.length ? [
328
- sql__default["default"]`"${sql.raw(prefix)}" #> ${suffix}`,
329
- sql__default["default"]`"${sql.raw(prefix)}" #>> ${suffix}`
330
- ] : [sql__default["default"]`"${sql.raw(prefix)}"`, sql__default["default"]`"${sql.raw(prefix)}" #>> '{}'`];
336
+ sql__default.default`"${sql.raw(prefix)}" #> ${suffix}`,
337
+ sql__default.default`"${sql.raw(prefix)}" #>> ${suffix}`
338
+ ] : [sql__default.default`"${sql.raw(prefix)}"`, sql__default.default`"${sql.raw(prefix)}" #>> '{}'`];
331
339
  return getBinarySql(lhs, "jsonb", op, ast[2], textLhs);
332
340
  } else {
333
341
  if (suffix.length)
334
342
  throw Error("pg.lookup_not_jsonb " + prefix);
335
- return getBinarySql(sql__default["default"]`"${sql.raw(prefix)}"`, types[prefix], op, ast[2]);
343
+ return getBinarySql(sql__default.default`"${sql.raw(prefix)}"`, types2[prefix], op, ast[2]);
336
344
  }
337
345
  }
338
346
  return getNodeSql(getAst(filter));
339
347
  }
340
- const getIdMeta = ({ idCol, verDefault }) => getJsonBuildTrusted({
341
- $key: sql__default["default"]`"${sql.raw(idCol)}"`,
342
- $ver: sql.raw(verDefault)
343
- });
344
- const getArgMeta = (key, { prefix, idCol, verDefault }) => getJsonBuildTrusted({
345
- $key: key,
346
- $ref: sql__default["default"]`jsonb_build_array(${sql.join(prefix.map((k) => sql__default["default"]`${k}::text`))}, "${sql.raw(idCol)}")`,
347
- $ver: sql.raw(verDefault)
348
- });
349
- const getAggMeta = (key, $group, { verDefault }) => {
350
- let $key = sql.join([key, getJsonBuildTrusted({ $group })].filter(Boolean), " || ");
351
- return getJsonBuildTrusted({
352
- $key,
353
- $ver: sql.raw(verDefault)
354
- });
355
- };
356
- function getArgSql(_a, options) {
357
- var _b = _a, { $first, $last, $after, $before, $since, $until, $all, $cursor: _ } = _b, rest = __objRest(_b, ["$first", "$last", "$after", "$before", "$since", "$until", "$all", "$cursor"]);
358
- const _a2 = rest, { $order, $group } = _a2, filter = __objRest(_a2, ["$order", "$group"]);
348
+ const getIdMeta = ({ idCol, verDefault }) => sql__default.default`"${sql.raw(idCol)}" AS "$key", ${sql.raw(verDefault)} AS "$ver"`;
349
+ const getArgMeta = (key, { prefix, idCol, verDefault }) => sql__default.default`
350
+ ${key} AS "$key",
351
+ ${sql.raw(verDefault)} AS "$ver",
352
+ array[
353
+ ${sql.join(prefix.map((k) => sql__default.default`${k}::text`))},
354
+ "${sql.raw(idCol)}"
355
+ ]::text[] AS "$ref"
356
+ `;
357
+ const getAggMeta = (key, { verDefault }) => sql__default.default`${key} AS "$key", ${sql.raw(verDefault)} AS "$ver"`;
358
+ function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $cursor: _, ...rest }, options) {
359
+ const { $order, $group, ...filter } = rest;
359
360
  const { prefix, idCol } = options;
361
+ const meta = (key2) => $group ? getAggMeta(key2, options) : getArgMeta(key2, options);
362
+ const hasRangeArg = $before || $after || $since || $until || $first || $last || $all;
360
363
  if ($order && $group) {
361
364
  throw Error("pg_arg.order_and_group_unsupported in " + prefix);
362
365
  }
363
- const meta = (key2) => $group ? getAggMeta(key2, $group, options) : getArgMeta(key2, options);
364
- const groupCols = Array.isArray($group) && $group.length && $group.map(lookup);
365
- const group = groupCols ? sql.join(groupCols, ", ") : void 0;
366
- const hasRangeArg = $before || $after || $since || $until || $first || $last || $all || $order;
367
- let filterKey;
366
+ if (($order || $group && $group !== true) && !hasRangeArg) {
367
+ throw Error("pg_arg.range_arg_expected in " + prefix);
368
+ }
369
+ const baseKey = sql__default.default`${JSON.stringify(rest)}::jsonb`;
368
370
  const where = [];
369
- if (!common.isEmpty(filter)) {
371
+ if (!common.isEmpty(filter))
370
372
  where.push(getSql(filter, options));
371
- filterKey = sql__default["default"]`${JSON.stringify(filter)}::jsonb`;
372
- }
373
373
  if (!hasRangeArg)
374
- return { meta: meta(filterKey), where, group, limit: 1 };
375
- const orderCols = ($order || [idCol]).map((orderItem) => orderItem[0] === "!" ? sql__default["default"]`-(${lookup(orderItem.slice(1))})::float8` : lookup(orderItem));
376
- Object.entries({ $after, $before, $since, $until }).forEach(([name, value]) => {
377
- if (value)
378
- where.push(getBoundCond(orderCols, value, name));
379
- });
380
- const order = !$group && sql.join(($order || [idCol]).map((orderItem) => orderItem[0] === "!" ? sql__default["default"]`${lookup(orderItem.slice(1))} ${$last ? sql__default["default"]`ASC` : sql__default["default"]`DESC`}` : sql__default["default"]`${lookup(orderItem)} ${$last ? sql__default["default"]`DESC` : sql__default["default"]`ASC`}`), `, `);
381
- const orderKey = $order && getJsonBuildTrusted({ $order: sql__default["default"]`${JSON.stringify($order)}::jsonb` });
382
- const cursorKey = $group !== true && getJsonBuildTrusted({
383
- $cursor: sql__default["default"]`jsonb_build_array(${sql.join(groupCols || orderCols)})`
374
+ return { meta: meta(baseKey), where, limit: 1 };
375
+ const groupCols = Array.isArray($group) && $group.length && $group.map(lookup);
376
+ const group = groupCols ? sql.join(groupCols, ", ") : void 0;
377
+ const orderCols = ($order || [idCol]).map(
378
+ (orderItem) => orderItem[0] === "!" ? sql__default.default`-(${lookup(orderItem.slice(1))})::float8` : lookup(orderItem)
379
+ );
380
+ Object.entries({ $after, $before, $since, $until }).forEach(
381
+ ([name, value]) => {
382
+ if (value)
383
+ where.push(getBoundCond(orderCols, value, name));
384
+ }
385
+ );
386
+ const order = !$group && sql.join(
387
+ ($order || [idCol]).map(
388
+ (orderItem) => orderItem[0] === "!" ? sql__default.default`${lookup(orderItem.slice(1))} ${$last ? sql__default.default`ASC` : sql__default.default`DESC`}` : sql__default.default`${lookup(orderItem)} ${$last ? sql__default.default`DESC` : sql__default.default`ASC`}`
389
+ ),
390
+ `, `
391
+ );
392
+ const cursorKey = getJsonBuildTrusted({
393
+ $cursor: $group === true ? sql__default.default`''` : sql__default.default`jsonb_build_array(${sql.join(groupCols || orderCols)})`
384
394
  });
385
- const keys = [filterKey, orderKey, cursorKey].filter(Boolean);
386
- const key = keys.length > 0 ? sql__default["default"]`(${sql.join(keys, ` || `)})` : void 0;
395
+ const key = sql__default.default`(${baseKey} || ${cursorKey})`;
387
396
  return {
388
397
  meta: meta(key),
389
398
  where,
@@ -403,21 +412,21 @@ function getBoundCond(orderCols, bound, kind) {
403
412
  switch (kind) {
404
413
  case "$after":
405
414
  case "$since":
406
- return sql__default["default"]`${lhs} > ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
415
+ return sql__default.default`${lhs} > ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
407
416
  case "$before":
408
417
  case "$until":
409
- return sql__default["default"]`${lhs} < ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
418
+ return sql__default.default`${lhs} < ${rhs} OR ${lhs} = ${rhs} AND (${subCond})`;
410
419
  }
411
420
  } else {
412
421
  switch (kind) {
413
422
  case "$after":
414
- return sql__default["default"]`${lhs} > ${rhs}`;
423
+ return sql__default.default`${lhs} > ${rhs}`;
415
424
  case "$since":
416
- return sql__default["default"]`${lhs} >= ${rhs}`;
425
+ return sql__default.default`${lhs} >= ${rhs}`;
417
426
  case "$before":
418
- return sql__default["default"]`${lhs} < ${rhs}`;
427
+ return sql__default.default`${lhs} < ${rhs}`;
419
428
  case "$until":
420
- return sql__default["default"]`${lhs} <= ${rhs}`;
429
+ return sql__default.default`${lhs} <= ${rhs}`;
421
430
  }
422
431
  }
423
432
  }
@@ -426,21 +435,21 @@ function selectByArgs(args, projection, options) {
426
435
  const { table } = options;
427
436
  const { where, order, group, limit, meta } = getArgSql(args, options);
428
437
  const clampedLimit = Math.min(MAX_LIMIT, limit || MAX_LIMIT);
429
- return sql__default["default"]`
438
+ return sql__default.default`
430
439
  SELECT
431
- ${getSelectCols(table, projection)} || ${meta}
440
+ ${getSelectCols(table, projection)}, ${meta}
432
441
  FROM "${sql.raw(table)}"
433
- ${where.length ? sql__default["default"]`WHERE ${sql.join(where, ` AND `)}` : sql.empty}
434
- ${group ? sql__default["default"]`GROUP BY ${group}` : sql.empty}
435
- ${order ? sql__default["default"]`ORDER BY ${order}` : sql.empty}
442
+ ${where.length ? sql__default.default`WHERE ${sql.join(where, ` AND `)}` : sql.empty}
443
+ ${group ? sql__default.default`GROUP BY ${group}` : sql.empty}
444
+ ${order ? sql__default.default`ORDER BY ${order}` : sql.empty}
436
445
  LIMIT ${clampedLimit}
437
446
  `;
438
447
  }
439
448
  function selectByIds(ids, projection, options) {
440
449
  const { table, idCol } = options;
441
- return sql__default["default"]`
450
+ return sql__default.default`
442
451
  SELECT
443
- ${getSelectCols(table, projection)} || ${getIdMeta(options)}
452
+ ${getSelectCols(table, projection)}, ${getIdMeta(options)}
444
453
  FROM "${sql.raw(table)}"
445
454
  WHERE "${sql.raw(idCol)}" IN (${sql.join(ids)})
446
455
  `;
@@ -449,7 +458,7 @@ function getSingleSql(arg, options) {
449
458
  const { table, idCol } = options;
450
459
  if (!common.isPlainObject(arg)) {
451
460
  return {
452
- where: sql__default["default"]`"${sql.raw(idCol)}" = ${arg}`,
461
+ where: sql__default.default`"${sql.raw(idCol)}" = ${arg}`,
453
462
  meta: getIdMeta(options)
454
463
  };
455
464
  }
@@ -457,7 +466,7 @@ function getSingleSql(arg, options) {
457
466
  if (!where || !where.length)
458
467
  throw Error("pg_write.no_condition");
459
468
  return {
460
- where: sql__default["default"]`"${sql.raw(idCol)}" = (
469
+ where: sql__default.default`"${sql.raw(idCol)}" = (
461
470
  SELECT "${sql.raw(idCol)}"
462
471
  FROM "${sql.raw(table)}"
463
472
  WHERE ${sql.join(where, ` AND `)}
@@ -470,10 +479,10 @@ function patch(object, arg, options) {
470
479
  const { table } = options;
471
480
  const { where, meta } = getSingleSql(arg, options);
472
481
  const row = object;
473
- return sql__default["default"]`
482
+ return sql__default.default`
474
483
  UPDATE "${sql.raw(table)}" SET ${getUpdates(row, options)}
475
484
  WHERE ${where}
476
- RETURNING (${getSelectCols(table)} || ${meta})`;
485
+ RETURNING ${getSelectCols()}, ${meta}`;
477
486
  }
478
487
  function put(object, arg, options) {
479
488
  const { idCol, table } = options;
@@ -481,38 +490,46 @@ function put(object, arg, options) {
481
490
  let meta, conflictTarget;
482
491
  if (common.isPlainObject(arg)) {
483
492
  ({ meta } = getArgSql(arg, options));
484
- conflictTarget = sql.join(Object.keys(arg).map((col) => sql__default["default"]`"${sql.raw(col)}"`));
493
+ conflictTarget = sql.join(Object.keys(arg).map((col) => sql__default.default`"${sql.raw(col)}"`));
485
494
  } else {
486
495
  meta = getIdMeta(options);
487
- conflictTarget = sql__default["default"]`"${sql.raw(idCol)}"`;
496
+ conflictTarget = sql__default.default`"${sql.raw(idCol)}"`;
488
497
  }
489
498
  const { cols, vals } = getInsert(row, options);
490
- return sql__default["default"]`
499
+ return sql__default.default`
491
500
  INSERT INTO "${sql.raw(table)}" (${cols}) VALUES (${vals})
492
501
  ON CONFLICT (${conflictTarget}) DO UPDATE SET (${cols}) = (${vals})
493
- RETURNING (${getSelectCols(table)} || ${meta})`;
502
+ RETURNING ${getSelectCols()}, ${meta}`;
494
503
  }
495
504
  function del(arg, options) {
496
505
  const { table } = options;
497
506
  const { where } = getSingleSql(arg, options);
498
- return sql__default["default"]`
507
+ return sql__default.default`
499
508
  DELETE FROM "${sql.raw(table)}"
500
509
  WHERE ${where}
501
- RETURNING (${getJsonBuildTrusted({ $key: arg })})`;
510
+ RETURNING ${arg} "$key"`;
502
511
  }
503
- const log = debug__default["default"]("graffy:pg:db");
512
+ const log = debug__default.default("graffy:pg:db");
513
+ const { Pool, Client, types } = pg__default.default;
504
514
  class Db {
505
515
  constructor(connection) {
506
- if (typeof connection === "object" && connection && (connection instanceof pg$1.Pool || connection instanceof pg$1.Client)) {
516
+ if (typeof connection === "object" && connection && (connection instanceof Pool || connection instanceof Client)) {
507
517
  this.client = connection;
508
518
  } else {
509
- this.client = new pg$1.Pool(connection);
519
+ this.client = new Pool(connection);
510
520
  }
511
521
  }
512
522
  async query(sql2) {
513
- sql2.rowMode = "array";
514
523
  log("Making SQL query: " + sql2.text, sql2.values);
515
524
  try {
525
+ sql2.types = {
526
+ getTypeParser: (oid, format) => {
527
+ if (oid === types.builtins.INT8) {
528
+ return (value) => parseInt(value, 10);
529
+ }
530
+ return types.getTypeParser(oid, format);
531
+ }
532
+ };
516
533
  return await this.client.query(sql2);
517
534
  } catch (e) {
518
535
  const message = [
@@ -527,7 +544,7 @@ class Db {
527
544
  }
528
545
  }
529
546
  async readSql(sql2) {
530
- const result = (await this.query(sql2)).rows.flat();
547
+ const result = (await this.query(sql2)).rows;
531
548
  log("Read result", result);
532
549
  return result;
533
550
  }
@@ -537,38 +554,38 @@ class Db {
537
554
  if (!res.rowCount) {
538
555
  throw Error("pg.nothing_written " + sql2.text + " with " + sql2.values);
539
556
  }
540
- return res.rows[0][0];
557
+ return res.rows[0];
541
558
  }
542
559
  async ensureSchema(tableOptions) {
543
560
  if (tableOptions.schema)
544
561
  return;
545
562
  const { table, verCol } = tableOptions;
546
- const tableSchema = (await this.query(sql__default["default"]`
563
+ const tableSchema = (await this.query(sql__default.default`
547
564
  SELECT table_schema
548
565
  FROM information_schema.tables
549
566
  WHERE table_name = ${table}
550
567
  ORDER BY array_position(current_schemas(false)::text[], table_schema::text) ASC
551
- LIMIT 1`)).rows[0][0];
552
- const types = (await this.query(sql__default["default"]`
553
- SELECT jsonb_object_agg(column_name, udt_name)
568
+ LIMIT 1`)).rows[0].table_schema;
569
+ const types2 = (await this.query(sql__default.default`
570
+ SELECT jsonb_object_agg(column_name, udt_name) AS column_types
554
571
  FROM information_schema.columns
555
572
  WHERE
556
573
  table_name = ${table} AND
557
- table_schema = ${tableSchema}`)).rows[0][0];
558
- if (!types)
574
+ table_schema = ${tableSchema}`)).rows[0].column_types;
575
+ if (!types2)
559
576
  throw Error(`pg.missing_table ${table}`);
560
- const verDefault = (await this.query(sql__default["default"]`
577
+ const verDefault = (await this.query(sql__default.default`
561
578
  SELECT column_default
562
579
  FROM information_schema.columns
563
580
  WHERE
564
581
  table_name = ${table} AND
565
582
  table_schema = ${tableSchema} AND
566
- column_name = ${verCol}`)).rows[0][0];
583
+ column_name = ${verCol}`)).rows[0].column_default;
567
584
  if (!verDefault) {
568
585
  throw Error(`pg.verCol_without_default ${verCol}`);
569
586
  }
570
- log("ensureSchema", types);
571
- tableOptions.schema = { types };
587
+ log("ensureSchema", types2);
588
+ tableOptions.schema = { types: types2 };
572
589
  tableOptions.verDefault = verDefault;
573
590
  }
574
591
  async read(rootQuery, tableOptions) {
@@ -578,13 +595,17 @@ class Db {
578
595
  const { prefix } = tableOptions;
579
596
  await this.ensureSchema(tableOptions);
580
597
  const getByArgs = async (args, projection) => {
581
- const result = await this.readSql(selectByArgs(args, projection, tableOptions));
598
+ const result = await this.readSql(
599
+ selectByArgs(args, projection, tableOptions)
600
+ );
582
601
  const wrappedGraph = common.encodeGraph(common.wrapObject(result, prefix));
583
602
  log("getByArgs", wrappedGraph);
584
603
  common.merge(results, wrappedGraph);
585
604
  };
586
605
  const getByIds = async () => {
587
- const result = await this.readSql(selectByIds(Object.keys(idQueries), null, tableOptions));
606
+ const result = await this.readSql(
607
+ selectByIds(Object.keys(idQueries), null, tableOptions)
608
+ );
588
609
  result.forEach((object) => {
589
610
  const wrappedGraph = common.encodeGraph(common.wrapObject(object, prefix));
590
611
  log("getByIds", wrappedGraph);
@@ -599,7 +620,7 @@ class Db {
599
620
  for (const childNode of node.children) {
600
621
  const childArgs = common.decodeArgs(childNode);
601
622
  const projection = childNode.children ? common.decodeQuery(childNode.children) : null;
602
- promises.push(getByArgs(__spreadValues(__spreadValues({}, args), childArgs), projection));
623
+ promises.push(getByArgs({ ...args, ...childArgs }, projection));
603
624
  }
604
625
  } else {
605
626
  const projection = node.children ? common.decodeQuery(node.children) : null;
@@ -638,9 +659,13 @@ class Db {
638
659
  return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
639
660
  });
640
661
  const result = [];
641
- await Promise.all(sqls.map((sql2) => this.writeSql(sql2).then((object) => {
642
- common.merge(result, common.encodeGraph(common.wrapObject(object, prefix)));
643
- })));
662
+ await Promise.all(
663
+ sqls.map(
664
+ (sql2) => this.writeSql(sql2).then((object) => {
665
+ common.merge(result, common.encodeGraph(common.wrapObject(object, prefix)));
666
+ })
667
+ )
668
+ );
644
669
  log("dbWrite", rootChange, result);
645
670
  return result;
646
671
  }
@@ -664,9 +689,11 @@ const pg = ({ table, idCol, verCol, connection, schema, verDefault }) => (store)
664
689
  const readPromise = db.read(query, tableOpts);
665
690
  const remainingQuery = common.remove(query, prefix);
666
691
  const nextPromise = next(remainingQuery);
667
- return Promise.all([readPromise, nextPromise]).then(([readRes, nextRes]) => {
668
- return common.merge(readRes, nextRes);
669
- });
692
+ return Promise.all([readPromise, nextPromise]).then(
693
+ ([readRes, nextRes]) => {
694
+ return common.merge(readRes, nextRes);
695
+ }
696
+ );
670
697
  }
671
698
  function write(change, options, next) {
672
699
  const { pgClient } = options;
@@ -674,9 +701,11 @@ const pg = ({ table, idCol, verCol, connection, schema, verDefault }) => (store)
674
701
  const writePromise = db.write(change, tableOpts);
675
702
  const remainingChange = common.remove(change, prefix);
676
703
  const nextPromise = next(remainingChange);
677
- return Promise.all([writePromise, nextPromise]).then(([writeRes, nextRes]) => {
678
- return common.merge(writeRes, nextRes);
679
- });
704
+ return Promise.all([writePromise, nextPromise]).then(
705
+ ([writeRes, nextRes]) => {
706
+ return common.merge(writeRes, nextRes);
707
+ }
708
+ );
680
709
  }
681
710
  };
682
711
  exports.pg = pg;
package/index.mjs CHANGED
@@ -1,33 +1,5 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
- var __hasOwnProp = Object.prototype.hasOwnProperty;
4
- var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __spreadValues = (a, b) => {
7
- for (var prop in b || (b = {}))
8
- if (__hasOwnProp.call(b, prop))
9
- __defNormalProp(a, prop, b[prop]);
10
- if (__getOwnPropSymbols)
11
- for (var prop of __getOwnPropSymbols(b)) {
12
- if (__propIsEnum.call(b, prop))
13
- __defNormalProp(a, prop, b[prop]);
14
- }
15
- return a;
16
- };
17
- var __objRest = (source, exclude) => {
18
- var target = {};
19
- for (var prop in source)
20
- if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
21
- target[prop] = source[prop];
22
- if (source != null && __getOwnPropSymbols)
23
- for (var prop of __getOwnPropSymbols(source)) {
24
- if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
25
- target[prop] = source[prop];
26
- }
27
- return target;
28
- };
29
- import { isEmpty, encodePath, isPlainObject, unwrap, decodeArgs, decodeQuery, finalize, wrap, isRange, decodeGraph, mergeObject, merge, encodeGraph, wrapObject, remove } from "@graffy/common";
30
- import { Pool, Client } from "pg";
1
+ import { encodePath, isEmpty, isPlainObject, unwrap, decodeArgs, decodeQuery, finalize, wrap, isRange, decodeGraph, mergeObject, merge, encodeGraph, wrapObject, remove } from "@graffy/common";
2
+ import pg$1 from "pg";
31
3
  import sql, { join, raw, Sql, empty } from "sql-template-tag";
32
4
  import debug from "debug";
33
5
  const valid = {
@@ -121,22 +93,27 @@ function simplify(node) {
121
93
  return !node[1];
122
94
  }
123
95
  if (op === "$or") {
124
- const { eqmap, noneq, change } = node[1].reduce((acc, item) => {
125
- if (item[0] !== "$eq") {
126
- acc.noneq.push(item);
127
- } else if (acc.eqmap[item[1]]) {
128
- acc.change = true;
129
- acc.eqmap[item[1]].push(item[2]);
96
+ const { eqmap, noneq, change } = node[1].reduce(
97
+ (acc, item) => {
98
+ if (item[0] !== "$eq") {
99
+ acc.noneq.push(item);
100
+ } else if (acc.eqmap[item[1]]) {
101
+ acc.change = true;
102
+ acc.eqmap[item[1]].push(item[2]);
103
+ return acc;
104
+ } else {
105
+ acc.eqmap[item[1]] = [item[2]];
106
+ }
130
107
  return acc;
131
- } else {
132
- acc.eqmap[item[1]] = [item[2]];
133
- }
134
- return acc;
135
- }, { eqmap: {}, noneq: [], change: false });
108
+ },
109
+ { eqmap: {}, noneq: [], change: false }
110
+ );
136
111
  if (change) {
137
112
  node[1] = [
138
113
  ...noneq,
139
- ...Object.entries(eqmap).map(([prop, val]) => val.length > 1 ? ["$in", prop, val] : ["$eq", prop, val[0]])
114
+ ...Object.entries(eqmap).map(
115
+ ([prop, val]) => val.length > 1 ? ["$in", prop, val] : ["$eq", prop, val[0]]
116
+ )
140
117
  ];
141
118
  }
142
119
  }
@@ -151,9 +128,11 @@ function simplify(node) {
151
128
  return node;
152
129
  }
153
130
  const getJsonBuildTrusted = (variadic) => {
154
- const args = join(Object.entries(variadic).map(([name, value]) => {
155
- return sql`'${raw(name)}', ${getJsonBuildValue(value)}`;
156
- }));
131
+ const args = join(
132
+ Object.entries(variadic).map(([name, value]) => {
133
+ return sql`'${raw(name)}', ${getJsonBuildValue(value)}`;
134
+ })
135
+ );
157
136
  return sql`jsonb_build_object(${args})`;
158
137
  };
159
138
  const getJsonBuildValue = (value) => {
@@ -167,40 +146,53 @@ const lookup = (prop) => {
167
146
  const [prefix, ...suffix] = encodePath(prop);
168
147
  return suffix.length ? sql`"${raw(prefix)}" #> ${suffix}` : sql`"${raw(prefix)}"`;
169
148
  };
149
+ const lookupNumeric = (prop) => {
150
+ const [prefix, ...suffix] = encodePath(prop);
151
+ return suffix.length ? sql`CASE WHEN "${raw(prefix)}" #> ${suffix} = 'null'::jsonb THEN 0 ELSE ("${raw(
152
+ prefix
153
+ )}" #> ${suffix})::numeric END` : sql`"${raw(prefix)}"`;
154
+ };
170
155
  const aggSql = {
171
- $sum: (prop) => sql`sum((${lookup(prop)})::numeric)`,
156
+ $sum: (prop) => sql`sum((${lookupNumeric(prop)})::numeric)`,
172
157
  $card: (prop) => sql`count(distinct(${lookup(prop)}))`,
173
- $avg: (prop) => sql`avg((${lookup(prop)})::numeric)`,
174
- $max: (prop) => sql`max((${lookup(prop)})::numeric)`,
175
- $min: (prop) => sql`min((${lookup(prop)})::numeric)`
158
+ $avg: (prop) => sql`avg((${lookupNumeric(prop)})::numeric)`,
159
+ $max: (prop) => sql`max((${lookupNumeric(prop)})::numeric)`,
160
+ $min: (prop) => sql`min((${lookupNumeric(prop)})::numeric)`
176
161
  };
177
162
  const getSelectCols = (table, projection = null) => {
178
163
  if (!projection)
179
- return sql`to_jsonb("${raw(table)}")`;
164
+ return sql`*`;
180
165
  const sqls = [];
181
166
  for (const key in projection) {
182
167
  if (key === "$count") {
183
- sqls.push(sql`'$count', count(*)`);
168
+ sqls.push(sql`count(*) AS "$count"`);
184
169
  } else if (aggSql[key]) {
185
170
  const subSqls = [];
186
171
  for (const prop in projection[key]) {
187
172
  subSqls.push(sql`${prop}::text, ${aggSql[key](prop)}`);
188
173
  }
189
- sqls.push(sql`${key}::text, jsonb_build_object(${join(subSqls, ", ")})`);
174
+ sqls.push(
175
+ sql`jsonb_build_object(${join(subSqls, ", ")}) AS "${raw(key)}"`
176
+ );
190
177
  } else {
191
- sqls.push(sql`${key}::text, "${raw(key)}"`);
178
+ sqls.push(sql`"${raw(key)}"`);
192
179
  }
193
180
  }
194
- return sql`jsonb_build_object(${join(sqls, ", ")})`;
181
+ return join(sqls, ", ");
195
182
  };
196
183
  function vertexSql(array, nullValue) {
197
- return sql`array[${join(array.map((num) => num === null ? nullValue : num))}]::float8[]`;
184
+ return sql`array[${join(
185
+ array.map((num) => num === null ? nullValue : num)
186
+ )}]::float8[]`;
198
187
  }
199
188
  function cubeLiteralSql(value) {
200
189
  if (!Array.isArray(value) || !value.length || Array.isArray(value[0]) && value.length !== 2) {
201
190
  throw Error("pg.castValue_bad_cube" + JSON.stringify(value));
202
191
  }
203
- return Array.isArray(value[0]) ? sql`cube(${vertexSql(value[0], sql`'-Infinity'`)}, ${vertexSql(value[1], sql`'Infinity'`)})` : sql`cube(${vertexSql(value, 0)})`;
192
+ return Array.isArray(value[0]) ? sql`cube(${vertexSql(value[0], sql`'-Infinity'`)}, ${vertexSql(
193
+ value[1],
194
+ sql`'Infinity'`
195
+ )})` : sql`cube(${vertexSql(value, 0)})`;
204
196
  }
205
197
  function castValue(value, type, name, isPut) {
206
198
  if (!type)
@@ -226,7 +218,17 @@ const getInsert = (row, options) => {
226
218
  return { cols: join(cols, ", "), vals: join(vals, ", ") };
227
219
  };
228
220
  const getUpdates = (row, options) => {
229
- return join(Object.entries(row).filter(([col]) => col !== options.idCol && col[0] !== "$").map(([col, val]) => sql`"${raw(col)}" = ${castValue(val, options.schema.types[col], col, row.$put)}`).concat(sql`"${raw(options.verCol)}" = default`), ", ");
221
+ return join(
222
+ Object.entries(row).filter(([col]) => col !== options.idCol && col[0] !== "$").map(
223
+ ([col, val]) => sql`"${raw(col)}" = ${castValue(
224
+ val,
225
+ options.schema.types[col],
226
+ col,
227
+ row.$put
228
+ )}`
229
+ ).concat(sql`"${raw(options.verCol)}" = default`),
230
+ ", "
231
+ );
230
232
  };
231
233
  function getJsonUpdate(object, col, path) {
232
234
  if (!object || typeof object !== "object" || Array.isArray(object) || object.$put) {
@@ -238,7 +240,12 @@ function getJsonUpdate(object, col, path) {
238
240
  return sql`(case jsonb_typeof(${curr})
239
241
  when 'object' then ${curr}
240
242
  else '{}'::jsonb
241
- end) || jsonb_build_object(${join(Object.entries(object).map(([key, value]) => sql`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`), ", ")})`;
243
+ end) || jsonb_build_object(${join(
244
+ Object.entries(object).map(
245
+ ([key, value]) => sql`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`
246
+ ),
247
+ ", "
248
+ )})`;
242
249
  }
243
250
  function stripAttributes(object) {
244
251
  if (typeof object !== "object" || !object)
@@ -307,15 +314,18 @@ function getSql(filter, options) {
307
314
  return ast;
308
315
  const op = ast[0];
309
316
  if (op === "$and" || op === "$or") {
310
- return sql`(${join(ast[1].map((node) => getNodeSql(node)), `) ${opSql[op]} (`)})`;
317
+ return sql`(${join(
318
+ ast[1].map((node) => getNodeSql(node)),
319
+ `) ${opSql[op]} (`
320
+ )})`;
311
321
  } else if (op === "$not") {
312
322
  return sql`${opSql[op]} (${getNodeSql(ast[1])})`;
313
323
  }
314
324
  const [prefix, ...suffix] = encodePath(ast[1]);
315
- const { types } = options.schema;
316
- if (!types[prefix])
325
+ const { types: types2 } = options.schema;
326
+ if (!types2[prefix])
317
327
  throw Error("pg.no_column " + prefix);
318
- if (types[prefix] === "jsonb") {
328
+ if (types2[prefix] === "jsonb") {
319
329
  const [lhs, textLhs] = suffix.length ? [
320
330
  sql`"${raw(prefix)}" #> ${suffix}`,
321
331
  sql`"${raw(prefix)}" #>> ${suffix}`
@@ -324,58 +334,59 @@ function getSql(filter, options) {
324
334
  } else {
325
335
  if (suffix.length)
326
336
  throw Error("pg.lookup_not_jsonb " + prefix);
327
- return getBinarySql(sql`"${raw(prefix)}"`, types[prefix], op, ast[2]);
337
+ return getBinarySql(sql`"${raw(prefix)}"`, types2[prefix], op, ast[2]);
328
338
  }
329
339
  }
330
340
  return getNodeSql(getAst(filter));
331
341
  }
332
- const getIdMeta = ({ idCol, verDefault }) => getJsonBuildTrusted({
333
- $key: sql`"${raw(idCol)}"`,
334
- $ver: raw(verDefault)
335
- });
336
- const getArgMeta = (key, { prefix, idCol, verDefault }) => getJsonBuildTrusted({
337
- $key: key,
338
- $ref: sql`jsonb_build_array(${join(prefix.map((k) => sql`${k}::text`))}, "${raw(idCol)}")`,
339
- $ver: raw(verDefault)
340
- });
341
- const getAggMeta = (key, $group, { verDefault }) => {
342
- let $key = join([key, getJsonBuildTrusted({ $group })].filter(Boolean), " || ");
343
- return getJsonBuildTrusted({
344
- $key,
345
- $ver: raw(verDefault)
346
- });
347
- };
348
- function getArgSql(_a, options) {
349
- var _b = _a, { $first, $last, $after, $before, $since, $until, $all, $cursor: _ } = _b, rest = __objRest(_b, ["$first", "$last", "$after", "$before", "$since", "$until", "$all", "$cursor"]);
350
- const _a2 = rest, { $order, $group } = _a2, filter = __objRest(_a2, ["$order", "$group"]);
342
+ const getIdMeta = ({ idCol, verDefault }) => sql`"${raw(idCol)}" AS "$key", ${raw(verDefault)} AS "$ver"`;
343
+ const getArgMeta = (key, { prefix, idCol, verDefault }) => sql`
344
+ ${key} AS "$key",
345
+ ${raw(verDefault)} AS "$ver",
346
+ array[
347
+ ${join(prefix.map((k) => sql`${k}::text`))},
348
+ "${raw(idCol)}"
349
+ ]::text[] AS "$ref"
350
+ `;
351
+ const getAggMeta = (key, { verDefault }) => sql`${key} AS "$key", ${raw(verDefault)} AS "$ver"`;
352
+ function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $cursor: _, ...rest }, options) {
353
+ const { $order, $group, ...filter } = rest;
351
354
  const { prefix, idCol } = options;
355
+ const meta = (key2) => $group ? getAggMeta(key2, options) : getArgMeta(key2, options);
356
+ const hasRangeArg = $before || $after || $since || $until || $first || $last || $all;
352
357
  if ($order && $group) {
353
358
  throw Error("pg_arg.order_and_group_unsupported in " + prefix);
354
359
  }
355
- const meta = (key2) => $group ? getAggMeta(key2, $group, options) : getArgMeta(key2, options);
356
- const groupCols = Array.isArray($group) && $group.length && $group.map(lookup);
357
- const group = groupCols ? join(groupCols, ", ") : void 0;
358
- const hasRangeArg = $before || $after || $since || $until || $first || $last || $all || $order;
359
- let filterKey;
360
+ if (($order || $group && $group !== true) && !hasRangeArg) {
361
+ throw Error("pg_arg.range_arg_expected in " + prefix);
362
+ }
363
+ const baseKey = sql`${JSON.stringify(rest)}::jsonb`;
360
364
  const where = [];
361
- if (!isEmpty(filter)) {
365
+ if (!isEmpty(filter))
362
366
  where.push(getSql(filter, options));
363
- filterKey = sql`${JSON.stringify(filter)}::jsonb`;
364
- }
365
367
  if (!hasRangeArg)
366
- return { meta: meta(filterKey), where, group, limit: 1 };
367
- const orderCols = ($order || [idCol]).map((orderItem) => orderItem[0] === "!" ? sql`-(${lookup(orderItem.slice(1))})::float8` : lookup(orderItem));
368
- Object.entries({ $after, $before, $since, $until }).forEach(([name, value]) => {
369
- if (value)
370
- where.push(getBoundCond(orderCols, value, name));
371
- });
372
- const order = !$group && join(($order || [idCol]).map((orderItem) => orderItem[0] === "!" ? sql`${lookup(orderItem.slice(1))} ${$last ? sql`ASC` : sql`DESC`}` : sql`${lookup(orderItem)} ${$last ? sql`DESC` : sql`ASC`}`), `, `);
373
- const orderKey = $order && getJsonBuildTrusted({ $order: sql`${JSON.stringify($order)}::jsonb` });
374
- const cursorKey = $group !== true && getJsonBuildTrusted({
375
- $cursor: sql`jsonb_build_array(${join(groupCols || orderCols)})`
368
+ return { meta: meta(baseKey), where, limit: 1 };
369
+ const groupCols = Array.isArray($group) && $group.length && $group.map(lookup);
370
+ const group = groupCols ? join(groupCols, ", ") : void 0;
371
+ const orderCols = ($order || [idCol]).map(
372
+ (orderItem) => orderItem[0] === "!" ? sql`-(${lookup(orderItem.slice(1))})::float8` : lookup(orderItem)
373
+ );
374
+ Object.entries({ $after, $before, $since, $until }).forEach(
375
+ ([name, value]) => {
376
+ if (value)
377
+ where.push(getBoundCond(orderCols, value, name));
378
+ }
379
+ );
380
+ const order = !$group && join(
381
+ ($order || [idCol]).map(
382
+ (orderItem) => orderItem[0] === "!" ? sql`${lookup(orderItem.slice(1))} ${$last ? sql`ASC` : sql`DESC`}` : sql`${lookup(orderItem)} ${$last ? sql`DESC` : sql`ASC`}`
383
+ ),
384
+ `, `
385
+ );
386
+ const cursorKey = getJsonBuildTrusted({
387
+ $cursor: $group === true ? sql`''` : sql`jsonb_build_array(${join(groupCols || orderCols)})`
376
388
  });
377
- const keys = [filterKey, orderKey, cursorKey].filter(Boolean);
378
- const key = keys.length > 0 ? sql`(${join(keys, ` || `)})` : void 0;
389
+ const key = sql`(${baseKey} || ${cursorKey})`;
379
390
  return {
380
391
  meta: meta(key),
381
392
  where,
@@ -420,7 +431,7 @@ function selectByArgs(args, projection, options) {
420
431
  const clampedLimit = Math.min(MAX_LIMIT, limit || MAX_LIMIT);
421
432
  return sql`
422
433
  SELECT
423
- ${getSelectCols(table, projection)} || ${meta}
434
+ ${getSelectCols(table, projection)}, ${meta}
424
435
  FROM "${raw(table)}"
425
436
  ${where.length ? sql`WHERE ${join(where, ` AND `)}` : empty}
426
437
  ${group ? sql`GROUP BY ${group}` : empty}
@@ -432,7 +443,7 @@ function selectByIds(ids, projection, options) {
432
443
  const { table, idCol } = options;
433
444
  return sql`
434
445
  SELECT
435
- ${getSelectCols(table, projection)} || ${getIdMeta(options)}
446
+ ${getSelectCols(table, projection)}, ${getIdMeta(options)}
436
447
  FROM "${raw(table)}"
437
448
  WHERE "${raw(idCol)}" IN (${join(ids)})
438
449
  `;
@@ -465,7 +476,7 @@ function patch(object, arg, options) {
465
476
  return sql`
466
477
  UPDATE "${raw(table)}" SET ${getUpdates(row, options)}
467
478
  WHERE ${where}
468
- RETURNING (${getSelectCols(table)} || ${meta})`;
479
+ RETURNING ${getSelectCols()}, ${meta}`;
469
480
  }
470
481
  function put(object, arg, options) {
471
482
  const { idCol, table } = options;
@@ -482,7 +493,7 @@ function put(object, arg, options) {
482
493
  return sql`
483
494
  INSERT INTO "${raw(table)}" (${cols}) VALUES (${vals})
484
495
  ON CONFLICT (${conflictTarget}) DO UPDATE SET (${cols}) = (${vals})
485
- RETURNING (${getSelectCols(table)} || ${meta})`;
496
+ RETURNING ${getSelectCols()}, ${meta}`;
486
497
  }
487
498
  function del(arg, options) {
488
499
  const { table } = options;
@@ -490,9 +501,10 @@ function del(arg, options) {
490
501
  return sql`
491
502
  DELETE FROM "${raw(table)}"
492
503
  WHERE ${where}
493
- RETURNING (${getJsonBuildTrusted({ $key: arg })})`;
504
+ RETURNING ${arg} "$key"`;
494
505
  }
495
506
  const log = debug("graffy:pg:db");
507
+ const { Pool, Client, types } = pg$1;
496
508
  class Db {
497
509
  constructor(connection) {
498
510
  if (typeof connection === "object" && connection && (connection instanceof Pool || connection instanceof Client)) {
@@ -502,9 +514,16 @@ class Db {
502
514
  }
503
515
  }
504
516
  async query(sql2) {
505
- sql2.rowMode = "array";
506
517
  log("Making SQL query: " + sql2.text, sql2.values);
507
518
  try {
519
+ sql2.types = {
520
+ getTypeParser: (oid, format) => {
521
+ if (oid === types.builtins.INT8) {
522
+ return (value) => parseInt(value, 10);
523
+ }
524
+ return types.getTypeParser(oid, format);
525
+ }
526
+ };
508
527
  return await this.client.query(sql2);
509
528
  } catch (e) {
510
529
  const message = [
@@ -519,7 +538,7 @@ class Db {
519
538
  }
520
539
  }
521
540
  async readSql(sql2) {
522
- const result = (await this.query(sql2)).rows.flat();
541
+ const result = (await this.query(sql2)).rows;
523
542
  log("Read result", result);
524
543
  return result;
525
544
  }
@@ -529,7 +548,7 @@ class Db {
529
548
  if (!res.rowCount) {
530
549
  throw Error("pg.nothing_written " + sql2.text + " with " + sql2.values);
531
550
  }
532
- return res.rows[0][0];
551
+ return res.rows[0];
533
552
  }
534
553
  async ensureSchema(tableOptions) {
535
554
  if (tableOptions.schema)
@@ -540,14 +559,14 @@ class Db {
540
559
  FROM information_schema.tables
541
560
  WHERE table_name = ${table}
542
561
  ORDER BY array_position(current_schemas(false)::text[], table_schema::text) ASC
543
- LIMIT 1`)).rows[0][0];
544
- const types = (await this.query(sql`
545
- SELECT jsonb_object_agg(column_name, udt_name)
562
+ LIMIT 1`)).rows[0].table_schema;
563
+ const types2 = (await this.query(sql`
564
+ SELECT jsonb_object_agg(column_name, udt_name) AS column_types
546
565
  FROM information_schema.columns
547
566
  WHERE
548
567
  table_name = ${table} AND
549
- table_schema = ${tableSchema}`)).rows[0][0];
550
- if (!types)
568
+ table_schema = ${tableSchema}`)).rows[0].column_types;
569
+ if (!types2)
551
570
  throw Error(`pg.missing_table ${table}`);
552
571
  const verDefault = (await this.query(sql`
553
572
  SELECT column_default
@@ -555,12 +574,12 @@ class Db {
555
574
  WHERE
556
575
  table_name = ${table} AND
557
576
  table_schema = ${tableSchema} AND
558
- column_name = ${verCol}`)).rows[0][0];
577
+ column_name = ${verCol}`)).rows[0].column_default;
559
578
  if (!verDefault) {
560
579
  throw Error(`pg.verCol_without_default ${verCol}`);
561
580
  }
562
- log("ensureSchema", types);
563
- tableOptions.schema = { types };
581
+ log("ensureSchema", types2);
582
+ tableOptions.schema = { types: types2 };
564
583
  tableOptions.verDefault = verDefault;
565
584
  }
566
585
  async read(rootQuery, tableOptions) {
@@ -570,13 +589,17 @@ class Db {
570
589
  const { prefix } = tableOptions;
571
590
  await this.ensureSchema(tableOptions);
572
591
  const getByArgs = async (args, projection) => {
573
- const result = await this.readSql(selectByArgs(args, projection, tableOptions));
592
+ const result = await this.readSql(
593
+ selectByArgs(args, projection, tableOptions)
594
+ );
574
595
  const wrappedGraph = encodeGraph(wrapObject(result, prefix));
575
596
  log("getByArgs", wrappedGraph);
576
597
  merge(results, wrappedGraph);
577
598
  };
578
599
  const getByIds = async () => {
579
- const result = await this.readSql(selectByIds(Object.keys(idQueries), null, tableOptions));
600
+ const result = await this.readSql(
601
+ selectByIds(Object.keys(idQueries), null, tableOptions)
602
+ );
580
603
  result.forEach((object) => {
581
604
  const wrappedGraph = encodeGraph(wrapObject(object, prefix));
582
605
  log("getByIds", wrappedGraph);
@@ -591,7 +614,7 @@ class Db {
591
614
  for (const childNode of node.children) {
592
615
  const childArgs = decodeArgs(childNode);
593
616
  const projection = childNode.children ? decodeQuery(childNode.children) : null;
594
- promises.push(getByArgs(__spreadValues(__spreadValues({}, args), childArgs), projection));
617
+ promises.push(getByArgs({ ...args, ...childArgs }, projection));
595
618
  }
596
619
  } else {
597
620
  const projection = node.children ? decodeQuery(node.children) : null;
@@ -630,9 +653,13 @@ class Db {
630
653
  return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
631
654
  });
632
655
  const result = [];
633
- await Promise.all(sqls.map((sql2) => this.writeSql(sql2).then((object) => {
634
- merge(result, encodeGraph(wrapObject(object, prefix)));
635
- })));
656
+ await Promise.all(
657
+ sqls.map(
658
+ (sql2) => this.writeSql(sql2).then((object) => {
659
+ merge(result, encodeGraph(wrapObject(object, prefix)));
660
+ })
661
+ )
662
+ );
636
663
  log("dbWrite", rootChange, result);
637
664
  return result;
638
665
  }
@@ -656,9 +683,11 @@ const pg = ({ table, idCol, verCol, connection, schema, verDefault }) => (store)
656
683
  const readPromise = db.read(query, tableOpts);
657
684
  const remainingQuery = remove(query, prefix);
658
685
  const nextPromise = next(remainingQuery);
659
- return Promise.all([readPromise, nextPromise]).then(([readRes, nextRes]) => {
660
- return merge(readRes, nextRes);
661
- });
686
+ return Promise.all([readPromise, nextPromise]).then(
687
+ ([readRes, nextRes]) => {
688
+ return merge(readRes, nextRes);
689
+ }
690
+ );
662
691
  }
663
692
  function write(change, options, next) {
664
693
  const { pgClient } = options;
@@ -666,9 +695,13 @@ const pg = ({ table, idCol, verCol, connection, schema, verDefault }) => (store)
666
695
  const writePromise = db.write(change, tableOpts);
667
696
  const remainingChange = remove(change, prefix);
668
697
  const nextPromise = next(remainingChange);
669
- return Promise.all([writePromise, nextPromise]).then(([writeRes, nextRes]) => {
670
- return merge(writeRes, nextRes);
671
- });
698
+ return Promise.all([writePromise, nextPromise]).then(
699
+ ([writeRes, nextRes]) => {
700
+ return merge(writeRes, nextRes);
701
+ }
702
+ );
672
703
  }
673
704
  };
674
- export { pg };
705
+ export {
706
+ pg
707
+ };
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.24-alpha.1",
5
+ "version": "0.15.25-alpha.2",
6
6
  "main": "./index.cjs",
7
7
  "exports": {
8
8
  "import": "./index.mjs",
@@ -16,8 +16,8 @@
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "dependencies": {
19
- "@graffy/common": "0.15.24-alpha.1",
20
- "sql-template-tag": "^4.1.0",
19
+ "@graffy/common": "0.15.25-alpha.2",
20
+ "sql-template-tag": "^5.0.3",
21
21
  "debug": "^4.3.3"
22
22
  },
23
23
  "peerDependencies": {
@@ -1,6 +1,7 @@
1
1
  export function cubeLiteralSql(value: any): Sql;
2
2
  export function getJsonBuildTrusted(variadic: any): Sql;
3
3
  export function lookup(prop: any): Sql;
4
+ export function lookupNumeric(prop: any): Sql;
4
5
  export function getSelectCols(table: any, projection?: any): Sql;
5
6
  export function getInsert(row: any, options: any): {
6
7
  cols: Sql;
@@ -2,14 +2,15 @@
2
2
  Uses the args object (typically passed in the $key attribute)
3
3
 
4
4
  @param {object} args
5
- @param {{prefix: string, idCol: string}} options
5
+ @param {{prefix: string, idCol: string, verDefault: string}} options
6
6
 
7
7
  @typedef { import('sql-template-tag').Sql } Sql
8
8
  @return {{ meta: Sql, where: Sql[], order?: Sql, group?: Sql, limit: number }}
9
9
  */
10
- export default function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $cursor: _, ...rest }: object, options: {
10
+ export default function getArgSql({ $first, $last, $after, $before, $since, $until, $all, $cursor, ...rest }: object, options: {
11
11
  prefix: string;
12
12
  idCol: string;
13
+ verDefault: string;
13
14
  }): {
14
15
  meta: Sql;
15
16
  where: Sql[];
@@ -7,6 +7,6 @@ export function getArgMeta(key: any, { prefix, idCol, verDefault }: {
7
7
  idCol: any;
8
8
  verDefault: any;
9
9
  }): import("sql-template-tag").Sql;
10
- export function getAggMeta(key: any, $group: any, { verDefault }: {
10
+ export function getAggMeta(key: any, { verDefault }: {
11
11
  verDefault: any;
12
12
  }): import("sql-template-tag").Sql;