@snowtop/ent 0.1.0-alpha7 → 0.1.0-alpha73
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 +35 -23
- package/core/base.js +16 -0
- package/core/clause.d.ts +69 -3
- package/core/clause.js +420 -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 +62 -27
- package/core/ent.js +272 -63
- 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 +5 -5
- 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 +21 -1
- package/index.js +24 -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 +67 -2
- package/schema/index.d.ts +2 -2
- package/schema/index.js +8 -1
- package/schema/schema.d.ts +100 -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} +76 -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.d.ts +6 -0
- package/testutils/parse_sql.js +16 -2
- 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
|
}
|
|
@@ -225,32 +226,78 @@ function isClause(opts) {
|
|
|
225
226
|
const cls = opts;
|
|
226
227
|
return cls.clause !== undefined && cls.values !== undefined;
|
|
227
228
|
}
|
|
228
|
-
function
|
|
229
|
+
function isParameterizedQuery(opts) {
|
|
229
230
|
return opts.query !== undefined;
|
|
230
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Note that if there's default read transformations (e.g. soft delete) and a clause is passed in
|
|
234
|
+
* either as Clause or QueryDataOptions without {disableTransformations: true}, the default transformation
|
|
235
|
+
* (e.g. soft delete) is applied.
|
|
236
|
+
*
|
|
237
|
+
* Passing a full SQL string or Paramterized SQL string doesn't apply it and the given string is sent to the
|
|
238
|
+
* database as written.
|
|
239
|
+
*
|
|
240
|
+
* e.g.
|
|
241
|
+
* Foo.loadCustom(opts, 'SELECT * FROM foo') // doesn't change the query
|
|
242
|
+
* Foo.loadCustom(opts, { query: 'SELECT * FROM foo WHERE id = ?', values: [1]}) // doesn't change the query
|
|
243
|
+
* Foo.loadCustom(opts, query.Eq('time', Date.now())) // changes the query
|
|
244
|
+
* Foo.loadCustom(opts, {
|
|
245
|
+
* clause: query.LessEq('time', Date.now()),
|
|
246
|
+
* limit: 100,
|
|
247
|
+
* orderby: 'time',
|
|
248
|
+
* }) // changes the query
|
|
249
|
+
* Foo.loadCustom(opts, {
|
|
250
|
+
* clause: query.LessEq('time', Date.now()),
|
|
251
|
+
* limit: 100,
|
|
252
|
+
* orderby: 'time',
|
|
253
|
+
* disableTransformations: false
|
|
254
|
+
* }) // doesn't change the query
|
|
255
|
+
*/
|
|
231
256
|
async function loadCustomData(options, query, context) {
|
|
257
|
+
function getClause(cls) {
|
|
258
|
+
if (options.clause && options.loaderFactory?.options?.clause) {
|
|
259
|
+
throw new Error(`cannot pass both options.clause && optsions.loaderFactory.options.clause`);
|
|
260
|
+
}
|
|
261
|
+
let optClause = options.clause || options.loaderFactory?.options?.clause;
|
|
262
|
+
if (typeof optClause === "function") {
|
|
263
|
+
optClause = optClause();
|
|
264
|
+
}
|
|
265
|
+
if (!optClause) {
|
|
266
|
+
return cls;
|
|
267
|
+
}
|
|
268
|
+
return clause.And(cls, optClause);
|
|
269
|
+
}
|
|
232
270
|
if (typeof query === "string") {
|
|
233
271
|
// no caching, perform raw query
|
|
234
272
|
return await performRawQuery(query, [], []);
|
|
235
273
|
}
|
|
236
274
|
else if (isClause(query)) {
|
|
275
|
+
// if a Clause is passed in and we have a default clause
|
|
276
|
+
// associated with the query, pass that in
|
|
277
|
+
// if we want to disableTransformations, need to indicate that with
|
|
278
|
+
// disableTransformations option
|
|
237
279
|
// this will have rudimentary caching but nothing crazy
|
|
238
280
|
return await loadRows({
|
|
239
281
|
...options,
|
|
240
|
-
clause: query,
|
|
282
|
+
clause: getClause(query),
|
|
241
283
|
context: context,
|
|
242
284
|
});
|
|
243
285
|
}
|
|
244
|
-
else if (
|
|
286
|
+
else if (isParameterizedQuery(query)) {
|
|
245
287
|
// no caching, perform raw query
|
|
246
288
|
return await performRawQuery(query.query, query.values || [], query.logValues);
|
|
247
289
|
}
|
|
248
290
|
else {
|
|
291
|
+
let cls = query.clause;
|
|
292
|
+
if (!query.disableTransformations) {
|
|
293
|
+
cls = getClause(cls);
|
|
294
|
+
}
|
|
249
295
|
// this will have rudimentary caching but nothing crazy
|
|
250
296
|
return await loadRows({
|
|
251
297
|
...query,
|
|
252
298
|
...options,
|
|
253
299
|
context: context,
|
|
300
|
+
clause: cls,
|
|
254
301
|
});
|
|
255
302
|
}
|
|
256
303
|
}
|
|
@@ -258,30 +305,60 @@ exports.loadCustomData = loadCustomData;
|
|
|
258
305
|
// Derived ents
|
|
259
306
|
async function loadDerivedEnt(viewer, data, loader) {
|
|
260
307
|
const ent = new loader(viewer, data);
|
|
261
|
-
return await applyPrivacyPolicyForEnt(viewer, ent
|
|
308
|
+
return await applyPrivacyPolicyForEnt(viewer, ent, data, {
|
|
309
|
+
ent: loader,
|
|
310
|
+
});
|
|
262
311
|
}
|
|
263
312
|
exports.loadDerivedEnt = loadDerivedEnt;
|
|
264
313
|
async function loadDerivedEntX(viewer, data, loader) {
|
|
265
314
|
const ent = new loader(viewer, data);
|
|
266
|
-
return await applyPrivacyPolicyForEntX(viewer, ent);
|
|
315
|
+
return await applyPrivacyPolicyForEntX(viewer, ent, data, { ent: loader });
|
|
267
316
|
}
|
|
268
317
|
exports.loadDerivedEntX = loadDerivedEntX;
|
|
269
|
-
|
|
318
|
+
// everything calls into this two so should be fine
|
|
319
|
+
// TODO is there a smarter way to not instantiate two objects here?
|
|
320
|
+
async function applyPrivacyPolicyForEnt(viewer, ent, data, fieldPrivacyOptions) {
|
|
270
321
|
if (ent) {
|
|
271
|
-
const visible = await (0, privacy_1.applyPrivacyPolicy)(viewer, ent.
|
|
272
|
-
if (visible) {
|
|
273
|
-
return
|
|
322
|
+
const visible = await (0, privacy_1.applyPrivacyPolicy)(viewer, ent.getPrivacyPolicy(), ent);
|
|
323
|
+
if (!visible) {
|
|
324
|
+
return null;
|
|
274
325
|
}
|
|
326
|
+
return doFieldPrivacy(viewer, ent, data, fieldPrivacyOptions);
|
|
275
327
|
}
|
|
276
328
|
return null;
|
|
277
329
|
}
|
|
278
|
-
|
|
279
|
-
async function applyPrivacyPolicyForEntX(viewer, ent) {
|
|
330
|
+
async function applyPrivacyPolicyForEntX(viewer, ent, data, options) {
|
|
280
331
|
// this will throw
|
|
281
|
-
await (0, privacy_1.applyPrivacyPolicyX)(viewer, ent.
|
|
332
|
+
await (0, privacy_1.applyPrivacyPolicyX)(viewer, ent.getPrivacyPolicy(), ent);
|
|
333
|
+
return doFieldPrivacy(viewer, ent, data, options);
|
|
334
|
+
}
|
|
335
|
+
async function doFieldPrivacy(viewer, ent, data, options) {
|
|
336
|
+
if (!options.fieldPrivacy) {
|
|
337
|
+
return ent;
|
|
338
|
+
}
|
|
339
|
+
const promises = [];
|
|
340
|
+
let somethingChanged = false;
|
|
341
|
+
for (const [k, policy] of options.fieldPrivacy) {
|
|
342
|
+
promises.push((async () => {
|
|
343
|
+
// don't do anything if key is null or for some reason missing
|
|
344
|
+
const curr = data[k];
|
|
345
|
+
if (curr === null || curr === undefined) {
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
|
|
349
|
+
if (!r) {
|
|
350
|
+
data[k] = null;
|
|
351
|
+
somethingChanged = true;
|
|
352
|
+
}
|
|
353
|
+
})());
|
|
354
|
+
}
|
|
355
|
+
await Promise.all(promises);
|
|
356
|
+
if (somethingChanged) {
|
|
357
|
+
// have to create new instance
|
|
358
|
+
return new options.ent(viewer, data);
|
|
359
|
+
}
|
|
282
360
|
return ent;
|
|
283
361
|
}
|
|
284
|
-
exports.applyPrivacyPolicyForEntX = applyPrivacyPolicyForEntX;
|
|
285
362
|
function logQuery(query, logValues) {
|
|
286
363
|
(0, logger_1.log)("query", {
|
|
287
364
|
query: query,
|
|
@@ -327,6 +404,8 @@ async function loadRow(options) {
|
|
|
327
404
|
return res.rows[0];
|
|
328
405
|
}
|
|
329
406
|
catch (e) {
|
|
407
|
+
// an example of an error being suppressed
|
|
408
|
+
// another one. TODO https://github.com/lolopinto/ent/issues/862
|
|
330
409
|
(0, logger_1.log)("error", e);
|
|
331
410
|
return null;
|
|
332
411
|
}
|
|
@@ -406,6 +485,7 @@ class EditNodeOperation {
|
|
|
406
485
|
constructor(options, existingEnt = null) {
|
|
407
486
|
this.options = options;
|
|
408
487
|
this.existingEnt = existingEnt;
|
|
488
|
+
this.row = null;
|
|
409
489
|
this.placeholderID = options.placeholderID;
|
|
410
490
|
}
|
|
411
491
|
resolve(executor) {
|
|
@@ -439,9 +519,12 @@ class EditNodeOperation {
|
|
|
439
519
|
};
|
|
440
520
|
if (this.existingEnt) {
|
|
441
521
|
if (this.hasData(options.fields)) {
|
|
442
|
-
this
|
|
522
|
+
// even this with returning * may not always work if transformed...
|
|
523
|
+
// we can have a transformed flag to see if it should be returned?
|
|
524
|
+
this.row = await editRow(queryer, options, "RETURNING *");
|
|
443
525
|
}
|
|
444
526
|
else {
|
|
527
|
+
// @ts-ignore
|
|
445
528
|
this.row = this.existingEnt["data"];
|
|
446
529
|
}
|
|
447
530
|
}
|
|
@@ -450,20 +533,36 @@ class EditNodeOperation {
|
|
|
450
533
|
}
|
|
451
534
|
}
|
|
452
535
|
reloadRow(queryer, id, options) {
|
|
536
|
+
// TODO this isn't always an ObjectLoader. should throw or figure out a way to get query
|
|
537
|
+
// and run this on its own...
|
|
538
|
+
const loader = this.options.loadEntOptions.loaderFactory.createLoader(options.context);
|
|
539
|
+
const opts = loader.getOptions();
|
|
540
|
+
let cls = clause.Eq(options.key, id);
|
|
541
|
+
if (opts.clause) {
|
|
542
|
+
let optionClause;
|
|
543
|
+
if (typeof opts.clause === "function") {
|
|
544
|
+
optionClause = opts.clause();
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
optionClause = opts.clause;
|
|
548
|
+
}
|
|
549
|
+
if (optionClause) {
|
|
550
|
+
cls = clause.And(optionClause, cls);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
453
553
|
const query = buildQuery({
|
|
454
|
-
fields: ["*"],
|
|
554
|
+
fields: opts.fields.length ? opts.fields : ["*"],
|
|
455
555
|
tableName: options.tableName,
|
|
456
|
-
clause:
|
|
556
|
+
clause: cls,
|
|
457
557
|
});
|
|
458
558
|
// special case log here because we're not going through any of the normal
|
|
459
559
|
// methods here because those are async and this is sync
|
|
460
560
|
// this is the only place we're doing this so only handling here
|
|
461
561
|
logQuery(query, [id]);
|
|
462
562
|
const r = queryer.querySync(query, [id]);
|
|
463
|
-
if (r.rows.length
|
|
464
|
-
|
|
563
|
+
if (r.rows.length === 1) {
|
|
564
|
+
this.row = r.rows[0];
|
|
465
565
|
}
|
|
466
|
-
this.row = r.rows[0];
|
|
467
566
|
}
|
|
468
567
|
performWriteSync(queryer, context) {
|
|
469
568
|
let options = {
|
|
@@ -472,10 +571,11 @@ class EditNodeOperation {
|
|
|
472
571
|
};
|
|
473
572
|
if (this.existingEnt) {
|
|
474
573
|
if (this.hasData(this.options.fields)) {
|
|
475
|
-
editRowSync(queryer, options,
|
|
574
|
+
editRowSync(queryer, options, "RETURNING *");
|
|
476
575
|
this.reloadRow(queryer, this.existingEnt.id, options);
|
|
477
576
|
}
|
|
478
577
|
else {
|
|
578
|
+
// @ts-ignore
|
|
479
579
|
this.row = this.existingEnt["data"];
|
|
480
580
|
}
|
|
481
581
|
}
|
|
@@ -492,12 +592,27 @@ class EditNodeOperation {
|
|
|
492
592
|
if (!this.row) {
|
|
493
593
|
return null;
|
|
494
594
|
}
|
|
495
|
-
return new this.options.ent(viewer, this.row);
|
|
595
|
+
return new this.options.loadEntOptions.ent(viewer, this.row);
|
|
496
596
|
}
|
|
497
597
|
}
|
|
498
598
|
exports.EditNodeOperation = EditNodeOperation;
|
|
599
|
+
let globalSchema;
|
|
600
|
+
function setGlobalSchema(val) {
|
|
601
|
+
globalSchema = val;
|
|
602
|
+
}
|
|
603
|
+
exports.setGlobalSchema = setGlobalSchema;
|
|
604
|
+
function clearGlobalSchema() {
|
|
605
|
+
globalSchema = undefined;
|
|
606
|
+
}
|
|
607
|
+
exports.clearGlobalSchema = clearGlobalSchema;
|
|
608
|
+
// used by tests. no guarantee will always exist
|
|
609
|
+
function __hasGlobalSchema() {
|
|
610
|
+
return globalSchema !== undefined;
|
|
611
|
+
}
|
|
612
|
+
exports.__hasGlobalSchema = __hasGlobalSchema;
|
|
499
613
|
class EdgeOperation {
|
|
500
|
-
constructor(edgeInput, options) {
|
|
614
|
+
constructor(builder, edgeInput, options) {
|
|
615
|
+
this.builder = builder;
|
|
501
616
|
this.edgeInput = edgeInput;
|
|
502
617
|
this.options = options;
|
|
503
618
|
}
|
|
@@ -533,7 +648,31 @@ class EdgeOperation {
|
|
|
533
648
|
}
|
|
534
649
|
}
|
|
535
650
|
getDeleteRowParams(edgeData, edge, context) {
|
|
651
|
+
let transformed = null;
|
|
652
|
+
let op = schema_1.SQLStatementOperation.Delete;
|
|
653
|
+
let updateData = null;
|
|
654
|
+
// TODO respect disableTransformations
|
|
655
|
+
if (globalSchema?.transformEdgeWrite) {
|
|
656
|
+
transformed = globalSchema.transformEdgeWrite({
|
|
657
|
+
op: schema_1.SQLStatementOperation.Delete,
|
|
658
|
+
edge,
|
|
659
|
+
});
|
|
660
|
+
if (transformed) {
|
|
661
|
+
op = transformed.op;
|
|
662
|
+
if (transformed.op === schema_1.SQLStatementOperation.Insert) {
|
|
663
|
+
throw new Error(`cannot currently transform a delete into an insert`);
|
|
664
|
+
}
|
|
665
|
+
if (transformed.op === schema_1.SQLStatementOperation.Update) {
|
|
666
|
+
if (!transformed.data) {
|
|
667
|
+
throw new Error(`cannot transform a delete into an update without providing data`);
|
|
668
|
+
}
|
|
669
|
+
updateData = transformed.data;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}
|
|
536
673
|
return {
|
|
674
|
+
op,
|
|
675
|
+
updateData,
|
|
537
676
|
options: {
|
|
538
677
|
tableName: edgeData.edgeTable,
|
|
539
678
|
context,
|
|
@@ -543,11 +682,35 @@ class EdgeOperation {
|
|
|
543
682
|
}
|
|
544
683
|
async performDeleteWrite(q, edgeData, edge, context) {
|
|
545
684
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
546
|
-
|
|
685
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
686
|
+
return deleteRows(q, params.options, params.clause);
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
690
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
691
|
+
}
|
|
692
|
+
await editRow(q, {
|
|
693
|
+
tableName: params.options.tableName,
|
|
694
|
+
whereClause: params.clause,
|
|
695
|
+
fields: params.updateData,
|
|
696
|
+
});
|
|
697
|
+
}
|
|
547
698
|
}
|
|
548
699
|
performDeleteWriteSync(q, edgeData, edge, context) {
|
|
549
700
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
550
|
-
|
|
701
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
702
|
+
return deleteRowsSync(q, params.options, params.clause);
|
|
703
|
+
}
|
|
704
|
+
else {
|
|
705
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
706
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
707
|
+
}
|
|
708
|
+
editRowSync(q, {
|
|
709
|
+
tableName: params.options.tableName,
|
|
710
|
+
whereClause: params.clause,
|
|
711
|
+
fields: params.updateData,
|
|
712
|
+
});
|
|
713
|
+
}
|
|
551
714
|
}
|
|
552
715
|
getInsertRowParams(edgeData, edge, context) {
|
|
553
716
|
const fields = {
|
|
@@ -566,6 +729,30 @@ class EdgeOperation {
|
|
|
566
729
|
// maybe when actions exist?
|
|
567
730
|
fields["time"] = new Date().toISOString();
|
|
568
731
|
}
|
|
732
|
+
const onConflictFields = ["data"];
|
|
733
|
+
if (globalSchema?.extraEdgeFields) {
|
|
734
|
+
for (const name in globalSchema.extraEdgeFields) {
|
|
735
|
+
const f = globalSchema.extraEdgeFields[name];
|
|
736
|
+
if (f.defaultValueOnCreate) {
|
|
737
|
+
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
738
|
+
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
739
|
+
// onconflict make sure we override the default values
|
|
740
|
+
// e.g. setting deleted_at = null for soft delete
|
|
741
|
+
onConflictFields.push(storageKey);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
// TODO respect disableTransformations
|
|
746
|
+
let transformed = null;
|
|
747
|
+
if (globalSchema?.transformEdgeWrite) {
|
|
748
|
+
transformed = globalSchema.transformEdgeWrite({
|
|
749
|
+
op: schema_1.SQLStatementOperation.Insert,
|
|
750
|
+
edge,
|
|
751
|
+
});
|
|
752
|
+
if (transformed) {
|
|
753
|
+
throw new Error(`transforming an insert edge not currently supported`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
569
756
|
return [
|
|
570
757
|
{
|
|
571
758
|
tableName: edgeData.edgeTable,
|
|
@@ -573,7 +760,9 @@ class EdgeOperation {
|
|
|
573
760
|
fieldsToLog: fields,
|
|
574
761
|
context,
|
|
575
762
|
},
|
|
576
|
-
|
|
763
|
+
`ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields
|
|
764
|
+
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
765
|
+
.join(", ")}`,
|
|
577
766
|
];
|
|
578
767
|
}
|
|
579
768
|
async performInsertWrite(q, edgeData, edge, context) {
|
|
@@ -610,7 +799,7 @@ class EdgeOperation {
|
|
|
610
799
|
}
|
|
611
800
|
}
|
|
612
801
|
symmetricEdge() {
|
|
613
|
-
return new EdgeOperation({
|
|
802
|
+
return new EdgeOperation(this.builder, {
|
|
614
803
|
id1: this.edgeInput.id2,
|
|
615
804
|
id1Type: this.edgeInput.id2Type,
|
|
616
805
|
id2: this.edgeInput.id1,
|
|
@@ -626,7 +815,7 @@ class EdgeOperation {
|
|
|
626
815
|
});
|
|
627
816
|
}
|
|
628
817
|
inverseEdge(edgeData) {
|
|
629
|
-
return new EdgeOperation({
|
|
818
|
+
return new EdgeOperation(this.builder, {
|
|
630
819
|
id1: this.edgeInput.id2,
|
|
631
820
|
id1Type: this.edgeInput.id2Type,
|
|
632
821
|
id2: this.edgeInput.id1,
|
|
@@ -694,7 +883,7 @@ class EdgeOperation {
|
|
|
694
883
|
if (data) {
|
|
695
884
|
edge.data = data;
|
|
696
885
|
}
|
|
697
|
-
return new EdgeOperation(edge, {
|
|
886
|
+
return new EdgeOperation(builder, edge, {
|
|
698
887
|
operation: action_1.WriteOperation.Insert,
|
|
699
888
|
id2Placeholder,
|
|
700
889
|
id1Placeholder,
|
|
@@ -715,7 +904,7 @@ class EdgeOperation {
|
|
|
715
904
|
if (data) {
|
|
716
905
|
edge.data = data;
|
|
717
906
|
}
|
|
718
|
-
return new EdgeOperation(edge, {
|
|
907
|
+
return new EdgeOperation(builder, edge, {
|
|
719
908
|
operation: action_1.WriteOperation.Insert,
|
|
720
909
|
id1Placeholder,
|
|
721
910
|
id2Placeholder,
|
|
@@ -733,7 +922,7 @@ class EdgeOperation {
|
|
|
733
922
|
id2Type: "",
|
|
734
923
|
id1Type: "",
|
|
735
924
|
};
|
|
736
|
-
return new EdgeOperation(edge, {
|
|
925
|
+
return new EdgeOperation(builder, edge, {
|
|
737
926
|
operation: action_1.WriteOperation.Delete,
|
|
738
927
|
});
|
|
739
928
|
}
|
|
@@ -748,7 +937,7 @@ class EdgeOperation {
|
|
|
748
937
|
id2Type: "",
|
|
749
938
|
id1Type: "",
|
|
750
939
|
};
|
|
751
|
-
return new EdgeOperation(edge, {
|
|
940
|
+
return new EdgeOperation(builder, edge, {
|
|
752
941
|
operation: action_1.WriteOperation.Delete,
|
|
753
942
|
});
|
|
754
943
|
}
|
|
@@ -845,43 +1034,42 @@ function createRowSync(queryer, options, suffix) {
|
|
|
845
1034
|
return null;
|
|
846
1035
|
}
|
|
847
1036
|
exports.createRowSync = createRowSync;
|
|
848
|
-
function buildUpdateQuery(options,
|
|
1037
|
+
function buildUpdateQuery(options, suffix) {
|
|
849
1038
|
let valsString = [];
|
|
850
1039
|
let values = [];
|
|
851
1040
|
let logValues = [];
|
|
852
1041
|
const dialect = db_1.default.getDialect();
|
|
853
1042
|
let idx = 1;
|
|
854
1043
|
for (const key in options.fields) {
|
|
855
|
-
|
|
1044
|
+
const val = options.fields[key];
|
|
1045
|
+
values.push(val);
|
|
856
1046
|
if (options.fieldsToLog) {
|
|
857
1047
|
logValues.push(options.fieldsToLog[key]);
|
|
858
1048
|
}
|
|
1049
|
+
// TODO would be nice to use clause here. need update version of the queries so that
|
|
1050
|
+
// we don't have to handle dialect specifics here
|
|
1051
|
+
// can't use clause because of IS NULL
|
|
1052
|
+
// valsString.push(clause.Eq(key, val).clause(idx));
|
|
859
1053
|
if (dialect === db_1.Dialect.Postgres) {
|
|
860
1054
|
valsString.push(`${key} = $${idx}`);
|
|
861
|
-
idx++;
|
|
862
1055
|
}
|
|
863
1056
|
else {
|
|
864
1057
|
valsString.push(`${key} = ?`);
|
|
865
1058
|
}
|
|
1059
|
+
idx++;
|
|
866
1060
|
}
|
|
867
1061
|
const vals = valsString.join(", ");
|
|
868
1062
|
let query = `UPDATE ${options.tableName} SET ${vals} WHERE `;
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
}
|
|
872
|
-
else {
|
|
873
|
-
query = query + `${options.key} = ?`;
|
|
874
|
-
}
|
|
1063
|
+
query = query + options.whereClause.clause(idx);
|
|
1064
|
+
values.push(...options.whereClause.values());
|
|
875
1065
|
if (suffix) {
|
|
876
1066
|
query = query + " " + suffix;
|
|
877
1067
|
}
|
|
878
1068
|
return [query, values, logValues];
|
|
879
1069
|
}
|
|
880
1070
|
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);
|
|
1071
|
+
async function editRow(queryer, options, suffix) {
|
|
1072
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
885
1073
|
const res = await mutateRow(queryer, query, values, logValues, options);
|
|
886
1074
|
if (res?.rowCount == 1) {
|
|
887
1075
|
// for now assume id primary key
|
|
@@ -892,10 +1080,8 @@ async function editRow(queryer, options, id, suffix) {
|
|
|
892
1080
|
return null;
|
|
893
1081
|
}
|
|
894
1082
|
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);
|
|
1083
|
+
function editRowSync(queryer, options, suffix) {
|
|
1084
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
899
1085
|
const res = mutateRowSync(queryer, query, values, logValues, options);
|
|
900
1086
|
if (res?.rowCount == 1) {
|
|
901
1087
|
// for now assume id primary key
|
|
@@ -946,6 +1132,12 @@ class AssocEdge {
|
|
|
946
1132
|
this.edgeType = data.edge_type;
|
|
947
1133
|
this.time = data.time;
|
|
948
1134
|
this.data = data.data;
|
|
1135
|
+
this.rawData = data;
|
|
1136
|
+
}
|
|
1137
|
+
__getRawData() {
|
|
1138
|
+
// incase there's extra db fields. useful for tests
|
|
1139
|
+
// in production, a subclass of this should be in use so we won't need this...
|
|
1140
|
+
return this.rawData;
|
|
949
1141
|
}
|
|
950
1142
|
getCursor() {
|
|
951
1143
|
return getCursor({
|
|
@@ -1052,6 +1244,21 @@ async function loadEdges(options) {
|
|
|
1052
1244
|
return loadCustomEdges({ ...options, ctr: AssocEdge });
|
|
1053
1245
|
}
|
|
1054
1246
|
exports.loadEdges = loadEdges;
|
|
1247
|
+
function getEdgeClauseAndFields(cls, options) {
|
|
1248
|
+
let fields = edgeFields;
|
|
1249
|
+
if (globalSchema?.transformEdgeRead) {
|
|
1250
|
+
const transformClause = globalSchema.transformEdgeRead();
|
|
1251
|
+
if (!options.disableTransformations) {
|
|
1252
|
+
cls = clause.And(cls, transformClause);
|
|
1253
|
+
}
|
|
1254
|
+
fields = edgeFields.concat(transformClause.columns());
|
|
1255
|
+
}
|
|
1256
|
+
return {
|
|
1257
|
+
cls,
|
|
1258
|
+
fields,
|
|
1259
|
+
};
|
|
1260
|
+
}
|
|
1261
|
+
exports.getEdgeClauseAndFields = getEdgeClauseAndFields;
|
|
1055
1262
|
async function loadCustomEdges(options) {
|
|
1056
1263
|
const { id1, edgeType, context } = options;
|
|
1057
1264
|
const edgeData = await loadEdgeData(edgeType);
|
|
@@ -1063,10 +1270,11 @@ async function loadCustomEdges(options) {
|
|
|
1063
1270
|
if (options.queryOptions?.clause) {
|
|
1064
1271
|
cls = clause.And(cls, options.queryOptions.clause);
|
|
1065
1272
|
}
|
|
1273
|
+
const { cls: actualClause, fields } = getEdgeClauseAndFields(cls, options);
|
|
1066
1274
|
const rows = await loadRows({
|
|
1067
1275
|
tableName: edgeData.edgeTable,
|
|
1068
|
-
fields:
|
|
1069
|
-
clause:
|
|
1276
|
+
fields: fields,
|
|
1277
|
+
clause: actualClause,
|
|
1070
1278
|
orderby: options.queryOptions?.orderby || defaultOptions.orderby,
|
|
1071
1279
|
limit: options.queryOptions?.limit || defaultOptions.limit,
|
|
1072
1280
|
context,
|
|
@@ -1082,10 +1290,11 @@ async function loadUniqueEdge(options) {
|
|
|
1082
1290
|
if (!edgeData) {
|
|
1083
1291
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1084
1292
|
}
|
|
1293
|
+
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1085
1294
|
const row = await loadRow({
|
|
1086
1295
|
tableName: edgeData.edgeTable,
|
|
1087
|
-
fields:
|
|
1088
|
-
clause:
|
|
1296
|
+
fields: fields,
|
|
1297
|
+
clause: cls,
|
|
1089
1298
|
context,
|
|
1090
1299
|
});
|
|
1091
1300
|
if (!row) {
|
|
@@ -1112,11 +1321,12 @@ async function loadRawEdgeCountX(options) {
|
|
|
1112
1321
|
if (!edgeData) {
|
|
1113
1322
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1114
1323
|
}
|
|
1324
|
+
const { cls } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1115
1325
|
const row = await loadRowX({
|
|
1116
1326
|
tableName: edgeData.edgeTable,
|
|
1117
1327
|
// sqlite needs as count otherwise it returns count(1)
|
|
1118
1328
|
fields: ["count(1) as count"],
|
|
1119
|
-
clause:
|
|
1329
|
+
clause: cls,
|
|
1120
1330
|
context,
|
|
1121
1331
|
});
|
|
1122
1332
|
return parseInt(row["count"], 10) || 0;
|
|
@@ -1146,20 +1356,19 @@ async function applyPrivacyPolicyForRow(viewer, options, row) {
|
|
|
1146
1356
|
return null;
|
|
1147
1357
|
}
|
|
1148
1358
|
const ent = new options.ent(viewer, row);
|
|
1149
|
-
return await applyPrivacyPolicyForEnt(viewer, ent);
|
|
1359
|
+
return await applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
1150
1360
|
}
|
|
1151
1361
|
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1152
1362
|
async function applyPrivacyPolicyForRowX(viewer, options, row) {
|
|
1153
1363
|
const ent = new options.ent(viewer, row);
|
|
1154
|
-
return await applyPrivacyPolicyForEntX(viewer, ent);
|
|
1364
|
+
return await applyPrivacyPolicyForEntX(viewer, ent, row, options);
|
|
1155
1365
|
}
|
|
1156
1366
|
exports.applyPrivacyPolicyForRowX = applyPrivacyPolicyForRowX;
|
|
1157
1367
|
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1158
1368
|
let m = new Map();
|
|
1159
1369
|
// apply privacy logic
|
|
1160
1370
|
await Promise.all(rows.map(async (row) => {
|
|
1161
|
-
|
|
1162
|
-
let privacyEnt = await applyPrivacyPolicyForEnt(viewer, ent);
|
|
1371
|
+
let privacyEnt = await applyPrivacyPolicyForRow(viewer, options, row);
|
|
1163
1372
|
if (privacyEnt) {
|
|
1164
1373
|
m.set(privacyEnt.id, privacyEnt);
|
|
1165
1374
|
}
|
|
@@ -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
|
}
|