leangraph 1.1.7 → 1.1.8
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/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +3 -6
- package/dist/auth.js.map +1 -1
- package/dist/db.d.ts +3 -1
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +38 -7
- package/dist/db.js.map +1 -1
- package/dist/executor.d.ts +1 -0
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +48 -36
- package/dist/executor.js.map +1 -1
- package/dist/parser.d.ts +2 -0
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +32 -12
- package/dist/parser.js.map +1 -1
- package/dist/routes.d.ts +1 -3
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +147 -102
- package/dist/routes.js.map +1 -1
- package/dist/translator.d.ts.map +1 -1
- package/dist/translator.js +105 -92
- package/dist/translator.js.map +1 -1
- package/package.json +1 -1
package/dist/translator.js
CHANGED
|
@@ -20,6 +20,15 @@ function toSqliteParam(value) {
|
|
|
20
20
|
function toSqliteParams(values) {
|
|
21
21
|
return values.map(toSqliteParam);
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Escape a string for safe interpolation inside a SQL string literal.
|
|
25
|
+
* Used for JSON path keys, label names, and other identifiers that are
|
|
26
|
+
* embedded directly in SQL rather than passed as bind parameters.
|
|
27
|
+
* Prevents SQL injection via backtick-quoted Cypher identifiers.
|
|
28
|
+
*/
|
|
29
|
+
function escSqlStr(s) {
|
|
30
|
+
return (s || "").replace(/'/g, "''");
|
|
31
|
+
}
|
|
23
32
|
/**
|
|
24
33
|
* Check if a string is an IANA timezone name (contains '/')
|
|
25
34
|
*/
|
|
@@ -314,15 +323,19 @@ export class Translator {
|
|
|
314
323
|
* The :Label is optional and ignored (global index) - only used if no custom name provided.
|
|
315
324
|
*/
|
|
316
325
|
translateCreateIndex(clause) {
|
|
317
|
-
const
|
|
318
|
-
|
|
326
|
+
const rawName = clause.indexName || `idx_${clause.property}`;
|
|
327
|
+
// Quote index name as a SQL identifier to prevent injection
|
|
328
|
+
const indexName = `"${rawName.replace(/"/g, '""')}"`;
|
|
329
|
+
const sql = `CREATE INDEX IF NOT EXISTS ${indexName} ON nodes(json_extract(properties, '$.${escSqlStr(clause.property)}'))`;
|
|
319
330
|
return [{ sql, params: [] }];
|
|
320
331
|
}
|
|
321
332
|
/**
|
|
322
333
|
* Translate DROP INDEX to SQL.
|
|
323
334
|
*/
|
|
324
335
|
translateDropIndex(clause) {
|
|
325
|
-
|
|
336
|
+
// Quote index name as a SQL identifier to prevent injection
|
|
337
|
+
const indexName = `"${clause.indexName.replace(/"/g, '""')}"`;
|
|
338
|
+
const sql = `DROP INDEX IF EXISTS ${indexName}`;
|
|
326
339
|
return [{ sql, params: [] }];
|
|
327
340
|
}
|
|
328
341
|
// ============================================================================
|
|
@@ -769,7 +782,7 @@ export class Translator {
|
|
|
769
782
|
const withAliases = this.ctx.withAliases;
|
|
770
783
|
for (const [key, value] of Object.entries(props)) {
|
|
771
784
|
if (this.isParameterRef(value)) {
|
|
772
|
-
conditions.push(`json_extract(properties, '$.${key}') = ?`);
|
|
785
|
+
conditions.push(`json_extract(properties, '$.${escSqlStr(key)}') = ?`);
|
|
773
786
|
params.push(this.ctx.paramValues[value.name]);
|
|
774
787
|
}
|
|
775
788
|
else if (this.isVariableRef(value)) {
|
|
@@ -777,7 +790,7 @@ export class Translator {
|
|
|
777
790
|
const varName = value.name;
|
|
778
791
|
if (withAliases && withAliases.has(varName)) {
|
|
779
792
|
const originalExpr = withAliases.get(varName);
|
|
780
|
-
conditions.push(`json_extract(properties, '$.${key}') = ?`);
|
|
793
|
+
conditions.push(`json_extract(properties, '$.${escSqlStr(key)}') = ?`);
|
|
781
794
|
if (originalExpr.type === "literal") {
|
|
782
795
|
params.push(originalExpr.value);
|
|
783
796
|
}
|
|
@@ -789,12 +802,12 @@ export class Translator {
|
|
|
789
802
|
}
|
|
790
803
|
}
|
|
791
804
|
else {
|
|
792
|
-
conditions.push(`json_extract(properties, '$.${key}') = ?`);
|
|
805
|
+
conditions.push(`json_extract(properties, '$.${escSqlStr(key)}') = ?`);
|
|
793
806
|
params.push(value);
|
|
794
807
|
}
|
|
795
808
|
}
|
|
796
809
|
else {
|
|
797
|
-
conditions.push(`json_extract(properties, '$.${key}') = ?`);
|
|
810
|
+
conditions.push(`json_extract(properties, '$.${escSqlStr(key)}') = ?`);
|
|
798
811
|
params.push(value);
|
|
799
812
|
}
|
|
800
813
|
}
|
|
@@ -898,7 +911,7 @@ export class Translator {
|
|
|
898
911
|
}
|
|
899
912
|
if (nullKeys.length > 0) {
|
|
900
913
|
// Need to merge non-null props and remove null keys
|
|
901
|
-
const removePaths = nullKeys.map(k => `'$.${k}'`).join(', ');
|
|
914
|
+
const removePaths = nullKeys.map(k => `'$.${escSqlStr(k)}'`).join(', ');
|
|
902
915
|
statements.push({
|
|
903
916
|
sql: `UPDATE ${table} SET properties = json_remove(json_patch(properties, ?), ${removePaths}) WHERE id = ?`,
|
|
904
917
|
params: [JSON.stringify(nonNullProps), varInfo.alias],
|
|
@@ -927,7 +940,7 @@ export class Translator {
|
|
|
927
940
|
// For expressions on created nodes, translate with subquery pattern
|
|
928
941
|
const { sql: exprSql, params: exprParams } = this.translateExpressionForCreatedNode(assignment.value, varInfo.alias);
|
|
929
942
|
statements.push({
|
|
930
|
-
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${assignment.property}', ${exprSql}) WHERE id = ?`,
|
|
943
|
+
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${escSqlStr(assignment.property)}', ${exprSql}) WHERE id = ?`,
|
|
931
944
|
params: [...exprParams, varInfo.alias],
|
|
932
945
|
});
|
|
933
946
|
}
|
|
@@ -935,7 +948,7 @@ export class Translator {
|
|
|
935
948
|
const { sql: exprSql, params: exprParams } = this.translateExpression(assignment.value);
|
|
936
949
|
// Use json_set with the SQL expression directly
|
|
937
950
|
statements.push({
|
|
938
|
-
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${assignment.property}', ${exprSql}) WHERE id = ?`,
|
|
951
|
+
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${escSqlStr(assignment.property)}', ${exprSql}) WHERE id = ?`,
|
|
939
952
|
params: [...exprParams, varInfo.alias],
|
|
940
953
|
});
|
|
941
954
|
}
|
|
@@ -945,7 +958,7 @@ export class Translator {
|
|
|
945
958
|
// If value is null, remove the property instead of setting it to null
|
|
946
959
|
if (value === null) {
|
|
947
960
|
statements.push({
|
|
948
|
-
sql: `UPDATE ${table} SET properties = json_remove(properties, '$.${assignment.property}') WHERE id = ?`,
|
|
961
|
+
sql: `UPDATE ${table} SET properties = json_remove(properties, '$.${escSqlStr(assignment.property)}') WHERE id = ?`,
|
|
949
962
|
params: [varInfo.alias],
|
|
950
963
|
});
|
|
951
964
|
}
|
|
@@ -953,7 +966,7 @@ export class Translator {
|
|
|
953
966
|
assertValidPropertyValue(value);
|
|
954
967
|
// Use json_set to update the property
|
|
955
968
|
statements.push({
|
|
956
|
-
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${assignment.property}', json(?)) WHERE id = ?`,
|
|
969
|
+
sql: `UPDATE ${table} SET properties = json_set(properties, '$.${escSqlStr(assignment.property)}', json(?)) WHERE id = ?`,
|
|
957
970
|
params: [JSON.stringify(value), varInfo.alias],
|
|
958
971
|
});
|
|
959
972
|
}
|
|
@@ -1070,7 +1083,7 @@ export class Translator {
|
|
|
1070
1083
|
else if (item.property) {
|
|
1071
1084
|
// Remove property
|
|
1072
1085
|
statements.push({
|
|
1073
|
-
sql: `UPDATE ${table} SET properties = json_remove(properties, '$.${item.property}') WHERE id = ?`,
|
|
1086
|
+
sql: `UPDATE ${table} SET properties = json_remove(properties, '$.${escSqlStr(item.property)}') WHERE id = ?`,
|
|
1074
1087
|
params: [varInfo.alias],
|
|
1075
1088
|
});
|
|
1076
1089
|
}
|
|
@@ -1404,11 +1417,11 @@ export class Translator {
|
|
|
1404
1417
|
if (pattern.properties) {
|
|
1405
1418
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
1406
1419
|
if (this.isParameterRef(value)) {
|
|
1407
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
1420
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1408
1421
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
1409
1422
|
}
|
|
1410
1423
|
else {
|
|
1411
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
1424
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1412
1425
|
whereParams.push(value);
|
|
1413
1426
|
}
|
|
1414
1427
|
}
|
|
@@ -1699,21 +1712,21 @@ export class Translator {
|
|
|
1699
1712
|
for (const [key, value] of Object.entries(relPattern.edge.properties)) {
|
|
1700
1713
|
if (this.isParameterRef(value)) {
|
|
1701
1714
|
if (isOptional) {
|
|
1702
|
-
edgeOnConditions.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${key}') = ?`);
|
|
1715
|
+
edgeOnConditions.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1703
1716
|
edgeOnParams.push(this.ctx.paramValues[value.name]);
|
|
1704
1717
|
}
|
|
1705
1718
|
else {
|
|
1706
|
-
whereParts.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${key}') = ?`);
|
|
1719
|
+
whereParts.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1707
1720
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
1708
1721
|
}
|
|
1709
1722
|
}
|
|
1710
1723
|
else {
|
|
1711
1724
|
if (isOptional) {
|
|
1712
|
-
edgeOnConditions.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${key}') = ?`);
|
|
1725
|
+
edgeOnConditions.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1713
1726
|
edgeOnParams.push(value);
|
|
1714
1727
|
}
|
|
1715
1728
|
else {
|
|
1716
|
-
whereParts.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${key}') = ?`);
|
|
1729
|
+
whereParts.push(`json_extract(${relPattern.edgeAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1717
1730
|
whereParams.push(value);
|
|
1718
1731
|
}
|
|
1719
1732
|
}
|
|
@@ -1926,11 +1939,11 @@ export class Translator {
|
|
|
1926
1939
|
if (isOptional && targetPattern?.properties) {
|
|
1927
1940
|
for (const [key, value] of Object.entries(targetPattern.properties)) {
|
|
1928
1941
|
if (this.isParameterRef(value)) {
|
|
1929
|
-
targetOnConditions.push(`json_extract(${relPattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
1942
|
+
targetOnConditions.push(`json_extract(${relPattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1930
1943
|
targetOnParams.push(this.ctx.paramValues[value.name]);
|
|
1931
1944
|
}
|
|
1932
1945
|
else {
|
|
1933
|
-
targetOnConditions.push(`json_extract(${relPattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
1946
|
+
targetOnConditions.push(`json_extract(${relPattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
1934
1947
|
targetOnParams.push(value);
|
|
1935
1948
|
}
|
|
1936
1949
|
}
|
|
@@ -1999,11 +2012,11 @@ export class Translator {
|
|
|
1999
2012
|
if (sourcePattern?.properties && !sourceIsOptional) {
|
|
2000
2013
|
for (const [key, value] of Object.entries(sourcePattern.properties)) {
|
|
2001
2014
|
if (this.isParameterRef(value)) {
|
|
2002
|
-
whereParts.push(`json_extract(${relPattern.sourceAlias}.properties, '$.${key}') = ?`);
|
|
2015
|
+
whereParts.push(`json_extract(${relPattern.sourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2003
2016
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
2004
2017
|
}
|
|
2005
2018
|
else {
|
|
2006
|
-
whereParts.push(`json_extract(${relPattern.sourceAlias}.properties, '$.${key}') = ?`);
|
|
2019
|
+
whereParts.push(`json_extract(${relPattern.sourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2007
2020
|
whereParams.push(value);
|
|
2008
2021
|
}
|
|
2009
2022
|
}
|
|
@@ -2022,11 +2035,11 @@ export class Translator {
|
|
|
2022
2035
|
if (targetPattern?.properties) {
|
|
2023
2036
|
for (const [key, value] of Object.entries(targetPattern.properties)) {
|
|
2024
2037
|
if (this.isParameterRef(value)) {
|
|
2025
|
-
whereParts.push(`json_extract(${relPattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
2038
|
+
whereParts.push(`json_extract(${relPattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2026
2039
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
2027
2040
|
}
|
|
2028
2041
|
else {
|
|
2029
|
-
whereParts.push(`json_extract(${relPattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
2042
|
+
whereParts.push(`json_extract(${relPattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2030
2043
|
whereParams.push(value);
|
|
2031
2044
|
}
|
|
2032
2045
|
}
|
|
@@ -2135,11 +2148,11 @@ export class Translator {
|
|
|
2135
2148
|
if (pattern.properties) {
|
|
2136
2149
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
2137
2150
|
if (this.isParameterRef(value)) {
|
|
2138
|
-
onConditions.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2151
|
+
onConditions.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2139
2152
|
onParams.push(this.ctx.paramValues[value.name]);
|
|
2140
2153
|
}
|
|
2141
2154
|
else {
|
|
2142
|
-
onConditions.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2155
|
+
onConditions.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2143
2156
|
onParams.push(value);
|
|
2144
2157
|
}
|
|
2145
2158
|
}
|
|
@@ -2164,11 +2177,11 @@ export class Translator {
|
|
|
2164
2177
|
if (pattern.properties) {
|
|
2165
2178
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
2166
2179
|
if (this.isParameterRef(value)) {
|
|
2167
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2180
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2168
2181
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
2169
2182
|
}
|
|
2170
2183
|
else {
|
|
2171
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2184
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2172
2185
|
whereParams.push(value);
|
|
2173
2186
|
}
|
|
2174
2187
|
}
|
|
@@ -2197,11 +2210,11 @@ export class Translator {
|
|
|
2197
2210
|
if (pattern.properties) {
|
|
2198
2211
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
2199
2212
|
if (this.isParameterRef(value)) {
|
|
2200
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2213
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2201
2214
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
2202
2215
|
}
|
|
2203
2216
|
else {
|
|
2204
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2217
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2205
2218
|
whereParams.push(value);
|
|
2206
2219
|
}
|
|
2207
2220
|
}
|
|
@@ -2219,11 +2232,11 @@ export class Translator {
|
|
|
2219
2232
|
if (pattern.properties) {
|
|
2220
2233
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
2221
2234
|
if (this.isParameterRef(value)) {
|
|
2222
|
-
onConditions.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2235
|
+
onConditions.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2223
2236
|
onParams.push(this.ctx.paramValues[value.name]);
|
|
2224
2237
|
}
|
|
2225
2238
|
else {
|
|
2226
|
-
onConditions.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2239
|
+
onConditions.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2227
2240
|
onParams.push(value);
|
|
2228
2241
|
}
|
|
2229
2242
|
}
|
|
@@ -2242,11 +2255,11 @@ export class Translator {
|
|
|
2242
2255
|
if (pattern.properties) {
|
|
2243
2256
|
for (const [key, value] of Object.entries(pattern.properties)) {
|
|
2244
2257
|
if (this.isParameterRef(value)) {
|
|
2245
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2258
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2246
2259
|
whereParams.push(this.ctx.paramValues[value.name]);
|
|
2247
2260
|
}
|
|
2248
2261
|
else {
|
|
2249
|
-
whereParts.push(`json_extract(${info.alias}.properties, '$.${key}') = ?`);
|
|
2262
|
+
whereParts.push(`json_extract(${info.alias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
2250
2263
|
whereParams.push(value);
|
|
2251
2264
|
}
|
|
2252
2265
|
}
|
|
@@ -3156,7 +3169,7 @@ export class Translator {
|
|
|
3156
3169
|
const edgePropParams = [];
|
|
3157
3170
|
if (edgeProperties) {
|
|
3158
3171
|
for (const [key, value] of Object.entries(edgeProperties)) {
|
|
3159
|
-
edgePropConditions.push(`json_extract(properties, '$.${key}') = ?`);
|
|
3172
|
+
edgePropConditions.push(`json_extract(properties, '$.${escSqlStr(key)}') = ?`);
|
|
3160
3173
|
edgePropParams.push(value);
|
|
3161
3174
|
}
|
|
3162
3175
|
}
|
|
@@ -3179,11 +3192,11 @@ export class Translator {
|
|
|
3179
3192
|
if (sourcePattern?.properties) {
|
|
3180
3193
|
for (const [key, value] of Object.entries(sourcePattern.properties)) {
|
|
3181
3194
|
if (this.isParameterRef(value)) {
|
|
3182
|
-
sourceFilterParts.push(`json_extract(src_n.properties, '$.${key}') = ?`);
|
|
3195
|
+
sourceFilterParts.push(`json_extract(src_n.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3183
3196
|
sourceFilterParams.push(this.ctx.paramValues[value.name]);
|
|
3184
3197
|
}
|
|
3185
3198
|
else {
|
|
3186
|
-
sourceFilterParts.push(`json_extract(src_n.properties, '$.${key}') = ?`);
|
|
3199
|
+
sourceFilterParts.push(`json_extract(src_n.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3187
3200
|
sourceFilterParams.push(value);
|
|
3188
3201
|
}
|
|
3189
3202
|
}
|
|
@@ -3408,11 +3421,11 @@ export class Translator {
|
|
|
3408
3421
|
if (sourcePattern?.properties) {
|
|
3409
3422
|
for (const [key, value] of Object.entries(sourcePattern.properties)) {
|
|
3410
3423
|
if (this.isParameterRef(value)) {
|
|
3411
|
-
whereParts.push(`json_extract(${pattern.sourceAlias}.properties, '$.${key}') = ?`);
|
|
3424
|
+
whereParts.push(`json_extract(${pattern.sourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3412
3425
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3413
3426
|
}
|
|
3414
3427
|
else {
|
|
3415
|
-
whereParts.push(`json_extract(${pattern.sourceAlias}.properties, '$.${key}') = ?`);
|
|
3428
|
+
whereParts.push(`json_extract(${pattern.sourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3416
3429
|
deferredWhereParams.push(value);
|
|
3417
3430
|
}
|
|
3418
3431
|
}
|
|
@@ -3522,11 +3535,11 @@ export class Translator {
|
|
|
3522
3535
|
if (sourcePattern?.properties) {
|
|
3523
3536
|
for (const [key, value] of Object.entries(sourcePattern.properties)) {
|
|
3524
3537
|
if (this.isParameterRef(value)) {
|
|
3525
|
-
whereParts.push(`json_extract(${varLengthSourceAlias}.properties, '$.${key}') = ?`);
|
|
3538
|
+
whereParts.push(`json_extract(${varLengthSourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3526
3539
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3527
3540
|
}
|
|
3528
3541
|
else {
|
|
3529
|
-
whereParts.push(`json_extract(${varLengthSourceAlias}.properties, '$.${key}') = ?`);
|
|
3542
|
+
whereParts.push(`json_extract(${varLengthSourceAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3530
3543
|
deferredWhereParams.push(value);
|
|
3531
3544
|
}
|
|
3532
3545
|
}
|
|
@@ -3582,11 +3595,11 @@ export class Translator {
|
|
|
3582
3595
|
if (targetPattern?.properties) {
|
|
3583
3596
|
for (const [key, value] of Object.entries(targetPattern.properties)) {
|
|
3584
3597
|
if (this.isParameterRef(value)) {
|
|
3585
|
-
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3598
|
+
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3586
3599
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3587
3600
|
}
|
|
3588
3601
|
else {
|
|
3589
|
-
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3602
|
+
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3590
3603
|
deferredWhereParams.push(value);
|
|
3591
3604
|
}
|
|
3592
3605
|
}
|
|
@@ -3627,11 +3640,11 @@ export class Translator {
|
|
|
3627
3640
|
if (targetPattern?.properties) {
|
|
3628
3641
|
for (const [key, value] of Object.entries(targetPattern.properties)) {
|
|
3629
3642
|
if (this.isParameterRef(value)) {
|
|
3630
|
-
targetOnConditions.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3643
|
+
targetOnConditions.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3631
3644
|
allParams.push(this.ctx.paramValues[value.name]);
|
|
3632
3645
|
}
|
|
3633
3646
|
else {
|
|
3634
|
-
targetOnConditions.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3647
|
+
targetOnConditions.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3635
3648
|
allParams.push(value);
|
|
3636
3649
|
}
|
|
3637
3650
|
}
|
|
@@ -3672,11 +3685,11 @@ export class Translator {
|
|
|
3672
3685
|
if (targetPattern?.properties) {
|
|
3673
3686
|
for (const [key, value] of Object.entries(targetPattern.properties)) {
|
|
3674
3687
|
if (this.isParameterRef(value)) {
|
|
3675
|
-
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3688
|
+
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3676
3689
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3677
3690
|
}
|
|
3678
3691
|
else {
|
|
3679
|
-
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${key}') = ?`);
|
|
3692
|
+
whereParts.push(`json_extract(${varLengthTargetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3680
3693
|
deferredWhereParams.push(value);
|
|
3681
3694
|
}
|
|
3682
3695
|
}
|
|
@@ -3839,11 +3852,11 @@ export class Translator {
|
|
|
3839
3852
|
if (targetPattern2?.properties) {
|
|
3840
3853
|
for (const [key, value] of Object.entries(targetPattern2.properties)) {
|
|
3841
3854
|
if (this.isParameterRef(value)) {
|
|
3842
|
-
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
3855
|
+
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3843
3856
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3844
3857
|
}
|
|
3845
3858
|
else {
|
|
3846
|
-
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
3859
|
+
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3847
3860
|
deferredWhereParams.push(value);
|
|
3848
3861
|
}
|
|
3849
3862
|
}
|
|
@@ -3903,11 +3916,11 @@ export class Translator {
|
|
|
3903
3916
|
if (afterTargetPattern?.properties) {
|
|
3904
3917
|
for (const [key, value] of Object.entries(afterTargetPattern.properties)) {
|
|
3905
3918
|
if (this.isParameterRef(value)) {
|
|
3906
|
-
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
3919
|
+
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3907
3920
|
deferredWhereParams.push(this.ctx.paramValues[value.name]);
|
|
3908
3921
|
}
|
|
3909
3922
|
else {
|
|
3910
|
-
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${key}') = ?`);
|
|
3923
|
+
whereParts.push(`json_extract(${pattern.targetAlias}.properties, '$.${escSqlStr(key)}') = ?`);
|
|
3911
3924
|
deferredWhereParams.push(value);
|
|
3912
3925
|
}
|
|
3913
3926
|
}
|
|
@@ -4090,7 +4103,7 @@ export class Translator {
|
|
|
4090
4103
|
if (!varInfo) {
|
|
4091
4104
|
throw new Error(`Unknown variable: ${clause.expression.variable}`);
|
|
4092
4105
|
}
|
|
4093
|
-
jsonExpr = `json_extract(${varInfo.alias}.properties, '$.${clause.expression.property}')`;
|
|
4106
|
+
jsonExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(clause.expression.property)}')`;
|
|
4094
4107
|
}
|
|
4095
4108
|
else if (clause.expression.type === "function" || clause.expression.type === "binary") {
|
|
4096
4109
|
// Function call like range(1, 10) or binary expression like (first + second)
|
|
@@ -4667,7 +4680,7 @@ export class Translator {
|
|
|
4667
4680
|
params.push(...objectResult.params);
|
|
4668
4681
|
// Access property from the result using json_extract
|
|
4669
4682
|
return {
|
|
4670
|
-
sql: `json_extract(${objectResult.sql}, '$.${expr.property}')`,
|
|
4683
|
+
sql: `json_extract(${objectResult.sql}, '$.${escSqlStr(expr.property)}')`,
|
|
4671
4684
|
tables,
|
|
4672
4685
|
params,
|
|
4673
4686
|
};
|
|
@@ -4702,7 +4715,7 @@ export class Translator {
|
|
|
4702
4715
|
}
|
|
4703
4716
|
// Access property from the unwound value using json_extract
|
|
4704
4717
|
return {
|
|
4705
|
-
sql: `json_extract(${baseSql}, '$.${expr.property}')`,
|
|
4718
|
+
sql: `json_extract(${baseSql}, '$.${escSqlStr(expr.property)}')`,
|
|
4706
4719
|
tables,
|
|
4707
4720
|
params,
|
|
4708
4721
|
};
|
|
@@ -4715,7 +4728,7 @@ export class Translator {
|
|
|
4715
4728
|
tables.push(varInfo.alias);
|
|
4716
4729
|
// Use -> operator to preserve JSON types (returns 'true'/'false' not 1/0)
|
|
4717
4730
|
return {
|
|
4718
|
-
sql: `${varInfo.alias}.properties -> '$.${expr.property}'`,
|
|
4731
|
+
sql: `${varInfo.alias}.properties -> '$.${escSqlStr(expr.property)}'`,
|
|
4719
4732
|
tables,
|
|
4720
4733
|
params,
|
|
4721
4734
|
};
|
|
@@ -4737,7 +4750,7 @@ export class Translator {
|
|
|
4737
4750
|
}
|
|
4738
4751
|
tables.push(varInfo.alias);
|
|
4739
4752
|
return {
|
|
4740
|
-
sql: `COUNT(${distinctKeyword}json_extract(${varInfo.alias}.properties, '$.${arg.property}'))`,
|
|
4753
|
+
sql: `COUNT(${distinctKeyword}json_extract(${varInfo.alias}.properties, '$.${escSqlStr(arg.property)}'))`,
|
|
4741
4754
|
tables,
|
|
4742
4755
|
params,
|
|
4743
4756
|
};
|
|
@@ -4871,7 +4884,7 @@ export class Translator {
|
|
|
4871
4884
|
tables.push(unwindClause.alias);
|
|
4872
4885
|
// UNWIND variables use the 'value' column from json_each
|
|
4873
4886
|
return {
|
|
4874
|
-
sql: `${expr.functionName}(${distinctKeyword}json_extract(${unwindClause.alias}.value, '$.${arg.property}'))`,
|
|
4887
|
+
sql: `${expr.functionName}(${distinctKeyword}json_extract(${unwindClause.alias}.value, '$.${escSqlStr(arg.property)}'))`,
|
|
4875
4888
|
tables,
|
|
4876
4889
|
params,
|
|
4877
4890
|
};
|
|
@@ -4884,7 +4897,7 @@ export class Translator {
|
|
|
4884
4897
|
tables.push(varInfo.alias);
|
|
4885
4898
|
// Use json_extract for numeric properties in aggregations
|
|
4886
4899
|
return {
|
|
4887
|
-
sql: `${expr.functionName}(${distinctKeyword}json_extract(${varInfo.alias}.properties, '$.${arg.property}'))`,
|
|
4900
|
+
sql: `${expr.functionName}(${distinctKeyword}json_extract(${varInfo.alias}.properties, '$.${escSqlStr(arg.property)}'))`,
|
|
4888
4901
|
tables,
|
|
4889
4902
|
params,
|
|
4890
4903
|
};
|
|
@@ -5044,7 +5057,7 @@ export class Translator {
|
|
|
5044
5057
|
throw new Error(`Unknown variable: ${arg.variable}`);
|
|
5045
5058
|
}
|
|
5046
5059
|
tables.push(varInfo.alias);
|
|
5047
|
-
valueSql = `json_extract(${varInfo.alias}.properties, '$.${arg.property}')`;
|
|
5060
|
+
valueSql = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(arg.property)}')`;
|
|
5048
5061
|
}
|
|
5049
5062
|
else if (arg.type === "variable") {
|
|
5050
5063
|
// Check if this is an UNWIND variable
|
|
@@ -5145,7 +5158,7 @@ export class Translator {
|
|
|
5145
5158
|
throw new Error(`Unknown variable: ${valueArg.variable}`);
|
|
5146
5159
|
}
|
|
5147
5160
|
tables.push(varInfo.alias);
|
|
5148
|
-
valueExpr = `json_extract(${varInfo.alias}.properties, '$.${valueArg.property}')`;
|
|
5161
|
+
valueExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(valueArg.property)}')`;
|
|
5149
5162
|
}
|
|
5150
5163
|
else {
|
|
5151
5164
|
const argResult = this.translateFunctionArg(valueArg);
|
|
@@ -5256,7 +5269,7 @@ END FROM (SELECT json_group_array(${valueExpr}) as sv))`,
|
|
|
5256
5269
|
// json_quote properly escapes strings for JSON
|
|
5257
5270
|
// Filter nulls: CASE WHEN value IS NULL THEN NULL ELSE json_quote(value) END
|
|
5258
5271
|
// GROUP_CONCAT ignores nulls
|
|
5259
|
-
const extractExpr = `json_extract(${varInfo.alias}.properties, '$.${arg.property}')`;
|
|
5272
|
+
const extractExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(arg.property)}')`;
|
|
5260
5273
|
params.push(...collectOrderParams);
|
|
5261
5274
|
return {
|
|
5262
5275
|
sql: `COALESCE(json('[' || GROUP_CONCAT(DISTINCT CASE WHEN ${extractExpr} IS NOT NULL THEN json_quote(${extractExpr}) END${collectOrderClause}) || ']'), json('[]'))`,
|
|
@@ -5265,7 +5278,7 @@ END FROM (SELECT json_group_array(${valueExpr}) as sv))`,
|
|
|
5265
5278
|
};
|
|
5266
5279
|
}
|
|
5267
5280
|
// Neo4j's collect() skips NULL values - use GROUP_CONCAT with null filtering
|
|
5268
|
-
const extractExpr = `json_extract(${varInfo.alias}.properties, '$.${arg.property}')`;
|
|
5281
|
+
const extractExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(arg.property)}')`;
|
|
5269
5282
|
params.push(...collectOrderParams);
|
|
5270
5283
|
return {
|
|
5271
5284
|
sql: `COALESCE(json('[' || GROUP_CONCAT(CASE WHEN ${extractExpr} IS NOT NULL THEN json_quote(${extractExpr}) END${collectOrderClause}) || ']'), json('[]'))`,
|
|
@@ -5751,7 +5764,7 @@ END FROM (SELECT json_group_array(${valueExpr}) as sv))`,
|
|
|
5751
5764
|
tables.push(...argResult.tables);
|
|
5752
5765
|
params.push(...argResult.params);
|
|
5753
5766
|
return {
|
|
5754
|
-
sql: `cypher_to_json_bool(json_type(${argResult.sql}, '$.${propName}') IS NOT NULL)`,
|
|
5767
|
+
sql: `cypher_to_json_bool(json_type(${argResult.sql}, '$.${escSqlStr(propName)}') IS NOT NULL)`,
|
|
5755
5768
|
tables,
|
|
5756
5769
|
params,
|
|
5757
5770
|
};
|
|
@@ -9072,7 +9085,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
9072
9085
|
const labelsToCheck = expr.labels || (expr.label ? [expr.label] : []);
|
|
9073
9086
|
// Use EXISTS with json_each to check if label is in the array
|
|
9074
9087
|
// For multiple labels, all must be present (AND)
|
|
9075
|
-
const labelChecks = labelsToCheck.map(l => `EXISTS(SELECT 1 FROM json_each(${varInfo.alias}.label) WHERE value = '${l}')`).join(' AND ');
|
|
9088
|
+
const labelChecks = labelsToCheck.map(l => `EXISTS(SELECT 1 FROM json_each(${varInfo.alias}.label) WHERE value = '${escSqlStr(l)}')`).join(' AND ');
|
|
9076
9089
|
return {
|
|
9077
9090
|
sql: `CASE WHEN ${varInfo.alias}.id IS NULL THEN NULL ELSE cypher_to_json_bool(${labelChecks}) END`,
|
|
9078
9091
|
tables,
|
|
@@ -9087,7 +9100,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
9087
9100
|
params.push(...objectResult.params);
|
|
9088
9101
|
// Access property from the result using json_extract
|
|
9089
9102
|
return {
|
|
9090
|
-
sql: `json_extract(${objectResult.sql}, '$.${expr.property}')`,
|
|
9103
|
+
sql: `json_extract(${objectResult.sql}, '$.${escSqlStr(expr.property)}')`,
|
|
9091
9104
|
tables,
|
|
9092
9105
|
params,
|
|
9093
9106
|
};
|
|
@@ -9104,7 +9117,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
9104
9117
|
if (item.type === "property") {
|
|
9105
9118
|
// .property shorthand - extract property from source
|
|
9106
9119
|
const key = item.property;
|
|
9107
|
-
jsonParts.push(`'${key}', json_extract(${sourceResult.sql}, '$.${key}')`);
|
|
9120
|
+
jsonParts.push(`'${escSqlStr(key)}', json_extract(${sourceResult.sql}, '$.${escSqlStr(key)}')`);
|
|
9108
9121
|
}
|
|
9109
9122
|
else if (item.type === "literal") {
|
|
9110
9123
|
// key: value syntax
|
|
@@ -9112,7 +9125,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
9112
9125
|
const valueResult = this.translateExpression(item.value);
|
|
9113
9126
|
tables.push(...valueResult.tables);
|
|
9114
9127
|
params.push(...valueResult.params);
|
|
9115
|
-
jsonParts.push(`'${key}', ${valueResult.sql}`);
|
|
9128
|
+
jsonParts.push(`'${escSqlStr(key)}', ${valueResult.sql}`);
|
|
9116
9129
|
}
|
|
9117
9130
|
else if (item.type === "allProperties") {
|
|
9118
9131
|
// .* - project all properties (not yet fully supported, just returns the source)
|
|
@@ -10456,7 +10469,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10456
10469
|
if (expr.type === "property") {
|
|
10457
10470
|
const varInfo = this.ctx.variables.get(expr.variable);
|
|
10458
10471
|
if (varInfo) {
|
|
10459
|
-
return `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`;
|
|
10472
|
+
return `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`;
|
|
10460
10473
|
}
|
|
10461
10474
|
}
|
|
10462
10475
|
return sql;
|
|
@@ -10467,7 +10480,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10467
10480
|
// Replace -> with json_extract for numeric operations
|
|
10468
10481
|
const varInfo = this.ctx.variables.get(expr.variable);
|
|
10469
10482
|
if (varInfo) {
|
|
10470
|
-
return `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`;
|
|
10483
|
+
return `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`;
|
|
10471
10484
|
}
|
|
10472
10485
|
}
|
|
10473
10486
|
return sql;
|
|
@@ -10496,7 +10509,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10496
10509
|
const propName = expr.property;
|
|
10497
10510
|
params.push(nodeId);
|
|
10498
10511
|
return {
|
|
10499
|
-
sql: `(SELECT json_extract(properties, '$.${propName}') FROM nodes WHERE id = ?)`,
|
|
10512
|
+
sql: `(SELECT json_extract(properties, '$.${escSqlStr(propName)}') FROM nodes WHERE id = ?)`,
|
|
10500
10513
|
params,
|
|
10501
10514
|
};
|
|
10502
10515
|
}
|
|
@@ -10743,7 +10756,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10743
10756
|
if (expr.type === "property") {
|
|
10744
10757
|
const varInfo = this.ctx.variables.get(expr.variable);
|
|
10745
10758
|
if (varInfo) {
|
|
10746
|
-
return `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`;
|
|
10759
|
+
return `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`;
|
|
10747
10760
|
}
|
|
10748
10761
|
}
|
|
10749
10762
|
return sql;
|
|
@@ -10850,7 +10863,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10850
10863
|
// For property access, use json_extract
|
|
10851
10864
|
const varInfo = this.ctx.variables.get(listExpr.variable);
|
|
10852
10865
|
if (varInfo) {
|
|
10853
|
-
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${listExpr.property}')`;
|
|
10866
|
+
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(listExpr.property)}')`;
|
|
10854
10867
|
}
|
|
10855
10868
|
}
|
|
10856
10869
|
// Determine what to select: the mapped expression or just the value
|
|
@@ -10990,7 +11003,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
10990
11003
|
// For property access, use json_extract
|
|
10991
11004
|
const varInfo = this.ctx.variables.get(listExpr.variable);
|
|
10992
11005
|
if (varInfo) {
|
|
10993
|
-
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${listExpr.property}')`;
|
|
11006
|
+
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(listExpr.property)}')`;
|
|
10994
11007
|
}
|
|
10995
11008
|
}
|
|
10996
11009
|
// Build the WHERE clause from the filter condition
|
|
@@ -11025,7 +11038,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
11025
11038
|
// For property access, use json_extract
|
|
11026
11039
|
const varInfo = this.ctx.variables.get(listExpr.variable);
|
|
11027
11040
|
if (varInfo) {
|
|
11028
|
-
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${listExpr.property}')`;
|
|
11041
|
+
sourceExpr = `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(listExpr.property)}')`;
|
|
11029
11042
|
}
|
|
11030
11043
|
}
|
|
11031
11044
|
// Translate the map expression
|
|
@@ -11061,18 +11074,18 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
11061
11074
|
case "property": {
|
|
11062
11075
|
if (expr.variable === iterVar) {
|
|
11063
11076
|
// Property access on the iterator variable: x.name
|
|
11064
|
-
return { sql: `json_extract(${elemAlias}.value, '$.${expr.property}')`, params };
|
|
11077
|
+
return { sql: `json_extract(${elemAlias}.value, '$.${escSqlStr(expr.property)}')`, params };
|
|
11065
11078
|
}
|
|
11066
11079
|
if (expr.variable === accVar) {
|
|
11067
11080
|
// Property access on accumulator (if acc is an object)
|
|
11068
|
-
return { sql: `json_extract(${tableAlias}.acc, '$.${expr.property}')`, params };
|
|
11081
|
+
return { sql: `json_extract(${tableAlias}.acc, '$.${escSqlStr(expr.property)}')`, params };
|
|
11069
11082
|
}
|
|
11070
11083
|
// Standard property translation
|
|
11071
11084
|
const varInfo = this.ctx.variables.get(expr.variable);
|
|
11072
11085
|
if (varInfo) {
|
|
11073
|
-
return { sql: `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`, params };
|
|
11086
|
+
return { sql: `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`, params };
|
|
11074
11087
|
}
|
|
11075
|
-
return { sql: `json_extract(${expr.variable}, '$.${expr.property}')`, params };
|
|
11088
|
+
return { sql: `json_extract(${expr.variable}, '$.${escSqlStr(expr.property)}')`, params };
|
|
11076
11089
|
}
|
|
11077
11090
|
case "literal": {
|
|
11078
11091
|
if (expr.value === null)
|
|
@@ -11510,13 +11523,13 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
11510
11523
|
return { sql: varResult.sql, params: varResult.params };
|
|
11511
11524
|
case "property":
|
|
11512
11525
|
if (expr.variable === startVar) {
|
|
11513
|
-
return { sql: `json_extract(${startAlias}.properties, '$.${expr.property}')`, params };
|
|
11526
|
+
return { sql: `json_extract(${startAlias}.properties, '$.${escSqlStr(expr.property)}')`, params };
|
|
11514
11527
|
}
|
|
11515
11528
|
if (expr.variable === edgeVar) {
|
|
11516
|
-
return { sql: `json_extract(${edgeAlias}.properties, '$.${expr.property}')`, params };
|
|
11529
|
+
return { sql: `json_extract(${edgeAlias}.properties, '$.${escSqlStr(expr.property)}')`, params };
|
|
11517
11530
|
}
|
|
11518
11531
|
if (expr.variable === targetVar) {
|
|
11519
|
-
return { sql: `json_extract(${targetAlias}.properties, '$.${expr.property}')`, params };
|
|
11532
|
+
return { sql: `json_extract(${targetAlias}.properties, '$.${escSqlStr(expr.property)}')`, params };
|
|
11520
11533
|
}
|
|
11521
11534
|
// Fall through to regular translation
|
|
11522
11535
|
const propResult = this.translateExpression(expr);
|
|
@@ -11595,7 +11608,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
11595
11608
|
const scope = findScope(expr.variable);
|
|
11596
11609
|
if (scope) {
|
|
11597
11610
|
// Extract property from the JSON value in the list element
|
|
11598
|
-
return { sql: `json_extract(${scope.tableAlias}.value, '$.${expr.property}')`, params };
|
|
11611
|
+
return { sql: `json_extract(${scope.tableAlias}.value, '$.${escSqlStr(expr.property)}')`, params };
|
|
11599
11612
|
}
|
|
11600
11613
|
// Fall through to regular translation for other variables
|
|
11601
11614
|
const propResult = this.translateExpression(expr);
|
|
@@ -11979,7 +11992,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
11979
11992
|
if (expr.type === "property") {
|
|
11980
11993
|
const varInfo = this.ctx.variables.get(expr.variable);
|
|
11981
11994
|
if (varInfo) {
|
|
11982
|
-
return `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`;
|
|
11995
|
+
return `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`;
|
|
11983
11996
|
}
|
|
11984
11997
|
}
|
|
11985
11998
|
// For literal arrays, the sql is already a json_array() call
|
|
@@ -12848,7 +12861,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
12848
12861
|
const originalExpr = withAliases.get(expr.variable);
|
|
12849
12862
|
const objectResult = this.translateExpression(originalExpr);
|
|
12850
12863
|
return {
|
|
12851
|
-
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${objectResult.sql}, '$.${expr.property}')`),
|
|
12864
|
+
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${objectResult.sql}, '$.${escSqlStr(expr.property)}')`),
|
|
12852
12865
|
params: objectResult.params,
|
|
12853
12866
|
};
|
|
12854
12867
|
}
|
|
@@ -12868,7 +12881,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
12868
12881
|
if (unwindClause) {
|
|
12869
12882
|
// UNWIND variables use the 'value' column from json_each
|
|
12870
12883
|
return {
|
|
12871
|
-
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${unwindClause.alias}.value, '$.${expr.property}')`),
|
|
12884
|
+
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${unwindClause.alias}.value, '$.${escSqlStr(expr.property)}')`),
|
|
12872
12885
|
params: [],
|
|
12873
12886
|
};
|
|
12874
12887
|
}
|
|
@@ -12878,7 +12891,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
12878
12891
|
throw new Error(`Unknown variable: ${expr.variable}`);
|
|
12879
12892
|
}
|
|
12880
12893
|
return {
|
|
12881
|
-
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${varInfo.alias}.properties, '$.${expr.property}')`),
|
|
12894
|
+
sql: this.buildDateTimeWithOffsetOrderBy(`json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`),
|
|
12882
12895
|
params: [],
|
|
12883
12896
|
};
|
|
12884
12897
|
}
|
|
@@ -13068,7 +13081,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
13068
13081
|
throw new Error(`Unknown variable: ${expr.variable}`);
|
|
13069
13082
|
}
|
|
13070
13083
|
return {
|
|
13071
|
-
sql: `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`,
|
|
13084
|
+
sql: `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`,
|
|
13072
13085
|
params: [],
|
|
13073
13086
|
};
|
|
13074
13087
|
}
|
|
@@ -13089,7 +13102,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
13089
13102
|
if (unwindClause) {
|
|
13090
13103
|
// UNWIND variables use the 'value' column from json_each
|
|
13091
13104
|
return {
|
|
13092
|
-
sql: `json_extract(${unwindClause.alias}.value, '$.${expr.property}')`,
|
|
13105
|
+
sql: `json_extract(${unwindClause.alias}.value, '$.${escSqlStr(expr.property)}')`,
|
|
13093
13106
|
params: [],
|
|
13094
13107
|
};
|
|
13095
13108
|
}
|
|
@@ -13099,7 +13112,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
13099
13112
|
throw new Error(`Unknown variable: ${expr.variable}`);
|
|
13100
13113
|
}
|
|
13101
13114
|
return {
|
|
13102
|
-
sql: `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`,
|
|
13115
|
+
sql: `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`,
|
|
13103
13116
|
params: [],
|
|
13104
13117
|
};
|
|
13105
13118
|
}
|
|
@@ -13213,7 +13226,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
13213
13226
|
const labelsToCheck = expr.labels || (expr.label ? [expr.label] : []);
|
|
13214
13227
|
// Use EXISTS with json_each to check if label is in the array
|
|
13215
13228
|
// For multiple labels, all must be present (AND)
|
|
13216
|
-
const labelChecks = labelsToCheck.map((l) => `EXISTS(SELECT 1 FROM json_each(${varInfo.alias}.label) WHERE value = '${l}')`).join(' AND ');
|
|
13229
|
+
const labelChecks = labelsToCheck.map((l) => `EXISTS(SELECT 1 FROM json_each(${varInfo.alias}.label) WHERE value = '${escSqlStr(l)}')`).join(' AND ');
|
|
13217
13230
|
return {
|
|
13218
13231
|
sql: `(${labelChecks})`,
|
|
13219
13232
|
params: [],
|
|
@@ -13256,7 +13269,7 @@ SELECT COALESCE(json_group_array(CAST(n AS INTEGER)), json_array()) FROM r)`,
|
|
|
13256
13269
|
}
|
|
13257
13270
|
tables.push(varInfo.alias);
|
|
13258
13271
|
return {
|
|
13259
|
-
sql: `json_extract(${varInfo.alias}.properties, '$.${expr.property}')`,
|
|
13272
|
+
sql: `json_extract(${varInfo.alias}.properties, '$.${escSqlStr(expr.property)}')`,
|
|
13260
13273
|
tables,
|
|
13261
13274
|
params,
|
|
13262
13275
|
};
|