@blitznocode/blitz-orm 0.0.42 → 0.0.44

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/index.js ADDED
@@ -0,0 +1,1661 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
22
+ mod
23
+ ));
24
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
25
+
26
+ // src/index.ts
27
+ var src_exports = {};
28
+ __export(src_exports, {
29
+ default: () => src_default
30
+ });
31
+ module.exports = __toCommonJS(src_exports);
32
+ var import_radash9 = require("radash");
33
+ var import_typedb_client3 = require("typedb-client");
34
+
35
+ // src/default.config.ts
36
+ var defaultConfig = {
37
+ query: {
38
+ simplifiedLinks: true
39
+ },
40
+ mutation: {}
41
+ };
42
+
43
+ // src/helpers.ts
44
+ var import_immer = __toESM(require("immer"));
45
+ var import_object_traversal = require("object-traversal");
46
+ var import_radash = require("radash");
47
+ var getDbPath = (thing, attribute, shared) => shared ? attribute : `${thing}\xB7${attribute}`;
48
+ var getPath = (dbPath) => {
49
+ const parts = dbPath.split("\xB7");
50
+ return parts[parts.length - 1];
51
+ };
52
+ var oFind = (obj, fn) => Object.values(Object.fromEntries(Object.entries(obj).filter(([k, v]) => fn(k, v))))[0];
53
+ var oFilter = (obj, fn) => Object.fromEntries(Object.entries(obj).filter(([k, v]) => fn(k, v)));
54
+ var enrichSchema = (schema) => {
55
+ const allLinkedFields = [];
56
+ const withExtensionsSchema = (0, import_immer.default)(
57
+ schema,
58
+ (draft) => (0, import_object_traversal.traverse)(
59
+ draft,
60
+ ({ key, value, meta }) => {
61
+ if (meta.depth !== 2) {
62
+ return;
63
+ }
64
+ if (key) {
65
+ value.dataFields = value.dataFields?.map((df) => ({
66
+ ...df,
67
+ dbPath: getDbPath(key, df.path, df.shared)
68
+ }));
69
+ }
70
+ if (value.extends) {
71
+ const extendedSchema = draft.entities[value.extends] || draft.relations[value.extends];
72
+ value;
73
+ value.idFields = extendedSchema.idFields ? (value.idFields || []).concat(extendedSchema.idFields) : value.idFields;
74
+ value.dataFields = extendedSchema.dataFields ? (value.dataFields || []).concat(
75
+ extendedSchema.dataFields.map((df) => {
76
+ let deepExtendedThing = value.extends;
77
+ let deepSchema = schema.entities[deepExtendedThing] || schema.relations[deepExtendedThing];
78
+ while (!deepSchema.dataFields?.find((deepDf) => deepDf.path === df.path)) {
79
+ deepExtendedThing = deepSchema.extends;
80
+ deepSchema = schema.entities[deepExtendedThing] || schema.relations[deepExtendedThing];
81
+ }
82
+ return {
83
+ ...df,
84
+ dbPath: getDbPath(deepExtendedThing, df.path, df.shared)
85
+ };
86
+ })
87
+ ) : value.dataFields;
88
+ value.linkFields = extendedSchema.linkFields ? (value.linkFields || []).concat(extendedSchema.linkFields) : value.linkFields;
89
+ if ("roles" in extendedSchema) {
90
+ const val = value;
91
+ const extendedRelationSchema = extendedSchema;
92
+ val.roles = val.roles || {};
93
+ val.roles = {
94
+ ...val.roles,
95
+ ...extendedRelationSchema.roles
96
+ };
97
+ if (Object.keys(val.roles).length === 0) {
98
+ val.roles = {};
99
+ }
100
+ }
101
+ }
102
+ },
103
+ { traversalType: "breadth-first" }
104
+ )
105
+ );
106
+ (0, import_object_traversal.traverse)(schema, ({ key, value, meta }) => {
107
+ if (key === "linkFields") {
108
+ const getThingTypes = () => {
109
+ if (!meta.nodePath) {
110
+ throw new Error("No path");
111
+ }
112
+ const [thingPath, thing] = meta.nodePath.split(".");
113
+ const thingType = thingPath === "entities" ? "entity" : thingPath === "relations" ? "relation" : "";
114
+ return {
115
+ thing,
116
+ thingType
117
+ };
118
+ };
119
+ const thingTypes = getThingTypes();
120
+ const withThing = !Array.isArray(value) ? [
121
+ {
122
+ ...value,
123
+ ...thingTypes
124
+ }
125
+ ] : value.map((x) => ({ ...x, ...thingTypes }));
126
+ allLinkedFields.push(...withThing);
127
+ }
128
+ });
129
+ const enrichedSchema = (0, import_immer.default)(
130
+ withExtensionsSchema,
131
+ (draft) => (0, import_object_traversal.traverse)(draft, ({ value, key, meta }) => {
132
+ if (meta.depth === 2 && value.idFields && !value.id) {
133
+ value.name = key;
134
+ const thingType = () => {
135
+ if (meta.nodePath?.split(".")[0] === "entities")
136
+ return "entity";
137
+ if (meta.nodePath?.split(".")[0] === "relations")
138
+ return "relation";
139
+ throw new Error("Unsupported node attributes");
140
+ };
141
+ value.thingType = thingType();
142
+ value.computedFields = [];
143
+ if ("roles" in value) {
144
+ const val = value;
145
+ Object.entries(val.roles).forEach(([roleKey, role]) => {
146
+ role.playedBy = allLinkedFields.filter((x) => x.relation === key && x.plays === roleKey) || [];
147
+ });
148
+ }
149
+ if ("linkFields" in value && value.linkFields) {
150
+ const val = value;
151
+ val.linkFields?.forEach((linkField) => {
152
+ if (linkField.target === "relation") {
153
+ linkField.oppositeLinkFieldsPlayedBy = [
154
+ {
155
+ plays: linkField.path,
156
+ thing: linkField.relation,
157
+ thingType: "relation"
158
+ }
159
+ ];
160
+ return;
161
+ }
162
+ const allOppositeLinkFields = allLinkedFields.filter((x) => x.relation === linkField.relation && x.plays !== linkField.plays) || [];
163
+ linkField.oppositeLinkFieldsPlayedBy = allOppositeLinkFields;
164
+ const { filter } = linkField;
165
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
166
+ (x) => x.target === "role"
167
+ );
168
+ if (filter && Array.isArray(filter)) {
169
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
170
+ (lf) => filter.some((ft) => lf.thing === ft.$role)
171
+ );
172
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
173
+ (lf) => filter.some((ft) => lf.thing === ft.$thing)
174
+ );
175
+ }
176
+ if (filter && !Array.isArray(filter)) {
177
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
178
+ (lf) => lf.$role === filter.$role
179
+ );
180
+ linkField.oppositeLinkFieldsPlayedBy = linkField.oppositeLinkFieldsPlayedBy.filter(
181
+ (lf) => lf.thing === filter.$thing
182
+ );
183
+ }
184
+ });
185
+ }
186
+ }
187
+ if (typeof value === "object" && "playedBy" in value) {
188
+ if ([...new Set(value.playedBy?.map((x) => x.thing))].length > 1) {
189
+ throw new Error(
190
+ `Unsupported: roleFields can be only played by one thing. Role: ${key} path:${meta.nodePath}`
191
+ );
192
+ }
193
+ if (value.playedBy.length === 0) {
194
+ throw new Error(
195
+ `Unsupported: roleFields should be played at least by one thing. Role: ${key}, path:${meta.nodePath}`
196
+ );
197
+ }
198
+ }
199
+ if (meta.depth === 4 && (value.default || value.computedValue)) {
200
+ const [type, thingId] = meta.nodePath?.split(".") || [];
201
+ draft[type][thingId].computedFields.push(value.path);
202
+ }
203
+ })
204
+ );
205
+ return enrichedSchema;
206
+ };
207
+ var getCurrentSchema = (schema, node) => {
208
+ if (node.$entity) {
209
+ if (!(node.$entity in schema.entities)) {
210
+ throw new Error(`Missing entity '${node.$entity}' in the schema`);
211
+ }
212
+ return schema.entities[node.$entity];
213
+ }
214
+ if (node.$relation) {
215
+ if (!(node.$relation in schema.relations)) {
216
+ throw new Error(`Missing relation '${node.$relation}' in the schema`);
217
+ }
218
+ return schema.relations[node.$relation];
219
+ }
220
+ throw new Error(`Wrong schema or query for ${JSON.stringify(node)}`);
221
+ };
222
+ var getCurrentFields = (currentSchema, node) => {
223
+ const availableDataFields = currentSchema.dataFields?.map((x) => x.path);
224
+ const availableLinkFields = currentSchema.linkFields?.map((x) => x.path) || [];
225
+ const availableRoleFields = "roles" in currentSchema ? (0, import_radash.listify)(currentSchema.roles, (k) => k) : [];
226
+ const availableFields = [
227
+ ...availableDataFields || [],
228
+ ...availableLinkFields || [],
229
+ ...availableRoleFields || []
230
+ ];
231
+ const reservedRootFields = [
232
+ "$entity",
233
+ "$op",
234
+ "$id",
235
+ "$tempId",
236
+ "$filer",
237
+ "$relation",
238
+ "$parentKey",
239
+ "$filter",
240
+ "$fields"
241
+ ];
242
+ const allowedFields = [...reservedRootFields, ...availableFields];
243
+ if (!node) {
244
+ return {
245
+ fields: availableFields,
246
+ dataFields: availableDataFields,
247
+ roleFields: availableRoleFields,
248
+ linkFields: availableLinkFields
249
+ };
250
+ }
251
+ const usedFields = node.$fields ? node.$fields.map((x) => {
252
+ if (typeof x === "string")
253
+ return x;
254
+ if ("$path" in x)
255
+ return x.$path;
256
+ throw new Error(" Wrongly structured query");
257
+ }) : (0, import_radash.listify)(node, (k) => k);
258
+ const localFilterFields = !node.$filter ? [] : (0, import_radash.listify)(node.$filter, (k) => k.toString().startsWith("$") ? void 0 : k.toString()).filter(
259
+ (x) => x && availableDataFields?.includes(x)
260
+ );
261
+ const nestedFilterFields = !node.$filter ? [] : (0, import_radash.listify)(node.$filter, (k) => k.toString().startsWith("$") ? void 0 : k.toString()).filter(
262
+ (x) => x && [...availableRoleFields || [], ...availableLinkFields || []]?.includes(x)
263
+ );
264
+ const unidentifiedFields = [...usedFields, ...localFilterFields].filter((x) => !allowedFields.includes(x));
265
+ const localFilters = !node.$filter ? {} : oFilter(node.$filter, (k, _v) => localFilterFields.includes(k));
266
+ const nestedFilters = !node.$filter ? {} : oFilter(node.$filter, (k, _v) => nestedFilterFields.includes(k));
267
+ return {
268
+ fields: availableFields,
269
+ dataFields: availableDataFields,
270
+ roleFields: availableRoleFields,
271
+ linkFields: availableLinkFields,
272
+ unidentifiedFields,
273
+ ...localFilterFields.length ? { localFilters } : {},
274
+ ...nestedFilterFields.length ? { nestedFilters } : {}
275
+ };
276
+ };
277
+ var getLocalFilters = (currentSchema, node) => {
278
+ const localFilters = node.$localFilters && (0, import_radash.listify)(node.$localFilters, (k, v) => {
279
+ const currentDataField = currentSchema.dataFields?.find((x) => x.path === k);
280
+ return `has ${currentDataField?.dbPath} '${v}'`;
281
+ });
282
+ const localFiltersTql = localFilters?.length ? `, ${localFilters.join(",")}` : "";
283
+ return localFiltersTql;
284
+ };
285
+
286
+ // src/pipeline/control/dispatchPipeline.ts
287
+ var import_radash6 = require("radash");
288
+
289
+ // src/pipeline/postprocess/parseTQLRes.ts
290
+ var import_radash2 = require("radash");
291
+ var extractEntities = (conceptMapGroups, schema) => {
292
+ const bormEntities = conceptMapGroups.map((conceptMapGroup) => {
293
+ const conceptMaps = [...conceptMapGroup.conceptMaps];
294
+ const typeDBEntity = conceptMapGroup.owner.asThing();
295
+ const thingName = typeDBEntity.type.label.name;
296
+ const currentSchema = schema.entities[thingName] ? schema.entities[thingName] : schema.relations[thingName];
297
+ if (!currentSchema.idFields) {
298
+ throw new Error(`No idFields defined for ${thingName}`);
299
+ }
300
+ const thingType = schema.entities[thingName] ? "entity" : "relation";
301
+ const entityAttributes = conceptMaps.map((conceptMap) => {
302
+ const attribute = conceptMap.get("attribute")?.asAttribute();
303
+ if (!attribute) {
304
+ return [];
305
+ }
306
+ return [getPath(attribute.type.label.name), attribute.value];
307
+ });
308
+ const entity = Object.fromEntries(entityAttributes);
309
+ return {
310
+ ...entity,
311
+ [`$${thingType}`]: thingName,
312
+ $id: entity[currentSchema.idFields[0]]
313
+ };
314
+ });
315
+ return bormEntities;
316
+ };
317
+ var extractRelations = (conceptMapGroups, entityNames) => {
318
+ const relations = conceptMapGroups.flatMap((conceptMapGroup) => {
319
+ const relationsInGroup = conceptMapGroup.conceptMaps.map((conceptMap) => {
320
+ const link = /* @__PURE__ */ new Map();
321
+ entityNames.forEach((entityName) => {
322
+ const id = conceptMap.get(`${entityName}_id`)?.asAttribute().value.toString();
323
+ if (id)
324
+ link.set(entityName, id);
325
+ });
326
+ return link;
327
+ });
328
+ return relationsInGroup;
329
+ });
330
+ return relations;
331
+ };
332
+ var extractRoles = (conceptMapGroups, ownerPath, rolePath) => {
333
+ const roles = conceptMapGroups.flatMap((conceptMapGroup) => {
334
+ const rolesInGroup = conceptMapGroup.conceptMaps.map((conceptMap) => {
335
+ const ownerId = conceptMap.get(`${ownerPath}_id`)?.asAttribute().value.toString();
336
+ const roleId = conceptMap.get(`${rolePath}_id`)?.asAttribute().value.toString();
337
+ return {
338
+ ownerId,
339
+ path: rolePath,
340
+ roleId
341
+ };
342
+ });
343
+ return rolesInGroup;
344
+ });
345
+ return roles;
346
+ };
347
+ var parseTQLRes = async (req, res) => {
348
+ const { schema, bqlRequest, config, tqlRequest } = req;
349
+ const { rawTqlRes } = res;
350
+ if (!bqlRequest) {
351
+ throw new Error("BQL request not parsed");
352
+ } else if (!rawTqlRes) {
353
+ throw new Error("TQL query not executed");
354
+ }
355
+ const { query } = bqlRequest;
356
+ if (!query) {
357
+ if (rawTqlRes.insertions?.length === 0 && !tqlRequest?.deletions) {
358
+ throw new Error("Nothing has changed in DB, probably one of the ids specified in the mutation does not exist");
359
+ }
360
+ const { mutation } = bqlRequest;
361
+ if (!mutation) {
362
+ throw new Error("TQL mutation not executed");
363
+ }
364
+ const expected = [...mutation.things, ...mutation.edges];
365
+ const result = expected.map((x) => {
366
+ const currentNode = rawTqlRes.insertions?.[0].get(`${x.$tempId || x.$id}`);
367
+ if (x.$op === "create" || x.$op === "update" || x.$op === "link") {
368
+ if (!currentNode?.asThing().iid) {
369
+ throw new Error(`Thing not received on mutation: ${JSON.stringify(x)}`);
370
+ }
371
+ const dbIdd = currentNode?.asThing().iid;
372
+ if (config.mutation?.noMetadata) {
373
+ return (0, import_radash2.mapEntries)(x, (k, v) => [
374
+ k.toString().startsWith("$") ? Symbol.for(k) : k,
375
+ v
376
+ ]);
377
+ }
378
+ return { $dbId: dbIdd, ...x };
379
+ }
380
+ if (x.$op === "delete" || x.$op === "unlink") {
381
+ return x;
382
+ }
383
+ if (x.$op === "noop") {
384
+ return void 0;
385
+ }
386
+ throw new Error(`Unsupported op ${x.$op}`);
387
+ }).filter((x) => x);
388
+ res.bqlRes = result.length > 1 ? result : result[0];
389
+ return;
390
+ }
391
+ if (!rawTqlRes.entity) {
392
+ throw new Error("TQL query not executed");
393
+ }
394
+ const entities = extractEntities(rawTqlRes.entity, schema);
395
+ const relations = rawTqlRes.relations?.map((relation) => {
396
+ const currentRelSchema = schema.relations[relation.relation];
397
+ const currentRelroles = (0, import_radash2.listify)(
398
+ currentRelSchema.roles,
399
+ (_k, v) => {
400
+ if ([...new Set(v.playedBy?.map((x) => x.thing))].length !== 1) {
401
+ throw new Error("a role can be played by two entities throws the same relation");
402
+ }
403
+ if (!v.playedBy)
404
+ throw new Error("Role not being played by nobody");
405
+ return v.playedBy[0].thing;
406
+ }
407
+ );
408
+ const links = extractRelations(relation.conceptMapGroups, [
409
+ ...currentRelroles,
410
+ currentRelSchema.name
411
+ ]);
412
+ return {
413
+ name: relation.relation,
414
+ links
415
+ };
416
+ });
417
+ const roles = rawTqlRes.roles?.map((role) => {
418
+ return {
419
+ name: role.ownerPath,
420
+ links: extractRoles(role.conceptMapGroups, role.ownerPath, role.path)
421
+ };
422
+ });
423
+ const cache = res.cache || {
424
+ entities: /* @__PURE__ */ new Map(),
425
+ relations: /* @__PURE__ */ new Map(),
426
+ roleLinks: /* @__PURE__ */ new Map()
427
+ };
428
+ entities.forEach((entity) => {
429
+ const entityName = entity.$entity || entity.$relation;
430
+ const entityId = entity.$id;
431
+ const entityCache = cache.entities.get(entityName) || /* @__PURE__ */ new Map();
432
+ entityCache.set(entityId, { ...entity, $show: true });
433
+ cache.entities.set(entityName, entityCache);
434
+ });
435
+ relations?.forEach((relation) => {
436
+ const relationName = relation.name;
437
+ const relationCache = cache.relations.get(relationName) || [];
438
+ relationCache.push(...relation.links);
439
+ cache.relations.set(relationName, relationCache);
440
+ relation.links.forEach((link) => {
441
+ [...link.entries()].forEach(([entityName, entityId]) => {
442
+ const entityCache = cache.entities.get(entityName) || /* @__PURE__ */ new Map();
443
+ const getEntityThingType = () => {
444
+ if (schema.entities[entityName])
445
+ return "entity";
446
+ if (schema.relations[entityName])
447
+ return "relation";
448
+ throw new Error("Entity or relation not found");
449
+ };
450
+ const entityThingType = getEntityThingType();
451
+ const entity = {
452
+ [entityThingType]: entityName,
453
+ $id: entityId,
454
+ ...entityCache.get(entityId)
455
+ };
456
+ entityCache.set(entityId, entity);
457
+ cache.entities.set(entityName, entityCache);
458
+ });
459
+ });
460
+ });
461
+ roles?.forEach((role) => {
462
+ const ownerSchema = schema.relations[role.name] || schema.entities[role.name];
463
+ role.links.forEach((link) => {
464
+ const cachedLinks = cache.roleLinks.get(link.ownerId) || {};
465
+ let cachedLinkID = cachedLinks[link.path];
466
+ if (cachedLinkID) {
467
+ if ((0, import_radash2.isArray)(cachedLinkID)) {
468
+ cachedLinkID.push(link.roleId);
469
+ } else if ((0, import_radash2.isString)(cachedLinkID) && cachedLinkID !== link.roleId) {
470
+ cachedLinkID = [cachedLinkID, link.roleId];
471
+ }
472
+ } else {
473
+ cachedLinkID = link.roleId;
474
+ }
475
+ cachedLinks[link.path] = cachedLinkID;
476
+ cache.roleLinks.set(link.ownerId, cachedLinks);
477
+ ownerSchema.roles[link.path].playedBy?.forEach((roleSchema) => {
478
+ const entityCache = cache.entities.get(roleSchema.thing) || /* @__PURE__ */ new Map();
479
+ const entity = {
480
+ $entity: roleSchema.thing,
481
+ $id: link.roleId,
482
+ ...entityCache.get(link.roleId)
483
+ };
484
+ entityCache.set(link.roleId, entity);
485
+ cache.entities.set(roleSchema.thing, entityCache);
486
+ });
487
+ });
488
+ });
489
+ res.cache = cache;
490
+ };
491
+
492
+ // src/pipeline/postprocess/fieldsOperator.ts
493
+ var import_radash3 = require("radash");
494
+
495
+ // src/pipeline/postprocess/buildBQLTree.ts
496
+ var import_immer2 = __toESM(require("immer"));
497
+ var import_object_traversal2 = require("object-traversal");
498
+ var import_radash4 = require("radash");
499
+ var cleanOutput = (obj, config) => (0, import_immer2.default)(
500
+ obj,
501
+ (draft) => (0, import_object_traversal2.traverse)(
502
+ draft,
503
+ ({ value }) => {
504
+ if (Array.isArray(value) || !(typeof value === "object"))
505
+ return;
506
+ if (value.$fields) {
507
+ delete value.$fields;
508
+ }
509
+ if (value.$filter) {
510
+ delete value.$filter;
511
+ }
512
+ if (value.$show) {
513
+ delete value.$show;
514
+ }
515
+ if (config.query?.noMetadata && (value.$entity || value.$relation)) {
516
+ delete value.$entity;
517
+ delete value.$relation;
518
+ delete value.$id;
519
+ }
520
+ const symbols = Object.getOwnPropertySymbols(obj);
521
+ symbols.forEach((symbol) => {
522
+ delete value[symbol];
523
+ });
524
+ }
525
+ )
526
+ );
527
+ var filterChildrenEntities = (things, ids, node, path) => things.map(([id, entity]) => {
528
+ if (!ids)
529
+ return null;
530
+ if (!ids.includes(id))
531
+ return null;
532
+ if (!node.$fields)
533
+ return id;
534
+ if (node.$fields.includes(path))
535
+ return id;
536
+ const currentFieldConf = node.$fields.find((f) => (0, import_radash4.isObject)(f) && f.$path === path);
537
+ if (currentFieldConf) {
538
+ const onlyMetadataEntity = {
539
+ ...oFilter(entity, (k, _v) => k.startsWith("$"))
540
+ };
541
+ const withFieldsEntity = currentFieldConf.$fields ? {
542
+ ...onlyMetadataEntity,
543
+ $fields: currentFieldConf.$fields
544
+ } : onlyMetadataEntity;
545
+ if (currentFieldConf.$id) {
546
+ if (Array.isArray(currentFieldConf.$id)) {
547
+ if (currentFieldConf.$id.includes(id))
548
+ return withFieldsEntity;
549
+ return null;
550
+ }
551
+ if (currentFieldConf.$id === id)
552
+ return withFieldsEntity;
553
+ }
554
+ return withFieldsEntity;
555
+ }
556
+ return null;
557
+ }).filter((x) => x);
558
+ var buildBQLTree = async (req, res) => {
559
+ const { bqlRequest, config, schema } = req;
560
+ const { cache } = res;
561
+ if (!bqlRequest) {
562
+ throw new Error("BQL request not parsed");
563
+ }
564
+ const { query } = bqlRequest;
565
+ if (!query) {
566
+ res.bqlRes = cleanOutput(res.bqlRes, config);
567
+ return;
568
+ }
569
+ if (!cache) {
570
+ return;
571
+ }
572
+ const thingSchema = "$entity" in query ? query.$entity : query.$relation;
573
+ const entityMap = cache.entities.get(thingSchema.name);
574
+ if (!entityMap) {
575
+ res.bqlRes = null;
576
+ return;
577
+ }
578
+ const filterFields = (0, import_radash4.listify)(query.$filter, (x) => x);
579
+ const atLeastOneUnique = filterFields.some(
580
+ (x) => thingSchema.dataFields?.find((y) => y.path === x)?.validations?.unique
581
+ );
582
+ const monoOutput = !Array.isArray(bqlRequest.query) && (bqlRequest.query?.$id && !Array.isArray(bqlRequest.query?.$id) || atLeastOneUnique);
583
+ if (Array.isArray(req.rawBqlRequest)) {
584
+ throw new Error("Query arrays not implemented yet");
585
+ }
586
+ const rootThings = entityMap;
587
+ const structuredAnswer = [...rootThings].length ? [...rootThings].map(([id, _entity]) => ({
588
+ ...req.rawBqlRequest,
589
+ $id: id
590
+ })) : req.rawBqlRequest;
591
+ const bqlTree = (0, import_immer2.default)(
592
+ structuredAnswer,
593
+ (draft) => (0, import_object_traversal2.traverse)(draft, ({ value: val }) => {
594
+ const value = val;
595
+ if (!value?.$entity && !value?.$relation)
596
+ return;
597
+ const thingName = "$entity" in value ? value.$entity : value.$relation;
598
+ if (thingName) {
599
+ const currentIds = Array.isArray(value.$id) ? value.$id : [value.$id];
600
+ const currentSchema = "$relation" in value ? schema.relations[value.$relation] : schema.entities[value.$entity];
601
+ const { dataFields, roleFields } = getCurrentFields(currentSchema);
602
+ const currentEntities = cache.entities.get(thingName);
603
+ if (!currentEntities)
604
+ return;
605
+ [...currentEntities].forEach(([id, entity]) => {
606
+ if (currentIds.includes(id)) {
607
+ const queriedDataFields = value.$fields ? value.$fields : dataFields;
608
+ (0, import_radash4.listify)(entity, (k, v) => {
609
+ if (k.startsWith("$"))
610
+ return;
611
+ if (!queriedDataFields?.includes(k))
612
+ return;
613
+ value[k] = v;
614
+ });
615
+ const links = cache.roleLinks.get(id);
616
+ const flatRoleFields = value.$fields ? value.$fields.filter((x) => typeof x === "string") : roleFields;
617
+ const embeddedRoleFields = value.$fields?.filter((x) => typeof x === "object")?.map((y) => y.$path) || [];
618
+ Object.entries(links || {}).forEach(([rolePath, linkedIds]) => {
619
+ if (![...flatRoleFields, ...embeddedRoleFields].includes(rolePath)) {
620
+ return;
621
+ }
622
+ if (!("roles" in currentSchema))
623
+ throw new Error("No roles in schema");
624
+ const uniqueLinkedIds = !Array.isArray(linkedIds) ? [linkedIds] : [...new Set(linkedIds)];
625
+ const { cardinality, playedBy } = currentSchema.roles[rolePath];
626
+ const thingNames = [...new Set(playedBy?.map((x) => x.thing))];
627
+ const children = thingNames?.flatMap((x) => {
628
+ const thingEntities = cache.entities.get(x);
629
+ if (!thingEntities)
630
+ return [];
631
+ return filterChildrenEntities([...thingEntities], uniqueLinkedIds, value, rolePath);
632
+ });
633
+ if (children?.length) {
634
+ if (children.length === 1 && children[0] === value.$id) {
635
+ return;
636
+ }
637
+ if (cardinality === "ONE") {
638
+ value[rolePath] = children[0];
639
+ return;
640
+ }
641
+ value[rolePath] = children.filter(
642
+ (x) => typeof x === "string" || typeof x === "object" && x?.$show
643
+ );
644
+ }
645
+ });
646
+ }
647
+ });
648
+ const currentLinkFields = currentSchema.linkFields;
649
+ if (currentLinkFields) {
650
+ currentLinkFields.forEach((linkField) => {
651
+ const currentRelation = cache.relations.get(linkField.relation);
652
+ const tunnel = linkField.oppositeLinkFieldsPlayedBy;
653
+ if (linkField.target === "relation") {
654
+ const targetRelation = tunnel[0];
655
+ const targetRelationThings = cache.relations.get(linkField.relation);
656
+ const matchedLinks = !targetRelationThings ? [] : [...targetRelationThings].filter((link) => {
657
+ return currentIds.includes(link.get(thingName));
658
+ }).map((x) => x.get(targetRelation.thing));
659
+ const targetRelationEntities = cache.entities.get(targetRelation.thing);
660
+ if (!targetRelationEntities)
661
+ return null;
662
+ const children = filterChildrenEntities(
663
+ [...targetRelationEntities],
664
+ matchedLinks,
665
+ value,
666
+ linkField.path
667
+ );
668
+ if (children.length) {
669
+ if (children.length === 1 && children[0] === value.$id) {
670
+ return null;
671
+ }
672
+ if (linkField.cardinality === "ONE") {
673
+ value[linkField.path] = children[0];
674
+ return null;
675
+ }
676
+ value[linkField.path] = children.filter(
677
+ (x) => typeof x === "string" || typeof x === "object" && x?.$show
678
+ );
679
+ }
680
+ return null;
681
+ }
682
+ if (linkField.target === "role") {
683
+ const linkFieldPlayers = tunnel.flatMap((t) => {
684
+ const allCurrentLinkFieldThings = cache.entities.get(t.thing);
685
+ const linkedIds = currentRelation ? [...currentRelation].filter((rel) => rel.get(thingName) === currentIds[0]).map((x) => x.get(t.thing)) : [];
686
+ const uniqueLinkedIds = [...new Set(linkedIds)];
687
+ if (!allCurrentLinkFieldThings)
688
+ return null;
689
+ const children = filterChildrenEntities(
690
+ [...allCurrentLinkFieldThings],
691
+ uniqueLinkedIds,
692
+ value,
693
+ linkField.path
694
+ );
695
+ if (children.length) {
696
+ return children.filter(
697
+ (x) => typeof x === "string" || typeof x === "object" && x?.$show
698
+ );
699
+ }
700
+ return null;
701
+ }).filter((x) => x);
702
+ if (linkFieldPlayers && linkFieldPlayers.length) {
703
+ if (linkField.cardinality === "ONE") {
704
+ value[linkField.path] = linkFieldPlayers[0];
705
+ return null;
706
+ }
707
+ value[linkField.path] = linkFieldPlayers;
708
+ }
709
+ return null;
710
+ }
711
+ return null;
712
+ });
713
+ }
714
+ }
715
+ })
716
+ );
717
+ const withoutFieldFilters = cleanOutput(bqlTree, config);
718
+ res.bqlRes = monoOutput ? withoutFieldFilters[0] : withoutFieldFilters;
719
+ };
720
+
721
+ // src/pipeline/preprocess/buildTQLQuery.ts
722
+ var import_radash5 = require("radash");
723
+ var buildTQLQuery = async (req) => {
724
+ const { schema, bqlRequest } = req;
725
+ if (!bqlRequest?.query) {
726
+ throw new Error("BQL query not parsed");
727
+ }
728
+ const { query } = bqlRequest;
729
+ const currentThingSchema = "$entity" in query ? query.$entity : query.$relation;
730
+ const thingPath = currentThingSchema.defaultDBConnector.path || currentThingSchema.name;
731
+ if (!currentThingSchema.idFields) {
732
+ throw new Error("No id fields");
733
+ }
734
+ const [idField] = currentThingSchema.idFields;
735
+ const idParam = `$${thingPath}_id`;
736
+ let idFilter = `, has ${idField} ${idParam};`;
737
+ if (query.$id) {
738
+ if (Array.isArray(query.$id)) {
739
+ idFilter += ` ${idParam} like "${query.$id.join("|")}";`;
740
+ } else {
741
+ idFilter += ` ${idParam} "${query.$id}";`;
742
+ }
743
+ }
744
+ const localFiltersTql = getLocalFilters(currentThingSchema, query);
745
+ const allRoles = "roles" in currentThingSchema ? (0, import_radash5.listify)(currentThingSchema.roles, (k, v) => ({
746
+ path: k,
747
+ var: `$${k}`,
748
+ schema: v
749
+ })) : [];
750
+ const queryStr = `match $${thingPath} isa ${thingPath}, has attribute $attribute ${localFiltersTql} ${idFilter} group $${thingPath};`;
751
+ const rolesObj = allRoles.map((role) => {
752
+ if (!role.schema.playedBy || [...new Set(role.schema.playedBy?.map((x) => x.thing))].length !== 1) {
753
+ throw new Error("Unsupported: Role played by multiple linkfields or none");
754
+ }
755
+ const roleThingName = role.schema.playedBy[0].thing;
756
+ return {
757
+ path: role.path,
758
+ owner: thingPath,
759
+ request: `match $${thingPath} (${role.path}: ${role.var} ) isa ${thingPath} ${idFilter} ${role.var} isa ${roleThingName}, has id ${role.var}_id; group $${thingPath};`
760
+ };
761
+ });
762
+ const relations = currentThingSchema.linkFields?.flatMap((linkField) => {
763
+ const entityMatch = `match $${thingPath} isa ${thingPath}${localFiltersTql} ${idFilter}`;
764
+ const dirRel = linkField.target === "relation";
765
+ const tarRel = linkField.relation;
766
+ const relVar = `$${tarRel}`;
767
+ const relationMatchStart = `${dirRel ? relVar : ""} (${linkField.plays}: $${thingPath}`;
768
+ const relationMatchOpposite = linkField.oppositeLinkFieldsPlayedBy.map(
769
+ (link) => !dirRel ? `${link.plays}: $${link.thing}` : null
770
+ );
771
+ const roles = [relationMatchStart, ...relationMatchOpposite].filter((x) => x).join(",");
772
+ const relationPath = schema.relations[linkField.relation].defaultDBConnector.path || linkField.relation;
773
+ const relationMatchEnd = `) isa ${relationPath};`;
774
+ const relationIdFilters = linkField.oppositeLinkFieldsPlayedBy.map(
775
+ (link) => `$${link.thing} isa ${link.thing}, has id $${link.thing}_id;`
776
+ ).join(", ");
777
+ const group = `group $${thingPath};`;
778
+ const request = `${entityMatch} ${roles} ${relationMatchEnd} ${relationIdFilters} ${group}`;
779
+ return { relation: relationPath, entity: thingPath, request };
780
+ });
781
+ req.tqlRequest = {
782
+ entity: queryStr,
783
+ ...rolesObj?.length ? { roles: rolesObj } : {},
784
+ ...relations?.length ? { relations } : {}
785
+ };
786
+ };
787
+
788
+ // src/pipeline/preprocess/parseBQLQuery.ts
789
+ var parseBQLQuery = async (req) => {
790
+ const { rawBqlRequest: rawBqlQuery, schema } = req;
791
+ if (!("$entity" in rawBqlQuery) && !("$relation" in rawBqlQuery)) {
792
+ throw new Error("No entity specified in query");
793
+ }
794
+ const currentSchema = getCurrentSchema(schema, rawBqlQuery);
795
+ if (!currentSchema) {
796
+ throw new Error(`Thing '${rawBqlQuery}' not found in schema`);
797
+ }
798
+ const { unidentifiedFields, localFilters, nestedFilters } = getCurrentFields(currentSchema, rawBqlQuery);
799
+ if (unidentifiedFields && unidentifiedFields.length > 0) {
800
+ throw new Error(`Unknown fields: [${unidentifiedFields.join(",")}] in ${JSON.stringify(rawBqlQuery)}`);
801
+ }
802
+ req.bqlRequest = {
803
+ query: {
804
+ ...req.rawBqlRequest,
805
+ ...currentSchema.thingType === "entity" ? { $entity: currentSchema } : {},
806
+ ...currentSchema.thingType === "relation" ? { $relation: currentSchema } : {},
807
+ ...localFilters ? { $localFilters: localFilters } : {},
808
+ ...nestedFilters ? { $nestedFilters: nestedFilters } : {}
809
+ }
810
+ };
811
+ };
812
+
813
+ // src/pipeline/transaction/runTQLQuery.ts
814
+ var import_typedb_client = require("typedb-client");
815
+ var runTQLQuery = async (req, res) => {
816
+ const { dbHandles, bqlRequest, tqlRequest, config } = req;
817
+ if (!bqlRequest) {
818
+ throw new Error("BQL request not parsed");
819
+ }
820
+ if (!tqlRequest) {
821
+ throw new Error("TQL request not built");
822
+ }
823
+ if (!tqlRequest.entity) {
824
+ throw new Error("BQL request error, no entities");
825
+ }
826
+ const { query } = bqlRequest;
827
+ if (!query) {
828
+ throw new Error("BQL request is not a query");
829
+ }
830
+ const singleHandlerV0 = config.dbConnectors[0].id;
831
+ const session = dbHandles.typeDB.get(singleHandlerV0)?.session;
832
+ if (!session?.isOpen()) {
833
+ throw new Error("Session is closed");
834
+ }
835
+ const transaction = await session.transaction(import_typedb_client.TransactionType.READ);
836
+ if (!transaction) {
837
+ throw new Error("Can't create transaction");
838
+ }
839
+ const entityStream = transaction.query.matchGroup(tqlRequest.entity);
840
+ const rolesStreams = tqlRequest.roles?.map((role) => ({
841
+ ...role,
842
+ stream: transaction.query.matchGroup(role.request)
843
+ }));
844
+ const relationStreams = tqlRequest.relations?.map((relation) => ({
845
+ ...relation,
846
+ stream: transaction.query.matchGroup(relation.request)
847
+ }));
848
+ const entityConceptMapGroups = await entityStream.collect();
849
+ const rolesConceptMapGroups = await Promise.all(
850
+ rolesStreams?.map(async (role) => ({
851
+ path: role.path,
852
+ ownerPath: role.owner,
853
+ conceptMapGroups: await role.stream.collect()
854
+ })) || []
855
+ );
856
+ const relationConceptMapGroups = await Promise.all(
857
+ relationStreams?.map(async (relation) => ({
858
+ relation: relation.relation,
859
+ entity: relation.entity,
860
+ conceptMapGroups: await relation.stream.collect()
861
+ })) || []
862
+ );
863
+ await transaction.close();
864
+ res.rawTqlRes = {
865
+ entity: entityConceptMapGroups,
866
+ ...rolesConceptMapGroups?.length && { roles: rolesConceptMapGroups },
867
+ ...relationConceptMapGroups?.length && {
868
+ relations: relationConceptMapGroups
869
+ }
870
+ };
871
+ };
872
+
873
+ // src/pipeline/control/dispatchPipeline.ts
874
+ var dispatchPipeline = async (req, res) => {
875
+ const { bqlRequest, schema } = req;
876
+ const { cache } = res;
877
+ if (!bqlRequest) {
878
+ throw new Error("BQL request not parsed");
879
+ }
880
+ if (!cache) {
881
+ throw new Error("Cache not initialized");
882
+ }
883
+ const { query } = bqlRequest;
884
+ if (!query) {
885
+ return;
886
+ }
887
+ const { $fields } = query;
888
+ if (!("$entity" in query) && !("$relation" in query)) {
889
+ throw new Error("Node attributes not supported");
890
+ }
891
+ const $thing = "$entity" in query ? query.$entity : query.$relation;
892
+ if (!$fields || !Array.isArray($fields)) {
893
+ return;
894
+ }
895
+ const expandedLinkAndRoleFields = $fields.filter((f) => typeof f !== "string" && f.$path);
896
+ const nestedThingsByLF = $thing.linkFields?.filter(
897
+ (linkField) => expandedLinkAndRoleFields.findIndex(
898
+ (expanded) => expanded.$path === linkField.path
899
+ ) !== -1
900
+ ).flatMap((linkField) => linkField.oppositeLinkFieldsPlayedBy) || [];
901
+ const nestedThingsByRF = "roles" in $thing ? (0, import_radash6.listify)($thing.roles, (k, v) => {
902
+ if (expandedLinkAndRoleFields.findIndex(
903
+ (expanded) => expanded.$path === k
904
+ ) !== -1) {
905
+ return v;
906
+ }
907
+ return null;
908
+ }).flatMap((role) => role?.playedBy).filter((x) => x) : [];
909
+ const nestedThings = [...nestedThingsByLF, ...nestedThingsByRF];
910
+ const nextOps = nestedThings?.map((linkField) => {
911
+ if (!linkField)
912
+ return null;
913
+ const { thing } = linkField;
914
+ const result = cache.entities.get(thing);
915
+ const resultIds = [...result?.keys() || []];
916
+ const currentSchema = schema.entities[thing] ? { ...schema.entities[thing], thingType: "entity" } : { ...schema.relations[thing], thingType: "relation" };
917
+ const $FieldsObj = $fields.find(
918
+ (x) => typeof x === "object" && x.$path === linkField.plays
919
+ );
920
+ const localIdsTemp = $FieldsObj?.$id;
921
+ const localIds = !localIdsTemp ? [] : Array.isArray(localIdsTemp) ? localIdsTemp : [localIdsTemp];
922
+ const localFilters = $FieldsObj?.$filter;
923
+ const commonIds = !localIds.length ? resultIds : localIds.filter((id) => resultIds.includes(id));
924
+ const newBqlRequest = {
925
+ query: {
926
+ $id: commonIds,
927
+ $fields: $FieldsObj?.$fields,
928
+ ...currentSchema.thingType === "entity" ? { $entity: currentSchema } : {},
929
+ ...currentSchema.thingType === "relation" ? { $relation: currentSchema } : {},
930
+ ...localFilters ? { $localFilters: localFilters } : {}
931
+ }
932
+ };
933
+ return {
934
+ req: {
935
+ ...req,
936
+ bqlRequest: newBqlRequest
937
+ },
938
+ res,
939
+ pipeline: [buildTQLQuery, runTQLQuery, parseTQLRes, dispatchPipeline]
940
+ };
941
+ }).filter((x) => x);
942
+ if (nextOps?.length) {
943
+ return nextOps;
944
+ }
945
+ };
946
+
947
+ // src/pipeline/preprocess/buildTQLMutation.ts
948
+ var import_radash7 = require("radash");
949
+ var buildTQLMutation = async (req) => {
950
+ const { bqlRequest, schema } = req;
951
+ if (!bqlRequest) {
952
+ throw new Error("BQL request not parsed");
953
+ }
954
+ const { mutation } = bqlRequest;
955
+ if (!mutation) {
956
+ throw new Error("BQL request is not a mutation");
957
+ }
958
+ const nodeToTypeQL = (node) => {
959
+ const op = node.$op;
960
+ const id = node.$tempId || node.$id;
961
+ const currentSchema = getCurrentSchema(schema, node);
962
+ const thingDbPath = currentSchema.defaultDBConnector?.path || node.$entity || node.$relation;
963
+ const { idFields } = currentSchema;
964
+ if (!idFields)
965
+ throw new Error("no idFields");
966
+ const idField = idFields[0];
967
+ const attributes = (0, import_radash7.listify)(node, (k, v) => {
968
+ if (k.startsWith("$") || k === idField || !v)
969
+ return "";
970
+ const currentDataField = currentSchema.dataFields?.find((x) => x.path === k);
971
+ const fieldDbPath = currentDataField?.path;
972
+ if (!fieldDbPath) {
973
+ return ``;
974
+ }
975
+ const dbField = currentDataField.dbPath;
976
+ if (["TEXT", "ID", "EMAIL"].includes(currentDataField.contentType)) {
977
+ return `has ${dbField} '${v}'`;
978
+ }
979
+ if (["NUMBER"].includes(currentDataField.contentType)) {
980
+ return `has ${dbField} ${v}`;
981
+ }
982
+ if (currentDataField.contentType === "DATE") {
983
+ if (Number.isNaN(v.valueOf())) {
984
+ throw new Error("Invalid format, Nan Date");
985
+ }
986
+ if (v instanceof Date) {
987
+ return `has ${dbField} ${v.toISOString().replace("Z", "")}`;
988
+ }
989
+ return `has ${dbField} ${new Date(v).toISOString().replace("Z", "")}`;
990
+ }
991
+ throw new Error(`Unsupported contentType ${currentDataField.contentType}`);
992
+ }).filter((x) => x);
993
+ const attributesVar = `$${id}-atts`;
994
+ const matchAttributes = (0, import_radash7.listify)(node, (k, v) => {
995
+ if (k.startsWith("$") || k === idField || !v)
996
+ return "";
997
+ const currentDataField = currentSchema.dataFields?.find((x) => x.path === k);
998
+ const fieldDbPath = currentDataField?.path;
999
+ if (!fieldDbPath) {
1000
+ return ``;
1001
+ }
1002
+ const dbField = currentDataField.dbPath;
1003
+ return `{${attributesVar} isa ${dbField};}`;
1004
+ }).filter((x) => x);
1005
+ const idFieldValue = node[idField] || node.$id;
1006
+ const idDataField = currentSchema.dataFields?.find((x) => x.path === idField);
1007
+ const idDefaultValue = node.$op === "create" ? idDataField?.default?.value() : null;
1008
+ const idValue = idFieldValue || idDefaultValue;
1009
+ const idAttributes = idValue ? [`has ${idField} '${idValue}'`] : [];
1010
+ const allAttributes = [...idAttributes, ...attributes].filter((x) => x).join(",");
1011
+ const getDeletionMatch = () => {
1012
+ if (node.$tempId)
1013
+ return "";
1014
+ if (op === "delete" || op === "unlink" || op === "noop") {
1015
+ return `$${id} isa ${[thingDbPath, ...idAttributes].filter((x) => x).join(",")};`;
1016
+ }
1017
+ if (op === "update") {
1018
+ if (!matchAttributes.length)
1019
+ throw new Error("update without attributes");
1020
+ return `$${id} isa ${thingDbPath}, ${idAttributes[0]}, has ${attributesVar};
1021
+ ${matchAttributes.join(" or ")};
1022
+ `;
1023
+ }
1024
+ return "";
1025
+ };
1026
+ const getInsertionMatch = () => {
1027
+ if (node.$tempId)
1028
+ return "";
1029
+ if (op === "update" || op === "link" || op === "noop") {
1030
+ return `$${id} isa ${[thingDbPath, ...idAttributes].filter((x) => x).join(",")};`;
1031
+ }
1032
+ return "";
1033
+ };
1034
+ if (node.$entity || node.$relation) {
1035
+ return {
1036
+ op,
1037
+ deletionMatch: getDeletionMatch(),
1038
+ insertionMatch: getInsertionMatch(),
1039
+ insertion: op === "create" ? `$${id} isa ${[thingDbPath, allAttributes].filter((x) => x).join(",")};` : op === "update" && attributes.length ? `$${id} ${attributes.join(",")};` : "",
1040
+ deletion: op === "delete" ? `$${id} isa ${thingDbPath};` : op === "update" && matchAttributes.length ? `$${id} has ${attributesVar};` : ""
1041
+ };
1042
+ }
1043
+ throw new Error("in attributes");
1044
+ };
1045
+ const edgeToTypeQL = (node) => {
1046
+ const op = node.$op;
1047
+ const id = node.$tempId || node.$id;
1048
+ const currentSchema = getCurrentSchema(schema, node);
1049
+ const relationDbPath = currentSchema.defaultDBConnector?.path || node.$relation;
1050
+ const roleFields = "roles" in currentSchema ? (0, import_radash7.listify)(currentSchema.roles, (k) => k) : [];
1051
+ const roleDbPaths = node.$relation && "roles" in currentSchema && (0, import_radash7.mapEntries)(currentSchema.roles, (k, v) => [k, v.dbConnector?.path || k]);
1052
+ const fromRoleFields = (0, import_radash7.listify)(node, (k, v) => {
1053
+ if (!roleFields.includes(k))
1054
+ return null;
1055
+ if (!("roles" in currentSchema)) {
1056
+ throw new Error("This should have roles! ");
1057
+ }
1058
+ const roleDbPath = roleDbPaths[k];
1059
+ if (Array.isArray(v)) {
1060
+ return v.map((x) => ({ path: roleDbPath, id: x }));
1061
+ }
1062
+ return { path: roleDbPath, id: v };
1063
+ }).filter((x) => x).flat();
1064
+ const fromRoleFieldsTql = fromRoleFields.map((x) => x ? `${x.path}: $${x.id}` : "");
1065
+ const roles = fromRoleFields.length > 0 ? `( ${fromRoleFieldsTql.join(" , ")} )` : "";
1066
+ const relationTql = !roles ? "" : `$${id} ${roles} ${node[Symbol.for("edgeType")] === "linkField" ? `isa ${relationDbPath}` : ""}`;
1067
+ const getInsertions = () => {
1068
+ if (!relationTql)
1069
+ return "";
1070
+ if (op === "link")
1071
+ return `${relationTql};`;
1072
+ if (op === "create")
1073
+ return `${relationTql}, has id '${id}';`;
1074
+ return "";
1075
+ };
1076
+ const getDeletions = () => {
1077
+ if (!relationTql)
1078
+ return "";
1079
+ if (op === "unlink")
1080
+ return `${relationTql};`;
1081
+ return "";
1082
+ };
1083
+ return {
1084
+ deletionMatch: "",
1085
+ insertionMatch: "",
1086
+ deletion: getDeletions(),
1087
+ insertion: getInsertions(),
1088
+ op: ""
1089
+ };
1090
+ };
1091
+ const toTypeQL = (nodes, mode) => {
1092
+ const typeQL = mode === "edges" ? edgeToTypeQL : nodeToTypeQL;
1093
+ if (Array.isArray(nodes)) {
1094
+ return nodes.map((x) => {
1095
+ const { insertionMatch: insertionMatch2, deletionMatch: deletionMatch2, insertion: insertion2, deletion: deletion2 } = typeQL(x);
1096
+ return (0, import_radash7.shake)({ insertionMatch: insertionMatch2, deletionMatch: deletionMatch2, insertion: insertion2, deletion: deletion2 }, (z) => !z);
1097
+ }).filter((y) => y);
1098
+ }
1099
+ const { insertionMatch, deletionMatch, insertion, deletion } = typeQL(nodes);
1100
+ return (0, import_radash7.shake)({ insertionMatch, deletionMatch, insertion, deletion }, (z) => !z);
1101
+ };
1102
+ const nodeOperations = toTypeQL(mutation.things);
1103
+ const arrayNodeOperations = Array.isArray(nodeOperations) ? nodeOperations : [nodeOperations];
1104
+ const edgeOperations = toTypeQL(mutation.edges, "edges");
1105
+ const arrayEdgeOperations = Array.isArray(edgeOperations) ? edgeOperations : [edgeOperations];
1106
+ const allOperations = [...arrayNodeOperations, ...arrayEdgeOperations];
1107
+ const tqlRequest = (0, import_radash7.shake)(
1108
+ {
1109
+ insertionMatches: allOperations.map((x) => x.insertionMatch).join(" ").trim(),
1110
+ deletionMatches: allOperations.map((x) => x.deletionMatch).join(" ").trim(),
1111
+ insertions: allOperations.map((x) => x.insertion).join(" ").trim(),
1112
+ deletions: allOperations.map((x) => x.deletion).join(" ").trim()
1113
+ },
1114
+ (x) => !x
1115
+ );
1116
+ req.tqlRequest = tqlRequest;
1117
+ };
1118
+
1119
+ // src/pipeline/preprocess/parseBQLMutation.ts
1120
+ var import_immer3 = __toESM(require("immer"));
1121
+ var import_object_traversal3 = require("object-traversal");
1122
+ var import_radash8 = require("radash");
1123
+ var import_uuid = require("uuid");
1124
+ var parseBQLMutation = async (req) => {
1125
+ const { rawBqlRequest, schema } = req;
1126
+ const stringToObjects = (blocks) => {
1127
+ return (0, import_immer3.default)(
1128
+ blocks,
1129
+ (draft) => (0, import_object_traversal3.traverse)(draft, ({ value: val, meta }) => {
1130
+ if ((0, import_radash8.isObject)(val)) {
1131
+ if (val.$arrayOp) {
1132
+ throw new Error("Array op not supported yet");
1133
+ }
1134
+ const value = val;
1135
+ const currentSchema = getCurrentSchema(schema, val);
1136
+ if (!currentSchema) {
1137
+ throw new Error(
1138
+ `Schema not found for ${val.$entity || val.$relation}`
1139
+ );
1140
+ }
1141
+ value[Symbol.for("thingType")] = currentSchema.thingType;
1142
+ value[Symbol.for("schema")] = currentSchema;
1143
+ value[Symbol.for("dbId")] = currentSchema.defaultDBConnector.id;
1144
+ const { linkFields, roleFields } = getCurrentFields(currentSchema);
1145
+ const currentPath = meta.nodePath;
1146
+ [
1147
+ ...linkFields.map((x) => ({ fieldType: "linkField", path: x })),
1148
+ ...roleFields.map((x) => ({ fieldType: "roleField", path: x }))
1149
+ ]?.forEach((currentField) => {
1150
+ const currentLinkFieldSchema = currentSchema.linkFields?.find((x) => x.path === currentField.path);
1151
+ const currentValue = value[currentField.path];
1152
+ if (currentValue === void 0)
1153
+ return;
1154
+ const currentRoleFieldSchema = "roles" in currentSchema ? oFind(currentSchema.roles, (k) => k === currentField.path) : null;
1155
+ const currentFieldSchema = currentLinkFieldSchema || currentRoleFieldSchema;
1156
+ if (currentRoleFieldSchema && [...new Set(currentRoleFieldSchema.playedBy?.map((x) => x.thing))].length !== 1) {
1157
+ throw new Error(
1158
+ `Field: ${currentField.path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(
1159
+ currentRoleFieldSchema.playedBy
1160
+ )}. Schema: ${JSON.stringify(currentFieldSchema)}`
1161
+ );
1162
+ }
1163
+ const currentEdgeSchema = currentRoleFieldSchema?.playedBy ? currentRoleFieldSchema?.playedBy[0] : currentLinkFieldSchema;
1164
+ const getCurrentRelation = () => {
1165
+ if (currentFieldSchema && "relation" in currentFieldSchema && currentEdgeSchema?.relation === value.$relation) {
1166
+ return "$self";
1167
+ }
1168
+ if (currentEdgeSchema?.relation) {
1169
+ return currentEdgeSchema?.relation;
1170
+ }
1171
+ return "$self";
1172
+ };
1173
+ const relation = getCurrentRelation();
1174
+ const relationSchema = relation === "$self" ? currentSchema : schema.relations[relation];
1175
+ const currentFieldRole = oFind(relationSchema.roles, (k, _v) => k === currentField.path);
1176
+ if (currentFieldRole?.playedBy?.length === 0)
1177
+ throw new Error(`unused role: ${currentPath}.${currentField.path}`);
1178
+ if (!currentFieldSchema) {
1179
+ throw new Error(`Field ${currentField.path} not found in schema`);
1180
+ }
1181
+ const oppositeFields = currentLinkFieldSchema?.oppositeLinkFieldsPlayedBy || currentRoleFieldSchema?.playedBy;
1182
+ if (!oppositeFields) {
1183
+ throw new Error(`No opposite fields found for ${JSON.stringify(currentFieldSchema)}`);
1184
+ }
1185
+ if ([...new Set(oppositeFields?.map((x) => x.thing))].length > 1)
1186
+ throw new Error(
1187
+ `Field: ${currentField.path} - If a role can be played by multiple things, you must specify the thing in the mutation: ${JSON.stringify(
1188
+ oppositeFields
1189
+ )}. Schema: ${JSON.stringify(currentFieldSchema)}`
1190
+ );
1191
+ if (currentValue === null) {
1192
+ value[currentField.path] = { $op: "unlink" };
1193
+ }
1194
+ if (currentFieldSchema.cardinality === "ONE" && Array.isArray(currentValue)) {
1195
+ throw new Error(`Can't have an array in a cardinality === ONE link field`);
1196
+ }
1197
+ if (currentValue.$entity || currentValue.$relation)
1198
+ return;
1199
+ const childrenLinkField = oppositeFields[0];
1200
+ const childrenThingObj = {
1201
+ [`$${childrenLinkField.thingType}`]: childrenLinkField.thing,
1202
+ [Symbol.for("relation")]: relation,
1203
+ [Symbol.for("edgeType")]: "plays" in currentFieldSchema ? "linkField" : "roleField",
1204
+ [Symbol.for("parent")]: {
1205
+ path: currentPath,
1206
+ id: value.$id || value.$tempId,
1207
+ links: oppositeFields
1208
+ },
1209
+ [Symbol.for("role")]: childrenLinkField.plays,
1210
+ [Symbol.for("oppositeRole")]: "plays" in currentFieldSchema ? currentFieldSchema.plays : void 0
1211
+ };
1212
+ if ((0, import_radash8.isObject)(currentValue)) {
1213
+ if (currentSchema.thingType === "relation" && currentValue.$tempId) {
1214
+ value[currentField.path] = currentValue.$tempId;
1215
+ } else {
1216
+ value[currentField.path] = {
1217
+ ...childrenThingObj,
1218
+ ...currentValue
1219
+ };
1220
+ }
1221
+ }
1222
+ if (Array.isArray(currentValue) && currentValue.every((x) => (0, import_radash8.isObject)(x))) {
1223
+ value[currentField.path] = currentValue.map((y) => ({
1224
+ ...childrenThingObj,
1225
+ ...y
1226
+ }));
1227
+ }
1228
+ if (typeof currentValue === "string") {
1229
+ value[currentField.path] = {
1230
+ ...childrenThingObj,
1231
+ $op: "link",
1232
+ $id: currentValue
1233
+ };
1234
+ }
1235
+ if (Array.isArray(currentValue) && currentValue.every((x) => typeof x === "string")) {
1236
+ value[currentField.path] = currentValue.map((y) => ({
1237
+ ...childrenThingObj,
1238
+ $op: "link",
1239
+ $id: y
1240
+ }));
1241
+ }
1242
+ });
1243
+ const nodePathArray = meta.nodePath?.split(".");
1244
+ const notRoot = nodePathArray?.filter((x) => Number.isNaN(parseInt(x, 10))).join(".");
1245
+ if (!notRoot && !value.$entity && !value.$relation) {
1246
+ throw new Error("Root things must specify $entity or $relation");
1247
+ }
1248
+ if (!notRoot) {
1249
+ }
1250
+ }
1251
+ })
1252
+ );
1253
+ };
1254
+ const withObjects = stringToObjects(rawBqlRequest);
1255
+ const fillBlocks = (blocks) => {
1256
+ return (0, import_immer3.default)(
1257
+ blocks,
1258
+ (draft) => (0, import_object_traversal3.traverse)(draft, ({ parent, key, value: val, meta }) => {
1259
+ if ((0, import_radash8.isObject)(val)) {
1260
+ if (Object.keys(val).length === 0) {
1261
+ throw new Error("Empty object!");
1262
+ }
1263
+ const value = val;
1264
+ const nodePathArray = meta.nodePath?.split(".");
1265
+ const notRoot = nodePathArray?.filter((x) => Number.isNaN(parseInt(x, 10))).join(".");
1266
+ const currentSchema = getCurrentSchema(schema, value);
1267
+ const { unidentifiedFields, dataFields, roleFields, linkFields } = getCurrentFields(currentSchema, value);
1268
+ const hasUpdatedDataFields = Object.keys(value).some((x) => dataFields?.includes(x));
1269
+ const hasUpdatedChildren = Object.keys(value).some((x) => [...roleFields, ...linkFields]?.includes(x));
1270
+ const getOp = () => {
1271
+ if (value.$op)
1272
+ return value.$op;
1273
+ if ((value.$id || value.$filter) && hasUpdatedDataFields)
1274
+ return "update";
1275
+ if ((value.$id || value.$filter) && notRoot && !hasUpdatedDataFields && !hasUpdatedChildren)
1276
+ return "link";
1277
+ if (!value.$filter && !value.$id)
1278
+ return "create";
1279
+ if ((value.$id || value.$filter) && !hasUpdatedDataFields && hasUpdatedChildren)
1280
+ return "noop";
1281
+ throw new Error("Wrong op");
1282
+ };
1283
+ if (!value.$op)
1284
+ value.$op = getOp();
1285
+ if (!parent)
1286
+ value.$parentKey = "";
1287
+ if (!(value.$id || value.$tempId || value.$filter) && ["delete", "link", "update", "unlink"].includes(value.$op)) {
1288
+ throw new Error("Targeted operations (update, delete, link & unlink) require an $id or a $filter");
1289
+ }
1290
+ if (typeof parent === "object") {
1291
+ const ArParent = Array.isArray(parent);
1292
+ if (ArParent)
1293
+ value[Symbol.for("index")] = key;
1294
+ value[Symbol.for("path")] = meta.nodePath;
1295
+ value[Symbol.for("isRoot")] = !notRoot;
1296
+ value[Symbol.for("depth")] = notRoot?.split(".").length;
1297
+ }
1298
+ if (!value.$entity && !value.$relation) {
1299
+ throw new Error(`Node ${JSON.stringify(value)} without $entity/$relation`);
1300
+ }
1301
+ const { idFields, computedFields } = currentSchema;
1302
+ if (!idFields)
1303
+ throw new Error("No idFields found");
1304
+ const idField = idFields[0];
1305
+ if (value[idField] && !value.$id) {
1306
+ value.$id = value[idField];
1307
+ }
1308
+ const filledFields = (0, import_radash8.listify)(value, (attKey, v) => v ? attKey : void 0);
1309
+ const missingComputedFields = computedFields.filter((x) => !filledFields.includes(x));
1310
+ missingComputedFields.forEach((fieldPath) => {
1311
+ const currentFieldDef = currentSchema.dataFields?.find((x) => x.path === fieldPath);
1312
+ const currentLinkDef = currentSchema.linkFields?.find((x) => x.path === fieldPath);
1313
+ const currentLinkedDef = currentLinkDef?.oppositeLinkFieldsPlayedBy[0];
1314
+ const currentRoleDef = "roles" in currentSchema ? oFind(currentSchema.roles, (k, _v) => k === fieldPath) : void 0;
1315
+ const currentDef = currentFieldDef || currentLinkedDef || currentRoleDef;
1316
+ if (!currentDef) {
1317
+ throw new Error(`no field Def for ${fieldPath}`);
1318
+ }
1319
+ if (fieldPath === idField && value.$op === "create" && !value[fieldPath]) {
1320
+ const defaultValue = "default" in currentDef ? currentDef.default?.value() : void 0;
1321
+ if (!defaultValue) {
1322
+ throw new Error(`No default value for ${fieldPath}`);
1323
+ }
1324
+ value[fieldPath] = defaultValue;
1325
+ value.$id = defaultValue;
1326
+ }
1327
+ });
1328
+ if (unidentifiedFields.length > 0) {
1329
+ throw new Error(`Unknown fields: [${unidentifiedFields.join(",")}] in ${JSON.stringify(value)}`);
1330
+ }
1331
+ }
1332
+ })
1333
+ );
1334
+ };
1335
+ const filledBQLMutation = fillBlocks(withObjects);
1336
+ const listNodes = (blocks) => {
1337
+ const nodes = [];
1338
+ const edges = [];
1339
+ const listOp = ({ value }) => {
1340
+ if (value.$entity || value.$relation) {
1341
+ if (!value.$id && !["link", "unlink"].includes(value.$op)) {
1342
+ throw new Error(
1343
+ "An id must be specified either in the mutation or has tu have a default value in the schema"
1344
+ );
1345
+ }
1346
+ const currentThingSchema = getCurrentSchema(schema, value);
1347
+ const { dataFields: dataFieldPaths, roleFields: roleFieldPaths } = getCurrentFields(currentThingSchema);
1348
+ const dataObj = {
1349
+ ...value.$entity && { $entity: value.$entity },
1350
+ ...value.$relation && { $relation: value.$relation },
1351
+ ...value.$id && { $id: value.$id },
1352
+ ...value.$tempId && { $tempId: value.$tempId },
1353
+ ...(0, import_radash8.shake)((0, import_radash8.pick)(value, dataFieldPaths || [""])),
1354
+ $op: value.$op,
1355
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1356
+ [Symbol.for("isRoot")]: value[Symbol.for("isRoot")]
1357
+ };
1358
+ if (value.$op === "create" || value.$op === "update" || value.$op === "delete") {
1359
+ nodes.push(dataObj);
1360
+ } else {
1361
+ nodes.push({ ...dataObj, $op: "noop" });
1362
+ }
1363
+ if (value[Symbol.for("relation")] && value[Symbol.for("edgeType")] === "linkField") {
1364
+ if (value.$op === "link" || value.$op === "unlink") {
1365
+ if (value.$id || value.$filter) {
1366
+ if (value.$tempId) {
1367
+ throw new Error("can't specify a existing and a new element at once. Use an id/filter or a tempId");
1368
+ }
1369
+ nodes.push({ ...value, $op: "noop" });
1370
+ }
1371
+ }
1372
+ const ownRelation = value[Symbol.for("relation")] === value.$relation;
1373
+ if (ownRelation && !(value.$id || value.$tempId)) {
1374
+ throw new Error("No id or tempId found for complex link");
1375
+ }
1376
+ const linkTempId = ownRelation ? value.$id || value.$tempId : (0, import_uuid.v4)();
1377
+ const parentMeta = value[Symbol.for("parent")];
1378
+ const parentPath = parentMeta.path;
1379
+ const parentNode = !parentPath ? blocks : (0, import_object_traversal3.getNodeByPath)(blocks, parentPath);
1380
+ const parentId = parentNode.$id || parentNode.$tempId;
1381
+ if (!parentId)
1382
+ throw new Error("No parent id found");
1383
+ if (value[Symbol.for("relation")] === "$self")
1384
+ return;
1385
+ const getLinkObjOp = () => {
1386
+ if (value.$op === "unlink" || value.$op === "delete") {
1387
+ if (ownRelation)
1388
+ return "unlink";
1389
+ return "delete";
1390
+ }
1391
+ if (value.$op === "link" || value.$op === "create") {
1392
+ if (ownRelation)
1393
+ return "link";
1394
+ return "create";
1395
+ }
1396
+ return "noop";
1397
+ };
1398
+ const linkObj = {
1399
+ $relation: value[Symbol.for("relation")],
1400
+ $op: getLinkObjOp(),
1401
+ ...value.$op === "unlink" ? { $tempId: linkTempId } : { $id: linkTempId },
1402
+ [value[Symbol.for("role")]]: value.$tempId || value.$id,
1403
+ [value[Symbol.for("oppositeRole")]]: parentId,
1404
+ [Symbol.for("isRoot")]: false,
1405
+ [Symbol.for("dbId")]: schema.relations[value[Symbol.for("relation")]].defaultDBConnector.id,
1406
+ [Symbol.for("edgeType")]: "linkField"
1407
+ };
1408
+ edges.push(linkObj);
1409
+ }
1410
+ if (value.$relation) {
1411
+ const val = value;
1412
+ if (!val.$id && !["link", "unlink"].includes(value.$op)) {
1413
+ throw new Error(
1414
+ "An id must be specified either in the mutation or has tu have a default value in the schema"
1415
+ );
1416
+ }
1417
+ const rolesObjFiltered = oFilter(val, (k, _v) => roleFieldPaths.includes(k));
1418
+ const rolesObjOnlyIds = (0, import_radash8.mapEntries)(rolesObjFiltered, (k, v) => {
1419
+ return [k, v.$id || v];
1420
+ });
1421
+ const objWithMetaDataOnly = oFilter(val, (k, _v) => {
1422
+ return k.startsWith("$") || k.startsWith("Symbol");
1423
+ });
1424
+ if (Object.keys(rolesObjFiltered).filter((x) => !x.startsWith("$")).length > 0) {
1425
+ if (val.$op === "create" || val.$op === "delete") {
1426
+ const getEdgeOp = () => {
1427
+ if (val.$op === "create")
1428
+ return "link";
1429
+ if (val.$op === "delete")
1430
+ return "unlink";
1431
+ throw new Error("Unsupported parent of edge op");
1432
+ };
1433
+ edges.push({
1434
+ ...objWithMetaDataOnly,
1435
+ $relation: val.$relation,
1436
+ $op: getEdgeOp(),
1437
+ ...rolesObjOnlyIds,
1438
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1439
+ [Symbol.for("info")]: "coming from created or deleted relation"
1440
+ });
1441
+ return;
1442
+ }
1443
+ if (val.$op === "noop") {
1444
+ const rolesWithLinks = oFilter(
1445
+ rolesObjOnlyIds,
1446
+ (_k, v) => v.some(
1447
+ (x) => x.$op === "link" || x.$op === "create"
1448
+ )
1449
+ );
1450
+ const rolesWithLinksFiltered = (0, import_radash8.mapEntries)(rolesWithLinks, (k, v) => [
1451
+ k,
1452
+ v.filter((x) => x.$op === "link" || x.$op === "create").map((y) => y.$id)
1453
+ ]);
1454
+ const rolesWithUnlinks = oFilter(
1455
+ rolesObjOnlyIds,
1456
+ (_k, v) => v.some((x) => x.$op === "unlink" || x.$op === "delete")
1457
+ );
1458
+ const rolesWithUnlinksFiltered = (0, import_radash8.mapEntries)(rolesWithUnlinks, (k, v) => [
1459
+ k,
1460
+ v.filter((x) => x.$op === "unlink" || x.$op === "delete").map((y) => y.$id)
1461
+ ]);
1462
+ const rolesWithReplaces = {};
1463
+ [
1464
+ { op: "link", obj: rolesWithLinksFiltered },
1465
+ { op: "unlink", obj: rolesWithUnlinksFiltered },
1466
+ { op: "replace", obj: rolesWithReplaces }
1467
+ ].forEach((x) => {
1468
+ if (Object.keys(x.obj).length) {
1469
+ edges.push({
1470
+ ...objWithMetaDataOnly,
1471
+ $relation: val.$relation,
1472
+ $op: x.op,
1473
+ ...x.obj,
1474
+ [Symbol.for("dbId")]: currentThingSchema.defaultDBConnector.id,
1475
+ [Symbol.for("info")]: "updating roleFields"
1476
+ });
1477
+ }
1478
+ });
1479
+ }
1480
+ }
1481
+ }
1482
+ }
1483
+ };
1484
+ (0, import_object_traversal3.traverse)(blocks, listOp);
1485
+ return [nodes, edges];
1486
+ };
1487
+ const [parsedThings, parsedEdges] = listNodes(filledBQLMutation);
1488
+ const mergedEdges = parsedEdges.reduce((acc, curr) => {
1489
+ const existingEdge = acc.find((r) => r.$id === curr.$id && r.$relation === curr.$relation);
1490
+ if (existingEdge) {
1491
+ const newRelation = {
1492
+ ...existingEdge,
1493
+ ...curr
1494
+ };
1495
+ const newAcc = acc.filter((r) => r.$id !== curr.$id || r.$relation !== curr.$relation);
1496
+ return [...newAcc, newRelation];
1497
+ }
1498
+ return [...acc, curr];
1499
+ }, []);
1500
+ req.bqlRequest = {
1501
+ mutation: {
1502
+ things: parsedThings,
1503
+ edges: mergedEdges
1504
+ }
1505
+ };
1506
+ };
1507
+
1508
+ // src/pipeline/transaction/runTQLMutation.ts
1509
+ var import_typedb_client2 = require("typedb-client");
1510
+ var runTQLMutation = async (req, res) => {
1511
+ const { dbHandles, tqlRequest, bqlRequest, config } = req;
1512
+ if (!tqlRequest) {
1513
+ throw new Error("TQL request not built");
1514
+ }
1515
+ if (!(tqlRequest.deletions && tqlRequest.deletionMatches || tqlRequest.insertions)) {
1516
+ throw new Error("TQL request error, no things");
1517
+ }
1518
+ if (!bqlRequest?.mutation) {
1519
+ throw new Error("BQL mutation not parsed");
1520
+ }
1521
+ const singleHandlerV0 = config.dbConnectors[0].id;
1522
+ const session = dbHandles.typeDB.get(singleHandlerV0)?.session;
1523
+ if (!session?.isOpen()) {
1524
+ throw new Error("Session is closed");
1525
+ }
1526
+ const mutateTransaction = await session.transaction(import_typedb_client2.TransactionType.WRITE);
1527
+ if (!mutateTransaction) {
1528
+ throw new Error("Can't create transaction");
1529
+ }
1530
+ const tqlDeletion = tqlRequest.deletionMatches && tqlRequest.deletions && `match ${tqlRequest.deletionMatches} delete ${tqlRequest.deletions}`;
1531
+ const tqlInsertion = tqlRequest.insertions && `${tqlRequest.insertionMatches ? `match ${tqlRequest.insertionMatches}` : ""} insert ${tqlRequest.insertions}`;
1532
+ if (tqlDeletion)
1533
+ mutateTransaction.query.delete(tqlDeletion);
1534
+ const insertionsStream = tqlInsertion && mutateTransaction.query.insert(tqlInsertion);
1535
+ const insertionsRes = insertionsStream ? await insertionsStream.collect() : void 0;
1536
+ await mutateTransaction.commit();
1537
+ await mutateTransaction.close();
1538
+ res.rawTqlRes = { insertions: insertionsRes };
1539
+ };
1540
+
1541
+ // src/pipeline/pipeline.ts
1542
+ var Pipelines = {
1543
+ query: [parseBQLQuery, buildTQLQuery, runTQLQuery, parseTQLRes, dispatchPipeline],
1544
+ mutation: [parseBQLMutation, buildTQLMutation, runTQLMutation, parseTQLRes]
1545
+ };
1546
+ var finalPipeline = [buildBQLTree];
1547
+ var runPipeline = async (pipeline, req, res = {}, root = true) => {
1548
+ for (const operation of pipeline) {
1549
+ const next = await operation(req, res);
1550
+ if (next && Array.isArray(next)) {
1551
+ for (const nextPipeline of next) {
1552
+ await runPipeline(nextPipeline.pipeline, nextPipeline.req, nextPipeline.res, false);
1553
+ }
1554
+ }
1555
+ }
1556
+ if (root) {
1557
+ await runPipeline(finalPipeline, req, res, false);
1558
+ return res.bqlRes;
1559
+ }
1560
+ };
1561
+ var queryPipeline = (bqlRequest, bormConfig, bormSchema, dbHandles) => runPipeline(
1562
+ Pipelines.query,
1563
+ {
1564
+ config: bormConfig,
1565
+ schema: bormSchema,
1566
+ rawBqlRequest: bqlRequest,
1567
+ dbHandles
1568
+ },
1569
+ {}
1570
+ );
1571
+ var mutationPipeline = (bqlRequest, bormConfig, bormSchema, dbHandles) => runPipeline(
1572
+ Pipelines.mutation,
1573
+ {
1574
+ config: bormConfig,
1575
+ schema: bormSchema,
1576
+ rawBqlRequest: bqlRequest,
1577
+ dbHandles
1578
+ },
1579
+ {}
1580
+ );
1581
+
1582
+ // src/index.ts
1583
+ var BormClient = class {
1584
+ schema;
1585
+ config;
1586
+ dbHandles;
1587
+ constructor({ schema, config }) {
1588
+ this.schema = schema;
1589
+ this.config = config;
1590
+ }
1591
+ init = async () => {
1592
+ const dbHandles = { typeDB: /* @__PURE__ */ new Map() };
1593
+ const enrichedSchema = enrichSchema(this.schema);
1594
+ await Promise.all(
1595
+ this.config.dbConnectors.map(async (dbc) => {
1596
+ if (dbc.provider === "typeDB" && dbc.dbName) {
1597
+ const [clientErr, client] = await (0, import_radash9.tryit)(import_typedb_client3.TypeDB.coreClient)(dbc.url);
1598
+ if (clientErr) {
1599
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}] ${clientErr.message ?? "Can't create TypeDB Client"}`;
1600
+ throw new Error(message);
1601
+ }
1602
+ try {
1603
+ const session = await client.session(dbc.dbName, import_typedb_client3.SessionType.DATA);
1604
+ dbHandles.typeDB.set(dbc.id, { client, session });
1605
+ } catch (sessionErr) {
1606
+ const message = `[BORM:${dbc.provider}:${dbc.dbName}] ${(sessionErr.messageTemplate?._messageBody() || sessionErr.message) ?? "Can't create TypeDB Session"}`;
1607
+ throw new Error(message);
1608
+ }
1609
+ }
1610
+ })
1611
+ );
1612
+ this.schema = enrichedSchema;
1613
+ this.dbHandles = dbHandles;
1614
+ };
1615
+ #enforceConnection = async () => {
1616
+ if (!this.dbHandles) {
1617
+ await this.init();
1618
+ if (!this.dbHandles) {
1619
+ throw new Error("Can't init BormClient");
1620
+ }
1621
+ }
1622
+ };
1623
+ introspect = async () => {
1624
+ await this.#enforceConnection();
1625
+ return this.schema;
1626
+ };
1627
+ query = async (query, queryConfig) => {
1628
+ await this.#enforceConnection();
1629
+ const qConfig = {
1630
+ ...this.config,
1631
+ query: { ...defaultConfig.query, ...this.config.query, ...queryConfig }
1632
+ };
1633
+ return queryPipeline(query, qConfig, this.schema, this.dbHandles);
1634
+ };
1635
+ mutate = async (mutation, mutationConfig) => {
1636
+ await this.#enforceConnection();
1637
+ const mConfig = {
1638
+ ...this.config,
1639
+ mutation: {
1640
+ ...defaultConfig.mutation,
1641
+ ...this.config.mutation,
1642
+ ...mutationConfig
1643
+ }
1644
+ };
1645
+ return mutationPipeline(mutation, mConfig, this.schema, this.dbHandles);
1646
+ };
1647
+ close = async () => {
1648
+ if (!this.dbHandles) {
1649
+ return;
1650
+ }
1651
+ this.dbHandles.typeDB.forEach(async ({ client, session }) => {
1652
+ console.log("Closing session");
1653
+ await session.close();
1654
+ console.log("Closing client");
1655
+ await client.close();
1656
+ });
1657
+ };
1658
+ };
1659
+ var src_default = BormClient;
1660
+ // Annotate the CommonJS export names for ESM import in node:
1661
+ 0 && (module.exports = {});