@graffy/pg 0.16.20-alpha.9 → 0.16.21-alpha.1
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 +82 -11
- package/index.mjs +82 -11
- package/package.json +3 -3
- package/types/Db.d.ts +2 -2
- package/types/sql/format.d.ts +1 -0
package/index.cjs
CHANGED
|
@@ -79,6 +79,20 @@ const empty = raw("");
|
|
|
79
79
|
function sql(strings, ...values) {
|
|
80
80
|
return new Sql(strings, values);
|
|
81
81
|
}
|
|
82
|
+
function formatSql(sql2) {
|
|
83
|
+
const strings = sql2.strings.slice(0);
|
|
84
|
+
const values = sql2.values.slice(0);
|
|
85
|
+
const output = [];
|
|
86
|
+
while (strings.length) {
|
|
87
|
+
output.push(strings.shift().replace(/\s+/g, " "));
|
|
88
|
+
if (!values.length) break;
|
|
89
|
+
const value = values.shift();
|
|
90
|
+
output.push(
|
|
91
|
+
typeof value === "number" ? value.toString() : typeof value === "object" ? `'${JSON.stringify(value)}'` : `'${value}'`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
return output.join("").trim();
|
|
95
|
+
}
|
|
82
96
|
const getJsonBuildTrusted = (variadic) => {
|
|
83
97
|
const args = join(
|
|
84
98
|
Object.entries(variadic).map(([name, value]) => {
|
|
@@ -116,6 +130,33 @@ const aggSql = {
|
|
|
116
130
|
$max: (prop) => sql`max((${lookupNumeric(prop)})::numeric)`,
|
|
117
131
|
$min: (prop) => sql`min((${lookupNumeric(prop)})::numeric)`
|
|
118
132
|
};
|
|
133
|
+
const getOptimisedJsonBuild = (object, path, parentPropertyName, options) => {
|
|
134
|
+
const propertyNames = Object.keys(object);
|
|
135
|
+
const propertyPath = [...path, parentPropertyName];
|
|
136
|
+
const buildConfig = [];
|
|
137
|
+
path = path || [];
|
|
138
|
+
propertyNames.forEach((propertyName) => {
|
|
139
|
+
const property = object[propertyName];
|
|
140
|
+
if (typeof property === "object") {
|
|
141
|
+
const childJSONBuild = getOptimisedJsonBuild(
|
|
142
|
+
property,
|
|
143
|
+
propertyPath,
|
|
144
|
+
propertyName,
|
|
145
|
+
options
|
|
146
|
+
);
|
|
147
|
+
buildConfig.push(
|
|
148
|
+
sql`${propertyName}::text, jsonb_build_object(${join(childJSONBuild, ", ")})`
|
|
149
|
+
);
|
|
150
|
+
} else {
|
|
151
|
+
if (property === true) {
|
|
152
|
+
buildConfig.push(
|
|
153
|
+
sql`${propertyName}::text, ${lookup([...propertyPath, propertyName].join("."), options)}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
return buildConfig;
|
|
159
|
+
};
|
|
119
160
|
const getSelectCols = (options, projection = null) => {
|
|
120
161
|
if (!projection) return sql`*`;
|
|
121
162
|
const sqls = [];
|
|
@@ -130,11 +171,23 @@ const getSelectCols = (options, projection = null) => {
|
|
|
130
171
|
sqls.push(
|
|
131
172
|
sql`jsonb_build_object(${join(subSqls, ", ")}) AS "${raw(key)}"`
|
|
132
173
|
);
|
|
174
|
+
}
|
|
175
|
+
if (key[0] === "$") continue;
|
|
176
|
+
if (typeof projection[key] === "object") {
|
|
177
|
+
const optimisedJsonBuild = getOptimisedJsonBuild(
|
|
178
|
+
projection[key],
|
|
179
|
+
[],
|
|
180
|
+
key,
|
|
181
|
+
options
|
|
182
|
+
);
|
|
183
|
+
sqls.push(
|
|
184
|
+
sql`jsonb_build_object(${join(optimisedJsonBuild, ", ")}) AS "${raw(key)}"`
|
|
185
|
+
);
|
|
133
186
|
} else {
|
|
134
187
|
sqls.push(sql`"${raw(key)}"`);
|
|
135
188
|
}
|
|
136
189
|
}
|
|
137
|
-
return join(sqls, ", ")
|
|
190
|
+
return sqls.length ? join(sqls, ", ") : sql`TRUE AS "$"`;
|
|
138
191
|
};
|
|
139
192
|
function vertexSql(array, nullValue) {
|
|
140
193
|
return sql`array[${join(
|
|
@@ -715,7 +768,7 @@ class Db {
|
|
|
715
768
|
/*
|
|
716
769
|
Adds .schema to tableOptions if it doesn't exist yet.
|
|
717
770
|
It mutates the argument, to "persist" the results and
|
|
718
|
-
avoid this query in every operation.
|
|
771
|
+
avoid this query in every operation.
|
|
719
772
|
*/
|
|
720
773
|
async ensureSchema(tableOptions, typeOids) {
|
|
721
774
|
if (tableOptions.schema) return;
|
|
@@ -766,19 +819,33 @@ class Db {
|
|
|
766
819
|
const prefix = common.encodePath(rawPrefix);
|
|
767
820
|
await this.ensureSchema(tableOptions);
|
|
768
821
|
const getByArgs = async (args, projection) => {
|
|
769
|
-
const
|
|
770
|
-
|
|
771
|
-
tableOptions
|
|
772
|
-
);
|
|
822
|
+
const sql2 = selectByArgs(args, projection, tableOptions);
|
|
823
|
+
const result = await this.readSql(sql2, tableOptions);
|
|
773
824
|
const wrappedGraph = common.encodeGraph(common.wrapObject(result, rawPrefix));
|
|
774
825
|
log("getByArgs", wrappedGraph);
|
|
775
826
|
common.merge(results, wrappedGraph);
|
|
776
827
|
};
|
|
777
|
-
const
|
|
778
|
-
const
|
|
779
|
-
|
|
780
|
-
|
|
828
|
+
const explainArgs = async (args, projection) => {
|
|
829
|
+
const { $analyze, ...qArgs } = args.$explain;
|
|
830
|
+
const qSql = selectByArgs(qArgs, null, tableOptions);
|
|
831
|
+
const sql$1 = sql`EXPLAIN (${$analyze ? sql`ANALYZE, BUFFERS, TIMING, ` : sql``}COSTS, VERBOSE, FORMAT JSON) ${qSql}`;
|
|
832
|
+
const result = await this.readSql(sql$1, tableOptions);
|
|
833
|
+
const wrappedGraph = common.encodeGraph(
|
|
834
|
+
common.wrapObject(
|
|
835
|
+
{
|
|
836
|
+
$key: args,
|
|
837
|
+
sql: formatSql(qSql),
|
|
838
|
+
plan: result[0]["QUERY PLAN"][0]
|
|
839
|
+
},
|
|
840
|
+
rawPrefix
|
|
841
|
+
)
|
|
781
842
|
);
|
|
843
|
+
log("explainArgs", wrappedGraph);
|
|
844
|
+
common.merge(results, wrappedGraph);
|
|
845
|
+
};
|
|
846
|
+
const getByIds = async () => {
|
|
847
|
+
const sql2 = selectByIds(Object.keys(idQueries), null, tableOptions);
|
|
848
|
+
const result = await this.readSql(sql2, tableOptions);
|
|
782
849
|
for (const object of result) {
|
|
783
850
|
const wrappedGraph = common.encodeGraph(common.wrapObject(object, rawPrefix));
|
|
784
851
|
log("getByIds", wrappedGraph);
|
|
@@ -797,7 +864,11 @@ class Db {
|
|
|
797
864
|
}
|
|
798
865
|
} else {
|
|
799
866
|
const projection = node.children ? common.decodeQuery(node.children) : null;
|
|
800
|
-
|
|
867
|
+
if (args.$explain) {
|
|
868
|
+
promises.push(explainArgs(args));
|
|
869
|
+
} else {
|
|
870
|
+
promises.push(getByArgs(args, projection));
|
|
871
|
+
}
|
|
801
872
|
}
|
|
802
873
|
} else {
|
|
803
874
|
idQueries[args] = node.children;
|
package/index.mjs
CHANGED
|
@@ -77,6 +77,20 @@ const empty = raw("");
|
|
|
77
77
|
function sql(strings, ...values) {
|
|
78
78
|
return new Sql(strings, values);
|
|
79
79
|
}
|
|
80
|
+
function formatSql(sql2) {
|
|
81
|
+
const strings = sql2.strings.slice(0);
|
|
82
|
+
const values = sql2.values.slice(0);
|
|
83
|
+
const output = [];
|
|
84
|
+
while (strings.length) {
|
|
85
|
+
output.push(strings.shift().replace(/\s+/g, " "));
|
|
86
|
+
if (!values.length) break;
|
|
87
|
+
const value = values.shift();
|
|
88
|
+
output.push(
|
|
89
|
+
typeof value === "number" ? value.toString() : typeof value === "object" ? `'${JSON.stringify(value)}'` : `'${value}'`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
return output.join("").trim();
|
|
93
|
+
}
|
|
80
94
|
const getJsonBuildTrusted = (variadic) => {
|
|
81
95
|
const args = join(
|
|
82
96
|
Object.entries(variadic).map(([name, value]) => {
|
|
@@ -114,6 +128,33 @@ const aggSql = {
|
|
|
114
128
|
$max: (prop) => sql`max((${lookupNumeric(prop)})::numeric)`,
|
|
115
129
|
$min: (prop) => sql`min((${lookupNumeric(prop)})::numeric)`
|
|
116
130
|
};
|
|
131
|
+
const getOptimisedJsonBuild = (object, path, parentPropertyName, options) => {
|
|
132
|
+
const propertyNames = Object.keys(object);
|
|
133
|
+
const propertyPath = [...path, parentPropertyName];
|
|
134
|
+
const buildConfig = [];
|
|
135
|
+
path = path || [];
|
|
136
|
+
propertyNames.forEach((propertyName) => {
|
|
137
|
+
const property = object[propertyName];
|
|
138
|
+
if (typeof property === "object") {
|
|
139
|
+
const childJSONBuild = getOptimisedJsonBuild(
|
|
140
|
+
property,
|
|
141
|
+
propertyPath,
|
|
142
|
+
propertyName,
|
|
143
|
+
options
|
|
144
|
+
);
|
|
145
|
+
buildConfig.push(
|
|
146
|
+
sql`${propertyName}::text, jsonb_build_object(${join(childJSONBuild, ", ")})`
|
|
147
|
+
);
|
|
148
|
+
} else {
|
|
149
|
+
if (property === true) {
|
|
150
|
+
buildConfig.push(
|
|
151
|
+
sql`${propertyName}::text, ${lookup([...propertyPath, propertyName].join("."), options)}`
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
return buildConfig;
|
|
157
|
+
};
|
|
117
158
|
const getSelectCols = (options, projection = null) => {
|
|
118
159
|
if (!projection) return sql`*`;
|
|
119
160
|
const sqls = [];
|
|
@@ -128,11 +169,23 @@ const getSelectCols = (options, projection = null) => {
|
|
|
128
169
|
sqls.push(
|
|
129
170
|
sql`jsonb_build_object(${join(subSqls, ", ")}) AS "${raw(key)}"`
|
|
130
171
|
);
|
|
172
|
+
}
|
|
173
|
+
if (key[0] === "$") continue;
|
|
174
|
+
if (typeof projection[key] === "object") {
|
|
175
|
+
const optimisedJsonBuild = getOptimisedJsonBuild(
|
|
176
|
+
projection[key],
|
|
177
|
+
[],
|
|
178
|
+
key,
|
|
179
|
+
options
|
|
180
|
+
);
|
|
181
|
+
sqls.push(
|
|
182
|
+
sql`jsonb_build_object(${join(optimisedJsonBuild, ", ")}) AS "${raw(key)}"`
|
|
183
|
+
);
|
|
131
184
|
} else {
|
|
132
185
|
sqls.push(sql`"${raw(key)}"`);
|
|
133
186
|
}
|
|
134
187
|
}
|
|
135
|
-
return join(sqls, ", ")
|
|
188
|
+
return sqls.length ? join(sqls, ", ") : sql`TRUE AS "$"`;
|
|
136
189
|
};
|
|
137
190
|
function vertexSql(array, nullValue) {
|
|
138
191
|
return sql`array[${join(
|
|
@@ -713,7 +766,7 @@ class Db {
|
|
|
713
766
|
/*
|
|
714
767
|
Adds .schema to tableOptions if it doesn't exist yet.
|
|
715
768
|
It mutates the argument, to "persist" the results and
|
|
716
|
-
avoid this query in every operation.
|
|
769
|
+
avoid this query in every operation.
|
|
717
770
|
*/
|
|
718
771
|
async ensureSchema(tableOptions, typeOids) {
|
|
719
772
|
if (tableOptions.schema) return;
|
|
@@ -764,19 +817,33 @@ class Db {
|
|
|
764
817
|
const prefix = encodePath(rawPrefix);
|
|
765
818
|
await this.ensureSchema(tableOptions);
|
|
766
819
|
const getByArgs = async (args, projection) => {
|
|
767
|
-
const
|
|
768
|
-
|
|
769
|
-
tableOptions
|
|
770
|
-
);
|
|
820
|
+
const sql2 = selectByArgs(args, projection, tableOptions);
|
|
821
|
+
const result = await this.readSql(sql2, tableOptions);
|
|
771
822
|
const wrappedGraph = encodeGraph(wrapObject(result, rawPrefix));
|
|
772
823
|
log("getByArgs", wrappedGraph);
|
|
773
824
|
merge(results, wrappedGraph);
|
|
774
825
|
};
|
|
775
|
-
const
|
|
776
|
-
const
|
|
777
|
-
|
|
778
|
-
|
|
826
|
+
const explainArgs = async (args, projection) => {
|
|
827
|
+
const { $analyze, ...qArgs } = args.$explain;
|
|
828
|
+
const qSql = selectByArgs(qArgs, null, tableOptions);
|
|
829
|
+
const sql$1 = sql`EXPLAIN (${$analyze ? sql`ANALYZE, BUFFERS, TIMING, ` : sql``}COSTS, VERBOSE, FORMAT JSON) ${qSql}`;
|
|
830
|
+
const result = await this.readSql(sql$1, tableOptions);
|
|
831
|
+
const wrappedGraph = encodeGraph(
|
|
832
|
+
wrapObject(
|
|
833
|
+
{
|
|
834
|
+
$key: args,
|
|
835
|
+
sql: formatSql(qSql),
|
|
836
|
+
plan: result[0]["QUERY PLAN"][0]
|
|
837
|
+
},
|
|
838
|
+
rawPrefix
|
|
839
|
+
)
|
|
779
840
|
);
|
|
841
|
+
log("explainArgs", wrappedGraph);
|
|
842
|
+
merge(results, wrappedGraph);
|
|
843
|
+
};
|
|
844
|
+
const getByIds = async () => {
|
|
845
|
+
const sql2 = selectByIds(Object.keys(idQueries), null, tableOptions);
|
|
846
|
+
const result = await this.readSql(sql2, tableOptions);
|
|
780
847
|
for (const object of result) {
|
|
781
848
|
const wrappedGraph = encodeGraph(wrapObject(object, rawPrefix));
|
|
782
849
|
log("getByIds", wrappedGraph);
|
|
@@ -795,7 +862,11 @@ class Db {
|
|
|
795
862
|
}
|
|
796
863
|
} else {
|
|
797
864
|
const projection = node.children ? decodeQuery(node.children) : null;
|
|
798
|
-
|
|
865
|
+
if (args.$explain) {
|
|
866
|
+
promises.push(explainArgs(args));
|
|
867
|
+
} else {
|
|
868
|
+
promises.push(getByArgs(args, projection));
|
|
869
|
+
}
|
|
799
870
|
}
|
|
800
871
|
} else {
|
|
801
872
|
idQueries[args] = node.children;
|
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.21-alpha.1",
|
|
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.16.
|
|
20
|
-
"debug": "^4.3.
|
|
19
|
+
"@graffy/common": "0.16.21-alpha.1",
|
|
20
|
+
"debug": "^4.3.3"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"pg": "^8.0.0"
|
package/types/Db.d.ts
CHANGED
|
@@ -6,8 +6,8 @@ export default class Db {
|
|
|
6
6
|
writeSql(sql: any, tableOptions: any): Promise<any>;
|
|
7
7
|
ensureSchema(tableOptions: any, typeOids: any): Promise<void>;
|
|
8
8
|
read(rootQuery: any, tableOptions: any): Promise<{
|
|
9
|
-
key: Uint8Array
|
|
10
|
-
end: Uint8Array
|
|
9
|
+
key: Uint8Array<ArrayBuffer>;
|
|
10
|
+
end: Uint8Array<ArrayBuffer>;
|
|
11
11
|
version: number;
|
|
12
12
|
}[]>;
|
|
13
13
|
write(rootChange: any, tableOptions: any): Promise<any[]>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function formatSql(sql: any): string;
|