@snowtop/ent 0.1.0-alpha99 → 0.1.0
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/action/action.d.ts +8 -1
- package/action/executor.d.ts +16 -3
- package/action/executor.js +83 -27
- package/action/index.d.ts +2 -1
- package/action/operations.d.ts +126 -0
- package/action/operations.js +686 -0
- package/action/orchestrator.d.ts +22 -8
- package/action/orchestrator.js +278 -67
- package/core/base.d.ts +34 -24
- package/core/clause.d.ts +62 -79
- package/core/clause.js +77 -5
- package/core/config.d.ts +5 -1
- package/core/config.js +3 -0
- package/core/const.d.ts +3 -0
- package/core/const.js +6 -0
- package/core/context.d.ts +4 -3
- package/core/context.js +2 -1
- package/core/db.d.ts +1 -0
- package/core/db.js +7 -7
- package/core/ent.d.ts +53 -105
- package/core/ent.js +104 -599
- package/core/global_schema.d.ts +7 -0
- package/core/global_schema.js +51 -0
- package/core/loaders/assoc_count_loader.d.ts +4 -2
- package/core/loaders/assoc_count_loader.js +10 -2
- package/core/loaders/assoc_edge_loader.d.ts +2 -3
- package/core/loaders/assoc_edge_loader.js +16 -7
- package/core/loaders/index.d.ts +0 -1
- package/core/loaders/index.js +1 -3
- package/core/loaders/loader.d.ts +3 -3
- package/core/loaders/loader.js +3 -20
- package/core/loaders/object_loader.d.ts +30 -10
- package/core/loaders/object_loader.js +179 -40
- package/core/loaders/query_loader.d.ts +4 -4
- package/core/loaders/query_loader.js +14 -19
- package/core/loaders/raw_count_loader.d.ts +1 -0
- package/core/loaders/raw_count_loader.js +3 -2
- package/core/privacy.d.ts +19 -10
- package/core/privacy.js +47 -26
- package/core/query/assoc_query.js +1 -1
- package/core/query/custom_clause_query.d.ts +6 -3
- package/core/query/custom_clause_query.js +36 -9
- package/core/query/custom_query.d.ts +3 -1
- package/core/query/custom_query.js +29 -6
- package/core/query/query.d.ts +12 -2
- package/core/query/query.js +67 -38
- package/core/query/shared_assoc_test.js +151 -10
- package/core/query/shared_test.d.ts +2 -2
- package/core/query/shared_test.js +90 -30
- package/core/query_impl.d.ts +8 -0
- package/core/query_impl.js +28 -0
- package/core/viewer.d.ts +2 -0
- package/core/viewer.js +2 -0
- package/graphql/graphql.d.ts +103 -19
- package/graphql/graphql.js +169 -134
- package/graphql/graphql_field_helpers.d.ts +9 -3
- package/graphql/graphql_field_helpers.js +22 -2
- package/graphql/index.d.ts +2 -1
- package/graphql/index.js +5 -2
- package/graphql/scalars/orderby_direction.d.ts +2 -0
- package/graphql/scalars/orderby_direction.js +15 -0
- package/imports/dataz/example1/_auth.js +128 -47
- package/imports/dataz/example1/_viewer.js +87 -39
- package/imports/index.d.ts +1 -1
- package/imports/index.js +2 -2
- package/index.d.ts +12 -1
- package/index.js +18 -6
- package/package.json +20 -17
- package/parse_schema/parse.d.ts +10 -4
- package/parse_schema/parse.js +70 -24
- package/schema/base_schema.d.ts +8 -0
- package/schema/base_schema.js +11 -0
- package/schema/field.d.ts +6 -3
- package/schema/field.js +72 -17
- package/schema/index.d.ts +1 -1
- package/schema/index.js +2 -1
- package/schema/json_field.d.ts +3 -3
- package/schema/json_field.js +4 -1
- package/schema/schema.d.ts +42 -5
- package/schema/schema.js +35 -41
- package/schema/struct_field.d.ts +8 -6
- package/schema/struct_field.js +67 -8
- package/schema/union_field.d.ts +1 -1
- package/scripts/custom_compiler.js +4 -4
- package/scripts/custom_graphql.js +105 -75
- package/scripts/move_types.js +4 -1
- package/scripts/read_schema.js +2 -2
- package/testutils/action/complex_schemas.d.ts +1 -1
- package/testutils/action/complex_schemas.js +10 -3
- package/testutils/builder.d.ts +3 -0
- package/testutils/builder.js +6 -0
- package/testutils/db/temp_db.d.ts +9 -1
- package/testutils/db/temp_db.js +82 -14
- package/testutils/db_mock.js +1 -3
- package/testutils/ent-graphql-tests/index.d.ts +1 -1
- package/testutils/ent-graphql-tests/index.js +30 -19
- package/testutils/fake_comms.js +1 -1
- package/testutils/fake_data/fake_contact.d.ts +1 -1
- package/testutils/fake_data/fake_tag.d.ts +1 -1
- package/testutils/fake_data/fake_user.d.ts +3 -3
- package/testutils/fake_data/fake_user.js +15 -4
- package/testutils/fake_data/tag_query.js +8 -3
- package/testutils/fake_data/test_helpers.d.ts +3 -2
- package/testutils/fake_data/test_helpers.js +4 -4
- package/testutils/fake_data/user_query.d.ts +5 -2
- package/testutils/fake_data/user_query.js +19 -2
- package/testutils/fake_log.js +1 -1
- package/tsc/ast.js +2 -1
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +2 -2
- package/tsc/transform.js +4 -3
- package/tsc/transform_ent.js +2 -1
- package/tsc/transform_schema.js +4 -3
- package/core/loaders/index_loader.d.ts +0 -14
- package/core/loaders/index_loader.js +0 -27
package/core/ent.js
CHANGED
|
@@ -26,41 +26,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
26
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
-
exports.
|
|
30
|
-
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows =
|
|
29
|
+
exports.applyPrivacyPolicyForRow = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = exports.getDefaultLimit = exports.setDefaultLimit = exports.loadEdgeDatas = exports.loadEdgeData = exports.assocEdgeLoader = exports.AssocEdgeData = exports.getCursor = exports.AssocEdge = exports.deleteRowsSync = exports.deleteRows = exports.editRowSync = exports.editRow = exports.buildUpdateQuery = exports.createRowSync = exports.createRow = exports.buildInsertQuery = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.___setLogQueryErrorWithError = exports.loadRow = exports.loadRowX = exports.logQuery = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadCustomCount = exports.loadCustomData = exports.loadCustomEnts = exports.loadEntsFromClause = exports.loadEntsList = exports.loadEnts = exports.loadEntXFromClause = exports.loadEntFromClause = exports.loadEntXViaKey = exports.loadEntX = exports.loadEntViaKey = exports.loadEnt = exports.getEntKey = exports.getEntLoader = exports.rowIsError = void 0;
|
|
30
|
+
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = void 0;
|
|
31
31
|
const db_1 = __importStar(require("./db"));
|
|
32
32
|
const privacy_1 = require("./privacy");
|
|
33
33
|
const clause = __importStar(require("./clause"));
|
|
34
|
-
const action_1 = require("../action");
|
|
35
34
|
const logger_1 = require("./logger");
|
|
36
35
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
constructor(options) {
|
|
41
|
-
this.options = options;
|
|
42
|
-
this.m = new Map();
|
|
43
|
-
}
|
|
44
|
-
get(key) {
|
|
45
|
-
const ret = this.m.get(key);
|
|
46
|
-
if (ret) {
|
|
47
|
-
(0, logger_1.log)("cache", {
|
|
48
|
-
"dataloader-cache-hit": key,
|
|
49
|
-
"tableName": this.options.tableName,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return ret;
|
|
53
|
-
}
|
|
54
|
-
set(key, value) {
|
|
55
|
-
return this.m.set(key, value);
|
|
56
|
-
}
|
|
57
|
-
delete(key) {
|
|
58
|
-
return this.m.delete(key);
|
|
59
|
-
}
|
|
60
|
-
clear() {
|
|
61
|
-
return this.m.clear();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
36
|
+
const global_schema_1 = require("./global_schema");
|
|
37
|
+
const query_impl_1 = require("./query_impl");
|
|
38
|
+
const loader_1 = require("./loaders/loader");
|
|
64
39
|
class entCacheMap {
|
|
65
40
|
constructor(viewer, options) {
|
|
66
41
|
this.viewer = viewer;
|
|
@@ -89,11 +64,11 @@ class entCacheMap {
|
|
|
89
64
|
return this.m.clear();
|
|
90
65
|
}
|
|
91
66
|
}
|
|
92
|
-
function
|
|
67
|
+
function createAssocEdgeConfigLoader(options) {
|
|
93
68
|
const loaderOptions = {};
|
|
94
69
|
// if query logging is enabled, we should log what's happening with loader
|
|
95
70
|
if ((0, logger_1.logEnabled)("query")) {
|
|
96
|
-
loaderOptions.cacheMap = new
|
|
71
|
+
loaderOptions.cacheMap = new loader_1.CacheMap(options);
|
|
97
72
|
}
|
|
98
73
|
// something here brokwn with strict:true
|
|
99
74
|
return new dataloader_1.default(async (ids) => {
|
|
@@ -101,9 +76,11 @@ function createDataLoader(options) {
|
|
|
101
76
|
return [];
|
|
102
77
|
}
|
|
103
78
|
let col = options.key;
|
|
79
|
+
// defaults to uuid
|
|
80
|
+
let typ = options.keyType || "uuid";
|
|
104
81
|
const rowOptions = {
|
|
105
82
|
...options,
|
|
106
|
-
clause: clause.
|
|
83
|
+
clause: clause.DBTypeIn(col, ids, typ),
|
|
107
84
|
};
|
|
108
85
|
// TODO is there a better way of doing this?
|
|
109
86
|
// context not needed because we're creating a loader which has its own cache which is being used here
|
|
@@ -126,6 +103,13 @@ class ErrorWrapper {
|
|
|
126
103
|
this.error = error;
|
|
127
104
|
}
|
|
128
105
|
}
|
|
106
|
+
// note if storing the result of this in something that checks instanceof Error e.g. DataLoader, we need to check instanceof at that callsite
|
|
107
|
+
function rowIsError(row) {
|
|
108
|
+
// jest does things that break instanceof checks
|
|
109
|
+
// so we need to check the name as well for native error SqliteError
|
|
110
|
+
return row instanceof Error || row?.constructor?.name === "SqliteError";
|
|
111
|
+
}
|
|
112
|
+
exports.rowIsError = rowIsError;
|
|
129
113
|
function createEntLoader(viewer, options, map) {
|
|
130
114
|
// share the cache across loaders even if we create a new instance
|
|
131
115
|
const loaderOptions = {};
|
|
@@ -143,8 +127,14 @@ function createEntLoader(viewer, options, map) {
|
|
|
143
127
|
for (let idx = 0; idx < rows.length; idx++) {
|
|
144
128
|
const row = rows[idx];
|
|
145
129
|
// db error
|
|
146
|
-
if (row
|
|
147
|
-
|
|
130
|
+
if (rowIsError(row)) {
|
|
131
|
+
if (row instanceof Error) {
|
|
132
|
+
result[idx] = row;
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
// @ts-ignore SqliteError
|
|
136
|
+
result[idx] = new Error(row.message);
|
|
137
|
+
}
|
|
148
138
|
continue;
|
|
149
139
|
}
|
|
150
140
|
else if (!row) {
|
|
@@ -157,7 +147,7 @@ function createEntLoader(viewer, options, map) {
|
|
|
157
147
|
}
|
|
158
148
|
else {
|
|
159
149
|
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
160
|
-
if (r
|
|
150
|
+
if (rowIsError(r)) {
|
|
161
151
|
result[idx] = new ErrorWrapper(r);
|
|
162
152
|
}
|
|
163
153
|
else {
|
|
@@ -201,6 +191,7 @@ function getEntLoader(viewer, options) {
|
|
|
201
191
|
const name = `ent-loader:${viewer.instanceKey()}:${options.loaderFactory.name}`;
|
|
202
192
|
return viewer.context.cache.getLoaderWithLoadMany(name, () => new EntLoader(viewer, options));
|
|
203
193
|
}
|
|
194
|
+
exports.getEntLoader = getEntLoader;
|
|
204
195
|
function getEntKey(viewer, id, options) {
|
|
205
196
|
return `${viewer.instanceKey()}:${options.loaderFactory.name}:${id}`;
|
|
206
197
|
}
|
|
@@ -231,7 +222,7 @@ loader) {
|
|
|
231
222
|
return result;
|
|
232
223
|
}
|
|
233
224
|
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
234
|
-
if (r
|
|
225
|
+
if (rowIsError(r)) {
|
|
235
226
|
loader.prime(id, new ErrorWrapper(r));
|
|
236
227
|
return new ErrorWrapper(r);
|
|
237
228
|
}
|
|
@@ -321,7 +312,7 @@ async function loadEnts(viewer, options, ...ids) {
|
|
|
321
312
|
let m = new Map();
|
|
322
313
|
const ret = await getEntLoader(viewer, options).loadMany(ids);
|
|
323
314
|
for (const r of ret) {
|
|
324
|
-
if (r
|
|
315
|
+
if (rowIsError(r)) {
|
|
325
316
|
throw r;
|
|
326
317
|
}
|
|
327
318
|
if (r instanceof ErrorWrapper) {
|
|
@@ -396,6 +387,12 @@ function isParameterizedQuery(opts) {
|
|
|
396
387
|
* orderby: 'time',
|
|
397
388
|
* disableTransformations: false
|
|
398
389
|
* }) // doesn't change the query
|
|
390
|
+
*
|
|
391
|
+
* For queries that pass in a clause, we batch them with an underlying dataloader so that multiple queries with the same clause
|
|
392
|
+
* or parallel queries with the same clause are batched together.
|
|
393
|
+
*
|
|
394
|
+
* If a raw or parameterized query is passed in, we don't attempt to batch them together and they're executed as is.
|
|
395
|
+
* If you end up with a scenario where you may need to coalesce or batch (non-clause) queries here, you should use some kind of memoization here.
|
|
399
396
|
*/
|
|
400
397
|
async function loadCustomData(options, query, context) {
|
|
401
398
|
const rows = await loadCustomDataImpl(options, query, context);
|
|
@@ -414,7 +411,10 @@ exports.loadCustomData = loadCustomData;
|
|
|
414
411
|
// NOTE: if you use a raw query or paramterized query with this,
|
|
415
412
|
// you should use `SELECT count(*) as count...`
|
|
416
413
|
async function loadCustomCount(options, query, context) {
|
|
417
|
-
//
|
|
414
|
+
// if clause, we'll use the loader and strong typing/coalescing it provides
|
|
415
|
+
if (typeof query !== "string" && isClause(query)) {
|
|
416
|
+
return options.loaderFactory.createCountLoader(context).load(query);
|
|
417
|
+
}
|
|
418
418
|
const rows = await loadCustomDataImpl({
|
|
419
419
|
...options,
|
|
420
420
|
fields: ["count(1) as count"],
|
|
@@ -429,46 +429,31 @@ function isPrimableLoader(loader) {
|
|
|
429
429
|
return loader != undefined;
|
|
430
430
|
}
|
|
431
431
|
async function loadCustomDataImpl(options, query, context) {
|
|
432
|
-
function getClause(cls) {
|
|
433
|
-
let optClause = options.loaderFactory?.options?.clause;
|
|
434
|
-
if (typeof optClause === "function") {
|
|
435
|
-
optClause = optClause();
|
|
436
|
-
}
|
|
437
|
-
if (!optClause) {
|
|
438
|
-
return cls;
|
|
439
|
-
}
|
|
440
|
-
return clause.And(cls, optClause);
|
|
441
|
-
}
|
|
442
432
|
if (typeof query === "string") {
|
|
443
433
|
// no caching, perform raw query
|
|
444
434
|
return performRawQuery(query, [], []);
|
|
445
435
|
}
|
|
446
436
|
else if (isClause(query)) {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
// this will have rudimentary caching but nothing crazy
|
|
452
|
-
return loadRows({
|
|
453
|
-
...options,
|
|
454
|
-
clause: getClause(query),
|
|
455
|
-
context: context,
|
|
456
|
-
});
|
|
437
|
+
const r = await options.loaderFactory
|
|
438
|
+
.createTypedLoader(context)
|
|
439
|
+
.load(query);
|
|
440
|
+
return r;
|
|
457
441
|
}
|
|
458
442
|
else if (isParameterizedQuery(query)) {
|
|
459
443
|
// no caching, perform raw query
|
|
460
444
|
return performRawQuery(query.query, query.values || [], query.logValues);
|
|
461
445
|
}
|
|
462
446
|
else {
|
|
447
|
+
// this will have rudimentary caching but nothing crazy
|
|
463
448
|
let cls = query.clause;
|
|
464
449
|
if (!query.disableTransformations) {
|
|
465
|
-
cls =
|
|
450
|
+
cls = clause.getCombinedClause(options.loaderFactory.options, query.clause);
|
|
466
451
|
}
|
|
467
|
-
// this will have rudimentary caching but nothing crazy
|
|
468
452
|
return loadRows({
|
|
469
453
|
...query,
|
|
470
454
|
...options,
|
|
471
455
|
context: context,
|
|
456
|
+
// @ts-expect-error
|
|
472
457
|
clause: cls,
|
|
473
458
|
});
|
|
474
459
|
}
|
|
@@ -480,7 +465,7 @@ async function loadDerivedEnt(viewer, data, loader) {
|
|
|
480
465
|
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, {
|
|
481
466
|
ent: loader,
|
|
482
467
|
});
|
|
483
|
-
if (r
|
|
468
|
+
if (rowIsError(r)) {
|
|
484
469
|
return null;
|
|
485
470
|
}
|
|
486
471
|
return r;
|
|
@@ -503,7 +488,7 @@ async function applyPrivacyPolicyForEnt(viewer, ent, data, fieldPrivacyOptions)
|
|
|
503
488
|
}
|
|
504
489
|
async function applyPrivacyPolicyForEntX(viewer, ent, data, options) {
|
|
505
490
|
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, options);
|
|
506
|
-
if (r
|
|
491
|
+
if (rowIsError(r)) {
|
|
507
492
|
throw r;
|
|
508
493
|
}
|
|
509
494
|
if (r === null) {
|
|
@@ -517,11 +502,12 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
517
502
|
}
|
|
518
503
|
const promises = [];
|
|
519
504
|
let somethingChanged = false;
|
|
505
|
+
const clone = { ...data };
|
|
520
506
|
const origData = {
|
|
521
507
|
...data,
|
|
522
508
|
};
|
|
523
509
|
for (const [k, policy] of options.fieldPrivacy) {
|
|
524
|
-
const curr =
|
|
510
|
+
const curr = clone[k];
|
|
525
511
|
if (curr === null || curr === undefined) {
|
|
526
512
|
continue;
|
|
527
513
|
}
|
|
@@ -529,7 +515,7 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
529
515
|
// don't do anything if key is null or for some reason missing
|
|
530
516
|
const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
|
|
531
517
|
if (!r) {
|
|
532
|
-
|
|
518
|
+
clone[k] = null;
|
|
533
519
|
somethingChanged = true;
|
|
534
520
|
}
|
|
535
521
|
})());
|
|
@@ -537,7 +523,7 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
537
523
|
await Promise.all(promises);
|
|
538
524
|
if (somethingChanged) {
|
|
539
525
|
// have to create new instance
|
|
540
|
-
const ent = new options.ent(viewer,
|
|
526
|
+
const ent = new options.ent(viewer, clone);
|
|
541
527
|
ent.__setRawDBData(origData);
|
|
542
528
|
return ent;
|
|
543
529
|
}
|
|
@@ -605,7 +591,7 @@ async function performRawQuery(query, values, logValues) {
|
|
|
605
591
|
catch (e) {
|
|
606
592
|
if (_logQueryWithError) {
|
|
607
593
|
const msg = e.message;
|
|
608
|
-
throw new Error(`error \`${msg}\` running query: \`${query}\``);
|
|
594
|
+
throw new Error(`error \`${msg}\` running query: \`${query}\` with values: \`${logValues}\``);
|
|
609
595
|
}
|
|
610
596
|
throw e;
|
|
611
597
|
}
|
|
@@ -634,17 +620,18 @@ function buildQuery(options) {
|
|
|
634
620
|
const fields = options.fields.join(", ");
|
|
635
621
|
// always start at 1
|
|
636
622
|
const whereClause = options.clause.clause(1);
|
|
637
|
-
|
|
623
|
+
const parts = [];
|
|
624
|
+
parts.push(`SELECT ${fields} FROM ${options.tableName} WHERE ${whereClause}`);
|
|
638
625
|
if (options.groupby) {
|
|
639
|
-
|
|
626
|
+
parts.push(`GROUP BY ${options.groupby}`);
|
|
640
627
|
}
|
|
641
628
|
if (options.orderby) {
|
|
642
|
-
|
|
629
|
+
parts.push(`ORDER BY ${(0, query_impl_1.getOrderByPhrase)(options.orderby)}`);
|
|
643
630
|
}
|
|
644
631
|
if (options.limit) {
|
|
645
|
-
|
|
632
|
+
parts.push(`LIMIT ${options.limit}`);
|
|
646
633
|
}
|
|
647
|
-
return
|
|
634
|
+
return parts.join(" ");
|
|
648
635
|
}
|
|
649
636
|
exports.buildQuery = buildQuery;
|
|
650
637
|
// this is used for queries when we select multiple ids at once
|
|
@@ -656,7 +643,7 @@ function buildGroupQuery(options) {
|
|
|
656
643
|
}
|
|
657
644
|
let orderby = "";
|
|
658
645
|
if (options.orderby) {
|
|
659
|
-
orderby = `ORDER BY ${options.orderby}`;
|
|
646
|
+
orderby = `ORDER BY ${(0, query_impl_1.getOrderByPhrase)(options.orderby)}`;
|
|
660
647
|
}
|
|
661
648
|
// window functions work in sqlite!
|
|
662
649
|
// https://www.sqlite.org/windowfunctions.html
|
|
@@ -666,499 +653,6 @@ function buildGroupQuery(options) {
|
|
|
666
653
|
];
|
|
667
654
|
}
|
|
668
655
|
exports.buildGroupQuery = buildGroupQuery;
|
|
669
|
-
class RawQueryOperation {
|
|
670
|
-
constructor(queries) {
|
|
671
|
-
this.queries = queries;
|
|
672
|
-
}
|
|
673
|
-
async performWrite(queryer, context) {
|
|
674
|
-
for (const q of this.queries) {
|
|
675
|
-
if (typeof q === "string") {
|
|
676
|
-
logQuery(q, []);
|
|
677
|
-
await queryer.query(q);
|
|
678
|
-
}
|
|
679
|
-
else {
|
|
680
|
-
logQuery(q.query, q.logValues || []);
|
|
681
|
-
await queryer.query(q.query, q.values);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
performWriteSync(queryer, context) {
|
|
686
|
-
for (const q of this.queries) {
|
|
687
|
-
if (typeof q === "string") {
|
|
688
|
-
logQuery(q, []);
|
|
689
|
-
queryer.execSync(q);
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
logQuery(q.query, q.logValues || []);
|
|
693
|
-
queryer.execSync(q.query, q.values);
|
|
694
|
-
}
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
exports.RawQueryOperation = RawQueryOperation;
|
|
699
|
-
class EditNodeOperation {
|
|
700
|
-
constructor(options, existingEnt = null) {
|
|
701
|
-
this.options = options;
|
|
702
|
-
this.existingEnt = existingEnt;
|
|
703
|
-
this.row = null;
|
|
704
|
-
this.placeholderID = options.placeholderID;
|
|
705
|
-
}
|
|
706
|
-
resolve(executor) {
|
|
707
|
-
if (!this.options.fieldsToResolve.length) {
|
|
708
|
-
return;
|
|
709
|
-
}
|
|
710
|
-
let fields = this.options.fields;
|
|
711
|
-
this.options.fieldsToResolve.forEach((fieldName) => {
|
|
712
|
-
let value = fields[fieldName];
|
|
713
|
-
if (!value) {
|
|
714
|
-
throw new Error(`trying to resolve field ${fieldName} but not a valid field`);
|
|
715
|
-
}
|
|
716
|
-
let ent = executor.resolveValue(value.placeholderID);
|
|
717
|
-
if (!ent) {
|
|
718
|
-
throw new Error(`couldn't resolve field \`${fieldName}\` with value ${value.placeholderID}`);
|
|
719
|
-
}
|
|
720
|
-
fields[fieldName] = ent.id;
|
|
721
|
-
});
|
|
722
|
-
this.options.fields = fields;
|
|
723
|
-
}
|
|
724
|
-
hasData(data) {
|
|
725
|
-
for (const _k in data) {
|
|
726
|
-
return true;
|
|
727
|
-
}
|
|
728
|
-
return false;
|
|
729
|
-
}
|
|
730
|
-
async performWrite(queryer, context) {
|
|
731
|
-
let options = {
|
|
732
|
-
...this.options,
|
|
733
|
-
context,
|
|
734
|
-
};
|
|
735
|
-
if (this.existingEnt) {
|
|
736
|
-
if (this.hasData(options.fields)) {
|
|
737
|
-
// even this with returning * may not always work if transformed...
|
|
738
|
-
// we can have a transformed flag to see if it should be returned?
|
|
739
|
-
this.row = await editRow(queryer, options, "RETURNING *");
|
|
740
|
-
}
|
|
741
|
-
else {
|
|
742
|
-
// @ts-ignore
|
|
743
|
-
this.row = this.existingEnt["data"];
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
else {
|
|
747
|
-
this.row = await createRow(queryer, options, "RETURNING *");
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
reloadRow(queryer, id, options) {
|
|
751
|
-
// TODO this isn't always an ObjectLoader. should throw or figure out a way to get query
|
|
752
|
-
// and run this on its own...
|
|
753
|
-
const loader = this.options.loadEntOptions.loaderFactory.createLoader(options.context);
|
|
754
|
-
const opts = loader.getOptions();
|
|
755
|
-
let cls = clause.Eq(options.key, id);
|
|
756
|
-
if (opts.clause) {
|
|
757
|
-
let optionClause;
|
|
758
|
-
if (typeof opts.clause === "function") {
|
|
759
|
-
optionClause = opts.clause();
|
|
760
|
-
}
|
|
761
|
-
else {
|
|
762
|
-
optionClause = opts.clause;
|
|
763
|
-
}
|
|
764
|
-
if (optionClause) {
|
|
765
|
-
cls = clause.And(cls, optionClause);
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
const query = buildQuery({
|
|
769
|
-
fields: opts.fields.length ? opts.fields : ["*"],
|
|
770
|
-
tableName: options.tableName,
|
|
771
|
-
clause: cls,
|
|
772
|
-
});
|
|
773
|
-
// special case log here because we're not going through any of the normal
|
|
774
|
-
// methods here because those are async and this is sync
|
|
775
|
-
// this is the only place we're doing this so only handling here
|
|
776
|
-
logQuery(query, [id]);
|
|
777
|
-
const r = queryer.querySync(query, [id]);
|
|
778
|
-
if (r.rows.length === 1) {
|
|
779
|
-
this.row = r.rows[0];
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
performWriteSync(queryer, context) {
|
|
783
|
-
let options = {
|
|
784
|
-
...this.options,
|
|
785
|
-
context,
|
|
786
|
-
};
|
|
787
|
-
if (this.existingEnt) {
|
|
788
|
-
if (this.hasData(this.options.fields)) {
|
|
789
|
-
editRowSync(queryer, options, "RETURNING *");
|
|
790
|
-
this.reloadRow(queryer, this.existingEnt.id, options);
|
|
791
|
-
}
|
|
792
|
-
else {
|
|
793
|
-
// @ts-ignore
|
|
794
|
-
this.row = this.existingEnt["data"];
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
else {
|
|
798
|
-
createRowSync(queryer, options, "RETURNING *");
|
|
799
|
-
const id = options.fields[options.key];
|
|
800
|
-
this.reloadRow(queryer, id, options);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
returnedRow() {
|
|
804
|
-
return this.row;
|
|
805
|
-
}
|
|
806
|
-
createdEnt(viewer) {
|
|
807
|
-
if (!this.row) {
|
|
808
|
-
return null;
|
|
809
|
-
}
|
|
810
|
-
return new this.options.loadEntOptions.ent(viewer, this.row);
|
|
811
|
-
}
|
|
812
|
-
}
|
|
813
|
-
exports.EditNodeOperation = EditNodeOperation;
|
|
814
|
-
let globalSchema;
|
|
815
|
-
function setGlobalSchema(val) {
|
|
816
|
-
globalSchema = val;
|
|
817
|
-
}
|
|
818
|
-
exports.setGlobalSchema = setGlobalSchema;
|
|
819
|
-
function clearGlobalSchema() {
|
|
820
|
-
globalSchema = undefined;
|
|
821
|
-
}
|
|
822
|
-
exports.clearGlobalSchema = clearGlobalSchema;
|
|
823
|
-
// used by tests. no guarantee will always exist
|
|
824
|
-
function __hasGlobalSchema() {
|
|
825
|
-
return globalSchema !== undefined;
|
|
826
|
-
}
|
|
827
|
-
exports.__hasGlobalSchema = __hasGlobalSchema;
|
|
828
|
-
class EdgeOperation {
|
|
829
|
-
constructor(builder, edgeInput, options) {
|
|
830
|
-
this.builder = builder;
|
|
831
|
-
this.edgeInput = edgeInput;
|
|
832
|
-
this.options = options;
|
|
833
|
-
}
|
|
834
|
-
async preFetch(queryer, context) {
|
|
835
|
-
let edgeData = await loadEdgeData(this.edgeInput.edgeType);
|
|
836
|
-
if (!edgeData) {
|
|
837
|
-
throw new Error(`error loading edge data for ${this.edgeInput.edgeType}`);
|
|
838
|
-
}
|
|
839
|
-
this.edgeData = edgeData;
|
|
840
|
-
}
|
|
841
|
-
async performWrite(queryer, context) {
|
|
842
|
-
if (!this.edgeData) {
|
|
843
|
-
throw new Error(`error fetching edgeData for type ${this.edgeInput.edgeType}`);
|
|
844
|
-
}
|
|
845
|
-
switch (this.options.operation) {
|
|
846
|
-
case action_1.WriteOperation.Delete:
|
|
847
|
-
return this.performDeleteWrite(queryer, this.edgeData, this.edgeInput, context);
|
|
848
|
-
case action_1.WriteOperation.Insert:
|
|
849
|
-
case action_1.WriteOperation.Edit:
|
|
850
|
-
return this.performInsertWrite(queryer, this.edgeData, this.edgeInput, context);
|
|
851
|
-
}
|
|
852
|
-
}
|
|
853
|
-
performWriteSync(queryer, context) {
|
|
854
|
-
if (!this.edgeData) {
|
|
855
|
-
throw new Error(`error fetching edgeData for type ${this.edgeInput.edgeType}`);
|
|
856
|
-
}
|
|
857
|
-
switch (this.options.operation) {
|
|
858
|
-
case action_1.WriteOperation.Delete:
|
|
859
|
-
return this.performDeleteWriteSync(queryer, this.edgeData, this.edgeInput, context);
|
|
860
|
-
case action_1.WriteOperation.Insert:
|
|
861
|
-
case action_1.WriteOperation.Edit:
|
|
862
|
-
return this.performInsertWriteSync(queryer, this.edgeData, this.edgeInput, context);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
getDeleteRowParams(edgeData, edge, context) {
|
|
866
|
-
let transformed = null;
|
|
867
|
-
let op = schema_1.SQLStatementOperation.Delete;
|
|
868
|
-
let updateData = null;
|
|
869
|
-
// TODO respect disableTransformations
|
|
870
|
-
if (globalSchema?.transformEdgeWrite) {
|
|
871
|
-
transformed = globalSchema.transformEdgeWrite({
|
|
872
|
-
op: schema_1.SQLStatementOperation.Delete,
|
|
873
|
-
edge,
|
|
874
|
-
});
|
|
875
|
-
if (transformed) {
|
|
876
|
-
op = transformed.op;
|
|
877
|
-
if (transformed.op === schema_1.SQLStatementOperation.Insert) {
|
|
878
|
-
throw new Error(`cannot currently transform a delete into an insert`);
|
|
879
|
-
}
|
|
880
|
-
if (transformed.op === schema_1.SQLStatementOperation.Update) {
|
|
881
|
-
if (!transformed.data) {
|
|
882
|
-
throw new Error(`cannot transform a delete into an update without providing data`);
|
|
883
|
-
}
|
|
884
|
-
updateData = transformed.data;
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
return {
|
|
889
|
-
op,
|
|
890
|
-
updateData,
|
|
891
|
-
options: {
|
|
892
|
-
tableName: edgeData.edgeTable,
|
|
893
|
-
context,
|
|
894
|
-
},
|
|
895
|
-
clause: clause.And(clause.Eq("id1", edge.id1), clause.Eq("id2", edge.id2), clause.Eq("edge_type", edge.edgeType)),
|
|
896
|
-
};
|
|
897
|
-
}
|
|
898
|
-
async performDeleteWrite(q, edgeData, edge, context) {
|
|
899
|
-
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
900
|
-
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
901
|
-
return deleteRows(q, params.options, params.clause);
|
|
902
|
-
}
|
|
903
|
-
else {
|
|
904
|
-
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
905
|
-
throw new Error(`invalid operation ${params.op}`);
|
|
906
|
-
}
|
|
907
|
-
await editRow(q, {
|
|
908
|
-
tableName: params.options.tableName,
|
|
909
|
-
whereClause: params.clause,
|
|
910
|
-
fields: params.updateData,
|
|
911
|
-
fieldsToLog: params.updateData,
|
|
912
|
-
});
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
performDeleteWriteSync(q, edgeData, edge, context) {
|
|
916
|
-
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
917
|
-
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
918
|
-
return deleteRowsSync(q, params.options, params.clause);
|
|
919
|
-
}
|
|
920
|
-
else {
|
|
921
|
-
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
922
|
-
throw new Error(`invalid operation ${params.op}`);
|
|
923
|
-
}
|
|
924
|
-
editRowSync(q, {
|
|
925
|
-
tableName: params.options.tableName,
|
|
926
|
-
whereClause: params.clause,
|
|
927
|
-
fields: params.updateData,
|
|
928
|
-
});
|
|
929
|
-
}
|
|
930
|
-
}
|
|
931
|
-
getInsertRowParams(edgeData, edge, context) {
|
|
932
|
-
const fields = {
|
|
933
|
-
id1: edge.id1,
|
|
934
|
-
id2: edge.id2,
|
|
935
|
-
id1_type: edge.id1Type,
|
|
936
|
-
id2_type: edge.id2Type,
|
|
937
|
-
edge_type: edge.edgeType,
|
|
938
|
-
data: edge.data || null,
|
|
939
|
-
};
|
|
940
|
-
if (edge.time) {
|
|
941
|
-
fields["time"] = edge.time.toISOString();
|
|
942
|
-
}
|
|
943
|
-
else {
|
|
944
|
-
// todo make this a schema field like what we do in generated base files...
|
|
945
|
-
// maybe when actions exist?
|
|
946
|
-
fields["time"] = new Date().toISOString();
|
|
947
|
-
}
|
|
948
|
-
const onConflictFields = ["data"];
|
|
949
|
-
if (globalSchema?.extraEdgeFields) {
|
|
950
|
-
for (const name in globalSchema.extraEdgeFields) {
|
|
951
|
-
const f = globalSchema.extraEdgeFields[name];
|
|
952
|
-
if (f.defaultValueOnCreate) {
|
|
953
|
-
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
954
|
-
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
955
|
-
// onconflict make sure we override the default values
|
|
956
|
-
// e.g. setting deleted_at = null for soft delete
|
|
957
|
-
onConflictFields.push(storageKey);
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
// TODO respect disableTransformations
|
|
962
|
-
let transformed = null;
|
|
963
|
-
if (globalSchema?.transformEdgeWrite) {
|
|
964
|
-
transformed = globalSchema.transformEdgeWrite({
|
|
965
|
-
op: schema_1.SQLStatementOperation.Insert,
|
|
966
|
-
edge,
|
|
967
|
-
});
|
|
968
|
-
if (transformed) {
|
|
969
|
-
throw new Error(`transforming an insert edge not currently supported`);
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
return [
|
|
973
|
-
{
|
|
974
|
-
tableName: edgeData.edgeTable,
|
|
975
|
-
fields: fields,
|
|
976
|
-
fieldsToLog: fields,
|
|
977
|
-
context,
|
|
978
|
-
},
|
|
979
|
-
`ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields
|
|
980
|
-
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
981
|
-
.join(", ")}`,
|
|
982
|
-
];
|
|
983
|
-
}
|
|
984
|
-
async performInsertWrite(q, edgeData, edge, context) {
|
|
985
|
-
const [options, suffix] = this.getInsertRowParams(edgeData, edge, context);
|
|
986
|
-
await createRow(q, options, suffix);
|
|
987
|
-
}
|
|
988
|
-
performInsertWriteSync(q, edgeData, edge, context) {
|
|
989
|
-
const [options, suffix] = this.getInsertRowParams(edgeData, edge, context);
|
|
990
|
-
createRowSync(q, options, suffix);
|
|
991
|
-
}
|
|
992
|
-
resolveImpl(executor, placeholder, desc) {
|
|
993
|
-
let ent = executor.resolveValue(placeholder);
|
|
994
|
-
if (!ent) {
|
|
995
|
-
throw new Error(`could not resolve placeholder value ${placeholder} for ${desc} for edge ${this.edgeInput.edgeType}`);
|
|
996
|
-
}
|
|
997
|
-
if (ent.id === undefined) {
|
|
998
|
-
throw new Error(`id of resolved ent is not defined`);
|
|
999
|
-
}
|
|
1000
|
-
return [ent.id, ent.nodeType];
|
|
1001
|
-
}
|
|
1002
|
-
resolve(executor) {
|
|
1003
|
-
if (this.options.id1Placeholder) {
|
|
1004
|
-
[this.edgeInput.id1, this.edgeInput.id1Type] = this.resolveImpl(executor, this.edgeInput.id1, "id1");
|
|
1005
|
-
}
|
|
1006
|
-
if (this.options.id2Placeholder) {
|
|
1007
|
-
[this.edgeInput.id2, this.edgeInput.id2Type] = this.resolveImpl(executor, this.edgeInput.id2, "id2");
|
|
1008
|
-
}
|
|
1009
|
-
if (this.options.dataPlaceholder) {
|
|
1010
|
-
if (!this.edgeInput.data) {
|
|
1011
|
-
throw new Error(`data placeholder set but edgeInput data undefined`);
|
|
1012
|
-
}
|
|
1013
|
-
let [data, _] = this.resolveImpl(executor, this.edgeInput.data.toString(), "data");
|
|
1014
|
-
this.edgeInput.data = data.toString();
|
|
1015
|
-
}
|
|
1016
|
-
}
|
|
1017
|
-
symmetricEdge() {
|
|
1018
|
-
return new EdgeOperation(this.builder, {
|
|
1019
|
-
id1: this.edgeInput.id2,
|
|
1020
|
-
id1Type: this.edgeInput.id2Type,
|
|
1021
|
-
id2: this.edgeInput.id1,
|
|
1022
|
-
id2Type: this.edgeInput.id1Type,
|
|
1023
|
-
edgeType: this.edgeInput.edgeType,
|
|
1024
|
-
time: this.edgeInput.time,
|
|
1025
|
-
data: this.edgeInput.data,
|
|
1026
|
-
}, {
|
|
1027
|
-
operation: this.options.operation,
|
|
1028
|
-
id1Placeholder: this.options.id2Placeholder,
|
|
1029
|
-
id2Placeholder: this.options.id1Placeholder,
|
|
1030
|
-
dataPlaceholder: this.options.dataPlaceholder,
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
1033
|
-
inverseEdge(edgeData) {
|
|
1034
|
-
return new EdgeOperation(this.builder, {
|
|
1035
|
-
id1: this.edgeInput.id2,
|
|
1036
|
-
id1Type: this.edgeInput.id2Type,
|
|
1037
|
-
id2: this.edgeInput.id1,
|
|
1038
|
-
id2Type: this.edgeInput.id1Type,
|
|
1039
|
-
edgeType: edgeData.inverseEdgeType,
|
|
1040
|
-
time: this.edgeInput.time,
|
|
1041
|
-
data: this.edgeInput.data,
|
|
1042
|
-
}, {
|
|
1043
|
-
operation: this.options.operation,
|
|
1044
|
-
id1Placeholder: this.options.id2Placeholder,
|
|
1045
|
-
id2Placeholder: this.options.id1Placeholder,
|
|
1046
|
-
dataPlaceholder: this.options.dataPlaceholder,
|
|
1047
|
-
});
|
|
1048
|
-
}
|
|
1049
|
-
static resolveIDs(srcBuilder, // id1
|
|
1050
|
-
destID) {
|
|
1051
|
-
let destIDVal;
|
|
1052
|
-
let destPlaceholder = false;
|
|
1053
|
-
if (this.isBuilder(destID)) {
|
|
1054
|
-
destIDVal = destID.placeholderID;
|
|
1055
|
-
destPlaceholder = true;
|
|
1056
|
-
}
|
|
1057
|
-
else {
|
|
1058
|
-
destIDVal = destID;
|
|
1059
|
-
}
|
|
1060
|
-
let srcIDVal;
|
|
1061
|
-
let srcType;
|
|
1062
|
-
let srcPlaceholder = false;
|
|
1063
|
-
if (srcBuilder.existingEnt) {
|
|
1064
|
-
srcIDVal = srcBuilder.existingEnt.id;
|
|
1065
|
-
srcType = srcBuilder.existingEnt.nodeType;
|
|
1066
|
-
}
|
|
1067
|
-
else {
|
|
1068
|
-
srcPlaceholder = true;
|
|
1069
|
-
// get placeholder.
|
|
1070
|
-
srcIDVal = srcBuilder.placeholderID;
|
|
1071
|
-
// expected to be filled later
|
|
1072
|
-
srcType = "";
|
|
1073
|
-
}
|
|
1074
|
-
return [srcIDVal, srcType, srcPlaceholder, destIDVal, destPlaceholder];
|
|
1075
|
-
}
|
|
1076
|
-
static isBuilder(val) {
|
|
1077
|
-
return val.placeholderID !== undefined;
|
|
1078
|
-
}
|
|
1079
|
-
static resolveData(data) {
|
|
1080
|
-
if (!data) {
|
|
1081
|
-
return [undefined, false];
|
|
1082
|
-
}
|
|
1083
|
-
if (this.isBuilder(data)) {
|
|
1084
|
-
return [data.placeholderID.toString(), true];
|
|
1085
|
-
}
|
|
1086
|
-
return [data, false];
|
|
1087
|
-
}
|
|
1088
|
-
static inboundEdge(builder, edgeType, id1, nodeType, options) {
|
|
1089
|
-
let [id2Val, id2Type, id2Placeholder, id1Val, id1Placeholder] = EdgeOperation.resolveIDs(builder, id1);
|
|
1090
|
-
let [data, dataPlaceholder] = EdgeOperation.resolveData(options?.data);
|
|
1091
|
-
const edge = {
|
|
1092
|
-
id1: id1Val,
|
|
1093
|
-
edgeType: edgeType,
|
|
1094
|
-
id2: id2Val,
|
|
1095
|
-
id2Type: id2Type,
|
|
1096
|
-
id1Type: nodeType,
|
|
1097
|
-
...options,
|
|
1098
|
-
};
|
|
1099
|
-
if (data) {
|
|
1100
|
-
edge.data = data;
|
|
1101
|
-
}
|
|
1102
|
-
return new EdgeOperation(builder, edge, {
|
|
1103
|
-
operation: action_1.WriteOperation.Insert,
|
|
1104
|
-
id2Placeholder,
|
|
1105
|
-
id1Placeholder,
|
|
1106
|
-
dataPlaceholder,
|
|
1107
|
-
});
|
|
1108
|
-
}
|
|
1109
|
-
static outboundEdge(builder, edgeType, id2, nodeType, options) {
|
|
1110
|
-
let [id1Val, id1Type, id1Placeholder, id2Val, id2Placeholder] = EdgeOperation.resolveIDs(builder, id2);
|
|
1111
|
-
let [data, dataPlaceholder] = EdgeOperation.resolveData(options?.data);
|
|
1112
|
-
const edge = {
|
|
1113
|
-
id1: id1Val,
|
|
1114
|
-
edgeType: edgeType,
|
|
1115
|
-
id2: id2Val,
|
|
1116
|
-
id2Type: nodeType,
|
|
1117
|
-
id1Type: id1Type,
|
|
1118
|
-
...options,
|
|
1119
|
-
};
|
|
1120
|
-
if (data) {
|
|
1121
|
-
edge.data = data;
|
|
1122
|
-
}
|
|
1123
|
-
return new EdgeOperation(builder, edge, {
|
|
1124
|
-
operation: action_1.WriteOperation.Insert,
|
|
1125
|
-
id1Placeholder,
|
|
1126
|
-
id2Placeholder,
|
|
1127
|
-
dataPlaceholder,
|
|
1128
|
-
});
|
|
1129
|
-
}
|
|
1130
|
-
static removeInboundEdge(builder, edgeType, id1) {
|
|
1131
|
-
if (!builder.existingEnt) {
|
|
1132
|
-
throw new Error("cannot remove an edge from a non-existing ent");
|
|
1133
|
-
}
|
|
1134
|
-
const edge = {
|
|
1135
|
-
id1: id1,
|
|
1136
|
-
edgeType: edgeType,
|
|
1137
|
-
id2: builder.existingEnt.id,
|
|
1138
|
-
id2Type: "",
|
|
1139
|
-
id1Type: "",
|
|
1140
|
-
};
|
|
1141
|
-
return new EdgeOperation(builder, edge, {
|
|
1142
|
-
operation: action_1.WriteOperation.Delete,
|
|
1143
|
-
});
|
|
1144
|
-
}
|
|
1145
|
-
static removeOutboundEdge(builder, edgeType, id2) {
|
|
1146
|
-
if (!builder.existingEnt) {
|
|
1147
|
-
throw new Error("cannot remove an edge from a non-existing ent");
|
|
1148
|
-
}
|
|
1149
|
-
const edge = {
|
|
1150
|
-
id2: id2,
|
|
1151
|
-
edgeType: edgeType,
|
|
1152
|
-
id1: builder.existingEnt.id,
|
|
1153
|
-
id2Type: "",
|
|
1154
|
-
id1Type: "",
|
|
1155
|
-
};
|
|
1156
|
-
return new EdgeOperation(builder, edge, {
|
|
1157
|
-
operation: action_1.WriteOperation.Delete,
|
|
1158
|
-
});
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
exports.EdgeOperation = EdgeOperation;
|
|
1162
656
|
function isSyncQueryer(queryer) {
|
|
1163
657
|
return queryer.execSync !== undefined;
|
|
1164
658
|
}
|
|
@@ -1228,8 +722,26 @@ function buildInsertQuery(options, suffix) {
|
|
|
1228
722
|
const cols = fields.join(", ");
|
|
1229
723
|
const vals = valsString.join(", ");
|
|
1230
724
|
let query = `INSERT INTO ${options.tableName} (${cols}) VALUES (${vals})`;
|
|
725
|
+
if (options.onConflict) {
|
|
726
|
+
let onConflict = "";
|
|
727
|
+
if (options.onConflict.onConflictConstraint) {
|
|
728
|
+
onConflict = `ON CONFLICT ON CONSTRAINT ${options.onConflict.onConflictConstraint}`;
|
|
729
|
+
}
|
|
730
|
+
else {
|
|
731
|
+
onConflict = `ON CONFLICT(${options.onConflict.onConflictCols.join(", ")})`;
|
|
732
|
+
}
|
|
733
|
+
if (options.onConflict.updateCols?.length) {
|
|
734
|
+
onConflict += ` DO UPDATE SET ${options.onConflict.updateCols
|
|
735
|
+
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
736
|
+
.join(", ")}`;
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
onConflict += ` DO NOTHING`;
|
|
740
|
+
}
|
|
741
|
+
query = query + " " + onConflict;
|
|
742
|
+
}
|
|
1231
743
|
if (suffix) {
|
|
1232
|
-
query
|
|
744
|
+
query += " " + suffix;
|
|
1233
745
|
}
|
|
1234
746
|
return [query, values, logValues];
|
|
1235
747
|
}
|
|
@@ -1336,27 +848,6 @@ function deleteRowsSync(queryer, options, cls) {
|
|
|
1336
848
|
mutateRowSync(queryer, query, cls.values(), cls.logValues(), options);
|
|
1337
849
|
}
|
|
1338
850
|
exports.deleteRowsSync = deleteRowsSync;
|
|
1339
|
-
class DeleteNodeOperation {
|
|
1340
|
-
constructor(id, options) {
|
|
1341
|
-
this.id = id;
|
|
1342
|
-
this.options = options;
|
|
1343
|
-
}
|
|
1344
|
-
async performWrite(queryer, context) {
|
|
1345
|
-
let options = {
|
|
1346
|
-
...this.options,
|
|
1347
|
-
context,
|
|
1348
|
-
};
|
|
1349
|
-
return deleteRows(queryer, options, clause.Eq("id", this.id));
|
|
1350
|
-
}
|
|
1351
|
-
performWriteSync(queryer, context) {
|
|
1352
|
-
let options = {
|
|
1353
|
-
...this.options,
|
|
1354
|
-
context,
|
|
1355
|
-
};
|
|
1356
|
-
return deleteRowsSync(queryer, options, clause.Eq("id", this.id));
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
exports.DeleteNodeOperation = DeleteNodeOperation;
|
|
1360
851
|
class AssocEdge {
|
|
1361
852
|
constructor(data) {
|
|
1362
853
|
this.id1 = data.id1;
|
|
@@ -1417,10 +908,11 @@ const assocEdgeFields = [
|
|
|
1417
908
|
"inverse_edge_type",
|
|
1418
909
|
"edge_table",
|
|
1419
910
|
];
|
|
1420
|
-
exports.assocEdgeLoader =
|
|
911
|
+
exports.assocEdgeLoader = createAssocEdgeConfigLoader({
|
|
1421
912
|
tableName: "assoc_edge_config",
|
|
1422
913
|
fields: assocEdgeFields,
|
|
1423
914
|
key: "edge_type",
|
|
915
|
+
keyType: "uuid",
|
|
1424
916
|
});
|
|
1425
917
|
// we don't expect assoc_edge_config information to change
|
|
1426
918
|
// so not using ContextCache but just caching it as needed once per server
|
|
@@ -1442,7 +934,7 @@ async function loadEdgeDatas(...edgeTypes) {
|
|
|
1442
934
|
if (!row) {
|
|
1443
935
|
return;
|
|
1444
936
|
}
|
|
1445
|
-
if (row
|
|
937
|
+
if (rowIsError(row)) {
|
|
1446
938
|
throw row;
|
|
1447
939
|
}
|
|
1448
940
|
m.set(row["edge_type"], new AssocEdgeData(row));
|
|
@@ -1459,8 +951,15 @@ const edgeFields = [
|
|
|
1459
951
|
"time",
|
|
1460
952
|
"data",
|
|
1461
953
|
];
|
|
1462
|
-
|
|
1463
|
-
|
|
954
|
+
let defaultLimit = 1000;
|
|
955
|
+
function setDefaultLimit(limit) {
|
|
956
|
+
defaultLimit = limit;
|
|
957
|
+
}
|
|
958
|
+
exports.setDefaultLimit = setDefaultLimit;
|
|
959
|
+
function getDefaultLimit() {
|
|
960
|
+
return defaultLimit;
|
|
961
|
+
}
|
|
962
|
+
exports.getDefaultLimit = getDefaultLimit;
|
|
1464
963
|
function defaultEdgeQueryOptions(id1, edgeType, id2) {
|
|
1465
964
|
let cls = clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType));
|
|
1466
965
|
if (id2) {
|
|
@@ -1468,8 +967,13 @@ function defaultEdgeQueryOptions(id1, edgeType, id2) {
|
|
|
1468
967
|
}
|
|
1469
968
|
return {
|
|
1470
969
|
clause: cls,
|
|
1471
|
-
orderby:
|
|
1472
|
-
|
|
970
|
+
orderby: [
|
|
971
|
+
{
|
|
972
|
+
column: "time",
|
|
973
|
+
direction: "DESC",
|
|
974
|
+
},
|
|
975
|
+
],
|
|
976
|
+
limit: defaultLimit,
|
|
1473
977
|
};
|
|
1474
978
|
}
|
|
1475
979
|
async function loadEdges(options) {
|
|
@@ -1478,9 +982,10 @@ async function loadEdges(options) {
|
|
|
1478
982
|
exports.loadEdges = loadEdges;
|
|
1479
983
|
function getEdgeClauseAndFields(cls, options) {
|
|
1480
984
|
let fields = edgeFields;
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
985
|
+
const transformEdgeRead = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeRead;
|
|
986
|
+
if (transformEdgeRead) {
|
|
987
|
+
const transformClause = transformEdgeRead();
|
|
988
|
+
if (!options.queryOptions?.disableTransformations) {
|
|
1484
989
|
cls = clause.And(cls, transformClause);
|
|
1485
990
|
}
|
|
1486
991
|
fields = edgeFields.concat(transformClause.columns());
|
|
@@ -1598,7 +1103,7 @@ async function loadNodesByEdge(viewer, id1, edgeType, options) {
|
|
|
1598
1103
|
exports.loadNodesByEdge = loadNodesByEdge;
|
|
1599
1104
|
async function applyPrivacyPolicyForRow(viewer, options, row) {
|
|
1600
1105
|
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
1601
|
-
return r
|
|
1106
|
+
return rowIsError(r) ? null : r;
|
|
1602
1107
|
}
|
|
1603
1108
|
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1604
1109
|
async function applyPrivacyPolicyForRowImpl(viewer, options, row) {
|
|
@@ -1656,7 +1161,7 @@ async function getEdgeTypeInGroup(viewer, id1, id2, m) {
|
|
|
1656
1161
|
tableToEdgeEnumMap.forEach((edgeEnums, tableName) => {
|
|
1657
1162
|
promises.push((async () => {
|
|
1658
1163
|
const edgeTypes = edgeEnums.map((edgeEnum) => m.get(edgeEnum));
|
|
1659
|
-
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.
|
|
1164
|
+
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.UuidIn("edge_type", edgeTypes), clause.Eq("id2", id2)), {});
|
|
1660
1165
|
const rows = await loadRows({
|
|
1661
1166
|
tableName,
|
|
1662
1167
|
fields,
|