@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 +53 -18
- package/index.mjs +53 -18
- package/package.json +2 -2
- package/types/Db.d.ts +5 -1
- package/types/sql/clauses.d.ts +1 -1
package/index.cjs
CHANGED
|
@@ -34,17 +34,29 @@ class Sql {
|
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
get text() {
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
|
|
232
|
+
return [curr, false];
|
|
233
|
+
const baseSql = sql`case jsonb_typeof(${curr})
|
|
217
234
|
when 'object' then ${curr}
|
|
218
235
|
else '{}'::jsonb
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
36
|
-
|
|
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
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
230
|
+
return [curr, false];
|
|
231
|
+
const baseSql = sql`case jsonb_typeof(${curr})
|
|
215
232
|
when 'object' then ${curr}
|
|
216
233
|
else '{}'::jsonb
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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.
|
|
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.
|
|
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<
|
|
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
|
}
|
package/types/sql/clauses.d.ts
CHANGED