@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.
Files changed (111) hide show
  1. package/action/action.d.ts +28 -24
  2. package/action/executor.d.ts +4 -4
  3. package/action/executor.js +2 -2
  4. package/action/experimental_action.d.ts +29 -22
  5. package/action/experimental_action.js +29 -6
  6. package/action/orchestrator.d.ts +44 -16
  7. package/action/orchestrator.js +287 -73
  8. package/action/privacy.d.ts +2 -2
  9. package/core/base.d.ts +26 -22
  10. package/core/base.js +16 -0
  11. package/core/clause.d.ts +65 -3
  12. package/core/clause.js +368 -5
  13. package/core/config.d.ts +26 -0
  14. package/core/config.js +17 -0
  15. package/core/context.d.ts +2 -2
  16. package/core/context.js +2 -2
  17. package/core/convert.d.ts +1 -1
  18. package/core/db.d.ts +3 -4
  19. package/core/db.js +2 -0
  20. package/core/ent.d.ts +35 -24
  21. package/core/ent.js +223 -60
  22. package/core/loaders/assoc_count_loader.d.ts +2 -2
  23. package/core/loaders/assoc_count_loader.js +6 -1
  24. package/core/loaders/assoc_edge_loader.d.ts +3 -3
  25. package/core/loaders/assoc_edge_loader.js +5 -4
  26. package/core/loaders/index_loader.js +1 -0
  27. package/core/loaders/loader.js +5 -5
  28. package/core/loaders/object_loader.d.ts +10 -5
  29. package/core/loaders/object_loader.js +58 -4
  30. package/core/loaders/query_loader.d.ts +2 -2
  31. package/core/loaders/raw_count_loader.d.ts +2 -2
  32. package/core/logger.d.ts +1 -1
  33. package/core/logger.js +1 -0
  34. package/core/privacy.d.ts +25 -25
  35. package/core/privacy.js +3 -0
  36. package/core/query/assoc_query.d.ts +6 -6
  37. package/core/query/custom_query.d.ts +5 -5
  38. package/core/query/query.d.ts +1 -1
  39. package/core/query/shared_assoc_test.d.ts +1 -1
  40. package/core/query/shared_assoc_test.js +17 -5
  41. package/core/query/shared_test.d.ts +3 -0
  42. package/core/query/shared_test.js +95 -17
  43. package/core/viewer.d.ts +4 -3
  44. package/core/viewer.js +4 -0
  45. package/graphql/builtins/connection.js +3 -3
  46. package/graphql/builtins/edge.js +2 -2
  47. package/graphql/builtins/node.js +1 -1
  48. package/graphql/graphql.d.ts +3 -2
  49. package/graphql/graphql.js +30 -23
  50. package/graphql/node_resolver.d.ts +0 -1
  51. package/graphql/query/connection_type.js +6 -6
  52. package/graphql/query/edge_connection.d.ts +9 -9
  53. package/graphql/query/page_info.d.ts +1 -1
  54. package/graphql/query/page_info.js +4 -4
  55. package/graphql/query/shared_assoc_test.js +2 -2
  56. package/graphql/scalars/time.d.ts +1 -1
  57. package/index.d.ts +18 -1
  58. package/index.js +21 -5
  59. package/package.json +3 -3
  60. package/parse_schema/parse.d.ts +24 -5
  61. package/parse_schema/parse.js +90 -8
  62. package/schema/base_schema.d.ts +36 -1
  63. package/schema/base_schema.js +51 -2
  64. package/schema/field.d.ts +34 -6
  65. package/schema/field.js +68 -3
  66. package/schema/index.d.ts +2 -2
  67. package/schema/index.js +8 -1
  68. package/schema/schema.d.ts +95 -2
  69. package/schema/schema.js +127 -5
  70. package/scripts/custom_graphql.js +127 -16
  71. package/scripts/{transform_schema.d.ts → migrate_v0.1.d.ts} +0 -0
  72. package/scripts/migrate_v0.1.js +36 -0
  73. package/scripts/read_schema.js +25 -2
  74. package/testutils/builder.d.ts +36 -22
  75. package/testutils/builder.js +110 -13
  76. package/testutils/context/test_context.d.ts +2 -2
  77. package/testutils/context/test_context.js +7 -1
  78. package/testutils/db/{test_db.d.ts → temp_db.d.ts} +17 -4
  79. package/testutils/db/{test_db.js → temp_db.js} +75 -19
  80. package/testutils/ent-graphql-tests/index.d.ts +2 -0
  81. package/testutils/ent-graphql-tests/index.js +26 -17
  82. package/testutils/fake_data/fake_contact.d.ts +5 -9
  83. package/testutils/fake_data/fake_contact.js +17 -21
  84. package/testutils/fake_data/fake_event.d.ts +5 -9
  85. package/testutils/fake_data/fake_event.js +24 -28
  86. package/testutils/fake_data/fake_user.d.ts +6 -10
  87. package/testutils/fake_data/fake_user.js +25 -29
  88. package/testutils/fake_data/test_helpers.d.ts +2 -2
  89. package/testutils/fake_data/test_helpers.js +6 -6
  90. package/testutils/fake_data/user_query.d.ts +2 -2
  91. package/testutils/fake_log.d.ts +3 -3
  92. package/testutils/parse_sql.js +4 -0
  93. package/testutils/test_edge_global_schema.d.ts +15 -0
  94. package/testutils/test_edge_global_schema.js +58 -0
  95. package/testutils/write.d.ts +2 -2
  96. package/testutils/write.js +3 -3
  97. package/tsc/ast.d.ts +44 -0
  98. package/tsc/ast.js +267 -0
  99. package/tsc/compilerOptions.d.ts +6 -0
  100. package/tsc/compilerOptions.js +40 -1
  101. package/tsc/move_generated.d.ts +1 -0
  102. package/tsc/move_generated.js +160 -0
  103. package/tsc/transform.d.ts +21 -0
  104. package/tsc/transform.js +167 -0
  105. package/tsc/transform_action.d.ts +22 -0
  106. package/tsc/transform_action.js +179 -0
  107. package/tsc/transform_ent.d.ts +17 -0
  108. package/tsc/transform_ent.js +59 -0
  109. package/tsc/transform_schema.d.ts +27 -0
  110. package/tsc/transform_schema.js +379 -0
  111. 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.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRowX = exports.applyPrivacyPolicyForRow = exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = 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.EditNodeOperation = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.loadRow = exports.loadRowX = exports.applyPrivacyPolicyForEntX = exports.applyPrivacyPolicyForEnt = 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 = 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)("query", {
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
- const ent = new options.ent(viewer, row);
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
- async function applyPrivacyPolicyForEnt(viewer, ent) {
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.privacyPolicy, ent);
272
- if (visible) {
273
- return ent;
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
- exports.applyPrivacyPolicyForEnt = applyPrivacyPolicyForEnt;
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.privacyPolicy, 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.row = await editRow(queryer, options, this.existingEnt.id, "RETURNING *");
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: clause.Eq(options.key, id),
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 !== 1) {
464
- throw new Error(`couldn't reload row for ${id}`);
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, this.existingEnt.id, "RETURNING *");
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
- return deleteRows(q, params.options, params.clause);
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
- return deleteRowsSync(q, params.options, params.clause);
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
- "ON CONFLICT(id1, edge_type, id2) DO UPDATE SET data = EXCLUDED.data",
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, id, suffix) {
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
- values.push(options.fields[key]);
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
- if (dialect === db_1.Dialect.Postgres) {
870
- query = query + `${options.key} = $${idx}`;
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, id, suffix) {
882
- const [query, values, logValues] = buildUpdateQuery(options, id, suffix);
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, id, suffix) {
896
- const [query, values, logValues] = buildUpdateQuery(options, id, suffix);
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: edgeFields,
1069
- clause: cls,
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: edgeFields,
1088
- clause: clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)),
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: clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)),
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
- const ent = new options.ent(viewer, row);
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: clause.Eq("edge_type", this.edgeType),
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 isFunction;
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
- isFunction(edgeCtr) {
165
- // not constructor
166
- return !(edgeCtr.prototype && edgeCtr.prototype.constructor === edgeCtr);
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.isFunction(edgeCtr)) {
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({