@snowtop/ent 0.1.0-alpha99 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/action/action.d.ts +8 -1
  2. package/action/executor.d.ts +16 -3
  3. package/action/executor.js +83 -27
  4. package/action/index.d.ts +2 -1
  5. package/action/operations.d.ts +126 -0
  6. package/action/operations.js +686 -0
  7. package/action/orchestrator.d.ts +22 -8
  8. package/action/orchestrator.js +278 -67
  9. package/core/base.d.ts +34 -24
  10. package/core/clause.d.ts +62 -79
  11. package/core/clause.js +77 -5
  12. package/core/config.d.ts +5 -1
  13. package/core/config.js +3 -0
  14. package/core/const.d.ts +3 -0
  15. package/core/const.js +6 -0
  16. package/core/context.d.ts +4 -3
  17. package/core/context.js +2 -1
  18. package/core/db.d.ts +1 -0
  19. package/core/db.js +7 -7
  20. package/core/ent.d.ts +53 -105
  21. package/core/ent.js +104 -599
  22. package/core/global_schema.d.ts +7 -0
  23. package/core/global_schema.js +51 -0
  24. package/core/loaders/assoc_count_loader.d.ts +4 -2
  25. package/core/loaders/assoc_count_loader.js +10 -2
  26. package/core/loaders/assoc_edge_loader.d.ts +2 -3
  27. package/core/loaders/assoc_edge_loader.js +16 -7
  28. package/core/loaders/index.d.ts +0 -1
  29. package/core/loaders/index.js +1 -3
  30. package/core/loaders/loader.d.ts +3 -3
  31. package/core/loaders/loader.js +3 -20
  32. package/core/loaders/object_loader.d.ts +30 -10
  33. package/core/loaders/object_loader.js +179 -40
  34. package/core/loaders/query_loader.d.ts +4 -4
  35. package/core/loaders/query_loader.js +14 -19
  36. package/core/loaders/raw_count_loader.d.ts +1 -0
  37. package/core/loaders/raw_count_loader.js +3 -2
  38. package/core/privacy.d.ts +19 -10
  39. package/core/privacy.js +47 -26
  40. package/core/query/assoc_query.js +1 -1
  41. package/core/query/custom_clause_query.d.ts +6 -3
  42. package/core/query/custom_clause_query.js +36 -9
  43. package/core/query/custom_query.d.ts +3 -1
  44. package/core/query/custom_query.js +29 -6
  45. package/core/query/query.d.ts +12 -2
  46. package/core/query/query.js +67 -38
  47. package/core/query/shared_assoc_test.js +151 -10
  48. package/core/query/shared_test.d.ts +2 -2
  49. package/core/query/shared_test.js +90 -30
  50. package/core/query_impl.d.ts +8 -0
  51. package/core/query_impl.js +28 -0
  52. package/core/viewer.d.ts +2 -0
  53. package/core/viewer.js +2 -0
  54. package/graphql/graphql.d.ts +103 -19
  55. package/graphql/graphql.js +169 -134
  56. package/graphql/graphql_field_helpers.d.ts +9 -3
  57. package/graphql/graphql_field_helpers.js +22 -2
  58. package/graphql/index.d.ts +2 -1
  59. package/graphql/index.js +5 -2
  60. package/graphql/scalars/orderby_direction.d.ts +2 -0
  61. package/graphql/scalars/orderby_direction.js +15 -0
  62. package/imports/dataz/example1/_auth.js +128 -47
  63. package/imports/dataz/example1/_viewer.js +87 -39
  64. package/imports/index.d.ts +1 -1
  65. package/imports/index.js +2 -2
  66. package/index.d.ts +12 -1
  67. package/index.js +18 -6
  68. package/package.json +20 -17
  69. package/parse_schema/parse.d.ts +10 -4
  70. package/parse_schema/parse.js +70 -24
  71. package/schema/base_schema.d.ts +8 -0
  72. package/schema/base_schema.js +11 -0
  73. package/schema/field.d.ts +6 -3
  74. package/schema/field.js +72 -17
  75. package/schema/index.d.ts +1 -1
  76. package/schema/index.js +2 -1
  77. package/schema/json_field.d.ts +3 -3
  78. package/schema/json_field.js +4 -1
  79. package/schema/schema.d.ts +42 -5
  80. package/schema/schema.js +35 -41
  81. package/schema/struct_field.d.ts +8 -6
  82. package/schema/struct_field.js +67 -8
  83. package/schema/union_field.d.ts +1 -1
  84. package/scripts/custom_compiler.js +4 -4
  85. package/scripts/custom_graphql.js +105 -75
  86. package/scripts/move_types.js +4 -1
  87. package/scripts/read_schema.js +2 -2
  88. package/testutils/action/complex_schemas.d.ts +1 -1
  89. package/testutils/action/complex_schemas.js +10 -3
  90. package/testutils/builder.d.ts +3 -0
  91. package/testutils/builder.js +6 -0
  92. package/testutils/db/temp_db.d.ts +9 -1
  93. package/testutils/db/temp_db.js +82 -14
  94. package/testutils/db_mock.js +1 -3
  95. package/testutils/ent-graphql-tests/index.d.ts +1 -1
  96. package/testutils/ent-graphql-tests/index.js +30 -19
  97. package/testutils/fake_comms.js +1 -1
  98. package/testutils/fake_data/fake_contact.d.ts +1 -1
  99. package/testutils/fake_data/fake_tag.d.ts +1 -1
  100. package/testutils/fake_data/fake_user.d.ts +3 -3
  101. package/testutils/fake_data/fake_user.js +15 -4
  102. package/testutils/fake_data/tag_query.js +8 -3
  103. package/testutils/fake_data/test_helpers.d.ts +3 -2
  104. package/testutils/fake_data/test_helpers.js +4 -4
  105. package/testutils/fake_data/user_query.d.ts +5 -2
  106. package/testutils/fake_data/user_query.js +19 -2
  107. package/testutils/fake_log.js +1 -1
  108. package/tsc/ast.js +2 -1
  109. package/tsc/move_generated.js +2 -2
  110. package/tsc/transform.d.ts +2 -2
  111. package/tsc/transform.js +4 -3
  112. package/tsc/transform_ent.js +2 -1
  113. package/tsc/transform_schema.js +4 -3
  114. package/core/loaders/index_loader.d.ts +0 -14
  115. package/core/loaders/index_loader.js +0 -27
package/core/privacy.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = exports.applyPrivacyPolicyImpl = exports.applyPrivacyPolicyX = exports.applyPrivacyPolicy = exports.AllowIfSubPolicyAllowsRule = exports.DelayedResultRule = exports.AllowIfConditionAppliesRule = exports.DenyIfViewerOutboundEdgeDoesNotExistRule = exports.DenyIfViewerInboundEdgeDoesNotExistRule = exports.DenyIfEdgeDoesNotExistRule = exports.DenyIfViewerOutboundEdgeExistsRule = exports.DenyIfViewerInboundEdgeExistsRule = exports.DenyIfEdgeExistsRule = exports.AllowIfViewerOutboundEdgeExistsRule = exports.AllowIfViewerInboundEdgeExistsRule = exports.AllowIfEdgeExistsRule = exports.DenyIfEntIsNotVisibleRule = exports.DenyIfEntIsVisibleRule = exports.DenyIfEntIsVisiblePolicy = exports.AllowIfEntIsVisiblePolicy = exports.AllowIfEntIsNotVisibleRule = exports.AllowIfEntIsVisibleRule = exports.DenyIfEntPropertyIsRule = exports.AllowIfEntPropertyIsRule = exports.AllowIfViewerIsEntPropertyRule = exports.AllowIfViewerIsRule = exports.DenyIfFuncRule = exports.AllowIfFuncRule = exports.DenyIfViewerEqualsRule = exports.AllowIfViewerEqualsRule = exports.AllowIfViewerRule = exports.AllowIfHasIdentity = exports.DenyIfLoggedInRule = exports.DenyIfLoggedOutRule = exports.AlwaysDenyRule = exports.AlwaysAllowRule = exports.EntPrivacyError = void 0;
4
+ const types_1 = require("util/types");
4
5
  const base_1 = require("./base");
5
6
  const ent_1 = require("./ent");
6
7
  // copied from ./base
@@ -102,7 +103,10 @@ class AllowIfFuncRule {
102
103
  this.fn = fn;
103
104
  }
104
105
  async apply(v, ent) {
105
- const result = await this.fn(v, ent);
106
+ let result = this.fn(v, ent);
107
+ if ((0, types_1.isPromise)(result)) {
108
+ result = await result;
109
+ }
106
110
  if (result) {
107
111
  return (0, base_1.Allow)();
108
112
  }
@@ -115,7 +119,10 @@ class DenyIfFuncRule {
115
119
  this.fn = fn;
116
120
  }
117
121
  async apply(v, ent) {
118
- const result = await this.fn(v, ent);
122
+ let result = this.fn(v, ent);
123
+ if ((0, types_1.isPromise)(result)) {
124
+ result = await result;
125
+ }
119
126
  if (result) {
120
127
  return (0, base_1.Deny)();
121
128
  }
@@ -255,7 +262,7 @@ class DenyIfEntIsNotVisibleRule {
255
262
  }
256
263
  }
257
264
  exports.DenyIfEntIsNotVisibleRule = DenyIfEntIsNotVisibleRule;
258
- async function allowIfEdgeExistsRule(id1, id2, edgeType, context) {
265
+ async function allowIfEdgeExistsRule(id1, id2, edgeType, context, options) {
259
266
  if (id1 && id2) {
260
267
  const edge = await (0, ent_1.loadEdgeForID2)({
261
268
  id1,
@@ -263,6 +270,7 @@ async function allowIfEdgeExistsRule(id1, id2, edgeType, context) {
263
270
  id2,
264
271
  context,
265
272
  ctr: ent_1.AssocEdge,
273
+ queryOptions: options,
266
274
  });
267
275
  if (edge) {
268
276
  return (0, base_1.Allow)();
@@ -271,35 +279,38 @@ async function allowIfEdgeExistsRule(id1, id2, edgeType, context) {
271
279
  return (0, base_1.Skip)();
272
280
  }
273
281
  class AllowIfEdgeExistsRule {
274
- constructor(id1, id2, edgeType) {
282
+ constructor(id1, id2, edgeType, options) {
275
283
  this.id1 = id1;
276
284
  this.id2 = id2;
277
285
  this.edgeType = edgeType;
286
+ this.options = options;
278
287
  }
279
288
  async apply(v, _ent) {
280
- return allowIfEdgeExistsRule(this.id1, this.id2, this.edgeType, v.context);
289
+ return allowIfEdgeExistsRule(this.id1, this.id2, this.edgeType, v.context, this.options);
281
290
  }
282
291
  }
283
292
  exports.AllowIfEdgeExistsRule = AllowIfEdgeExistsRule;
284
293
  class AllowIfViewerInboundEdgeExistsRule {
285
- constructor(edgeType) {
294
+ constructor(edgeType, options) {
286
295
  this.edgeType = edgeType;
296
+ this.options = options;
287
297
  }
288
298
  async apply(v, ent) {
289
- return allowIfEdgeExistsRule(v.viewerID, ent?.id, this.edgeType, v.context);
299
+ return allowIfEdgeExistsRule(v.viewerID, ent?.id, this.edgeType, v.context, this.options);
290
300
  }
291
301
  }
292
302
  exports.AllowIfViewerInboundEdgeExistsRule = AllowIfViewerInboundEdgeExistsRule;
293
303
  class AllowIfViewerOutboundEdgeExistsRule {
294
- constructor(edgeType) {
304
+ constructor(edgeType, options) {
295
305
  this.edgeType = edgeType;
306
+ this.options = options;
296
307
  }
297
308
  async apply(v, ent) {
298
- return allowIfEdgeExistsRule(ent?.id, v.viewerID, this.edgeType, v.context);
309
+ return allowIfEdgeExistsRule(ent?.id, v.viewerID, this.edgeType, v.context, this.options);
299
310
  }
300
311
  }
301
312
  exports.AllowIfViewerOutboundEdgeExistsRule = AllowIfViewerOutboundEdgeExistsRule;
302
- async function denyIfEdgeExistsRule(id1, id2, edgeType, context) {
313
+ async function denyIfEdgeExistsRule(id1, id2, edgeType, context, options) {
303
314
  // edge doesn't exist if no viewer
304
315
  if (id1 && id2) {
305
316
  const edge = await (0, ent_1.loadEdgeForID2)({
@@ -308,6 +319,7 @@ async function denyIfEdgeExistsRule(id1, id2, edgeType, context) {
308
319
  id2,
309
320
  context,
310
321
  ctr: ent_1.AssocEdge,
322
+ queryOptions: options,
311
323
  });
312
324
  if (edge) {
313
325
  return (0, base_1.Deny)();
@@ -315,7 +327,7 @@ async function denyIfEdgeExistsRule(id1, id2, edgeType, context) {
315
327
  }
316
328
  return (0, base_1.Skip)();
317
329
  }
318
- async function denyIfEdgeDoesNotExistRule(id1, id2, edgeType, context) {
330
+ async function denyIfEdgeDoesNotExistRule(id1, id2, edgeType, context, options) {
319
331
  // edge doesn't exist if no viewer
320
332
  if (!id1 || !id2) {
321
333
  return (0, base_1.Deny)();
@@ -326,6 +338,7 @@ async function denyIfEdgeDoesNotExistRule(id1, id2, edgeType, context) {
326
338
  id2,
327
339
  context,
328
340
  ctr: ent_1.AssocEdge,
341
+ queryOptions: options,
329
342
  });
330
343
  if (!edge) {
331
344
  return (0, base_1.Deny)();
@@ -333,60 +346,66 @@ async function denyIfEdgeDoesNotExistRule(id1, id2, edgeType, context) {
333
346
  return (0, base_1.Skip)();
334
347
  }
335
348
  class DenyIfEdgeExistsRule {
336
- constructor(id1, id2, edgeType) {
349
+ constructor(id1, id2, edgeType, options) {
337
350
  this.id1 = id1;
338
351
  this.id2 = id2;
339
352
  this.edgeType = edgeType;
353
+ this.options = options;
340
354
  }
341
355
  async apply(v, _ent) {
342
- return denyIfEdgeExistsRule(this.id1, this.id2, this.edgeType, v.context);
356
+ return denyIfEdgeExistsRule(this.id1, this.id2, this.edgeType, v.context, this.options);
343
357
  }
344
358
  }
345
359
  exports.DenyIfEdgeExistsRule = DenyIfEdgeExistsRule;
346
360
  class DenyIfViewerInboundEdgeExistsRule {
347
- constructor(edgeType) {
361
+ constructor(edgeType, options) {
348
362
  this.edgeType = edgeType;
363
+ this.options = options;
349
364
  }
350
365
  async apply(v, ent) {
351
- return denyIfEdgeExistsRule(v.viewerID, ent?.id, this.edgeType, v.context);
366
+ return denyIfEdgeExistsRule(v.viewerID, ent?.id, this.edgeType, v.context, this.options);
352
367
  }
353
368
  }
354
369
  exports.DenyIfViewerInboundEdgeExistsRule = DenyIfViewerInboundEdgeExistsRule;
355
370
  class DenyIfViewerOutboundEdgeExistsRule {
356
- constructor(edgeType) {
371
+ constructor(edgeType, options) {
357
372
  this.edgeType = edgeType;
373
+ this.options = options;
358
374
  }
359
375
  async apply(v, ent) {
360
- return denyIfEdgeExistsRule(ent?.id, v.viewerID, this.edgeType, v.context);
376
+ return denyIfEdgeExistsRule(ent?.id, v.viewerID, this.edgeType, v.context, this.options);
361
377
  }
362
378
  }
363
379
  exports.DenyIfViewerOutboundEdgeExistsRule = DenyIfViewerOutboundEdgeExistsRule;
364
380
  class DenyIfEdgeDoesNotExistRule {
365
- constructor(id1, id2, edgeType) {
381
+ constructor(id1, id2, edgeType, options) {
366
382
  this.id1 = id1;
367
383
  this.id2 = id2;
368
384
  this.edgeType = edgeType;
385
+ this.options = options;
369
386
  }
370
387
  async apply(v, _ent) {
371
- return denyIfEdgeDoesNotExistRule(this.id1, this.id2, this.edgeType, v.context);
388
+ return denyIfEdgeDoesNotExistRule(this.id1, this.id2, this.edgeType, v.context, this.options);
372
389
  }
373
390
  }
374
391
  exports.DenyIfEdgeDoesNotExistRule = DenyIfEdgeDoesNotExistRule;
375
392
  class DenyIfViewerInboundEdgeDoesNotExistRule {
376
- constructor(edgeType) {
393
+ constructor(edgeType, options) {
377
394
  this.edgeType = edgeType;
395
+ this.options = options;
378
396
  }
379
397
  async apply(v, ent) {
380
- return denyIfEdgeDoesNotExistRule(v.viewerID, ent?.id, this.edgeType, v.context);
398
+ return denyIfEdgeDoesNotExistRule(v.viewerID, ent?.id, this.edgeType, v.context, this.options);
381
399
  }
382
400
  }
383
401
  exports.DenyIfViewerInboundEdgeDoesNotExistRule = DenyIfViewerInboundEdgeDoesNotExistRule;
384
402
  class DenyIfViewerOutboundEdgeDoesNotExistRule {
385
- constructor(edgeType) {
403
+ constructor(edgeType, options) {
386
404
  this.edgeType = edgeType;
405
+ this.options = options;
387
406
  }
388
407
  async apply(v, ent) {
389
- return denyIfEdgeDoesNotExistRule(ent?.id, v.viewerID, this.edgeType, v.context);
408
+ return denyIfEdgeDoesNotExistRule(ent?.id, v.viewerID, this.edgeType, v.context, this.options);
390
409
  }
391
410
  }
392
411
  exports.DenyIfViewerOutboundEdgeDoesNotExistRule = DenyIfViewerOutboundEdgeDoesNotExistRule;
@@ -412,12 +431,14 @@ class DelayedResultRule {
412
431
  this.fn = fn;
413
432
  }
414
433
  async apply(v, ent) {
415
- const rule = await this.fn(v, ent);
434
+ let rule = this.fn(v, ent);
435
+ if ((0, types_1.isPromise)(rule)) {
436
+ rule = await rule;
437
+ }
416
438
  if (!rule) {
417
439
  return (0, base_1.Skip)();
418
440
  }
419
- const res = await rule.apply(v, ent);
420
- return res;
441
+ return rule.apply(v, ent);
421
442
  }
422
443
  }
423
444
  exports.DelayedResultRule = DelayedResultRule;
@@ -43,7 +43,7 @@ class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
43
43
  return 0;
44
44
  }
45
45
  return this.countLoaderFactory
46
- .createLoader(this.viewer.context)
46
+ .createConfigurableLoader(this.getDefaultEdgeQueryOptions() ?? {}, this.viewer.context)
47
47
  .load(info.id);
48
48
  }
49
49
  async queryAllRawCount() {
@@ -1,12 +1,16 @@
1
1
  import { Data, EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, Viewer } from "../base";
2
2
  import { Clause } from "../clause";
3
+ import { OrderBy } from "../query_impl";
3
4
  import { BaseEdgeQuery, IDInfo } from "./query";
4
- interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
5
+ export interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
5
6
  loadEntOptions: LoadEntOptions<TDest, TViewer>;
6
7
  clause: Clause;
7
8
  name: string;
9
+ primarySortColIsUnique?: boolean;
10
+ orderby?: OrderBy;
8
11
  sortColumn?: string;
9
- sortColumnUnique?: boolean;
12
+ orderByDirection?: "ASC" | "DESC";
13
+ nullsPlacement?: "first" | "last";
10
14
  disableTransformations?: boolean;
11
15
  }
12
16
  export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<any, TDest, Data> {
@@ -23,4 +27,3 @@ export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer exten
23
27
  dataToID(edge: Data): ID;
24
28
  protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
25
29
  }
26
- export {};
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CustomClauseQuery = void 0;
4
4
  const clause_1 = require("../clause");
5
5
  const ent_1 = require("../ent");
6
- const query_loader_1 = require("../loaders/query_loader");
7
6
  const query_1 = require("./query");
8
7
  function getClause(opts) {
9
8
  let cls = opts.clause;
@@ -21,11 +20,33 @@ function getClause(opts) {
21
20
  }
22
21
  class CustomClauseQuery extends query_1.BaseEdgeQuery {
23
22
  constructor(viewer, options) {
24
- const sortCol = options.sortColumn || "id";
25
- let unique = options.sortColumnUnique
26
- ? sortCol
23
+ let orderby;
24
+ let primarySortCol;
25
+ if (options.orderby &&
26
+ (options.sortColumn || options.orderByDirection || options.nullsPlacement)) {
27
+ throw new Error(`cannot pass orderby and sortColumn|orderByDirection|nullsPlacement`);
28
+ }
29
+ if (options.orderby) {
30
+ primarySortCol = options.orderby[0].column;
31
+ orderby = options.orderby;
32
+ }
33
+ else {
34
+ primarySortCol = options.sortColumn || "id";
35
+ orderby = [
36
+ {
37
+ column: primarySortCol,
38
+ direction: options.orderByDirection ?? "DESC",
39
+ nullsPlacement: options.nullsPlacement,
40
+ },
41
+ ];
42
+ }
43
+ let cursorCol = options.primarySortColIsUnique
44
+ ? primarySortCol
27
45
  : options.loadEntOptions.loaderFactory.options?.key || "id";
28
- super(viewer, options.sortColumn || sortCol, unique);
46
+ super(viewer, {
47
+ orderby,
48
+ cursorCol,
49
+ });
29
50
  this.viewer = viewer;
30
51
  this.options = options;
31
52
  this.clause = getClause(options);
@@ -53,17 +74,23 @@ class CustomClauseQuery extends query_1.BaseEdgeQuery {
53
74
  async loadRawIDs(_addID) { }
54
75
  async loadRawData(_infos, options) {
55
76
  if (!options.orderby) {
56
- options.orderby = `${this.options.sortColumn} DESC`;
77
+ options.orderby = [
78
+ {
79
+ column: this.getSortCol(),
80
+ direction: this.options.orderByDirection ?? "DESC",
81
+ nullsPlacement: this.options.nullsPlacement,
82
+ },
83
+ ];
57
84
  }
58
85
  if (!options.limit) {
59
- options.limit = ent_1.DefaultLimit;
86
+ options.limit = (0, ent_1.getDefaultLimit)();
60
87
  }
61
88
  const rows = await (0, ent_1.loadRows)({
62
89
  tableName: this.options.loadEntOptions.tableName,
63
90
  fields: this.options.loadEntOptions.fields,
64
91
  clause: (0, clause_1.AndOptional)(this.clause, options.clause),
65
- orderby: (0, query_loader_1.getOrderBy)(this.getSortCol(), options?.orderby),
66
- limit: options?.limit || ent_1.DefaultLimit,
92
+ orderby: options.orderby,
93
+ limit: options?.limit || (0, ent_1.getDefaultLimit)(),
67
94
  context: this.viewer.context,
68
95
  });
69
96
  this.edges.set(1, rows);
@@ -1,5 +1,6 @@
1
1
  import { Data, Ent, ID, EdgeQueryableDataOptions, LoadEntOptions, Viewer, LoaderFactory, ConfigurableLoaderFactory } from "../base";
2
2
  import { Clause } from "../clause";
3
+ import { OrderBy } from "../query_impl";
3
4
  import { BaseEdgeQuery, IDInfo, EdgeQuery } from "./query";
4
5
  export interface CustomEdgeQueryOptionsDeprecated<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
5
6
  src: TSource | ID;
@@ -15,7 +16,8 @@ export interface CustomEdgeQueryOptions<TSource extends Ent<TViewer>, TDest exte
15
16
  clause?: Clause;
16
17
  name: string;
17
18
  sortColumn?: string;
18
- sortColumnUnique?: boolean;
19
+ orderby?: OrderBy;
20
+ primarySortColIsUnique?: boolean;
19
21
  disableTransformations?: boolean;
20
22
  }
21
23
  export declare abstract class CustomEdgeQueryBase<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<TSource, TDest, Data> implements EdgeQuery<TSource, TDest, Data> {
@@ -54,21 +54,39 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
54
54
  let opts;
55
55
  let defaultSort = "id";
56
56
  let uniqueColIsSort = false;
57
+ let orderby;
58
+ let sortCol;
57
59
  if (isDeprecatedOptions(options)) {
58
60
  opts = options.options;
59
61
  }
60
62
  else {
61
63
  opts = options.loadEntOptions;
62
- if (options.sortColumnUnique) {
64
+ if (options.primarySortColIsUnique) {
63
65
  uniqueColIsSort = true;
64
66
  }
67
+ if (options.orderby) {
68
+ orderby = options.orderby;
69
+ sortCol = options.orderby[0].column;
70
+ }
65
71
  }
66
72
  let uniqueCol = opts.loaderFactory.options?.key || "id";
73
+ if (!orderby) {
74
+ options.sortColumn = options.sortColumn || defaultSort;
75
+ sortCol = options.sortColumn;
76
+ orderby = [
77
+ {
78
+ column: options.sortColumn,
79
+ direction: "DESC",
80
+ },
81
+ ];
82
+ }
67
83
  if (uniqueColIsSort) {
68
- uniqueCol = options.sortColumn || defaultSort;
84
+ uniqueCol = sortCol || defaultSort;
69
85
  }
70
- options.sortColumn = options.sortColumn || defaultSort;
71
- super(viewer, options.sortColumn, uniqueCol);
86
+ super(viewer, {
87
+ cursorCol: uniqueCol,
88
+ orderby,
89
+ });
72
90
  this.viewer = viewer;
73
91
  this.options = options;
74
92
  if (typeof options.src === "object") {
@@ -124,10 +142,15 @@ class CustomEdgeQueryBase extends query_1.BaseEdgeQuery {
124
142
  throw new Error(`expected 1 info passed to loadRawData. ${infos.length} passed`);
125
143
  }
126
144
  if (!options.orderby) {
127
- options.orderby = `${this.getSortCol()} DESC`;
145
+ options.orderby = [
146
+ {
147
+ column: this.getSortCol(),
148
+ direction: "DESC",
149
+ },
150
+ ];
128
151
  }
129
152
  if (!options.limit) {
130
- options.limit = ent_1.DefaultLimit;
153
+ options.limit = (0, ent_1.getDefaultLimit)();
131
154
  }
132
155
  const loader = this.getQueryLoader(options);
133
156
  const info = infos[0];
@@ -1,4 +1,5 @@
1
- import { ID, Ent, Viewer, EdgeQueryableDataOptions, Data, PrivacyPolicy } from "../base";
1
+ import { ID, Ent, Viewer, EdgeQueryableDataOptions, Data, PrivacyPolicy, EdgeQueryableDataOptionsConfigureLoader } from "../base";
2
+ import { OrderBy } from "../query_impl";
2
3
  export interface EdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> {
3
4
  queryEdges(): Promise<TEdge[]>;
4
5
  queryAllEdges(): Promise<Map<ID, TEdge[]>>;
@@ -29,6 +30,10 @@ export interface PaginationInfo {
29
30
  startCursor: string;
30
31
  endCursor: string;
31
32
  }
33
+ interface EdgeQueryOptions {
34
+ cursorCol: string;
35
+ orderby: OrderBy;
36
+ }
32
37
  export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends Ent, TEdge extends Data> implements EdgeQuery<TSource, TDest, TEdge> {
33
38
  viewer: Viewer;
34
39
  private filters;
@@ -41,8 +46,9 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
41
46
  private idsToFetch;
42
47
  private sortCol;
43
48
  private cursorCol;
44
- private defaultDirection?;
49
+ private edgeQueryOptions;
45
50
  constructor(viewer: Viewer, sortCol: string, cursorCol: string);
51
+ constructor(viewer: Viewer, options: EdgeQueryOptions);
46
52
  protected getSortCol(): string;
47
53
  getPrivacyPolicy(): PrivacyPolicy<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>>;
48
54
  abstract sourceEnt(id: ID): Promise<Ent | null>;
@@ -69,6 +75,9 @@ export declare abstract class BaseEdgeQuery<TSource extends Ent, TDest extends E
69
75
  private addID;
70
76
  abstract getTableName(): string | Promise<string>;
71
77
  protected genIDInfosToFetchImpl(): Promise<IDInfo[]>;
78
+ private _defaultEdgeQueryableOptions;
79
+ protected configureEdgeQueryableDataOptions(opts: EdgeQueryableDataOptionsConfigureLoader): void;
80
+ protected getDefaultEdgeQueryOptions(): Partial<Pick<import("../base").QueryableDataOptions, "clause" | "limit" | "orderby" | "disableTransformations">> | undefined;
72
81
  private loadEdges;
73
82
  getCursor(row: TEdge): string;
74
83
  }
@@ -76,3 +85,4 @@ export interface IDInfo {
76
85
  id: ID;
77
86
  invalidated?: boolean;
78
87
  }
88
+ export {};
@@ -32,7 +32,8 @@ const clause = __importStar(require("../clause"));
32
32
  const memoizee_1 = __importDefault(require("memoizee"));
33
33
  const privacy_1 = require("../privacy");
34
34
  const uuid_1 = require("uuid");
35
- const util_1 = require("util");
35
+ const query_impl_1 = require("../query_impl");
36
+ const types_1 = require("util/types");
36
37
  // TODO can we generalize EdgeQuery to support any clause
37
38
  function assertPositive(n) {
38
39
  if (n < 0) {
@@ -95,22 +96,24 @@ class FirstFilter {
95
96
  // we fetch an extra one to see if we're at the end
96
97
  const limit = this.options.limit + 1;
97
98
  options.limit = limit;
98
- let orderby = this.options.defaultDirection || "DESC";
99
99
  // we sort by most recent first
100
100
  // so when paging, we fetch afterCursor X
101
- const less = orderby === "DESC";
101
+ const less = this.options.orderby[0].direction === "DESC";
102
+ const orderby = this.options.orderby;
102
103
  if (this.options.cursorCol !== this.sortCol) {
103
- // we also sort unique col in same direction since it doesn't matter...
104
- options.orderby = `${this.sortCol} ${orderby}, ${this.options.cursorCol} ${orderby}`;
104
+ // we also sort cursor col in same direction. (direction doesn't matter)
105
+ orderby.push({
106
+ column: this.options.cursorCol,
107
+ direction: orderby[0].direction,
108
+ });
105
109
  if (this.offset) {
106
110
  const res = this.edgeQuery.getTableName();
107
- const tableName = util_1.types.isPromise(res) ? await res : res;
111
+ const tableName = (0, types_1.isPromise)(res) ? await res : res;
108
112
  // inner col time
109
113
  options.clause = clause.PaginationMultipleColsSubQuery(this.sortCol, less ? "<" : ">", tableName, this.options.cursorCol, this.offset);
110
114
  }
111
115
  }
112
116
  else {
113
- options.orderby = `${this.sortCol} ${orderby}`;
114
117
  if (this.offset) {
115
118
  let clauseFn = less ? clause.Less : clause.Greater;
116
119
  let val = this.options.sortColTime
@@ -119,6 +122,7 @@ class FirstFilter {
119
122
  options.clause = clauseFn(this.sortCol, val);
120
123
  }
121
124
  }
125
+ options.orderby = orderby;
122
126
  return options;
123
127
  }
124
128
  // TODO?
@@ -165,31 +169,23 @@ class LastFilter {
165
169
  return ret;
166
170
  }
167
171
  async query(options) {
168
- // assume desc by default
169
- // so last is reverse
170
- let orderby = "ASC";
171
- if (this.options.defaultDirection) {
172
- // reverse sort col shown...
173
- if (this.options.defaultDirection === "DESC") {
174
- orderby = "ASC";
175
- }
176
- else {
177
- orderby = "DESC";
178
- }
179
- }
180
- const greater = orderby === "ASC";
172
+ const orderby = (0, query_impl_1.reverseOrderBy)(this.options.orderby);
173
+ const greater = orderby[0].direction === "ASC";
181
174
  options.limit = this.options.limit + 1; // fetch an extra so we know if previous pag
182
175
  if (this.options.cursorCol !== this.sortCol) {
183
176
  const res = this.edgeQuery.getTableName();
184
- const tableName = util_1.types.isPromise(res) ? await res : res;
177
+ const tableName = (0, types_1.isPromise)(res) ? await res : res;
185
178
  if (this.offset) {
186
179
  // inner col time
187
180
  options.clause = clause.PaginationMultipleColsSubQuery(this.sortCol, greater ? ">" : "<", tableName, this.options.cursorCol, this.offset);
188
181
  }
189
- options.orderby = `${this.sortCol} ${orderby}, ${this.options.cursorCol} ${orderby}`;
182
+ // we also sort cursor col in same direction. (direction doesn't matter)
183
+ orderby.push({
184
+ column: this.options.cursorCol,
185
+ direction: orderby[0].direction,
186
+ });
190
187
  }
191
188
  else {
192
- options.orderby = `${this.sortCol} ${orderby}`;
193
189
  if (this.offset) {
194
190
  let clauseFn = greater ? clause.Greater : clause.Less;
195
191
  let val = this.options.sortColTime
@@ -198,6 +194,7 @@ class LastFilter {
198
194
  options.clause = clauseFn(this.sortCol, val);
199
195
  }
200
196
  }
197
+ options.orderby = orderby;
201
198
  return options;
202
199
  }
203
200
  paginationInfo(id) {
@@ -205,7 +202,7 @@ class LastFilter {
205
202
  }
206
203
  }
207
204
  class BaseEdgeQuery {
208
- constructor(viewer, sortCol, cursorCol) {
205
+ constructor(viewer, sortColOrOptions, cursorColMaybe) {
209
206
  this.viewer = viewer;
210
207
  this.filters = [];
211
208
  this.edges = new Map();
@@ -217,7 +214,7 @@ class BaseEdgeQuery {
217
214
  return await this.querySingleEdge("queryEdges");
218
215
  };
219
216
  this.queryAllEdges = async () => {
220
- return await this.memoizedloadEdges();
217
+ return this.memoizedloadEdges();
221
218
  };
222
219
  this.queryIDs = async () => {
223
220
  const edges = await this.querySingleEdge("queryIDs");
@@ -245,7 +242,7 @@ class BaseEdgeQuery {
245
242
  };
246
243
  this.queryEnts = async () => {
247
244
  const edges = await this.querySingleEdge("queryEnts");
248
- return await this.loadEntsFromEdges("id", edges);
245
+ return this.loadEntsFromEdges("id", edges);
249
246
  };
250
247
  this.queryAllEnts = async () => {
251
248
  // applies filters and then gets things after
@@ -262,20 +259,42 @@ class BaseEdgeQuery {
262
259
  await Promise.all(promises);
263
260
  return results;
264
261
  };
262
+ let sortCol;
263
+ let cursorCol;
264
+ if (typeof sortColOrOptions === "string") {
265
+ sortCol = sortColOrOptions;
266
+ cursorCol = cursorColMaybe;
267
+ this.edgeQueryOptions = {
268
+ cursorCol,
269
+ orderby: [
270
+ {
271
+ column: sortCol,
272
+ direction: "DESC",
273
+ },
274
+ ],
275
+ };
276
+ }
277
+ else {
278
+ if (typeof sortColOrOptions.orderby === "string") {
279
+ sortCol = sortColOrOptions.orderby;
280
+ }
281
+ else {
282
+ // TODO this orderby isn't consistent and this logic needs to be changed anywhere that's using this and this.getSortCol()
283
+ sortCol = sortColOrOptions.orderby[0].column;
284
+ }
285
+ cursorCol = sortColOrOptions.cursorCol;
286
+ this.edgeQueryOptions = sortColOrOptions;
287
+ }
288
+ this.sortCol = sortCol;
265
289
  let m = orderbyRegex.exec(sortCol);
266
290
  if (!m) {
267
291
  throw new Error(`invalid sort column ${sortCol}`);
268
292
  }
269
293
  this.sortCol = m[1];
270
294
  if (m[2]) {
271
- // @ts-ignore
272
- this.defaultDirection = m[2].toUpperCase();
273
- }
274
- let m2 = orderbyRegex.exec(cursorCol);
275
- if (!m2) {
276
- throw new Error(`invalid sort column ${cursorCol}`);
295
+ throw new Error(`passing direction in sort column is not supproted. use orderby`);
277
296
  }
278
- this.cursorCol = m2[1];
297
+ this.cursorCol = cursorCol;
279
298
  this.memoizedloadEdges = (0, memoizee_1.default)(this.loadEdges.bind(this));
280
299
  this.genIDInfosToFetch = (0, memoizee_1.default)(this.genIDInfosToFetchImpl.bind(this));
281
300
  }
@@ -293,7 +312,7 @@ class BaseEdgeQuery {
293
312
  after,
294
313
  sortCol: this.sortCol,
295
314
  cursorCol: this.cursorCol,
296
- defaultDirection: this.defaultDirection,
315
+ orderby: this.edgeQueryOptions.orderby,
297
316
  query: this,
298
317
  }));
299
318
  return this;
@@ -305,7 +324,7 @@ class BaseEdgeQuery {
305
324
  before,
306
325
  sortCol: this.sortCol,
307
326
  cursorCol: this.cursorCol,
308
- defaultDirection: this.defaultDirection,
327
+ orderby: this.edgeQueryOptions.orderby,
309
328
  query: this,
310
329
  }));
311
330
  return this;
@@ -347,20 +366,30 @@ class BaseEdgeQuery {
347
366
  await this.loadRawIDs(this.addID.bind(this));
348
367
  return applyPrivacyPolicyForEdgeQ(this.viewer, this, this.idsToFetch, this.idMap);
349
368
  }
369
+ // FYI: this should be used sparingly.
370
+ // currently only exists so that disableTransformations can be configured by the developer
371
+ // so we're only exposing a partial API for now but maybe in the future we can expose
372
+ // the full API if there's a reason to use this that's not via filters
373
+ configureEdgeQueryableDataOptions(opts) {
374
+ this._defaultEdgeQueryableOptions = opts;
375
+ }
376
+ getDefaultEdgeQueryOptions() {
377
+ return this._defaultEdgeQueryableOptions;
378
+ }
350
379
  async loadEdges() {
351
380
  const idsInfo = await this.genIDInfosToFetch();
352
381
  if (!this.filters.length) {
353
382
  // if no filter, we add the firstN filter to ensure we get pagination info
354
- this.first(ent_1.DefaultLimit);
383
+ this.first((0, ent_1.getDefaultLimit)());
355
384
  }
356
- let options = {};
385
+ let options = this._defaultEdgeQueryableOptions ?? {};
357
386
  // TODO once we add a lot of complex filters, this needs to be more complicated
358
387
  // e.g. commutative filters. what can be done in sql or combined together etc
359
388
  // may need to bring sql mode or something back
360
389
  for (const filter of this.filters) {
361
390
  if (filter.query) {
362
391
  let res = filter.query(options);
363
- options = util_1.types.isPromise(res) ? await res : res;
392
+ options = (0, types_1.isPromise)(res) ? await res : res;
364
393
  }
365
394
  }
366
395
  await this.loadRawData(idsInfo, options);