@snowtop/ent 0.1.0-alpha99 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/action/action.d.ts +8 -1
- package/action/executor.d.ts +16 -3
- package/action/executor.js +83 -27
- package/action/index.d.ts +2 -1
- package/action/operations.d.ts +126 -0
- package/action/operations.js +686 -0
- package/action/orchestrator.d.ts +22 -8
- package/action/orchestrator.js +278 -67
- package/core/base.d.ts +34 -24
- package/core/clause.d.ts +62 -79
- package/core/clause.js +77 -5
- package/core/config.d.ts +5 -1
- package/core/config.js +3 -0
- package/core/const.d.ts +3 -0
- package/core/const.js +6 -0
- package/core/context.d.ts +4 -3
- package/core/context.js +2 -1
- package/core/db.d.ts +1 -0
- package/core/db.js +7 -7
- package/core/ent.d.ts +53 -105
- package/core/ent.js +104 -599
- package/core/global_schema.d.ts +7 -0
- package/core/global_schema.js +51 -0
- package/core/loaders/assoc_count_loader.d.ts +4 -2
- package/core/loaders/assoc_count_loader.js +10 -2
- package/core/loaders/assoc_edge_loader.d.ts +2 -3
- package/core/loaders/assoc_edge_loader.js +16 -7
- package/core/loaders/index.d.ts +0 -1
- package/core/loaders/index.js +1 -3
- package/core/loaders/loader.d.ts +3 -3
- package/core/loaders/loader.js +3 -20
- package/core/loaders/object_loader.d.ts +30 -10
- package/core/loaders/object_loader.js +179 -40
- package/core/loaders/query_loader.d.ts +4 -4
- package/core/loaders/query_loader.js +14 -19
- package/core/loaders/raw_count_loader.d.ts +1 -0
- package/core/loaders/raw_count_loader.js +3 -2
- package/core/privacy.d.ts +19 -10
- package/core/privacy.js +47 -26
- package/core/query/assoc_query.js +1 -1
- package/core/query/custom_clause_query.d.ts +6 -3
- package/core/query/custom_clause_query.js +36 -9
- package/core/query/custom_query.d.ts +3 -1
- package/core/query/custom_query.js +29 -6
- package/core/query/query.d.ts +12 -2
- package/core/query/query.js +67 -38
- package/core/query/shared_assoc_test.js +151 -10
- package/core/query/shared_test.d.ts +2 -2
- package/core/query/shared_test.js +90 -30
- package/core/query_impl.d.ts +8 -0
- package/core/query_impl.js +28 -0
- package/core/viewer.d.ts +2 -0
- package/core/viewer.js +2 -0
- package/graphql/graphql.d.ts +103 -19
- package/graphql/graphql.js +169 -134
- package/graphql/graphql_field_helpers.d.ts +9 -3
- package/graphql/graphql_field_helpers.js +22 -2
- package/graphql/index.d.ts +2 -1
- package/graphql/index.js +5 -2
- package/graphql/scalars/orderby_direction.d.ts +2 -0
- package/graphql/scalars/orderby_direction.js +15 -0
- package/imports/dataz/example1/_auth.js +128 -47
- package/imports/dataz/example1/_viewer.js +87 -39
- package/imports/index.d.ts +1 -1
- package/imports/index.js +2 -2
- package/index.d.ts +12 -1
- package/index.js +18 -6
- package/package.json +20 -17
- package/parse_schema/parse.d.ts +10 -4
- package/parse_schema/parse.js +70 -24
- package/schema/base_schema.d.ts +8 -0
- package/schema/base_schema.js +11 -0
- package/schema/field.d.ts +6 -3
- package/schema/field.js +72 -17
- package/schema/index.d.ts +1 -1
- package/schema/index.js +2 -1
- package/schema/json_field.d.ts +3 -3
- package/schema/json_field.js +4 -1
- package/schema/schema.d.ts +42 -5
- package/schema/schema.js +35 -41
- package/schema/struct_field.d.ts +8 -6
- package/schema/struct_field.js +67 -8
- package/schema/union_field.d.ts +1 -1
- package/scripts/custom_compiler.js +4 -4
- package/scripts/custom_graphql.js +105 -75
- package/scripts/move_types.js +4 -1
- package/scripts/read_schema.js +2 -2
- package/testutils/action/complex_schemas.d.ts +1 -1
- package/testutils/action/complex_schemas.js +10 -3
- package/testutils/builder.d.ts +3 -0
- package/testutils/builder.js +6 -0
- package/testutils/db/temp_db.d.ts +9 -1
- package/testutils/db/temp_db.js +82 -14
- package/testutils/db_mock.js +1 -3
- package/testutils/ent-graphql-tests/index.d.ts +1 -1
- package/testutils/ent-graphql-tests/index.js +30 -19
- package/testutils/fake_comms.js +1 -1
- package/testutils/fake_data/fake_contact.d.ts +1 -1
- package/testutils/fake_data/fake_tag.d.ts +1 -1
- package/testutils/fake_data/fake_user.d.ts +3 -3
- package/testutils/fake_data/fake_user.js +15 -4
- package/testutils/fake_data/tag_query.js +8 -3
- package/testutils/fake_data/test_helpers.d.ts +3 -2
- package/testutils/fake_data/test_helpers.js +4 -4
- package/testutils/fake_data/user_query.d.ts +5 -2
- package/testutils/fake_data/user_query.js +19 -2
- package/testutils/fake_log.js +1 -1
- package/tsc/ast.js +2 -1
- package/tsc/move_generated.js +2 -2
- package/tsc/transform.d.ts +2 -2
- package/tsc/transform.js +4 -3
- package/tsc/transform_ent.js +2 -1
- package/tsc/transform_schema.js +4 -3
- package/core/loaders/index_loader.d.ts +0 -14
- package/core/loaders/index_loader.js +0 -27
package/core/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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
.
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
let
|
|
26
|
-
|
|
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,
|
|
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 =
|
|
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.
|
|
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:
|
|
66
|
-
limit: options?.limit || ent_1.
|
|
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
|
-
|
|
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.
|
|
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 =
|
|
84
|
+
uniqueCol = sortCol || defaultSort;
|
|
69
85
|
}
|
|
70
|
-
|
|
71
|
-
|
|
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 =
|
|
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.
|
|
153
|
+
options.limit = (0, ent_1.getDefaultLimit)();
|
|
131
154
|
}
|
|
132
155
|
const loader = this.getQueryLoader(options);
|
|
133
156
|
const info = infos[0];
|
package/core/query/query.d.ts
CHANGED
|
@@ -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
|
|
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 {};
|
package/core/query/query.js
CHANGED
|
@@ -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
|
|
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
|
|
104
|
-
|
|
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 =
|
|
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
|
-
|
|
169
|
-
|
|
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 =
|
|
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
|
-
|
|
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,
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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 =
|
|
392
|
+
options = (0, types_1.isPromise)(res) ? await res : res;
|
|
364
393
|
}
|
|
365
394
|
}
|
|
366
395
|
await this.loadRawData(idsInfo, options);
|