@peerbit/indexer-sqlite3 1.1.3 → 1.1.4-5cf61cb
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/peerbit/sqlite3-bundler-friendly.mjs +7 -7
- package/dist/peerbit/sqlite3-node.mjs +7 -7
- package/dist/peerbit/sqlite3.js +7 -7
- package/dist/peerbit/sqlite3.min.js +651 -163
- package/dist/peerbit/sqlite3.mjs +7 -7
- package/dist/peerbit/sqlite3.wasm +0 -0
- package/dist/peerbit/sqlite3.worker.min.js +19 -5
- package/dist/src/engine.d.ts +4 -1
- package/dist/src/engine.d.ts.map +1 -1
- package/dist/src/engine.js +125 -48
- package/dist/src/engine.js.map +1 -1
- package/dist/src/query-planner.d.ts +47 -0
- package/dist/src/query-planner.d.ts.map +1 -0
- package/dist/src/query-planner.js +290 -0
- package/dist/src/query-planner.js.map +1 -0
- package/dist/src/schema.d.ts +29 -7
- package/dist/src/schema.d.ts.map +1 -1
- package/dist/src/schema.js +354 -119
- package/dist/src/schema.js.map +1 -1
- package/dist/src/sqlite3-messages.worker.d.ts +4 -1
- package/dist/src/sqlite3-messages.worker.d.ts.map +1 -1
- package/dist/src/sqlite3-messages.worker.js.map +1 -1
- package/dist/src/sqlite3.browser.d.ts.map +1 -1
- package/dist/src/sqlite3.browser.js +7 -0
- package/dist/src/sqlite3.browser.js.map +1 -1
- package/dist/src/sqlite3.d.ts.map +1 -1
- package/dist/src/sqlite3.js +24 -14
- package/dist/src/sqlite3.js.map +1 -1
- package/dist/src/sqlite3.wasm.d.ts +1 -0
- package/dist/src/sqlite3.wasm.d.ts.map +1 -1
- package/dist/src/sqlite3.wasm.js +9 -1
- package/dist/src/sqlite3.wasm.js.map +1 -1
- package/dist/src/sqlite3.worker.js +7 -0
- package/dist/src/sqlite3.worker.js.map +1 -1
- package/dist/src/types.d.ts +1 -0
- package/dist/src/types.d.ts.map +1 -1
- package/package.json +78 -78
- package/src/engine.ts +143 -68
- package/src/query-planner.ts +334 -0
- package/src/schema.ts +498 -160
- package/src/sqlite3-messages.worker.ts +5 -0
- package/src/sqlite3.browser.ts +8 -0
- package/src/sqlite3.ts +24 -13
- package/src/sqlite3.wasm.ts +11 -1
- package/src/sqlite3.worker.ts +6 -1
- package/src/types.ts +1 -0
package/dist/src/schema.js
CHANGED
|
@@ -8,8 +8,9 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
10
|
import { FixedArrayKind, OptionKind, VecKind, WrappedType, deserialize, field as fieldDecalaration, getDependencies, getSchema, serialize, variant, } from "@dao-xyz/borsh";
|
|
11
|
-
import { toHexString } from "@peerbit/crypto";
|
|
11
|
+
import { fromHexString, toHexString } from "@peerbit/crypto";
|
|
12
12
|
import * as types from "@peerbit/indexer-interface";
|
|
13
|
+
import { flattenQuery } from "./query-planner.js";
|
|
13
14
|
const SQLConversionMap = {
|
|
14
15
|
u8: "INTEGER",
|
|
15
16
|
u16: "INTEGER",
|
|
@@ -27,6 +28,8 @@ const SQLConversionMap = {
|
|
|
27
28
|
Date: "TEXT",
|
|
28
29
|
};
|
|
29
30
|
const WRAPPED_SIMPLE_VALUE_VARIANT = "wrapped";
|
|
31
|
+
let JSON_GROUP_ARRAY = "json_group_array";
|
|
32
|
+
let JSON_OBJECT = "distinct json_object";
|
|
30
33
|
export const u64ToI64 = (u64) => {
|
|
31
34
|
return (typeof u64 === "number" ? BigInt(u64) : u64) - 9223372036854775808n;
|
|
32
35
|
};
|
|
@@ -45,7 +48,7 @@ export const convertToSQLType = (value, type) => {
|
|
|
45
48
|
return value;
|
|
46
49
|
};
|
|
47
50
|
const nullAsUndefined = (value) => (value === null ? undefined : value);
|
|
48
|
-
export const escapeColumnName = (name) =>
|
|
51
|
+
export const escapeColumnName = (name, char = '"') => `${char}${name}${char}`;
|
|
49
52
|
export class MissingFieldError extends Error {
|
|
50
53
|
constructor(message) {
|
|
51
54
|
super(message);
|
|
@@ -127,6 +130,7 @@ export const getSQLTable = (ctor, path, primary, inline, addJoinField, fromOptio
|
|
|
127
130
|
referencedInArray: false,
|
|
128
131
|
isSimpleValue: false,
|
|
129
132
|
inline,
|
|
133
|
+
indices: new Set(),
|
|
130
134
|
};
|
|
131
135
|
ret.push(table);
|
|
132
136
|
for (const dep of dependencies) {
|
|
@@ -158,12 +162,21 @@ const getNameOfClass = (ctor) => {
|
|
|
158
162
|
return name;
|
|
159
163
|
};
|
|
160
164
|
export const getTableName = (path = [], clazz) => {
|
|
165
|
+
let pathKey = path.length > 0 ? path.join("__") + "__" : "";
|
|
166
|
+
if (typeof clazz !== "string") {
|
|
167
|
+
const tableName = clazz["__table_" + pathKey];
|
|
168
|
+
if (tableName) {
|
|
169
|
+
return tableName;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
161
172
|
let name = typeof clazz === "string" ? clazz : getNameOfClass(clazz);
|
|
162
173
|
// prefix the generated table name so that the name is a valid SQL identifier (table name)
|
|
163
174
|
// choose prefix which is readable and explains that this is a generated table name
|
|
164
175
|
// leading _ to allow path to have numbers
|
|
165
|
-
const ret =
|
|
166
|
-
|
|
176
|
+
const ret = pathKey + name.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
177
|
+
if (typeof clazz !== "string") {
|
|
178
|
+
clazz["__table_" + pathKey] = ret;
|
|
179
|
+
}
|
|
167
180
|
return ret;
|
|
168
181
|
};
|
|
169
182
|
export const CHILD_TABLE_ID = "__id";
|
|
@@ -186,12 +199,12 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
186
199
|
? addJoinFieldFromParent
|
|
187
200
|
: (fields, contstraints) => {
|
|
188
201
|
// we resolve primary field here since it might be unknown until this point
|
|
189
|
-
const
|
|
202
|
+
const parentPrimaryField = primary != null
|
|
190
203
|
? sqlFields.find((field) => field.name === primary)
|
|
191
204
|
: undefined;
|
|
192
|
-
const parentPrimaryFieldName =
|
|
193
|
-
const parentPrimaryFieldType =
|
|
194
|
-
?
|
|
205
|
+
const parentPrimaryFieldName = parentPrimaryField?.key || CHILD_TABLE_ID;
|
|
206
|
+
const parentPrimaryFieldType = parentPrimaryField
|
|
207
|
+
? parentPrimaryField.type
|
|
195
208
|
: "INTEGER";
|
|
196
209
|
fields.unshift({
|
|
197
210
|
name: CHILD_TABLE_ID,
|
|
@@ -200,6 +213,7 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
200
213
|
type: "INTEGER",
|
|
201
214
|
isPrimary: true,
|
|
202
215
|
from: undefined,
|
|
216
|
+
unwrappedType: undefined,
|
|
203
217
|
path: [CHILD_TABLE_ID],
|
|
204
218
|
},
|
|
205
219
|
// foreign key parent document
|
|
@@ -208,8 +222,9 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
208
222
|
key: PARENT_TABLE_ID,
|
|
209
223
|
definition: `${PARENT_TABLE_ID} ${parentPrimaryFieldType}`,
|
|
210
224
|
type: parentPrimaryFieldType,
|
|
225
|
+
from: parentPrimaryField?.from,
|
|
226
|
+
unwrappedType: parentPrimaryField?.unwrappedType,
|
|
211
227
|
isPrimary: false,
|
|
212
|
-
from: undefined,
|
|
213
228
|
path: [PARENT_TABLE_ID],
|
|
214
229
|
});
|
|
215
230
|
contstraints.push({
|
|
@@ -268,6 +283,7 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
268
283
|
type: "INTEGER",
|
|
269
284
|
isPrimary: false,
|
|
270
285
|
from: undefined,
|
|
286
|
+
unwrappedType: undefined,
|
|
271
287
|
path: [ARRAY_INDEX_COLUMN],
|
|
272
288
|
},
|
|
273
289
|
...table.fields.slice(2),
|
|
@@ -290,6 +306,7 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
290
306
|
type: fieldType,
|
|
291
307
|
isPrimary,
|
|
292
308
|
from: field,
|
|
309
|
+
unwrappedType: unwrapNestedType(field.type),
|
|
293
310
|
path: [...path.slice(1), key],
|
|
294
311
|
});
|
|
295
312
|
};
|
|
@@ -364,6 +381,7 @@ export const getSQLFields = (tableName, path, ctor, primary, addJoinFieldFromPar
|
|
|
364
381
|
type: "bool",
|
|
365
382
|
isPrimary: false,
|
|
366
383
|
from: undefined,
|
|
384
|
+
unwrappedType: undefined,
|
|
367
385
|
path: [...path.slice(1), key],
|
|
368
386
|
describesExistenceOfAnother: path[path.length - 1],
|
|
369
387
|
});
|
|
@@ -450,7 +468,7 @@ const getTableFromValue = (parentTable, tables, field, value) => {
|
|
|
450
468
|
continue;
|
|
451
469
|
}
|
|
452
470
|
if (ctor) {
|
|
453
|
-
clazzName =
|
|
471
|
+
clazzName = ctor;
|
|
454
472
|
break;
|
|
455
473
|
}
|
|
456
474
|
}
|
|
@@ -539,14 +557,14 @@ export const insert = async (insertFn, obj, tables, table, fields, handleNestedC
|
|
|
539
557
|
for (const _field of subTable.fields) {
|
|
540
558
|
bindableValues.push(null);
|
|
541
559
|
}
|
|
542
|
-
bindableValues[bindableValues.length - 1] =
|
|
560
|
+
bindableValues[bindableValues.length - 1] = 0; // assign the value "false" to the exist field column
|
|
543
561
|
continue;
|
|
544
562
|
}
|
|
545
563
|
await insert((values, table) => {
|
|
546
564
|
if (table.inline) {
|
|
547
565
|
bindableValues.push(...values); // insert the bindable values into the parent bindable array
|
|
548
566
|
if (field.type instanceof OptionKind) {
|
|
549
|
-
bindableValues.push(
|
|
567
|
+
bindableValues.push(1); // assign the value "true" to the exist field column
|
|
550
568
|
}
|
|
551
569
|
return undefined;
|
|
552
570
|
}
|
|
@@ -630,16 +648,15 @@ const matchFieldInShape = (shape, path, field) => {
|
|
|
630
648
|
};
|
|
631
649
|
export const selectChildren = (childrenTable) => "select * from " + childrenTable.name + " where " + PARENT_TABLE_ID + " = ?";
|
|
632
650
|
export const generateSelectQuery = (table, selects) => {
|
|
633
|
-
return `
|
|
651
|
+
return `select ${selects.map((x) => `${x.from} as ${x.as}`).join(", ")} FROM ${table.name}`;
|
|
634
652
|
};
|
|
635
653
|
export const selectAllFieldsFromTables = (tables, shape) => {
|
|
636
654
|
const selectsPerTable = [];
|
|
637
655
|
for (const table of tables) {
|
|
638
|
-
const { selects, join: joinFromSelect } = selectAllFieldsFromTable(table, shape);
|
|
639
|
-
selectsPerTable.push({ selects, joins: joinFromSelect });
|
|
656
|
+
const { selects, join: joinFromSelect, groupBy, } = selectAllFieldsFromTable(table, shape);
|
|
657
|
+
selectsPerTable.push({ selects, joins: joinFromSelect, groupBy });
|
|
640
658
|
}
|
|
641
659
|
// pad with empty selects to make sure all selects have the same length
|
|
642
|
-
/* const maxSelects = Math.max(...selectsPerTable.map(x => x.selects.length)); */
|
|
643
660
|
let newSelects = [];
|
|
644
661
|
for (const [i, selects] of selectsPerTable.entries()) {
|
|
645
662
|
const newSelect = [];
|
|
@@ -654,10 +671,6 @@ export const selectAllFieldsFromTables = (tables, shape) => {
|
|
|
654
671
|
}
|
|
655
672
|
}
|
|
656
673
|
newSelects.push(newSelect);
|
|
657
|
-
/* let pad = 0;
|
|
658
|
-
while (select.selects.length < maxSelects) {
|
|
659
|
-
select.selects.push({ from: "NULL", as: `'pad#${++pad}'` });
|
|
660
|
-
} */
|
|
661
674
|
}
|
|
662
675
|
// also return table name
|
|
663
676
|
for (const [i, selects] of selectsPerTable.entries()) {
|
|
@@ -669,8 +682,58 @@ export const selectAllFieldsFromTable = (table, shape) => {
|
|
|
669
682
|
let stack = [{ table, shape }];
|
|
670
683
|
let join = new Map();
|
|
671
684
|
const fieldResolvers = [];
|
|
685
|
+
let groupByParentId = false;
|
|
672
686
|
for (const tableAndShape of stack) {
|
|
673
|
-
if (
|
|
687
|
+
if (tableAndShape.table.referencedInArray) {
|
|
688
|
+
let selectBuilder = `${JSON_GROUP_ARRAY}(${JSON_OBJECT}(`;
|
|
689
|
+
groupByParentId = true; // we need to group by the parent id as else we will not be returned with more than 1 result
|
|
690
|
+
let first = false;
|
|
691
|
+
const as = createReconstructReferenceName(tableAndShape.table);
|
|
692
|
+
for (const field of tableAndShape.table.fields) {
|
|
693
|
+
if ((field.isPrimary ||
|
|
694
|
+
!tableAndShape.shape ||
|
|
695
|
+
matchFieldInShape(tableAndShape.shape, [], field) ||
|
|
696
|
+
// also always include the index field
|
|
697
|
+
field.name === ARRAY_INDEX_COLUMN) &&
|
|
698
|
+
field.name !== PARENT_TABLE_ID) {
|
|
699
|
+
let resolveField = `${as}.${escapeColumnName(field.name)}`;
|
|
700
|
+
// if field is bigint we need to convert it to string, so that later in a JSON.parse scenario it is not converted to a number, but remains a string until we can convert it back to a bigint manually
|
|
701
|
+
if (field.unwrappedType === "u64") {
|
|
702
|
+
resolveField = `CAST(${resolveField} AS TEXT)`;
|
|
703
|
+
}
|
|
704
|
+
// if field is blob we need to convert it to hex string
|
|
705
|
+
if (field.type === "BLOB") {
|
|
706
|
+
resolveField = `HEX(${resolveField})`;
|
|
707
|
+
}
|
|
708
|
+
if (first) {
|
|
709
|
+
selectBuilder += `, `;
|
|
710
|
+
}
|
|
711
|
+
first = true;
|
|
712
|
+
selectBuilder += `${escapeColumnName(field.name, "'")}, ${resolveField}`;
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
selectBuilder += `)) `; // FILTER (WHERE ${tableAndShape.table.name}.${tableAndShape.table.primary} IS NOT NULL)
|
|
716
|
+
fieldResolvers.push({
|
|
717
|
+
from: selectBuilder,
|
|
718
|
+
as,
|
|
719
|
+
});
|
|
720
|
+
join.set(createReconstructReferenceName(tableAndShape.table), {
|
|
721
|
+
as,
|
|
722
|
+
table: tableAndShape.table,
|
|
723
|
+
type: "left",
|
|
724
|
+
columns: [],
|
|
725
|
+
});
|
|
726
|
+
}
|
|
727
|
+
else if (!tableAndShape.table.inline) {
|
|
728
|
+
// we end up here when we have simple joins we want to make that are not arrays, and not inlined
|
|
729
|
+
if (tableAndShape.table.parent != null) {
|
|
730
|
+
join.set(createReconstructReferenceName(tableAndShape.table), {
|
|
731
|
+
as: tableAndShape.table.name,
|
|
732
|
+
table: tableAndShape.table,
|
|
733
|
+
type: "left",
|
|
734
|
+
columns: [],
|
|
735
|
+
});
|
|
736
|
+
}
|
|
674
737
|
for (const field of tableAndShape.table.fields) {
|
|
675
738
|
if (field.isPrimary ||
|
|
676
739
|
!tableAndShape.shape ||
|
|
@@ -683,9 +746,6 @@ export const selectAllFieldsFromTable = (table, shape) => {
|
|
|
683
746
|
}
|
|
684
747
|
}
|
|
685
748
|
for (const child of tableAndShape.table.children) {
|
|
686
|
-
if (child.referencedInArray) {
|
|
687
|
-
continue;
|
|
688
|
-
}
|
|
689
749
|
let childShape = undefined;
|
|
690
750
|
if (tableAndShape.shape) {
|
|
691
751
|
const parentPath = child.parentPath?.slice(1);
|
|
@@ -703,15 +763,16 @@ export const selectAllFieldsFromTable = (table, shape) => {
|
|
|
703
763
|
: maybeShape;
|
|
704
764
|
}
|
|
705
765
|
stack.push({ table: child, shape: childShape });
|
|
706
|
-
if (!child.inline) {
|
|
707
|
-
join.set(child.name, { as: child.name, table: child });
|
|
708
|
-
}
|
|
709
766
|
}
|
|
710
767
|
}
|
|
711
768
|
if (fieldResolvers.length === 0) {
|
|
712
769
|
throw new Error("No fields to resolve");
|
|
713
770
|
}
|
|
714
771
|
return {
|
|
772
|
+
groupBy: groupByParentId
|
|
773
|
+
? `${table.name}.${escapeColumnName(table.primary)}` ||
|
|
774
|
+
undefined
|
|
775
|
+
: undefined,
|
|
715
776
|
selects: fieldResolvers, // `SELECT ${fieldResolvers.join(", ")} FROM ${table.name}`,
|
|
716
777
|
join,
|
|
717
778
|
};
|
|
@@ -746,14 +807,48 @@ export const resolveInstanceFromValue = async (fromTablePrefixedValues, tables,
|
|
|
746
807
|
? maybeShape[0]
|
|
747
808
|
: maybeShape;
|
|
748
809
|
if (isArray) {
|
|
749
|
-
let once = false;
|
|
810
|
+
/* let once = false; */
|
|
750
811
|
let resolvedArr = [];
|
|
751
812
|
for (const subtable of subTables) {
|
|
752
|
-
//
|
|
753
|
-
let
|
|
754
|
-
const
|
|
755
|
-
if (
|
|
756
|
-
|
|
813
|
+
// check if the array already in the provided row
|
|
814
|
+
let arr = undefined;
|
|
815
|
+
const tableName = createReconstructReferenceName(subtable);
|
|
816
|
+
if (fromTablePrefixedValues[tableName]) {
|
|
817
|
+
arr = JSON.parse(fromTablePrefixedValues[tableName]);
|
|
818
|
+
arr = arr.filter((x) => x[subtable.primary] != null);
|
|
819
|
+
// we need to go over all fields that are to be bigints and convert
|
|
820
|
+
// them back to bigints
|
|
821
|
+
// for blob fields we need to convert them back to Uint8Array
|
|
822
|
+
for (const field of subtable.fields) {
|
|
823
|
+
if (field.name === PARENT_TABLE_ID) {
|
|
824
|
+
continue;
|
|
825
|
+
}
|
|
826
|
+
if (field.unwrappedType === "u64") {
|
|
827
|
+
for (const item of arr) {
|
|
828
|
+
item[field.name] = BigInt(item[field.name]);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
else if (field.type === "BLOB") {
|
|
832
|
+
for (const item of arr) {
|
|
833
|
+
item[field.name] = fromHexString(item[field.name]);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
else {
|
|
839
|
+
if (subtable.children) {
|
|
840
|
+
// TODO we only end up where when we resolve nested arrays,
|
|
841
|
+
// which shoulld instead be resolved in a nested select (with json_group_array and json_object)
|
|
842
|
+
let rootTable = getNonInlinedTable(table);
|
|
843
|
+
const parentId = fromTablePrefixedValues[getTablePrefixedField(rootTable, rootTable.primary, !tablePrefixed)];
|
|
844
|
+
arr = await resolveChildren(parentId, subtable);
|
|
845
|
+
}
|
|
846
|
+
else {
|
|
847
|
+
arr = [];
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
if (arr && arr.length > 0) {
|
|
851
|
+
/* once = true; */
|
|
757
852
|
for (const element of arr) {
|
|
758
853
|
const resolved = await resolveInstanceFromValue(element, tables, subtable, // TODO fix
|
|
759
854
|
resolveChildren, false, subshape);
|
|
@@ -763,12 +858,7 @@ export const resolveInstanceFromValue = async (fromTablePrefixedValues, tables,
|
|
|
763
858
|
}
|
|
764
859
|
}
|
|
765
860
|
}
|
|
766
|
-
|
|
767
|
-
obj[field.key] = undefined;
|
|
768
|
-
}
|
|
769
|
-
else {
|
|
770
|
-
obj[field.key] = resolvedArr;
|
|
771
|
-
}
|
|
861
|
+
obj[field.key] = resolvedArr; // we can not do option(vec('T')) since we dont store the option type for Arrays (TODO)
|
|
772
862
|
}
|
|
773
863
|
else {
|
|
774
864
|
// resolve nested object from row directly
|
|
@@ -857,14 +947,14 @@ export const fromRowToObj = (row, ctor) => {
|
|
|
857
947
|
return Object.assign(Object.create(ctor.prototype), obj);
|
|
858
948
|
};
|
|
859
949
|
export const convertDeleteRequestToQuery = (request, tables, table) => {
|
|
860
|
-
const { query, bindable } = convertRequestToQuery("delete", request, tables, table);
|
|
950
|
+
const { query, bindable } = convertRequestToQuery("delete", { query: types.toQuery(request.query) }, tables, table);
|
|
861
951
|
return {
|
|
862
952
|
sql: `DELETE FROM ${table.name} WHERE ${table.primary} IN (SELECT ${table.primary} from ${table.name} ${query}) returning ${table.primary}`,
|
|
863
953
|
bindable,
|
|
864
954
|
};
|
|
865
955
|
};
|
|
866
956
|
export const convertSumRequestToQuery = (request, tables, table) => {
|
|
867
|
-
const { query, bindable } = convertRequestToQuery("sum", request, tables, table);
|
|
957
|
+
const { query, bindable } = convertRequestToQuery("sum", { query: types.toQuery(request.query), key: request.key }, tables, table);
|
|
868
958
|
const inlineName = getInlineTableFieldName(request.key);
|
|
869
959
|
const field = table.fields.find((x) => x.name === inlineName);
|
|
870
960
|
if (unwrapNestedType(field.from.type) === "u64") {
|
|
@@ -877,12 +967,45 @@ export const convertSumRequestToQuery = (request, tables, table) => {
|
|
|
877
967
|
};
|
|
878
968
|
};
|
|
879
969
|
export const convertCountRequestToQuery = (request, tables, table) => {
|
|
880
|
-
const { query, bindable } = convertRequestToQuery("count", request, tables, table);
|
|
970
|
+
const { query, bindable } = convertRequestToQuery("count", { query: request?.query ? types.toQuery(request.query) : undefined }, tables, table);
|
|
881
971
|
return {
|
|
882
972
|
sql: `SELECT count(*) as count FROM ${table.name} ${query}`,
|
|
883
973
|
bindable,
|
|
884
974
|
};
|
|
885
975
|
};
|
|
976
|
+
const buildOrderBy = (sort, tables, table, joinBuilder, resolverBuilder, path = [], options) => {
|
|
977
|
+
let orderByBuilder = undefined;
|
|
978
|
+
if ((!sort || (Array.isArray(sort) && sort.length === 0)) &&
|
|
979
|
+
!options?.fetchAll) {
|
|
980
|
+
sort =
|
|
981
|
+
table.primary && path.length === 0
|
|
982
|
+
? [{ key: [table.primary], direction: types.SortDirection.ASC }]
|
|
983
|
+
: undefined;
|
|
984
|
+
}
|
|
985
|
+
if (sort) {
|
|
986
|
+
let sortArr = Array.isArray(sort) ? sort : [sort];
|
|
987
|
+
if (sortArr.length > 0) {
|
|
988
|
+
orderByBuilder = "";
|
|
989
|
+
let once = false;
|
|
990
|
+
for (const sort of sortArr) {
|
|
991
|
+
const { foreignTables, queryKey } = resolveTableToQuery(table, tables, joinBuilder, [...path, ...sort.key], undefined, true);
|
|
992
|
+
for (const foreignTable of foreignTables) {
|
|
993
|
+
if (once) {
|
|
994
|
+
orderByBuilder += ", ";
|
|
995
|
+
}
|
|
996
|
+
once = true;
|
|
997
|
+
foreignTable.columns.push(queryKey); // add the sort key to the list of columns that will be used for this query
|
|
998
|
+
orderByBuilder += `"${foreignTable.as}#${queryKey}" ${sort.direction === types.SortDirection.ASC ? "ASC" : "DESC"}`;
|
|
999
|
+
resolverBuilder.push({
|
|
1000
|
+
from: `${table.name}.${escapeColumnName(queryKey)}`,
|
|
1001
|
+
as: `'${foreignTable.as}#${queryKey}'`,
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return { orderByBuilder };
|
|
1008
|
+
};
|
|
886
1009
|
export const convertSearchRequestToQuery = (request, tables, rootTables, options) => {
|
|
887
1010
|
let unionBuilder = "";
|
|
888
1011
|
let orderByClause = "";
|
|
@@ -891,21 +1014,19 @@ export const convertSearchRequestToQuery = (request, tables, rootTables, options
|
|
|
891
1014
|
const selectsPerTable = selectAllFieldsFromTables(rootTables, options?.shape);
|
|
892
1015
|
let bindableBuilder = [];
|
|
893
1016
|
for (const [i, table] of rootTables.entries()) {
|
|
894
|
-
const { selects, joins
|
|
895
|
-
const selectQuery = generateSelectQuery(table, selects);
|
|
1017
|
+
const { selects, joins, groupBy } = selectsPerTable[i];
|
|
896
1018
|
try {
|
|
897
|
-
const {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
:
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
bindableBuilder.push(...bindable);
|
|
1019
|
+
const { orderByBuilder } = buildOrderBy(request?.sort, tables, table, joins, selects, [], options);
|
|
1020
|
+
if (!orderByClause && orderByBuilder) {
|
|
1021
|
+
// assume all order by clauses will be the same
|
|
1022
|
+
orderByClause =
|
|
1023
|
+
orderByBuilder.length > 0
|
|
1024
|
+
? orderByClause.length > 0
|
|
1025
|
+
? orderByClause + ", " + orderByBuilder
|
|
1026
|
+
: orderByBuilder
|
|
1027
|
+
: orderByClause;
|
|
1028
|
+
}
|
|
1029
|
+
//orderByAddedOnce = true;
|
|
909
1030
|
}
|
|
910
1031
|
catch (error) {
|
|
911
1032
|
if (error instanceof MissingFieldError) {
|
|
@@ -914,138 +1035,209 @@ export const convertSearchRequestToQuery = (request, tables, rootTables, options
|
|
|
914
1035
|
}
|
|
915
1036
|
throw error;
|
|
916
1037
|
}
|
|
1038
|
+
const selectQuery = generateSelectQuery(table, selects);
|
|
1039
|
+
for (const flattenRequest of flattenQuery(request)) {
|
|
1040
|
+
try {
|
|
1041
|
+
const { query, bindable } = convertRequestToQuery("iterate", flattenRequest, tables, table, new Map(joins), // copy the map, else we might might do unececessary joins
|
|
1042
|
+
[], options);
|
|
1043
|
+
unionBuilder += `${unionBuilder.length > 0 ? " UNION " : ""} ${selectQuery} ${query} ${groupBy ? "GROUP BY " + groupBy : ""}`;
|
|
1044
|
+
matchedOnce = true;
|
|
1045
|
+
bindableBuilder.push(...bindable);
|
|
1046
|
+
}
|
|
1047
|
+
catch (error) {
|
|
1048
|
+
if (error instanceof MissingFieldError) {
|
|
1049
|
+
lastError = error;
|
|
1050
|
+
orderByClause = "";
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
throw error;
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
917
1056
|
}
|
|
918
1057
|
if (!matchedOnce) {
|
|
919
1058
|
throw lastError;
|
|
920
1059
|
}
|
|
921
1060
|
return {
|
|
922
|
-
sql: `${unionBuilder} ${orderByClause ? "ORDER BY " + orderByClause : ""} limit ? offset
|
|
1061
|
+
sql: `${unionBuilder} ${orderByClause ? "ORDER BY " + orderByClause : ""} ${options?.fetchAll ? "" : "limit ? offset ?"}`,
|
|
923
1062
|
bindable: bindableBuilder,
|
|
924
1063
|
};
|
|
925
1064
|
};
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1065
|
+
const getOrSetRootTable = (joinBuilder, table) => {
|
|
1066
|
+
const refName = createQueryTableReferenceName(table);
|
|
1067
|
+
let ref = joinBuilder.get(refName);
|
|
1068
|
+
if (ref) {
|
|
1069
|
+
return ref;
|
|
1070
|
+
}
|
|
1071
|
+
const join = {
|
|
1072
|
+
// add the root as a join even though it is not, just so we can collect the columns it will be queried
|
|
1073
|
+
table: table,
|
|
1074
|
+
type: "root",
|
|
1075
|
+
as: table.name,
|
|
1076
|
+
columns: [],
|
|
1077
|
+
};
|
|
1078
|
+
joinBuilder.set(refName, join);
|
|
1079
|
+
return join;
|
|
1080
|
+
};
|
|
929
1081
|
const convertRequestToQuery = (type, request, tables, table, extraJoin, path = [], options) => {
|
|
930
1082
|
let whereBuilder = "";
|
|
931
1083
|
let bindableBuilder = [];
|
|
932
|
-
let orderByBuilder = undefined;
|
|
1084
|
+
/* let orderByBuilder: string | undefined = undefined; */
|
|
933
1085
|
/* let tablesToSelect: string[] = [table.name]; */
|
|
934
1086
|
let joinBuilder = extraJoin || new Map();
|
|
1087
|
+
getOrSetRootTable(joinBuilder, table);
|
|
935
1088
|
const coercedQuery = types.toQuery(request?.query);
|
|
936
1089
|
if (coercedQuery.length === 1) {
|
|
937
|
-
const { where, bindable } = convertQueryToSQLQuery(coercedQuery[0], tables, table, joinBuilder, path);
|
|
1090
|
+
const { where, bindable } = convertQueryToSQLQuery(coercedQuery[0], tables, table, joinBuilder, path, undefined, 0);
|
|
938
1091
|
whereBuilder += where;
|
|
939
1092
|
bindableBuilder.push(...bindable);
|
|
940
1093
|
}
|
|
941
1094
|
else if (coercedQuery.length > 1) {
|
|
942
|
-
const { where, bindable } = convertQueryToSQLQuery(new types.And(coercedQuery), tables, table, joinBuilder, path);
|
|
1095
|
+
const { where, bindable } = convertQueryToSQLQuery(new types.And(coercedQuery), tables, table, joinBuilder, path, undefined, 0);
|
|
943
1096
|
whereBuilder += where;
|
|
944
1097
|
bindableBuilder.push(...bindable);
|
|
945
1098
|
}
|
|
946
|
-
if (isIterateRequest(request, type)) {
|
|
1099
|
+
/* if (isIterateRequest(request, type)) {
|
|
947
1100
|
let sort = request?.sort;
|
|
948
|
-
if (
|
|
1101
|
+
if (
|
|
1102
|
+
(!sort || (Array.isArray(sort) && sort.length === 0)) &&
|
|
1103
|
+
!options?.fetchAll
|
|
1104
|
+
) {
|
|
949
1105
|
sort =
|
|
950
1106
|
table.primary && path.length === 0
|
|
951
1107
|
? [{ key: [table.primary], direction: types.SortDirection.ASC }]
|
|
952
1108
|
: undefined;
|
|
953
1109
|
}
|
|
1110
|
+
|
|
954
1111
|
if (sort) {
|
|
955
1112
|
let sortArr = Array.isArray(sort) ? sort : [sort];
|
|
956
1113
|
if (sortArr.length > 0) {
|
|
957
1114
|
orderByBuilder = "";
|
|
958
1115
|
let once = false;
|
|
959
1116
|
for (const sort of sortArr) {
|
|
960
|
-
const { foreignTables, queryKey } = resolveTableToQuery(
|
|
961
|
-
|
|
1117
|
+
const { foreignTables, queryKey } = resolveTableToQuery(
|
|
1118
|
+
table,
|
|
1119
|
+
tables,
|
|
1120
|
+
joinBuilder,
|
|
1121
|
+
[...path, ...sort.key],
|
|
1122
|
+
undefined,
|
|
1123
|
+
true,
|
|
1124
|
+
);
|
|
1125
|
+
|
|
1126
|
+
for (const foreignTable of foreignTables) {
|
|
962
1127
|
if (once) {
|
|
963
1128
|
orderByBuilder += ", ";
|
|
964
1129
|
}
|
|
965
1130
|
once = true;
|
|
966
|
-
|
|
1131
|
+
|
|
1132
|
+
foreignTable.columns.push(queryKey); // add the sort key to the list of columns that will be used for this query
|
|
1133
|
+
|
|
1134
|
+
orderByBuilder += `${foreignTable.as}.${queryKey} ${sort.direction === types.SortDirection.ASC ? "ASC" : "DESC"}`;
|
|
967
1135
|
}
|
|
968
1136
|
}
|
|
969
|
-
/* orderByBuilder += request.sort
|
|
970
|
-
.map(
|
|
971
|
-
(sort) =>
|
|
972
|
-
`${table.name}.${sort.key} ${sort.direction === types.SortDirection.ASC ? "ASC" : "DESC"}`
|
|
973
|
-
)
|
|
974
|
-
.join(", "); */
|
|
975
1137
|
}
|
|
976
1138
|
}
|
|
977
|
-
}
|
|
1139
|
+
} */
|
|
978
1140
|
const where = whereBuilder.length > 0 ? "where " + whereBuilder : undefined;
|
|
979
1141
|
if (extraJoin && extraJoin.size > 0) {
|
|
980
1142
|
insertMapIntoMap(joinBuilder, extraJoin);
|
|
981
1143
|
}
|
|
982
|
-
let join = buildJoin(joinBuilder,
|
|
1144
|
+
let { join } = buildJoin(joinBuilder, options);
|
|
983
1145
|
const query = `${join ? join : ""} ${where ? where : ""}`;
|
|
984
1146
|
return {
|
|
985
1147
|
query,
|
|
986
|
-
orderBy: orderByBuilder,
|
|
1148
|
+
/* orderBy: orderByBuilder, */
|
|
987
1149
|
bindable: bindableBuilder,
|
|
988
1150
|
};
|
|
989
1151
|
};
|
|
990
|
-
export const buildJoin = (joinBuilder,
|
|
991
|
-
let joinTypeDefault = resolveAllColumns
|
|
992
|
-
?
|
|
993
|
-
: "JOIN";
|
|
1152
|
+
export const buildJoin = (joinBuilder, options) => {
|
|
1153
|
+
/* let joinTypeDefault = resolveAllColumns
|
|
1154
|
+
? "CROSS JOIN"
|
|
1155
|
+
: "JOIN"; */
|
|
994
1156
|
let join = "";
|
|
995
1157
|
for (const [_key, table] of joinBuilder) {
|
|
1158
|
+
if (table.type !== "root") {
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
const out = _buildJoin(table, options);
|
|
1162
|
+
join += out.join;
|
|
1163
|
+
}
|
|
1164
|
+
for (const [_key, table] of joinBuilder) {
|
|
1165
|
+
if (table.type === "root") {
|
|
1166
|
+
continue;
|
|
1167
|
+
}
|
|
1168
|
+
const out = _buildJoin(table, options);
|
|
1169
|
+
join += out.join;
|
|
1170
|
+
}
|
|
1171
|
+
return { join };
|
|
1172
|
+
};
|
|
1173
|
+
const _buildJoin = (table, options) => {
|
|
1174
|
+
let join = "";
|
|
1175
|
+
let indexedBy = undefined;
|
|
1176
|
+
if (table.type !== "root") {
|
|
1177
|
+
table.columns.push(PARENT_TABLE_ID); // we unshift because we join on the parent id before where clause
|
|
1178
|
+
}
|
|
1179
|
+
if (table.columns.length > 0) {
|
|
1180
|
+
const usedColumns = removeDuplicatesOrdered(table.columns);
|
|
1181
|
+
indexedBy = options?.planner
|
|
1182
|
+
? ` INDEXED BY ${options.planner.resolveIndex(table.table.name, usedColumns)} `
|
|
1183
|
+
: "";
|
|
1184
|
+
}
|
|
1185
|
+
if (table.type !== "root") {
|
|
996
1186
|
let nonInlinedParent = table.table.parent && getNonInlinedTable(table.table.parent);
|
|
997
1187
|
if (!nonInlinedParent) {
|
|
998
1188
|
throw new Error("Unexpected: missing parent");
|
|
999
1189
|
}
|
|
1000
|
-
let joinType = table.
|
|
1001
|
-
|
|
1002
|
-
: joinTypeDefault;
|
|
1003
|
-
join += `${joinType} ${table.table.name} AS ${table.as} ON ${nonInlinedParent.name}.${nonInlinedParent.primary} = ${table.as}.${PARENT_TABLE_ID} `;
|
|
1190
|
+
let joinType = table.type === "cross" ? "LEFT JOIN" : "LEFT JOIN";
|
|
1191
|
+
join += ` ${joinType} ${table.table.name} AS ${table.as} ${indexedBy} ON ${nonInlinedParent.name}.${nonInlinedParent.primary} = ${table.as}.${PARENT_TABLE_ID} `;
|
|
1004
1192
|
}
|
|
1005
|
-
|
|
1193
|
+
else if (indexedBy) {
|
|
1194
|
+
join += indexedBy;
|
|
1195
|
+
}
|
|
1196
|
+
return { join };
|
|
1006
1197
|
};
|
|
1007
1198
|
const insertMapIntoMap = (map, insert) => {
|
|
1008
1199
|
for (const [key, value] of insert) {
|
|
1009
1200
|
map.set(key, value);
|
|
1010
1201
|
}
|
|
1011
1202
|
};
|
|
1012
|
-
export const convertQueryToSQLQuery = (query, tables, table, joinBuilder, path
|
|
1203
|
+
export const convertQueryToSQLQuery = (query, tables, table, joinBuilder, path, tableAlias, skipKeys) => {
|
|
1013
1204
|
let whereBuilder = "";
|
|
1014
1205
|
let bindableBuilder = [];
|
|
1015
1206
|
/* let tablesToSelect: string[] = []; */
|
|
1016
|
-
const handleAnd = (queries, path, tableAlias) => {
|
|
1207
|
+
const handleAnd = (queries, path, tableAlias, keysOffset) => {
|
|
1017
1208
|
for (const query of queries) {
|
|
1018
|
-
const { where, bindable } = convertQueryToSQLQuery(query, tables, table, joinBuilder, path, tableAlias);
|
|
1209
|
+
const { where, bindable } = convertQueryToSQLQuery(query, tables, table, joinBuilder, path, tableAlias, keysOffset);
|
|
1019
1210
|
whereBuilder =
|
|
1020
1211
|
whereBuilder.length > 0 ? `(${whereBuilder}) AND (${where})` : where;
|
|
1021
1212
|
bindableBuilder.push(...bindable);
|
|
1022
1213
|
}
|
|
1023
1214
|
};
|
|
1024
1215
|
if (query instanceof types.StateFieldQuery) {
|
|
1025
|
-
const { where, bindable } = convertStateFieldQuery(query, tables, table, joinBuilder, path, tableAlias);
|
|
1216
|
+
const { where, bindable } = convertStateFieldQuery(query, tables, table, joinBuilder, path, tableAlias, skipKeys);
|
|
1026
1217
|
whereBuilder += where;
|
|
1027
1218
|
bindableBuilder.push(...bindable);
|
|
1028
1219
|
}
|
|
1029
1220
|
else if (query instanceof types.Nested) {
|
|
1030
1221
|
let joinPrefix = "__" + String(tables.size);
|
|
1031
|
-
path = [...path, query.path];
|
|
1032
|
-
|
|
1222
|
+
path = [...path, ...query.path];
|
|
1223
|
+
let newSkipKeys = skipKeys + query.path.length;
|
|
1224
|
+
handleAnd(query.query, path, joinPrefix, newSkipKeys);
|
|
1033
1225
|
}
|
|
1034
1226
|
else if (query instanceof types.LogicalQuery) {
|
|
1035
1227
|
if (query instanceof types.And) {
|
|
1036
|
-
handleAnd(query.and, path, tableAlias);
|
|
1228
|
+
handleAnd(query.and, path, tableAlias, skipKeys);
|
|
1037
1229
|
}
|
|
1038
1230
|
else if (query instanceof types.Or) {
|
|
1039
1231
|
for (const subquery of query.or) {
|
|
1040
|
-
const { where, bindable } = convertQueryToSQLQuery(subquery, tables, table, joinBuilder, path, tableAlias);
|
|
1232
|
+
const { where, bindable } = convertQueryToSQLQuery(subquery, tables, table, joinBuilder, path, tableAlias, skipKeys);
|
|
1041
1233
|
whereBuilder =
|
|
1042
|
-
whereBuilder.length > 0 ? `(${whereBuilder}) OR
|
|
1234
|
+
whereBuilder.length > 0 ? `(${whereBuilder}) OR(${where})` : where;
|
|
1043
1235
|
bindableBuilder.push(...bindable);
|
|
1044
1236
|
}
|
|
1045
1237
|
}
|
|
1046
1238
|
else if (query instanceof types.Not) {
|
|
1047
|
-
const { where, bindable } = convertQueryToSQLQuery(query.not, tables, table, joinBuilder, path, tableAlias);
|
|
1048
|
-
whereBuilder = `NOT
|
|
1239
|
+
const { where, bindable } = convertQueryToSQLQuery(query.not, tables, table, joinBuilder, path, tableAlias, skipKeys);
|
|
1240
|
+
whereBuilder = `NOT(${where})`;
|
|
1049
1241
|
bindableBuilder.push(...bindable);
|
|
1050
1242
|
}
|
|
1051
1243
|
else {
|
|
@@ -1063,16 +1255,26 @@ export const convertQueryToSQLQuery = (query, tables, table, joinBuilder, path =
|
|
|
1063
1255
|
const cloneQuery = (query) => {
|
|
1064
1256
|
return deserialize(serialize(query), types.StateFieldQuery);
|
|
1065
1257
|
};
|
|
1066
|
-
const
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1258
|
+
/* const createQueryTableReferenceName = (
|
|
1259
|
+
table: Table,
|
|
1260
|
+
alias: string | undefined,
|
|
1261
|
+
) => {
|
|
1262
|
+
|
|
1263
|
+
if (
|
|
1264
|
+
!alias
|
|
1265
|
+
) {
|
|
1266
|
+
let aliasSuffix =
|
|
1267
|
+
"_query"; // "_" + String(joinSize); TODO this property will make every join unique, which is not wanted unless (ever?) since we can do OR in SQL which means we can do one join and perform AND/OR logic without joining multiple times to apply multiple conditions
|
|
1072
1268
|
alias = aliasSuffix;
|
|
1073
1269
|
}
|
|
1074
1270
|
const tableNameAs = alias ? alias + "_" + table.name : table.name;
|
|
1075
1271
|
return tableNameAs;
|
|
1272
|
+
}; */
|
|
1273
|
+
const createQueryTableReferenceName = (table) => {
|
|
1274
|
+
return table.parent == null ? table.name : "_query_" + table.name;
|
|
1275
|
+
};
|
|
1276
|
+
const createReconstructReferenceName = (table) => {
|
|
1277
|
+
return table.name; /* table.parent == null ? table.name : "_rec_" + table.name; */
|
|
1076
1278
|
};
|
|
1077
1279
|
const resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
|
|
1078
1280
|
// we are matching in two ways.
|
|
@@ -1088,11 +1290,18 @@ const resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
|
|
|
1088
1290
|
if (field) {
|
|
1089
1291
|
return {
|
|
1090
1292
|
queryKey: field.name,
|
|
1091
|
-
foreignTables: [
|
|
1293
|
+
foreignTables: [getOrSetRootTable(join, table)],
|
|
1092
1294
|
};
|
|
1093
1295
|
}
|
|
1094
1296
|
}
|
|
1095
|
-
let currentTables = [
|
|
1297
|
+
let currentTables = [
|
|
1298
|
+
{
|
|
1299
|
+
table,
|
|
1300
|
+
as: alias || table.name,
|
|
1301
|
+
type: "cross",
|
|
1302
|
+
columns: [],
|
|
1303
|
+
},
|
|
1304
|
+
];
|
|
1096
1305
|
let prevTables = undefined;
|
|
1097
1306
|
// outer:
|
|
1098
1307
|
for (const [_i, key] of path /* .slice(0, -1) */
|
|
@@ -1103,13 +1312,20 @@ const resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
|
|
|
1103
1312
|
const field = schema.fields.find((x) => x.key === key);
|
|
1104
1313
|
if (!field && currentTable.children.length > 0) {
|
|
1105
1314
|
// second arg is needed because of polymorphic fields we might end up here intentially to check what tables to query
|
|
1106
|
-
throw new MissingFieldError(`Property with key "${key}" is not found in the schema ${JSON.stringify(schema.fields.map((x) => x.key))}`);
|
|
1315
|
+
throw new MissingFieldError(`Property with key "${key}" is not found in the schema ${JSON.stringify(schema.fields.map((x) => x.key))} `);
|
|
1107
1316
|
}
|
|
1108
1317
|
for (const child of currentTable.children) {
|
|
1109
|
-
const tableNameAs =
|
|
1318
|
+
const tableNameAs = createQueryTableReferenceName(child);
|
|
1110
1319
|
let isMatching = child.parentPath[child.parentPath.length - 1] === key;
|
|
1111
1320
|
if (isMatching) {
|
|
1112
|
-
const tableWithAlias = {
|
|
1321
|
+
const tableWithAlias = {
|
|
1322
|
+
columns: [],
|
|
1323
|
+
table: child,
|
|
1324
|
+
as: tableNameAs,
|
|
1325
|
+
type: currentTable.children.length > 1
|
|
1326
|
+
? "left"
|
|
1327
|
+
: "cross",
|
|
1328
|
+
};
|
|
1113
1329
|
if (child.isSimpleValue) {
|
|
1114
1330
|
if (!child.inline) {
|
|
1115
1331
|
join.set(tableNameAs, tableWithAlias);
|
|
@@ -1156,13 +1372,17 @@ const resolveTableToQuery = (table, tables, join, path, alias, searchSelf) => {
|
|
|
1156
1372
|
: FOREIGN_VALUE_PROPERTY;
|
|
1157
1373
|
return { queryKey, foreignTables };
|
|
1158
1374
|
};
|
|
1159
|
-
const convertStateFieldQuery = (query, tables, table, join, path, tableAlias
|
|
1375
|
+
const convertStateFieldQuery = (query, tables, table, join, path, tableAlias, skipKeys) => {
|
|
1160
1376
|
// if field id represented as foreign table, do join and compare
|
|
1161
1377
|
const inlinedName = getInlineTableFieldName(query.key);
|
|
1162
1378
|
const tableField = table.fields.find((x) => x.name === inlinedName); /* stringArraysEquals(query.key, [...table.parentPath, x.name]) )*/
|
|
1163
1379
|
const isForeign = !tableField; // table.fields.find(x => x.name === query.key[query.key.length - 1])
|
|
1164
1380
|
if (isForeign) {
|
|
1165
|
-
const
|
|
1381
|
+
const tablePath = [...path];
|
|
1382
|
+
for (let i = skipKeys; i < query.key.length; i++) {
|
|
1383
|
+
tablePath.push(query.key[i]);
|
|
1384
|
+
}
|
|
1385
|
+
const { queryKey, foreignTables } = resolveTableToQuery(table, tables, join, tablePath, tableAlias, false);
|
|
1166
1386
|
query = cloneQuery(query);
|
|
1167
1387
|
query.key = [queryKey];
|
|
1168
1388
|
let whereBuilder = [];
|
|
@@ -1171,7 +1391,7 @@ const convertStateFieldQuery = (query, tables, table, join, path, tableAlias = u
|
|
|
1171
1391
|
if (ftable.table === table) {
|
|
1172
1392
|
throw new Error("Unexpected");
|
|
1173
1393
|
}
|
|
1174
|
-
const { where, bindable } = convertQueryToSQLQuery(query, tables, ftable.table, join, path, ftable.as);
|
|
1394
|
+
const { where, bindable } = convertQueryToSQLQuery(query, tables, ftable.table, join, path, ftable.as, skipKeys);
|
|
1175
1395
|
whereBuilder.push(where);
|
|
1176
1396
|
bindableBuilder.push(bindable);
|
|
1177
1397
|
}
|
|
@@ -1180,17 +1400,22 @@ const convertStateFieldQuery = (query, tables, table, join, path, tableAlias = u
|
|
|
1180
1400
|
bindable: bindableBuilder.flat(),
|
|
1181
1401
|
};
|
|
1182
1402
|
}
|
|
1403
|
+
const columnAggregator = join.get(createQueryTableReferenceName(table));
|
|
1404
|
+
if (!columnAggregator) {
|
|
1405
|
+
throw new Error("Unexpected");
|
|
1406
|
+
}
|
|
1407
|
+
columnAggregator.columns.push(inlinedName);
|
|
1183
1408
|
let bindable = [];
|
|
1184
1409
|
const keyWithTable = (tableAlias || table.name) + "." + escapeColumnName(inlinedName);
|
|
1185
1410
|
let where;
|
|
1186
1411
|
if (query instanceof types.StringMatch) {
|
|
1187
1412
|
let statement = "";
|
|
1188
1413
|
if (query.method === types.StringMatchMethod.contains) {
|
|
1189
|
-
statement = `${keyWithTable} LIKE
|
|
1414
|
+
statement = `${keyWithTable} LIKE ? `;
|
|
1190
1415
|
bindable.push(`%${query.value}%`);
|
|
1191
1416
|
}
|
|
1192
1417
|
else if (query.method === types.StringMatchMethod.prefix) {
|
|
1193
|
-
statement = `${keyWithTable} LIKE
|
|
1418
|
+
statement = `${keyWithTable} LIKE ? `;
|
|
1194
1419
|
bindable.push(`${query.value}%`);
|
|
1195
1420
|
}
|
|
1196
1421
|
else if (query.method === types.StringMatchMethod.exact) {
|
|
@@ -1211,7 +1436,7 @@ const convertStateFieldQuery = (query, tables, table, join, path, tableAlias = u
|
|
|
1211
1436
|
else if (query instanceof types.IntegerCompare) {
|
|
1212
1437
|
if (tableField.type === "BLOB") {
|
|
1213
1438
|
// TODO perf
|
|
1214
|
-
where = `hex(${keyWithTable}) LIKE
|
|
1439
|
+
where = `hex(${keyWithTable}) LIKE ? `;
|
|
1215
1440
|
bindable.push(`%${toHexString(new Uint8Array([Number(query.value.value)]))}%`);
|
|
1216
1441
|
}
|
|
1217
1442
|
else {
|
|
@@ -1219,19 +1444,19 @@ const convertStateFieldQuery = (query, tables, table, join, path, tableAlias = u
|
|
|
1219
1444
|
where = `${keyWithTable} = ?`;
|
|
1220
1445
|
}
|
|
1221
1446
|
else if (query.compare === types.Compare.Greater) {
|
|
1222
|
-
where = `${keyWithTable} >
|
|
1447
|
+
where = `${keyWithTable} > ? `;
|
|
1223
1448
|
}
|
|
1224
1449
|
else if (query.compare === types.Compare.Less) {
|
|
1225
|
-
where = `${keyWithTable}
|
|
1450
|
+
where = `${keyWithTable} <?`;
|
|
1226
1451
|
}
|
|
1227
1452
|
else if (query.compare === types.Compare.GreaterOrEqual) {
|
|
1228
|
-
where = `${keyWithTable} >=
|
|
1453
|
+
where = `${keyWithTable} >= ? `;
|
|
1229
1454
|
}
|
|
1230
1455
|
else if (query.compare === types.Compare.LessOrEqual) {
|
|
1231
|
-
where = `${keyWithTable} <=
|
|
1456
|
+
where = `${keyWithTable} <= ? `;
|
|
1232
1457
|
}
|
|
1233
1458
|
else {
|
|
1234
|
-
throw new Error(`Unsupported compare type: ${query.compare}`);
|
|
1459
|
+
throw new Error(`Unsupported compare type: ${query.compare} `);
|
|
1235
1460
|
}
|
|
1236
1461
|
if (unwrapNestedType(tableField.from.type) === "u64") {
|
|
1237
1462
|
// shift left because that is how we insert the value
|
|
@@ -1254,4 +1479,14 @@ const convertStateFieldQuery = (query, tables, table, join, path, tableAlias = u
|
|
|
1254
1479
|
}
|
|
1255
1480
|
return { where, bindable };
|
|
1256
1481
|
};
|
|
1482
|
+
const removeDuplicatesOrdered = (arr) => {
|
|
1483
|
+
let seen = new Set();
|
|
1484
|
+
return arr.filter((item) => {
|
|
1485
|
+
if (seen.has(item)) {
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
seen.add(item);
|
|
1489
|
+
return true;
|
|
1490
|
+
});
|
|
1491
|
+
};
|
|
1257
1492
|
//# sourceMappingURL=schema.js.map
|