@graffy/pg 0.16.14 → 0.16.15-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
@@ -34,17 +34,29 @@ class Sql {
34
34
  }
35
35
  }
36
36
  get text() {
37
- let i = 1, value = this.strings[0];
38
- while (i < this.strings.length)
37
+ const len = this.strings.length;
38
+ let i = 1;
39
+ let value = this.strings[0];
40
+ while (i < len)
39
41
  value += `$${i}${this.strings[i++]}`;
40
42
  return value;
41
43
  }
42
44
  get sql() {
43
- let i = 1, value = this.strings[0];
44
- while (i < this.strings.length)
45
+ const len = this.strings.length;
46
+ let i = 1;
47
+ let value = this.strings[0];
48
+ while (i < len)
45
49
  value += `?${this.strings[i++]}`;
46
50
  return value;
47
51
  }
52
+ get statement() {
53
+ const len = this.strings.length;
54
+ let i = 1;
55
+ let value = this.strings[0];
56
+ while (i < len)
57
+ value += `:${i}${this.strings[i++]}`;
58
+ return value;
59
+ }
48
60
  inspect() {
49
61
  return {
50
62
  text: this.text,
@@ -90,7 +102,7 @@ const lookup = (prop, options) => {
90
102
  return sql`"${raw(prefix)}" #> ${suffix}`;
91
103
  }
92
104
  if (types2[prefix] === "cube" && suffix.length === 1) {
93
- return sql`"${raw(prefix)}" ~> ${parseInt(suffix[0])}`;
105
+ return sql`"${raw(prefix)}" ~> ${Number.parseInt(suffix[0])}`;
94
106
  }
95
107
  throw Error(`pg.cannot_lookup ${prop}`);
96
108
  };
@@ -149,7 +161,7 @@ function castValue(value, type, name, isPut) {
149
161
  if (value === null)
150
162
  return sql`NULL`;
151
163
  if (type === "jsonb") {
152
- return isPut ? JSON.stringify(stripAttributes(value)) : getJsonUpdate(value, name, []);
164
+ return isPut ? JSON.stringify(stripAttributes(value)) : getJsonUpdate(value, name, [])[0];
153
165
  }
154
166
  if (type === "cube")
155
167
  return cubeLiteralSql(value);
@@ -208,20 +220,37 @@ const getUpdates = (row, options) => {
208
220
  };
209
221
  function getJsonUpdate(object, col, path) {
210
222
  if (!object || typeof object !== "object" || Array.isArray(object) || object.$put) {
211
- return getJsonBuildValue(object);
223
+ const patch2 = stripAttributes(object);
224
+ return [sql`${JSON.stringify(patch2)}::jsonb`, patch2 === null];
225
+ }
226
+ if ("$val" in object) {
227
+ const value = object.$val === true ? stripAttributes(object) : object.$val;
228
+ return [sql`${JSON.stringify({ $val: value })}::jsonb`, false];
212
229
  }
213
230
  const curr = sql`"${raw(col)}"${path.length ? sql`#>${path}` : empty}`;
214
231
  if (common.isEmpty(object))
215
- return curr;
216
- return sql`nullif(jsonb_strip_nulls((case jsonb_typeof(${curr})
232
+ return [curr, false];
233
+ const baseSql = sql`case jsonb_typeof(${curr})
217
234
  when 'object' then ${curr}
218
235
  else '{}'::jsonb
219
- end) || jsonb_build_object(${join(
220
- Object.entries(object).map(
221
- ([key, value]) => sql`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`
222
- ),
223
- ", "
224
- )})), '{}'::jsonb)`;
236
+ end`;
237
+ let maybeNull = true;
238
+ let hasNulls = false;
239
+ const patchSqls = Object.entries(object).map(([key, value]) => {
240
+ const [valSql, nullable] = getJsonUpdate(value, col, path.concat(key));
241
+ maybeNull && (maybeNull = nullable);
242
+ hasNulls || (hasNulls = nullable);
243
+ return sql`${key}::text, ${valSql}`;
244
+ });
245
+ let clause = sql`${baseSql} || jsonb_build_object(${join(patchSqls, ", ")})`;
246
+ if (hasNulls) {
247
+ clause = sql`(select jsonb_object_agg(key, value)
248
+ from jsonb_each(${clause}) where value <> 'null'::jsonb)`;
249
+ }
250
+ if (maybeNull) {
251
+ clause = sql`nullif(${clause}, '{}'::jsonb)`;
252
+ }
253
+ return [clause, maybeNull];
225
254
  }
226
255
  function stripAttributes(object) {
227
256
  if (typeof object !== "object" || !object)
@@ -386,6 +415,7 @@ function simplify(node) {
386
415
  }
387
416
  const opSql = {
388
417
  $and: "AND",
418
+ // Not SQL as these are used as delimiters
389
419
  $or: "OR",
390
420
  $not: sql`NOT`,
391
421
  $eq: sql`=`,
@@ -675,17 +705,17 @@ class Db {
675
705
  async query(sql2, tableOptions) {
676
706
  var _a, _b;
677
707
  log(`Making SQL query: ${sql2.text}`, sql2.values);
678
- const cubeOid = parseInt(((_b = (_a = tableOptions == null ? void 0 : tableOptions.schema) == null ? void 0 : _a.typeOids) == null ? void 0 : _b.cube) || "0") || null;
708
+ const cubeOid = Number.parseInt(((_b = (_a = tableOptions == null ? void 0 : tableOptions.schema) == null ? void 0 : _a.typeOids) == null ? void 0 : _b.cube) || "0") || null;
679
709
  try {
680
710
  sql2.types = {
681
711
  getTypeParser: (oid, format) => {
682
712
  if (oid === types.builtins.INT8) {
683
- return (value) => parseInt(value, 10);
713
+ return (value) => Number.parseInt(value, 10);
684
714
  }
685
715
  if (oid === cubeOid) {
686
716
  return (value) => {
687
717
  const array = value.slice(1, -1).split(/\)\s*,\s*\(/).map(
688
- (corner) => corner.split(",").map((coord) => parseFloat(coord.trim()))
718
+ (corner) => corner.split(",").map((coord) => Number.parseFloat(coord.trim()))
689
719
  );
690
720
  return array.length > 1 ? array : array[0];
691
721
  };
@@ -719,6 +749,11 @@ class Db {
719
749
  }
720
750
  return res.rows;
721
751
  }
752
+ /*
753
+ Adds .schema to tableOptions if it doesn't exist yet.
754
+ It mutates the argument, to "persist" the results and
755
+ avoid this query in every operation.
756
+ */
722
757
  async ensureSchema(tableOptions, typeOids) {
723
758
  if (tableOptions.schema)
724
759
  return;
package/index.mjs CHANGED
@@ -32,17 +32,29 @@ class Sql {
32
32
  }
33
33
  }
34
34
  get text() {
35
- let i = 1, value = this.strings[0];
36
- while (i < this.strings.length)
35
+ const len = this.strings.length;
36
+ let i = 1;
37
+ let value = this.strings[0];
38
+ while (i < len)
37
39
  value += `$${i}${this.strings[i++]}`;
38
40
  return value;
39
41
  }
40
42
  get sql() {
41
- let i = 1, value = this.strings[0];
42
- while (i < this.strings.length)
43
+ const len = this.strings.length;
44
+ let i = 1;
45
+ let value = this.strings[0];
46
+ while (i < len)
43
47
  value += `?${this.strings[i++]}`;
44
48
  return value;
45
49
  }
50
+ get statement() {
51
+ const len = this.strings.length;
52
+ let i = 1;
53
+ let value = this.strings[0];
54
+ while (i < len)
55
+ value += `:${i}${this.strings[i++]}`;
56
+ return value;
57
+ }
46
58
  inspect() {
47
59
  return {
48
60
  text: this.text,
@@ -88,7 +100,7 @@ const lookup = (prop, options) => {
88
100
  return sql`"${raw(prefix)}" #> ${suffix}`;
89
101
  }
90
102
  if (types2[prefix] === "cube" && suffix.length === 1) {
91
- return sql`"${raw(prefix)}" ~> ${parseInt(suffix[0])}`;
103
+ return sql`"${raw(prefix)}" ~> ${Number.parseInt(suffix[0])}`;
92
104
  }
93
105
  throw Error(`pg.cannot_lookup ${prop}`);
94
106
  };
@@ -147,7 +159,7 @@ function castValue(value, type, name, isPut) {
147
159
  if (value === null)
148
160
  return sql`NULL`;
149
161
  if (type === "jsonb") {
150
- return isPut ? JSON.stringify(stripAttributes(value)) : getJsonUpdate(value, name, []);
162
+ return isPut ? JSON.stringify(stripAttributes(value)) : getJsonUpdate(value, name, [])[0];
151
163
  }
152
164
  if (type === "cube")
153
165
  return cubeLiteralSql(value);
@@ -206,20 +218,37 @@ const getUpdates = (row, options) => {
206
218
  };
207
219
  function getJsonUpdate(object, col, path) {
208
220
  if (!object || typeof object !== "object" || Array.isArray(object) || object.$put) {
209
- return getJsonBuildValue(object);
221
+ const patch2 = stripAttributes(object);
222
+ return [sql`${JSON.stringify(patch2)}::jsonb`, patch2 === null];
223
+ }
224
+ if ("$val" in object) {
225
+ const value = object.$val === true ? stripAttributes(object) : object.$val;
226
+ return [sql`${JSON.stringify({ $val: value })}::jsonb`, false];
210
227
  }
211
228
  const curr = sql`"${raw(col)}"${path.length ? sql`#>${path}` : empty}`;
212
229
  if (isEmpty(object))
213
- return curr;
214
- return sql`nullif(jsonb_strip_nulls((case jsonb_typeof(${curr})
230
+ return [curr, false];
231
+ const baseSql = sql`case jsonb_typeof(${curr})
215
232
  when 'object' then ${curr}
216
233
  else '{}'::jsonb
217
- end) || jsonb_build_object(${join(
218
- Object.entries(object).map(
219
- ([key, value]) => sql`${key}::text, ${getJsonUpdate(value, col, path.concat(key))}`
220
- ),
221
- ", "
222
- )})), '{}'::jsonb)`;
234
+ end`;
235
+ let maybeNull = true;
236
+ let hasNulls = false;
237
+ const patchSqls = Object.entries(object).map(([key, value]) => {
238
+ const [valSql, nullable] = getJsonUpdate(value, col, path.concat(key));
239
+ maybeNull && (maybeNull = nullable);
240
+ hasNulls || (hasNulls = nullable);
241
+ return sql`${key}::text, ${valSql}`;
242
+ });
243
+ let clause = sql`${baseSql} || jsonb_build_object(${join(patchSqls, ", ")})`;
244
+ if (hasNulls) {
245
+ clause = sql`(select jsonb_object_agg(key, value)
246
+ from jsonb_each(${clause}) where value <> 'null'::jsonb)`;
247
+ }
248
+ if (maybeNull) {
249
+ clause = sql`nullif(${clause}, '{}'::jsonb)`;
250
+ }
251
+ return [clause, maybeNull];
223
252
  }
224
253
  function stripAttributes(object) {
225
254
  if (typeof object !== "object" || !object)
@@ -384,6 +413,7 @@ function simplify(node) {
384
413
  }
385
414
  const opSql = {
386
415
  $and: "AND",
416
+ // Not SQL as these are used as delimiters
387
417
  $or: "OR",
388
418
  $not: sql`NOT`,
389
419
  $eq: sql`=`,
@@ -673,17 +703,17 @@ class Db {
673
703
  async query(sql2, tableOptions) {
674
704
  var _a, _b;
675
705
  log(`Making SQL query: ${sql2.text}`, sql2.values);
676
- const cubeOid = parseInt(((_b = (_a = tableOptions == null ? void 0 : tableOptions.schema) == null ? void 0 : _a.typeOids) == null ? void 0 : _b.cube) || "0") || null;
706
+ const cubeOid = Number.parseInt(((_b = (_a = tableOptions == null ? void 0 : tableOptions.schema) == null ? void 0 : _a.typeOids) == null ? void 0 : _b.cube) || "0") || null;
677
707
  try {
678
708
  sql2.types = {
679
709
  getTypeParser: (oid, format) => {
680
710
  if (oid === types.builtins.INT8) {
681
- return (value) => parseInt(value, 10);
711
+ return (value) => Number.parseInt(value, 10);
682
712
  }
683
713
  if (oid === cubeOid) {
684
714
  return (value) => {
685
715
  const array = value.slice(1, -1).split(/\)\s*,\s*\(/).map(
686
- (corner) => corner.split(",").map((coord) => parseFloat(coord.trim()))
716
+ (corner) => corner.split(",").map((coord) => Number.parseFloat(coord.trim()))
687
717
  );
688
718
  return array.length > 1 ? array : array[0];
689
719
  };
@@ -717,6 +747,11 @@ class Db {
717
747
  }
718
748
  return res.rows;
719
749
  }
750
+ /*
751
+ Adds .schema to tableOptions if it doesn't exist yet.
752
+ It mutates the argument, to "persist" the results and
753
+ avoid this query in every operation.
754
+ */
720
755
  async ensureSchema(tableOptions, typeOids) {
721
756
  if (tableOptions.schema)
722
757
  return;
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.16.14",
5
+ "version": "0.16.15-alpha.2",
6
6
  "main": "./index.cjs",
7
7
  "exports": {
8
8
  "import": "./index.mjs",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "dependencies": {
19
- "@graffy/common": "0.16.14",
19
+ "@graffy/common": "0.16.15-alpha.2",
20
20
  "debug": "^4.3.3"
21
21
  },
22
22
  "peerDependencies": {
package/types/Db.d.ts CHANGED
@@ -5,6 +5,10 @@ export default class Db {
5
5
  readSql(sql: any, tableOptions: any): Promise<any>;
6
6
  writeSql(sql: any, tableOptions: any): Promise<any>;
7
7
  ensureSchema(tableOptions: any, typeOids: any): Promise<void>;
8
- read(rootQuery: any, tableOptions: any): Promise<any>;
8
+ read(rootQuery: any, tableOptions: any): Promise<{
9
+ key: Uint8Array;
10
+ end: Uint8Array;
11
+ version: number;
12
+ }[]>;
9
13
  write(rootChange: any, tableOptions: any): Promise<any[]>;
10
14
  }
@@ -9,4 +9,4 @@ export function getInsert(rows: any, options: any): {
9
9
  updates: Sql;
10
10
  };
11
11
  export function getUpdates(row: any, options: any): Sql;
12
- import { Sql } from "sql-template-tag";
12
+ import { Sql } from 'sql-template-tag';