@snowtop/ent 0.1.0-alpha6 → 0.1.0-alpha63
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 +28 -24
- package/action/executor.d.ts +4 -4
- package/action/executor.js +2 -2
- package/action/experimental_action.d.ts +29 -22
- package/action/experimental_action.js +29 -6
- package/action/orchestrator.d.ts +44 -16
- package/action/orchestrator.js +287 -73
- package/action/privacy.d.ts +2 -2
- package/core/base.d.ts +26 -22
- package/core/base.js +16 -0
- package/core/clause.d.ts +65 -3
- package/core/clause.js +368 -5
- package/core/config.d.ts +26 -0
- package/core/config.js +17 -0
- package/core/context.d.ts +2 -2
- package/core/context.js +2 -2
- package/core/convert.d.ts +1 -1
- package/core/db.d.ts +3 -4
- package/core/db.js +2 -0
- package/core/ent.d.ts +35 -24
- package/core/ent.js +223 -60
- package/core/loaders/assoc_count_loader.d.ts +2 -2
- package/core/loaders/assoc_count_loader.js +6 -1
- package/core/loaders/assoc_edge_loader.d.ts +3 -3
- package/core/loaders/assoc_edge_loader.js +5 -4
- package/core/loaders/index_loader.js +1 -0
- package/core/loaders/loader.js +5 -5
- package/core/loaders/object_loader.d.ts +10 -5
- package/core/loaders/object_loader.js +58 -4
- package/core/loaders/query_loader.d.ts +2 -2
- package/core/loaders/raw_count_loader.d.ts +2 -2
- package/core/logger.d.ts +1 -1
- package/core/logger.js +1 -0
- package/core/privacy.d.ts +25 -25
- package/core/privacy.js +3 -0
- package/core/query/assoc_query.d.ts +6 -6
- package/core/query/custom_query.d.ts +5 -5
- package/core/query/query.d.ts +1 -1
- package/core/query/shared_assoc_test.d.ts +1 -1
- package/core/query/shared_assoc_test.js +17 -5
- package/core/query/shared_test.d.ts +3 -0
- package/core/query/shared_test.js +95 -17
- package/core/viewer.d.ts +4 -3
- package/core/viewer.js +4 -0
- package/graphql/builtins/connection.js +3 -3
- package/graphql/builtins/edge.js +2 -2
- package/graphql/builtins/node.js +1 -1
- package/graphql/graphql.d.ts +3 -2
- package/graphql/graphql.js +30 -23
- package/graphql/node_resolver.d.ts +0 -1
- package/graphql/query/connection_type.js +6 -6
- package/graphql/query/edge_connection.d.ts +9 -9
- package/graphql/query/page_info.d.ts +1 -1
- package/graphql/query/page_info.js +4 -4
- package/graphql/query/shared_assoc_test.js +2 -2
- package/graphql/scalars/time.d.ts +1 -1
- package/index.d.ts +18 -1
- package/index.js +21 -5
- package/package.json +3 -3
- package/parse_schema/parse.d.ts +24 -5
- package/parse_schema/parse.js +90 -8
- package/schema/base_schema.d.ts +36 -1
- package/schema/base_schema.js +51 -2
- package/schema/field.d.ts +34 -6
- package/schema/field.js +68 -3
- package/schema/index.d.ts +2 -2
- package/schema/index.js +8 -1
- package/schema/schema.d.ts +95 -2
- package/schema/schema.js +127 -5
- package/scripts/custom_graphql.js +127 -16
- package/scripts/{transform_schema.d.ts → migrate_v0.1.d.ts} +0 -0
- package/scripts/migrate_v0.1.js +36 -0
- package/scripts/read_schema.js +25 -2
- package/testutils/builder.d.ts +36 -22
- package/testutils/builder.js +110 -13
- package/testutils/context/test_context.d.ts +2 -2
- package/testutils/context/test_context.js +7 -1
- package/testutils/db/{test_db.d.ts → temp_db.d.ts} +17 -4
- package/testutils/db/{test_db.js → temp_db.js} +75 -19
- package/testutils/ent-graphql-tests/index.d.ts +2 -0
- package/testutils/ent-graphql-tests/index.js +26 -17
- package/testutils/fake_data/fake_contact.d.ts +5 -9
- package/testutils/fake_data/fake_contact.js +17 -21
- package/testutils/fake_data/fake_event.d.ts +5 -9
- package/testutils/fake_data/fake_event.js +24 -28
- package/testutils/fake_data/fake_user.d.ts +6 -10
- package/testutils/fake_data/fake_user.js +25 -29
- package/testutils/fake_data/test_helpers.d.ts +2 -2
- package/testutils/fake_data/test_helpers.js +6 -6
- package/testutils/fake_data/user_query.d.ts +2 -2
- package/testutils/fake_log.d.ts +3 -3
- package/testutils/parse_sql.js +4 -0
- package/testutils/test_edge_global_schema.d.ts +15 -0
- package/testutils/test_edge_global_schema.js +58 -0
- package/testutils/write.d.ts +2 -2
- package/testutils/write.js +3 -3
- package/tsc/ast.d.ts +44 -0
- package/tsc/ast.js +267 -0
- package/tsc/compilerOptions.d.ts +6 -0
- package/tsc/compilerOptions.js +40 -1
- package/tsc/move_generated.d.ts +1 -0
- package/tsc/move_generated.js +160 -0
- package/tsc/transform.d.ts +21 -0
- package/tsc/transform.js +167 -0
- package/tsc/transform_action.d.ts +22 -0
- package/tsc/transform_action.js +179 -0
- package/tsc/transform_ent.d.ts +17 -0
- package/tsc/transform_ent.js +59 -0
- package/tsc/transform_schema.d.ts +27 -0
- package/tsc/transform_schema.js +379 -0
- package/scripts/transform_schema.js +0 -288
package/core/ent.js
CHANGED
|
@@ -22,14 +22,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
22
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
23
|
};
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
26
|
-
exports.getEdgeTypeInGroup = void 0;
|
|
25
|
+
exports.applyPrivacyPolicyForRow = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = exports.defaultEdgeQueryOptions = exports.DefaultLimit = exports.loadEdgeDatas = exports.loadEdgeData = exports.assocEdgeLoader = exports.AssocEdgeData = exports.getCursor = exports.AssocEdge = exports.DeleteNodeOperation = exports.deleteRowsSync = exports.deleteRows = exports.editRowSync = exports.editRow = exports.buildUpdateQuery = exports.createRowSync = exports.createRow = exports.buildInsertQuery = exports.EdgeOperation = exports.__hasGlobalSchema = exports.clearGlobalSchema = exports.setGlobalSchema = exports.EditNodeOperation = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.loadRow = exports.loadRowX = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadCustomData = exports.loadCustomEnts = exports.loadEntsFromClause = exports.loadEntsList = exports.loadEnts = exports.loadEntXFromClause = exports.loadEntFromClause = exports.loadEntXViaKey = exports.loadEntX = exports.loadEntViaKey = exports.loadEnt = void 0;
|
|
26
|
+
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRowX = void 0;
|
|
27
27
|
const db_1 = __importStar(require("./db"));
|
|
28
28
|
const privacy_1 = require("./privacy");
|
|
29
29
|
const clause = __importStar(require("./clause"));
|
|
30
30
|
const action_1 = require("../action");
|
|
31
31
|
const logger_1 = require("./logger");
|
|
32
32
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
33
|
+
const schema_1 = require("../schema/");
|
|
33
34
|
// TODO kill this and createDataLoader
|
|
34
35
|
class cacheMap {
|
|
35
36
|
constructor(options) {
|
|
@@ -39,7 +40,7 @@ class cacheMap {
|
|
|
39
40
|
get(key) {
|
|
40
41
|
const ret = this.m.get(key);
|
|
41
42
|
if (ret) {
|
|
42
|
-
(0, logger_1.log)("
|
|
43
|
+
(0, logger_1.log)("cache", {
|
|
43
44
|
"dataloader-cache-hit": key,
|
|
44
45
|
"tableName": this.options.tableName,
|
|
45
46
|
});
|
|
@@ -62,6 +63,7 @@ function createDataLoader(options) {
|
|
|
62
63
|
if ((0, logger_1.logEnabled)("query")) {
|
|
63
64
|
loaderOptions.cacheMap = new cacheMap(options);
|
|
64
65
|
}
|
|
66
|
+
// something here brokwn with strict:true
|
|
65
67
|
return new dataloader_1.default(async (ids) => {
|
|
66
68
|
if (!ids.length) {
|
|
67
69
|
return [];
|
|
@@ -140,8 +142,7 @@ async function loadEntXFromClause(viewer, options, clause) {
|
|
|
140
142
|
context: viewer.context,
|
|
141
143
|
};
|
|
142
144
|
const row = await loadRowX(rowOptions);
|
|
143
|
-
|
|
144
|
-
return await applyPrivacyPolicyForEntX(viewer, ent);
|
|
145
|
+
return await applyPrivacyPolicyForRowX(viewer, options, row);
|
|
145
146
|
}
|
|
146
147
|
exports.loadEntXFromClause = loadEntXFromClause;
|
|
147
148
|
async function loadEnts(viewer, options, ...ids) {
|
|
@@ -212,7 +213,7 @@ async function loadCustomEnts(viewer, options, query) {
|
|
|
212
213
|
const result = new Array(rows.length);
|
|
213
214
|
await Promise.all(rows.map(async (row, idx) => {
|
|
214
215
|
const ent = new options.ent(viewer, row);
|
|
215
|
-
let privacyEnt = await applyPrivacyPolicyForEnt(viewer, ent);
|
|
216
|
+
let privacyEnt = await applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
216
217
|
if (privacyEnt) {
|
|
217
218
|
result[idx] = privacyEnt;
|
|
218
219
|
}
|
|
@@ -258,30 +259,60 @@ exports.loadCustomData = loadCustomData;
|
|
|
258
259
|
// Derived ents
|
|
259
260
|
async function loadDerivedEnt(viewer, data, loader) {
|
|
260
261
|
const ent = new loader(viewer, data);
|
|
261
|
-
return await applyPrivacyPolicyForEnt(viewer, ent
|
|
262
|
+
return await applyPrivacyPolicyForEnt(viewer, ent, data, {
|
|
263
|
+
ent: loader,
|
|
264
|
+
});
|
|
262
265
|
}
|
|
263
266
|
exports.loadDerivedEnt = loadDerivedEnt;
|
|
264
267
|
async function loadDerivedEntX(viewer, data, loader) {
|
|
265
268
|
const ent = new loader(viewer, data);
|
|
266
|
-
return await applyPrivacyPolicyForEntX(viewer, ent);
|
|
269
|
+
return await applyPrivacyPolicyForEntX(viewer, ent, data, { ent: loader });
|
|
267
270
|
}
|
|
268
271
|
exports.loadDerivedEntX = loadDerivedEntX;
|
|
269
|
-
|
|
272
|
+
// everything calls into this two so should be fine
|
|
273
|
+
// TODO is there a smarter way to not instantiate two objects here?
|
|
274
|
+
async function applyPrivacyPolicyForEnt(viewer, ent, data, fieldPrivacyOptions) {
|
|
270
275
|
if (ent) {
|
|
271
|
-
const visible = await (0, privacy_1.applyPrivacyPolicy)(viewer, ent.
|
|
272
|
-
if (visible) {
|
|
273
|
-
return
|
|
276
|
+
const visible = await (0, privacy_1.applyPrivacyPolicy)(viewer, ent.getPrivacyPolicy(), ent);
|
|
277
|
+
if (!visible) {
|
|
278
|
+
return null;
|
|
274
279
|
}
|
|
280
|
+
return doFieldPrivacy(viewer, ent, data, fieldPrivacyOptions);
|
|
275
281
|
}
|
|
276
282
|
return null;
|
|
277
283
|
}
|
|
278
|
-
|
|
279
|
-
async function applyPrivacyPolicyForEntX(viewer, ent) {
|
|
284
|
+
async function applyPrivacyPolicyForEntX(viewer, ent, data, options) {
|
|
280
285
|
// this will throw
|
|
281
|
-
await (0, privacy_1.applyPrivacyPolicyX)(viewer, ent.
|
|
286
|
+
await (0, privacy_1.applyPrivacyPolicyX)(viewer, ent.getPrivacyPolicy(), ent);
|
|
287
|
+
return doFieldPrivacy(viewer, ent, data, options);
|
|
288
|
+
}
|
|
289
|
+
async function doFieldPrivacy(viewer, ent, data, options) {
|
|
290
|
+
if (!options.fieldPrivacy) {
|
|
291
|
+
return ent;
|
|
292
|
+
}
|
|
293
|
+
const promises = [];
|
|
294
|
+
let somethingChanged = false;
|
|
295
|
+
for (const [k, policy] of options.fieldPrivacy) {
|
|
296
|
+
promises.push((async () => {
|
|
297
|
+
// don't do anything if key is null or for some reason missing
|
|
298
|
+
const curr = data[k];
|
|
299
|
+
if (curr === null || curr === undefined) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
|
|
303
|
+
if (!r) {
|
|
304
|
+
data[k] = null;
|
|
305
|
+
somethingChanged = true;
|
|
306
|
+
}
|
|
307
|
+
})());
|
|
308
|
+
}
|
|
309
|
+
await Promise.all(promises);
|
|
310
|
+
if (somethingChanged) {
|
|
311
|
+
// have to create new instance
|
|
312
|
+
return new options.ent(viewer, data);
|
|
313
|
+
}
|
|
282
314
|
return ent;
|
|
283
315
|
}
|
|
284
|
-
exports.applyPrivacyPolicyForEntX = applyPrivacyPolicyForEntX;
|
|
285
316
|
function logQuery(query, logValues) {
|
|
286
317
|
(0, logger_1.log)("query", {
|
|
287
318
|
query: query,
|
|
@@ -327,6 +358,8 @@ async function loadRow(options) {
|
|
|
327
358
|
return res.rows[0];
|
|
328
359
|
}
|
|
329
360
|
catch (e) {
|
|
361
|
+
// an example of an error being suppressed
|
|
362
|
+
// another one. TODO https://github.com/lolopinto/ent/issues/862
|
|
330
363
|
(0, logger_1.log)("error", e);
|
|
331
364
|
return null;
|
|
332
365
|
}
|
|
@@ -406,6 +439,7 @@ class EditNodeOperation {
|
|
|
406
439
|
constructor(options, existingEnt = null) {
|
|
407
440
|
this.options = options;
|
|
408
441
|
this.existingEnt = existingEnt;
|
|
442
|
+
this.row = null;
|
|
409
443
|
this.placeholderID = options.placeholderID;
|
|
410
444
|
}
|
|
411
445
|
resolve(executor) {
|
|
@@ -439,9 +473,12 @@ class EditNodeOperation {
|
|
|
439
473
|
};
|
|
440
474
|
if (this.existingEnt) {
|
|
441
475
|
if (this.hasData(options.fields)) {
|
|
442
|
-
this
|
|
476
|
+
// even this with returning * may not always work if transformed...
|
|
477
|
+
// we can have a transformed flag to see if it should be returned?
|
|
478
|
+
this.row = await editRow(queryer, options, "RETURNING *");
|
|
443
479
|
}
|
|
444
480
|
else {
|
|
481
|
+
// @ts-ignore
|
|
445
482
|
this.row = this.existingEnt["data"];
|
|
446
483
|
}
|
|
447
484
|
}
|
|
@@ -450,20 +487,36 @@ class EditNodeOperation {
|
|
|
450
487
|
}
|
|
451
488
|
}
|
|
452
489
|
reloadRow(queryer, id, options) {
|
|
490
|
+
// TODO this isn't always an ObjectLoader. should throw or figure out a way to get query
|
|
491
|
+
// and run this on its own...
|
|
492
|
+
const loader = this.options.loadEntOptions.loaderFactory.createLoader(options.context);
|
|
493
|
+
const opts = loader.getOptions();
|
|
494
|
+
let cls = clause.Eq(options.key, id);
|
|
495
|
+
if (opts.clause) {
|
|
496
|
+
let optionClause;
|
|
497
|
+
if (typeof opts.clause === "function") {
|
|
498
|
+
optionClause = opts.clause();
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
optionClause = opts.clause;
|
|
502
|
+
}
|
|
503
|
+
if (optionClause) {
|
|
504
|
+
cls = clause.And(optionClause, cls);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
453
507
|
const query = buildQuery({
|
|
454
|
-
fields: ["*"],
|
|
508
|
+
fields: opts.fields.length ? opts.fields : ["*"],
|
|
455
509
|
tableName: options.tableName,
|
|
456
|
-
clause:
|
|
510
|
+
clause: cls,
|
|
457
511
|
});
|
|
458
512
|
// special case log here because we're not going through any of the normal
|
|
459
513
|
// methods here because those are async and this is sync
|
|
460
514
|
// this is the only place we're doing this so only handling here
|
|
461
515
|
logQuery(query, [id]);
|
|
462
516
|
const r = queryer.querySync(query, [id]);
|
|
463
|
-
if (r.rows.length
|
|
464
|
-
|
|
517
|
+
if (r.rows.length === 1) {
|
|
518
|
+
this.row = r.rows[0];
|
|
465
519
|
}
|
|
466
|
-
this.row = r.rows[0];
|
|
467
520
|
}
|
|
468
521
|
performWriteSync(queryer, context) {
|
|
469
522
|
let options = {
|
|
@@ -472,10 +525,11 @@ class EditNodeOperation {
|
|
|
472
525
|
};
|
|
473
526
|
if (this.existingEnt) {
|
|
474
527
|
if (this.hasData(this.options.fields)) {
|
|
475
|
-
editRowSync(queryer, options,
|
|
528
|
+
editRowSync(queryer, options, "RETURNING *");
|
|
476
529
|
this.reloadRow(queryer, this.existingEnt.id, options);
|
|
477
530
|
}
|
|
478
531
|
else {
|
|
532
|
+
// @ts-ignore
|
|
479
533
|
this.row = this.existingEnt["data"];
|
|
480
534
|
}
|
|
481
535
|
}
|
|
@@ -492,12 +546,27 @@ class EditNodeOperation {
|
|
|
492
546
|
if (!this.row) {
|
|
493
547
|
return null;
|
|
494
548
|
}
|
|
495
|
-
return new this.options.ent(viewer, this.row);
|
|
549
|
+
return new this.options.loadEntOptions.ent(viewer, this.row);
|
|
496
550
|
}
|
|
497
551
|
}
|
|
498
552
|
exports.EditNodeOperation = EditNodeOperation;
|
|
553
|
+
let globalSchema;
|
|
554
|
+
function setGlobalSchema(val) {
|
|
555
|
+
globalSchema = val;
|
|
556
|
+
}
|
|
557
|
+
exports.setGlobalSchema = setGlobalSchema;
|
|
558
|
+
function clearGlobalSchema() {
|
|
559
|
+
globalSchema = undefined;
|
|
560
|
+
}
|
|
561
|
+
exports.clearGlobalSchema = clearGlobalSchema;
|
|
562
|
+
// used by tests. no guarantee will always exist
|
|
563
|
+
function __hasGlobalSchema() {
|
|
564
|
+
return globalSchema !== undefined;
|
|
565
|
+
}
|
|
566
|
+
exports.__hasGlobalSchema = __hasGlobalSchema;
|
|
499
567
|
class EdgeOperation {
|
|
500
|
-
constructor(edgeInput, options) {
|
|
568
|
+
constructor(builder, edgeInput, options) {
|
|
569
|
+
this.builder = builder;
|
|
501
570
|
this.edgeInput = edgeInput;
|
|
502
571
|
this.options = options;
|
|
503
572
|
}
|
|
@@ -533,7 +602,31 @@ class EdgeOperation {
|
|
|
533
602
|
}
|
|
534
603
|
}
|
|
535
604
|
getDeleteRowParams(edgeData, edge, context) {
|
|
605
|
+
let transformed = null;
|
|
606
|
+
let op = schema_1.SQLStatementOperation.Delete;
|
|
607
|
+
let updateData = null;
|
|
608
|
+
// TODO respect disableTransformations
|
|
609
|
+
if (globalSchema?.transformEdgeWrite) {
|
|
610
|
+
transformed = globalSchema.transformEdgeWrite({
|
|
611
|
+
op: schema_1.SQLStatementOperation.Delete,
|
|
612
|
+
edge,
|
|
613
|
+
});
|
|
614
|
+
if (transformed) {
|
|
615
|
+
op = transformed.op;
|
|
616
|
+
if (transformed.op === schema_1.SQLStatementOperation.Insert) {
|
|
617
|
+
throw new Error(`cannot currently transform a delete into an insert`);
|
|
618
|
+
}
|
|
619
|
+
if (transformed.op === schema_1.SQLStatementOperation.Update) {
|
|
620
|
+
if (!transformed.data) {
|
|
621
|
+
throw new Error(`cannot transform a delete into an update without providing data`);
|
|
622
|
+
}
|
|
623
|
+
updateData = transformed.data;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
536
627
|
return {
|
|
628
|
+
op,
|
|
629
|
+
updateData,
|
|
537
630
|
options: {
|
|
538
631
|
tableName: edgeData.edgeTable,
|
|
539
632
|
context,
|
|
@@ -543,11 +636,35 @@ class EdgeOperation {
|
|
|
543
636
|
}
|
|
544
637
|
async performDeleteWrite(q, edgeData, edge, context) {
|
|
545
638
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
546
|
-
|
|
639
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
640
|
+
return deleteRows(q, params.options, params.clause);
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
644
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
645
|
+
}
|
|
646
|
+
await editRow(q, {
|
|
647
|
+
tableName: params.options.tableName,
|
|
648
|
+
whereClause: params.clause,
|
|
649
|
+
fields: params.updateData,
|
|
650
|
+
});
|
|
651
|
+
}
|
|
547
652
|
}
|
|
548
653
|
performDeleteWriteSync(q, edgeData, edge, context) {
|
|
549
654
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
550
|
-
|
|
655
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
656
|
+
return deleteRowsSync(q, params.options, params.clause);
|
|
657
|
+
}
|
|
658
|
+
else {
|
|
659
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
660
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
661
|
+
}
|
|
662
|
+
editRowSync(q, {
|
|
663
|
+
tableName: params.options.tableName,
|
|
664
|
+
whereClause: params.clause,
|
|
665
|
+
fields: params.updateData,
|
|
666
|
+
});
|
|
667
|
+
}
|
|
551
668
|
}
|
|
552
669
|
getInsertRowParams(edgeData, edge, context) {
|
|
553
670
|
const fields = {
|
|
@@ -566,6 +683,30 @@ class EdgeOperation {
|
|
|
566
683
|
// maybe when actions exist?
|
|
567
684
|
fields["time"] = new Date().toISOString();
|
|
568
685
|
}
|
|
686
|
+
const onConflictFields = ["data"];
|
|
687
|
+
if (globalSchema?.extraEdgeFields) {
|
|
688
|
+
for (const name in globalSchema.extraEdgeFields) {
|
|
689
|
+
const f = globalSchema.extraEdgeFields[name];
|
|
690
|
+
if (f.defaultValueOnCreate) {
|
|
691
|
+
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
692
|
+
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
693
|
+
// onconflict make sure we override the default values
|
|
694
|
+
// e.g. setting deleted_at = null for soft delete
|
|
695
|
+
onConflictFields.push(storageKey);
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
// TODO respect disableTransformations
|
|
700
|
+
let transformed = null;
|
|
701
|
+
if (globalSchema?.transformEdgeWrite) {
|
|
702
|
+
transformed = globalSchema.transformEdgeWrite({
|
|
703
|
+
op: schema_1.SQLStatementOperation.Insert,
|
|
704
|
+
edge,
|
|
705
|
+
});
|
|
706
|
+
if (transformed) {
|
|
707
|
+
throw new Error(`transforming an insert edge not currently supported`);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
569
710
|
return [
|
|
570
711
|
{
|
|
571
712
|
tableName: edgeData.edgeTable,
|
|
@@ -573,7 +714,9 @@ class EdgeOperation {
|
|
|
573
714
|
fieldsToLog: fields,
|
|
574
715
|
context,
|
|
575
716
|
},
|
|
576
|
-
|
|
717
|
+
`ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields
|
|
718
|
+
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
719
|
+
.join(", ")}`,
|
|
577
720
|
];
|
|
578
721
|
}
|
|
579
722
|
async performInsertWrite(q, edgeData, edge, context) {
|
|
@@ -610,7 +753,7 @@ class EdgeOperation {
|
|
|
610
753
|
}
|
|
611
754
|
}
|
|
612
755
|
symmetricEdge() {
|
|
613
|
-
return new EdgeOperation({
|
|
756
|
+
return new EdgeOperation(this.builder, {
|
|
614
757
|
id1: this.edgeInput.id2,
|
|
615
758
|
id1Type: this.edgeInput.id2Type,
|
|
616
759
|
id2: this.edgeInput.id1,
|
|
@@ -626,7 +769,7 @@ class EdgeOperation {
|
|
|
626
769
|
});
|
|
627
770
|
}
|
|
628
771
|
inverseEdge(edgeData) {
|
|
629
|
-
return new EdgeOperation({
|
|
772
|
+
return new EdgeOperation(this.builder, {
|
|
630
773
|
id1: this.edgeInput.id2,
|
|
631
774
|
id1Type: this.edgeInput.id2Type,
|
|
632
775
|
id2: this.edgeInput.id1,
|
|
@@ -694,7 +837,7 @@ class EdgeOperation {
|
|
|
694
837
|
if (data) {
|
|
695
838
|
edge.data = data;
|
|
696
839
|
}
|
|
697
|
-
return new EdgeOperation(edge, {
|
|
840
|
+
return new EdgeOperation(builder, edge, {
|
|
698
841
|
operation: action_1.WriteOperation.Insert,
|
|
699
842
|
id2Placeholder,
|
|
700
843
|
id1Placeholder,
|
|
@@ -715,7 +858,7 @@ class EdgeOperation {
|
|
|
715
858
|
if (data) {
|
|
716
859
|
edge.data = data;
|
|
717
860
|
}
|
|
718
|
-
return new EdgeOperation(edge, {
|
|
861
|
+
return new EdgeOperation(builder, edge, {
|
|
719
862
|
operation: action_1.WriteOperation.Insert,
|
|
720
863
|
id1Placeholder,
|
|
721
864
|
id2Placeholder,
|
|
@@ -733,7 +876,7 @@ class EdgeOperation {
|
|
|
733
876
|
id2Type: "",
|
|
734
877
|
id1Type: "",
|
|
735
878
|
};
|
|
736
|
-
return new EdgeOperation(edge, {
|
|
879
|
+
return new EdgeOperation(builder, edge, {
|
|
737
880
|
operation: action_1.WriteOperation.Delete,
|
|
738
881
|
});
|
|
739
882
|
}
|
|
@@ -748,7 +891,7 @@ class EdgeOperation {
|
|
|
748
891
|
id2Type: "",
|
|
749
892
|
id1Type: "",
|
|
750
893
|
};
|
|
751
|
-
return new EdgeOperation(edge, {
|
|
894
|
+
return new EdgeOperation(builder, edge, {
|
|
752
895
|
operation: action_1.WriteOperation.Delete,
|
|
753
896
|
});
|
|
754
897
|
}
|
|
@@ -845,43 +988,42 @@ function createRowSync(queryer, options, suffix) {
|
|
|
845
988
|
return null;
|
|
846
989
|
}
|
|
847
990
|
exports.createRowSync = createRowSync;
|
|
848
|
-
function buildUpdateQuery(options,
|
|
991
|
+
function buildUpdateQuery(options, suffix) {
|
|
849
992
|
let valsString = [];
|
|
850
993
|
let values = [];
|
|
851
994
|
let logValues = [];
|
|
852
995
|
const dialect = db_1.default.getDialect();
|
|
853
996
|
let idx = 1;
|
|
854
997
|
for (const key in options.fields) {
|
|
855
|
-
|
|
998
|
+
const val = options.fields[key];
|
|
999
|
+
values.push(val);
|
|
856
1000
|
if (options.fieldsToLog) {
|
|
857
1001
|
logValues.push(options.fieldsToLog[key]);
|
|
858
1002
|
}
|
|
1003
|
+
// TODO would be nice to use clause here. need update version of the queries so that
|
|
1004
|
+
// we don't have to handle dialect specifics here
|
|
1005
|
+
// can't use clause because of IS NULL
|
|
1006
|
+
// valsString.push(clause.Eq(key, val).clause(idx));
|
|
859
1007
|
if (dialect === db_1.Dialect.Postgres) {
|
|
860
1008
|
valsString.push(`${key} = $${idx}`);
|
|
861
|
-
idx++;
|
|
862
1009
|
}
|
|
863
1010
|
else {
|
|
864
1011
|
valsString.push(`${key} = ?`);
|
|
865
1012
|
}
|
|
1013
|
+
idx++;
|
|
866
1014
|
}
|
|
867
1015
|
const vals = valsString.join(", ");
|
|
868
1016
|
let query = `UPDATE ${options.tableName} SET ${vals} WHERE `;
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
query = query + `${options.key} = ?`;
|
|
874
|
-
}
|
|
1017
|
+
query = query + options.whereClause.clause(idx);
|
|
1018
|
+
values.push(...options.whereClause.values());
|
|
875
1019
|
if (suffix) {
|
|
876
1020
|
query = query + " " + suffix;
|
|
877
1021
|
}
|
|
878
1022
|
return [query, values, logValues];
|
|
879
1023
|
}
|
|
880
1024
|
exports.buildUpdateQuery = buildUpdateQuery;
|
|
881
|
-
async function editRow(queryer, options,
|
|
882
|
-
const [query, values, logValues] = buildUpdateQuery(options,
|
|
883
|
-
// add id as value to prepared query
|
|
884
|
-
values.push(id);
|
|
1025
|
+
async function editRow(queryer, options, suffix) {
|
|
1026
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
885
1027
|
const res = await mutateRow(queryer, query, values, logValues, options);
|
|
886
1028
|
if (res?.rowCount == 1) {
|
|
887
1029
|
// for now assume id primary key
|
|
@@ -892,10 +1034,8 @@ async function editRow(queryer, options, id, suffix) {
|
|
|
892
1034
|
return null;
|
|
893
1035
|
}
|
|
894
1036
|
exports.editRow = editRow;
|
|
895
|
-
function editRowSync(queryer, options,
|
|
896
|
-
const [query, values, logValues] = buildUpdateQuery(options,
|
|
897
|
-
// add id as value to prepared query
|
|
898
|
-
values.push(id);
|
|
1037
|
+
function editRowSync(queryer, options, suffix) {
|
|
1038
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
899
1039
|
const res = mutateRowSync(queryer, query, values, logValues, options);
|
|
900
1040
|
if (res?.rowCount == 1) {
|
|
901
1041
|
// for now assume id primary key
|
|
@@ -946,6 +1086,12 @@ class AssocEdge {
|
|
|
946
1086
|
this.edgeType = data.edge_type;
|
|
947
1087
|
this.time = data.time;
|
|
948
1088
|
this.data = data.data;
|
|
1089
|
+
this.rawData = data;
|
|
1090
|
+
}
|
|
1091
|
+
__getRawData() {
|
|
1092
|
+
// incase there's extra db fields. useful for tests
|
|
1093
|
+
// in production, a subclass of this should be in use so we won't need this...
|
|
1094
|
+
return this.rawData;
|
|
949
1095
|
}
|
|
950
1096
|
getCursor() {
|
|
951
1097
|
return getCursor({
|
|
@@ -1052,6 +1198,21 @@ async function loadEdges(options) {
|
|
|
1052
1198
|
return loadCustomEdges({ ...options, ctr: AssocEdge });
|
|
1053
1199
|
}
|
|
1054
1200
|
exports.loadEdges = loadEdges;
|
|
1201
|
+
function getEdgeClauseAndFields(cls, options) {
|
|
1202
|
+
let fields = edgeFields;
|
|
1203
|
+
if (globalSchema?.transformEdgeRead) {
|
|
1204
|
+
const transformClause = globalSchema.transformEdgeRead();
|
|
1205
|
+
if (!options.disableTransformations) {
|
|
1206
|
+
cls = clause.And(cls, transformClause);
|
|
1207
|
+
}
|
|
1208
|
+
fields = edgeFields.concat(transformClause.columns());
|
|
1209
|
+
}
|
|
1210
|
+
return {
|
|
1211
|
+
cls,
|
|
1212
|
+
fields,
|
|
1213
|
+
};
|
|
1214
|
+
}
|
|
1215
|
+
exports.getEdgeClauseAndFields = getEdgeClauseAndFields;
|
|
1055
1216
|
async function loadCustomEdges(options) {
|
|
1056
1217
|
const { id1, edgeType, context } = options;
|
|
1057
1218
|
const edgeData = await loadEdgeData(edgeType);
|
|
@@ -1063,10 +1224,11 @@ async function loadCustomEdges(options) {
|
|
|
1063
1224
|
if (options.queryOptions?.clause) {
|
|
1064
1225
|
cls = clause.And(cls, options.queryOptions.clause);
|
|
1065
1226
|
}
|
|
1227
|
+
const { cls: actualClause, fields } = getEdgeClauseAndFields(cls, options);
|
|
1066
1228
|
const rows = await loadRows({
|
|
1067
1229
|
tableName: edgeData.edgeTable,
|
|
1068
|
-
fields:
|
|
1069
|
-
clause:
|
|
1230
|
+
fields: fields,
|
|
1231
|
+
clause: actualClause,
|
|
1070
1232
|
orderby: options.queryOptions?.orderby || defaultOptions.orderby,
|
|
1071
1233
|
limit: options.queryOptions?.limit || defaultOptions.limit,
|
|
1072
1234
|
context,
|
|
@@ -1082,10 +1244,11 @@ async function loadUniqueEdge(options) {
|
|
|
1082
1244
|
if (!edgeData) {
|
|
1083
1245
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1084
1246
|
}
|
|
1247
|
+
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1085
1248
|
const row = await loadRow({
|
|
1086
1249
|
tableName: edgeData.edgeTable,
|
|
1087
|
-
fields:
|
|
1088
|
-
clause:
|
|
1250
|
+
fields: fields,
|
|
1251
|
+
clause: cls,
|
|
1089
1252
|
context,
|
|
1090
1253
|
});
|
|
1091
1254
|
if (!row) {
|
|
@@ -1112,11 +1275,12 @@ async function loadRawEdgeCountX(options) {
|
|
|
1112
1275
|
if (!edgeData) {
|
|
1113
1276
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1114
1277
|
}
|
|
1278
|
+
const { cls } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1115
1279
|
const row = await loadRowX({
|
|
1116
1280
|
tableName: edgeData.edgeTable,
|
|
1117
1281
|
// sqlite needs as count otherwise it returns count(1)
|
|
1118
1282
|
fields: ["count(1) as count"],
|
|
1119
|
-
clause:
|
|
1283
|
+
clause: cls,
|
|
1120
1284
|
context,
|
|
1121
1285
|
});
|
|
1122
1286
|
return parseInt(row["count"], 10) || 0;
|
|
@@ -1146,20 +1310,19 @@ async function applyPrivacyPolicyForRow(viewer, options, row) {
|
|
|
1146
1310
|
return null;
|
|
1147
1311
|
}
|
|
1148
1312
|
const ent = new options.ent(viewer, row);
|
|
1149
|
-
return await applyPrivacyPolicyForEnt(viewer, ent);
|
|
1313
|
+
return await applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
1150
1314
|
}
|
|
1151
1315
|
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1152
1316
|
async function applyPrivacyPolicyForRowX(viewer, options, row) {
|
|
1153
1317
|
const ent = new options.ent(viewer, row);
|
|
1154
|
-
return await applyPrivacyPolicyForEntX(viewer, ent);
|
|
1318
|
+
return await applyPrivacyPolicyForEntX(viewer, ent, row, options);
|
|
1155
1319
|
}
|
|
1156
1320
|
exports.applyPrivacyPolicyForRowX = applyPrivacyPolicyForRowX;
|
|
1157
1321
|
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1158
1322
|
let m = new Map();
|
|
1159
1323
|
// apply privacy logic
|
|
1160
1324
|
await Promise.all(rows.map(async (row) => {
|
|
1161
|
-
|
|
1162
|
-
let privacyEnt = await applyPrivacyPolicyForEnt(viewer, ent);
|
|
1325
|
+
let privacyEnt = await applyPrivacyPolicyForRow(viewer, options, row);
|
|
1163
1326
|
if (privacyEnt) {
|
|
1164
1327
|
m.set(privacyEnt.id, privacyEnt);
|
|
1165
1328
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { ID, Context, Loader, LoaderFactory } from "../base";
|
|
2
2
|
export declare class AssocEdgeCountLoader implements Loader<ID, number> {
|
|
3
3
|
private edgeType;
|
|
4
|
-
context?: Context | undefined;
|
|
4
|
+
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
5
5
|
private loaderFn;
|
|
6
6
|
private loader;
|
|
7
|
-
constructor(edgeType: string, context?: Context | undefined);
|
|
7
|
+
constructor(edgeType: string, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
8
8
|
private getLoader;
|
|
9
9
|
load(id: ID): Promise<number>;
|
|
10
10
|
clearAll(): void;
|
|
@@ -41,10 +41,15 @@ class AssocEdgeCountLoader {
|
|
|
41
41
|
if (!edgeData) {
|
|
42
42
|
throw new Error(`error loading edge data for ${this.edgeType}`);
|
|
43
43
|
}
|
|
44
|
+
const { cls } = (0, ent_1.getEdgeClauseAndFields)(clause.Eq("edge_type", this.edgeType), {
|
|
45
|
+
// don't need this..
|
|
46
|
+
id1: "1",
|
|
47
|
+
edgeType: this.edgeType,
|
|
48
|
+
});
|
|
44
49
|
this.loader = (0, raw_count_loader_1.createCountDataLoader)({
|
|
45
50
|
tableName: edgeData.edgeTable,
|
|
46
51
|
groupCol: "id1",
|
|
47
|
-
clause:
|
|
52
|
+
clause: cls,
|
|
48
53
|
});
|
|
49
54
|
return this.loader;
|
|
50
55
|
}
|
|
@@ -20,8 +20,8 @@ export declare class AssocDirectEdgeLoader<T extends AssocEdge> implements Loade
|
|
|
20
20
|
private edgeType;
|
|
21
21
|
private edgeCtr;
|
|
22
22
|
private options?;
|
|
23
|
-
context?: Context | undefined;
|
|
24
|
-
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: Partial<Pick<import("../base").QueryableDataOptions, "limit" | "orderby" | "clause">> | undefined, context?: Context | undefined);
|
|
23
|
+
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
24
|
+
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T>, options?: Partial<Pick<import("../base").QueryableDataOptions, "limit" | "orderby" | "clause">> | undefined, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
25
25
|
load(id: ID): Promise<T[]>;
|
|
26
26
|
loadEdgeForID2(id: ID, id2: ID): Promise<T | undefined>;
|
|
27
27
|
clearAll(): void;
|
|
@@ -32,7 +32,7 @@ export declare class AssocEdgeLoaderFactory<T extends AssocEdge> implements Load
|
|
|
32
32
|
name: string;
|
|
33
33
|
constructor(edgeType: string, edgeCtr: AssocEdgeConstructor<T> | (() => AssocEdgeConstructor<T>));
|
|
34
34
|
createLoader(context?: Context): AssocLoader<T>;
|
|
35
|
-
private
|
|
35
|
+
private isConstructor;
|
|
36
36
|
createConfigurableLoader(options: EdgeQueryableDataOptions, context?: Context): AssocLoader<T>;
|
|
37
37
|
}
|
|
38
38
|
export {};
|
|
@@ -161,16 +161,17 @@ class AssocEdgeLoaderFactory {
|
|
|
161
161
|
createLoader(context) {
|
|
162
162
|
return this.createConfigurableLoader({}, context);
|
|
163
163
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
164
|
+
isConstructor(edgeCtr) {
|
|
165
|
+
return (edgeCtr.prototype &&
|
|
166
|
+
edgeCtr.prototype.constructor &&
|
|
167
|
+
edgeCtr.prototype.constructor.name.length > 0);
|
|
167
168
|
}
|
|
168
169
|
createConfigurableLoader(options, context) {
|
|
169
170
|
let edgeCtr = this.edgeCtr;
|
|
170
171
|
// in generated code, the edge is not necessarily defined at the time of loading
|
|
171
172
|
// so we call this as follows:
|
|
172
173
|
// const loader = new AssocEdgeLoaderFactory(EdgeType.Foo, ()=>DerivedEdgeClass);
|
|
173
|
-
if (this.
|
|
174
|
+
if (!this.isConstructor(edgeCtr)) {
|
|
174
175
|
edgeCtr = edgeCtr();
|
|
175
176
|
}
|
|
176
177
|
// rename to make TS happy
|
|
@@ -4,6 +4,7 @@ exports.IndexLoaderFactory = void 0;
|
|
|
4
4
|
const query_loader_1 = require("./query_loader");
|
|
5
5
|
// we're keeping this for legacy reasons so as to not break existing callers
|
|
6
6
|
// and to decouple the change here but all callers can safely be changed here to use QueryLoaderFactory
|
|
7
|
+
// @deprecated use QueryLoaderFactory
|
|
7
8
|
class IndexLoaderFactory {
|
|
8
9
|
constructor(options, col, opts) {
|
|
9
10
|
this.factory = new query_loader_1.QueryLoaderFactory({
|