@snowtop/ent 0.1.0-alpha88 → 0.1.0-alpha89-16dc3410-33c4-11ed-9fc4-5d4a927887be
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 +1 -1
- package/action/orchestrator.js +15 -11
- package/core/clause.d.ts +3 -0
- package/core/clause.js +34 -12
- package/core/db.d.ts +1 -0
- package/core/ent.d.ts +1 -1
- package/core/ent.js +30 -19
- package/core/loaders/index.d.ts +1 -1
- package/core/loaders/index.js +1 -3
- package/core/loaders/index_loader.d.ts +2 -2
- package/core/loaders/query_loader.d.ts +5 -11
- package/core/loaders/query_loader.js +47 -10
- package/core/query/custom_clause_query.d.ts +24 -0
- package/core/query/custom_clause_query.js +72 -0
- package/core/query/custom_query.d.ts +17 -2
- package/core/query/custom_query.js +77 -10
- package/core/query/index.d.ts +1 -0
- package/core/query/index.js +3 -1
- package/core/query/query.js +8 -1
- package/core/query/shared_test.js +118 -15
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/package.json +1 -1
- package/schema/schema.d.ts +3 -1
- package/scripts/custom_graphql.js +1 -0
- package/testutils/db/temp_db.js +7 -1
- package/testutils/fake_data/fake_contact.d.ts +2 -1
- package/testutils/fake_data/fake_contact.js +5 -0
- package/testutils/fake_data/fake_event.d.ts +2 -0
- package/testutils/fake_data/test_helpers.d.ts +1 -0
- package/testutils/fake_data/test_helpers.js +3 -1
- package/testutils/fake_data/user_query.d.ts +6 -4
- package/testutils/fake_data/user_query.js +28 -21
package/action/action.d.ts
CHANGED
|
@@ -46,7 +46,7 @@ export interface Observer<TEnt extends Ent<TViewer>, TBuilder extends Builder<TE
|
|
|
46
46
|
observe(builder: TBuilder, input: TInput): void | Promise<void>;
|
|
47
47
|
}
|
|
48
48
|
export interface Validator<TEnt extends Ent<TViewer>, TBuilder extends Builder<TEnt, TViewer, TExistingEnt>, TViewer extends Viewer = Viewer, TInput extends Data = Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
|
|
49
|
-
validate(builder: TBuilder, input: TInput): Promise<void> | void;
|
|
49
|
+
validate(builder: TBuilder, input: TInput): Promise<void | undefined | Error> | void | Error | undefined;
|
|
50
50
|
}
|
|
51
51
|
export interface Action<TEnt extends Ent<TViewer>, TBuilder extends Builder<TEnt, TViewer, TExistingEnt>, TViewer extends Viewer = Viewer, TInput extends Data = Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
|
|
52
52
|
readonly viewer: Viewer;
|
package/action/orchestrator.js
CHANGED
|
@@ -368,13 +368,14 @@ class Orchestrator {
|
|
|
368
368
|
// not ideal we're calling this twice. fix...
|
|
369
369
|
// needed for now. may need to rewrite some of this?
|
|
370
370
|
const editedFields2 = await this.options.editedFields();
|
|
371
|
-
const [errors,
|
|
371
|
+
const [errors, errs2] = await Promise.all([
|
|
372
372
|
this.formatAndValidateFields(schemaFields, editedFields2),
|
|
373
373
|
this.validators(validators, action, builder),
|
|
374
374
|
]);
|
|
375
375
|
if (privacyError !== null) {
|
|
376
376
|
errors.unshift(privacyError);
|
|
377
377
|
}
|
|
378
|
+
errors.push(...errs2);
|
|
378
379
|
return errors;
|
|
379
380
|
}
|
|
380
381
|
async triggers(action, builder, triggers) {
|
|
@@ -420,16 +421,19 @@ class Orchestrator {
|
|
|
420
421
|
}
|
|
421
422
|
}
|
|
422
423
|
async validators(validators, action, builder) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
|
|
424
|
+
const errors = [];
|
|
425
|
+
await Promise.all(validators.map(async (v) => {
|
|
426
|
+
try {
|
|
427
|
+
const r = await v.validate(builder, action.getInput());
|
|
428
|
+
if (r instanceof Error) {
|
|
429
|
+
errors.push(r);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch (err) {
|
|
433
|
+
errors.push(err);
|
|
434
|
+
}
|
|
435
|
+
}));
|
|
436
|
+
return errors;
|
|
433
437
|
}
|
|
434
438
|
isBuilder(val) {
|
|
435
439
|
return val.placeholderID !== undefined;
|
package/core/clause.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export interface Clause {
|
|
|
4
4
|
values(): any[];
|
|
5
5
|
instanceKey(): string;
|
|
6
6
|
logValues(): any[];
|
|
7
|
+
compositeOp?: string;
|
|
7
8
|
}
|
|
8
9
|
export interface SensitiveValue {
|
|
9
10
|
value(): any;
|
|
@@ -37,6 +38,7 @@ export declare class inClause implements Clause {
|
|
|
37
38
|
declare class compositeClause implements Clause {
|
|
38
39
|
private clauses;
|
|
39
40
|
private sep;
|
|
41
|
+
compositeOp: string;
|
|
40
42
|
constructor(clauses: Clause[], sep: string);
|
|
41
43
|
clause(idx: number): string;
|
|
42
44
|
columns(): string[];
|
|
@@ -97,6 +99,7 @@ export declare function LessEq(col: string, value: any): simpleClause;
|
|
|
97
99
|
export declare function And(...args: Clause[]): compositeClause;
|
|
98
100
|
export declare function AndOptional(...args: (Clause | undefined)[]): Clause;
|
|
99
101
|
export declare function Or(...args: Clause[]): compositeClause;
|
|
102
|
+
export declare function OrOptional(...args: (Clause | undefined)[]): Clause;
|
|
100
103
|
export declare function In(col: string, ...values: any): Clause;
|
|
101
104
|
export declare function In(col: string, values: any[], type?: string): Clause;
|
|
102
105
|
interface TsQuery {
|
package/core/clause.js
CHANGED
|
@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
19
19
|
return result;
|
|
20
20
|
};
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.JSONPathValuePredicate = exports.JSONObjectFieldKeyAsText = exports.JSONObjectFieldKeyASJSON = exports.sensitiveValue = exports.TsVectorWebsearchToTsQuery = exports.TsVectorPhraseToTsQuery = exports.TsVectorPlainToTsQuery = exports.TsVectorColTsQuery = exports.WebsearchToTsQuery = exports.PhraseToTsQuery = exports.PlainToTsQuery = exports.TsQuery = exports.In = exports.Or = exports.AndOptional = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = exports.ArrayNotEq = exports.ArrayEq = exports.PostgresArrayNotOverlaps = exports.PostgresArrayOverlaps = exports.PostgresArrayNotContains = exports.PostgresArrayNotContainsValue = exports.PostgresArrayContains = exports.PostgresArrayContainsValue = exports.inClause = void 0;
|
|
22
|
+
exports.JSONPathValuePredicate = exports.JSONObjectFieldKeyAsText = exports.JSONObjectFieldKeyASJSON = exports.sensitiveValue = exports.TsVectorWebsearchToTsQuery = exports.TsVectorPhraseToTsQuery = exports.TsVectorPlainToTsQuery = exports.TsVectorColTsQuery = exports.WebsearchToTsQuery = exports.PhraseToTsQuery = exports.PlainToTsQuery = exports.TsQuery = exports.In = exports.OrOptional = exports.Or = exports.AndOptional = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = exports.ArrayNotEq = exports.ArrayEq = exports.PostgresArrayNotOverlaps = exports.PostgresArrayOverlaps = exports.PostgresArrayNotContains = exports.PostgresArrayNotContainsValue = exports.PostgresArrayContains = exports.PostgresArrayContainsValue = exports.inClause = void 0;
|
|
23
23
|
const db_1 = __importStar(require("./db"));
|
|
24
24
|
function isSensitive(val) {
|
|
25
25
|
return (val !== null &&
|
|
@@ -59,9 +59,9 @@ class simpleClause {
|
|
|
59
59
|
return [this.col];
|
|
60
60
|
}
|
|
61
61
|
values() {
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
return
|
|
62
|
+
const nullClause = this.nullClause();
|
|
63
|
+
if (nullClause) {
|
|
64
|
+
return nullClause.values();
|
|
65
65
|
}
|
|
66
66
|
if (isSensitive(this.value)) {
|
|
67
67
|
return [this.value.value()];
|
|
@@ -69,9 +69,9 @@ class simpleClause {
|
|
|
69
69
|
return [this.value];
|
|
70
70
|
}
|
|
71
71
|
logValues() {
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
74
|
-
return
|
|
72
|
+
const nullClause = this.nullClause();
|
|
73
|
+
if (nullClause) {
|
|
74
|
+
return nullClause.logValues();
|
|
75
75
|
}
|
|
76
76
|
if (isSensitive(this.value)) {
|
|
77
77
|
return [this.value.logValue()];
|
|
@@ -79,9 +79,9 @@ class simpleClause {
|
|
|
79
79
|
return [this.value];
|
|
80
80
|
}
|
|
81
81
|
instanceKey() {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
84
|
-
return
|
|
82
|
+
const nullClause = this.nullClause();
|
|
83
|
+
if (nullClause) {
|
|
84
|
+
return nullClause.instanceKey();
|
|
85
85
|
}
|
|
86
86
|
return `${this.col}${this.op}${rawValue(this.value)}`;
|
|
87
87
|
}
|
|
@@ -300,11 +300,17 @@ class compositeClause {
|
|
|
300
300
|
constructor(clauses, sep) {
|
|
301
301
|
this.clauses = clauses;
|
|
302
302
|
this.sep = sep;
|
|
303
|
+
this.compositeOp = this.sep;
|
|
303
304
|
}
|
|
304
305
|
clause(idx) {
|
|
305
306
|
let clauses = [];
|
|
306
307
|
for (const clause of this.clauses) {
|
|
307
|
-
|
|
308
|
+
let cls = clause.clause(idx);
|
|
309
|
+
// if composite clause and a different op, add parens so that we enforce order of precedence
|
|
310
|
+
if (clause.compositeOp && clause.compositeOp !== this.sep) {
|
|
311
|
+
cls = `(${cls})`;
|
|
312
|
+
}
|
|
313
|
+
clauses.push(cls);
|
|
308
314
|
idx = idx + clause.values().length;
|
|
309
315
|
}
|
|
310
316
|
return clauses.join(this.sep);
|
|
@@ -332,7 +338,14 @@ class compositeClause {
|
|
|
332
338
|
}
|
|
333
339
|
instanceKey() {
|
|
334
340
|
let keys = [];
|
|
335
|
-
this.clauses.forEach((clause) =>
|
|
341
|
+
this.clauses.forEach((clause) => {
|
|
342
|
+
if (clause.compositeOp && clause.compositeOp != this.sep) {
|
|
343
|
+
keys.push(`(${clause.instanceKey()})`);
|
|
344
|
+
}
|
|
345
|
+
else {
|
|
346
|
+
keys.push(clause.instanceKey());
|
|
347
|
+
}
|
|
348
|
+
});
|
|
336
349
|
return keys.join(this.sep);
|
|
337
350
|
}
|
|
338
351
|
}
|
|
@@ -513,6 +526,15 @@ function Or(...args) {
|
|
|
513
526
|
return new compositeClause(args, " OR ");
|
|
514
527
|
}
|
|
515
528
|
exports.Or = Or;
|
|
529
|
+
function OrOptional(...args) {
|
|
530
|
+
// @ts-ignore
|
|
531
|
+
let filtered = args.filter((v) => v !== undefined);
|
|
532
|
+
if (filtered.length === 1) {
|
|
533
|
+
return filtered[0];
|
|
534
|
+
}
|
|
535
|
+
return Or(...filtered);
|
|
536
|
+
}
|
|
537
|
+
exports.OrOptional = OrOptional;
|
|
516
538
|
function In(...args) {
|
|
517
539
|
if (args.length < 2) {
|
|
518
540
|
throw new Error(`invalid args passed to In`);
|
package/core/db.d.ts
CHANGED
package/core/ent.d.ts
CHANGED
|
@@ -229,6 +229,6 @@ interface loadEdgeForIDOptions<T extends AssocEdge> extends loadCustomEdgesOptio
|
|
|
229
229
|
export declare function loadEdgeForID2<T extends AssocEdge>(options: loadEdgeForIDOptions<T>): Promise<T | undefined>;
|
|
230
230
|
export declare function loadNodesByEdge<T extends Ent>(viewer: Viewer, id1: ID, edgeType: string, options: LoadEntOptions<T>): Promise<T[]>;
|
|
231
231
|
export declare function applyPrivacyPolicyForRow<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, row: Data): Promise<TEnt | null>;
|
|
232
|
-
export declare function applyPrivacyPolicyForRows<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, rows: Data[], options: LoadEntOptions<TEnt, TViewer>): Promise<
|
|
232
|
+
export declare function applyPrivacyPolicyForRows<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, rows: Data[], options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt[]>;
|
|
233
233
|
export declare function getEdgeTypeInGroup<T extends string>(viewer: Viewer, id1: ID, id2: ID, m: Map<T, string>): Promise<[T, AssocEdge] | undefined>;
|
|
234
234
|
export {};
|
package/core/ent.js
CHANGED
|
@@ -196,6 +196,11 @@ function getEntKey(viewer, id, options) {
|
|
|
196
196
|
}
|
|
197
197
|
exports.getEntKey = getEntKey;
|
|
198
198
|
async function loadEnt(viewer, id, options) {
|
|
199
|
+
if (typeof id !== "string" &&
|
|
200
|
+
typeof id !== "number" &&
|
|
201
|
+
typeof id !== "bigint") {
|
|
202
|
+
throw new Error(`invalid id ${id} passed to loadEnt`);
|
|
203
|
+
}
|
|
199
204
|
const r = await getEntLoader(viewer, options).load(id);
|
|
200
205
|
return r instanceof ErrorWrapper ? null : r;
|
|
201
206
|
}
|
|
@@ -239,6 +244,11 @@ async function loadEntViaKey(viewer, key, options) {
|
|
|
239
244
|
}
|
|
240
245
|
exports.loadEntViaKey = loadEntViaKey;
|
|
241
246
|
async function loadEntX(viewer, id, options) {
|
|
247
|
+
if (typeof id !== "string" &&
|
|
248
|
+
typeof id !== "number" &&
|
|
249
|
+
typeof id !== "bigint") {
|
|
250
|
+
throw new Error(`invalid id ${id} passed to loadEntX`);
|
|
251
|
+
}
|
|
242
252
|
const r = await getEntLoader(viewer, options).load(id);
|
|
243
253
|
if (r instanceof ErrorWrapper) {
|
|
244
254
|
throw r.error;
|
|
@@ -338,25 +348,12 @@ async function loadEntsFromClause(viewer, clause, options) {
|
|
|
338
348
|
context: viewer.context,
|
|
339
349
|
};
|
|
340
350
|
const rows = await loadRows(rowOptions);
|
|
341
|
-
return
|
|
351
|
+
return applyPrivacyPolicyForRowsDeprecated(viewer, rows, options);
|
|
342
352
|
}
|
|
343
353
|
exports.loadEntsFromClause = loadEntsFromClause;
|
|
344
354
|
async function loadCustomEnts(viewer, options, query) {
|
|
345
355
|
const rows = await loadCustomData(options, query, viewer.context);
|
|
346
|
-
|
|
347
|
-
if (!rows.length) {
|
|
348
|
-
return [];
|
|
349
|
-
}
|
|
350
|
-
const entLoader = getEntLoader(viewer, options);
|
|
351
|
-
await Promise.all(rows.map(async (row, idx) => {
|
|
352
|
-
const r = await applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options, entLoader);
|
|
353
|
-
if (r instanceof ErrorWrapper) {
|
|
354
|
-
return;
|
|
355
|
-
}
|
|
356
|
-
result[idx] = r;
|
|
357
|
-
}));
|
|
358
|
-
// filter ents that aren't visible because of privacy
|
|
359
|
-
return result.filter((r) => r !== undefined);
|
|
356
|
+
return applyPrivacyPolicyForRows(viewer, rows, options);
|
|
360
357
|
}
|
|
361
358
|
exports.loadCustomEnts = loadCustomEnts;
|
|
362
359
|
function isClause(opts) {
|
|
@@ -1540,10 +1537,8 @@ async function applyPrivacyPolicyForRowX(viewer, options, row) {
|
|
|
1540
1537
|
const ent = new options.ent(viewer, row);
|
|
1541
1538
|
return await applyPrivacyPolicyForEntX(viewer, ent, row, options);
|
|
1542
1539
|
}
|
|
1543
|
-
//
|
|
1544
|
-
|
|
1545
|
-
// custom_query is one that should be updated
|
|
1546
|
-
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1540
|
+
// deprecated. doesn't use entcache
|
|
1541
|
+
async function applyPrivacyPolicyForRowsDeprecated(viewer, rows, options) {
|
|
1547
1542
|
let m = new Map();
|
|
1548
1543
|
// apply privacy logic
|
|
1549
1544
|
await Promise.all(rows.map(async (row) => {
|
|
@@ -1554,6 +1549,22 @@ async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
|
1554
1549
|
}));
|
|
1555
1550
|
return m;
|
|
1556
1551
|
}
|
|
1552
|
+
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1553
|
+
const result = new Array(rows.length);
|
|
1554
|
+
if (!rows.length) {
|
|
1555
|
+
return [];
|
|
1556
|
+
}
|
|
1557
|
+
const entLoader = getEntLoader(viewer, options);
|
|
1558
|
+
await Promise.all(rows.map(async (row, idx) => {
|
|
1559
|
+
const r = await applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options, entLoader);
|
|
1560
|
+
if (r instanceof ErrorWrapper) {
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
result[idx] = r;
|
|
1564
|
+
}));
|
|
1565
|
+
// filter ents that aren't visible because of privacy
|
|
1566
|
+
return result.filter((r) => r !== undefined);
|
|
1567
|
+
}
|
|
1557
1568
|
exports.applyPrivacyPolicyForRows = applyPrivacyPolicyForRows;
|
|
1558
1569
|
async function loadEdgeWithConst(viewer, id1, id2, edgeEnum, edgeType) {
|
|
1559
1570
|
const edge = await loadEdgeForID2({
|
package/core/loaders/index.d.ts
CHANGED
|
@@ -3,4 +3,4 @@ export { RawCountLoader, RawCountLoaderFactory } from "./raw_count_loader";
|
|
|
3
3
|
export { AssocEdgeCountLoader, AssocEdgeCountLoaderFactory, } from "./assoc_count_loader";
|
|
4
4
|
export { AssocDirectEdgeLoader, AssocEdgeLoader, AssocEdgeLoaderFactory, } from "./assoc_edge_loader";
|
|
5
5
|
export { IndexLoaderFactory } from "./index_loader";
|
|
6
|
-
export {
|
|
6
|
+
export { QueryLoaderFactory } from "./query_loader";
|
package/core/loaders/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.QueryLoaderFactory = exports.
|
|
3
|
+
exports.QueryLoaderFactory = exports.IndexLoaderFactory = exports.AssocEdgeLoaderFactory = exports.AssocEdgeLoader = exports.AssocDirectEdgeLoader = exports.AssocEdgeCountLoaderFactory = exports.AssocEdgeCountLoader = exports.RawCountLoaderFactory = exports.RawCountLoader = exports.ObjectLoaderFactory = exports.ObjectLoader = void 0;
|
|
4
4
|
var object_loader_1 = require("./object_loader");
|
|
5
5
|
Object.defineProperty(exports, "ObjectLoader", { enumerable: true, get: function () { return object_loader_1.ObjectLoader; } });
|
|
6
6
|
Object.defineProperty(exports, "ObjectLoaderFactory", { enumerable: true, get: function () { return object_loader_1.ObjectLoaderFactory; } });
|
|
@@ -17,6 +17,4 @@ Object.defineProperty(exports, "AssocEdgeLoaderFactory", { enumerable: true, get
|
|
|
17
17
|
var index_loader_1 = require("./index_loader");
|
|
18
18
|
Object.defineProperty(exports, "IndexLoaderFactory", { enumerable: true, get: function () { return index_loader_1.IndexLoaderFactory; } });
|
|
19
19
|
var query_loader_1 = require("./query_loader");
|
|
20
|
-
Object.defineProperty(exports, "QueryLoader", { enumerable: true, get: function () { return query_loader_1.QueryLoader; } });
|
|
21
|
-
Object.defineProperty(exports, "QueryDirectLoader", { enumerable: true, get: function () { return query_loader_1.QueryDirectLoader; } });
|
|
22
20
|
Object.defineProperty(exports, "QueryLoaderFactory", { enumerable: true, get: function () { return query_loader_1.QueryLoaderFactory; } });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ID, SelectBaseDataOptions, Context, Data, LoaderFactory, EdgeQueryableDataOptions } from "../base";
|
|
1
|
+
import { ID, SelectBaseDataOptions, Context, Data, LoaderFactory, EdgeQueryableDataOptions, Loader } from "../base";
|
|
2
2
|
import * as clause from "../clause";
|
|
3
3
|
import { ObjectLoaderFactory } from "./object_loader";
|
|
4
4
|
export declare class IndexLoaderFactory implements LoaderFactory<ID, Data[]> {
|
|
@@ -10,5 +10,5 @@ export declare class IndexLoaderFactory implements LoaderFactory<ID, Data[]> {
|
|
|
10
10
|
toPrime?: ObjectLoaderFactory<ID>[];
|
|
11
11
|
});
|
|
12
12
|
createLoader(context?: Context): any;
|
|
13
|
-
createConfigurableLoader(options: EdgeQueryableDataOptions, context?: Context):
|
|
13
|
+
createConfigurableLoader(options: EdgeQueryableDataOptions, context?: Context): Loader<ID, Data[]>;
|
|
14
14
|
}
|
|
@@ -1,21 +1,14 @@
|
|
|
1
1
|
import { Context, ID, EdgeQueryableDataOptions, Loader, LoaderFactory, Data } from "../base";
|
|
2
2
|
import * as clause from "../clause";
|
|
3
3
|
import { ObjectLoaderFactory } from "./object_loader";
|
|
4
|
-
export declare
|
|
4
|
+
export declare function getOrderBy(sortCol: string, orderby?: string): string;
|
|
5
|
+
declare class QueryDirectLoader<K extends any> implements Loader<K, Data[]> {
|
|
5
6
|
private options;
|
|
6
7
|
private queryOptions?;
|
|
7
|
-
constructor(options: QueryOptions, queryOptions?: Partial<Pick<import("../base").QueryableDataOptions, "limit" | "orderby" | "clause">> | undefined);
|
|
8
|
-
load(id: K): Promise<Data[]>;
|
|
9
|
-
clearAll(): void;
|
|
10
|
-
}
|
|
11
|
-
export declare class QueryLoader<K extends any> implements Loader<K, Data[]> {
|
|
12
|
-
private options;
|
|
13
8
|
context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined;
|
|
14
|
-
private queryOptions?;
|
|
15
|
-
private loader;
|
|
16
|
-
private primedLoaders;
|
|
17
9
|
private memoizedInitPrime;
|
|
18
|
-
|
|
10
|
+
private primedLoaders;
|
|
11
|
+
constructor(options: QueryOptions, queryOptions?: Partial<Pick<import("../base").QueryableDataOptions, "limit" | "orderby" | "clause">> | undefined, context?: Context<import("../base").Viewer<import("../base").Ent<any> | null, ID | null>> | undefined);
|
|
19
12
|
private initPrime;
|
|
20
13
|
load(id: K): Promise<Data[]>;
|
|
21
14
|
clearAll(): void;
|
|
@@ -34,5 +27,6 @@ export declare class QueryLoaderFactory<K extends any> implements LoaderFactory<
|
|
|
34
27
|
constructor(options: QueryOptions);
|
|
35
28
|
createLoader(context?: Context): any;
|
|
36
29
|
createConfigurableLoader(options: EdgeQueryableDataOptions, context?: Context): Loader<unknown, Data[]> | QueryDirectLoader<unknown>;
|
|
30
|
+
static createConfigurableLoader(name: string, queryOptions: QueryOptions, options: EdgeQueryableDataOptions, context?: Context): Loader<unknown, Data[]> | QueryDirectLoader<unknown>;
|
|
37
31
|
}
|
|
38
32
|
export {};
|
|
@@ -22,7 +22,7 @@ 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.QueryLoaderFactory = exports.
|
|
25
|
+
exports.QueryLoaderFactory = exports.getOrderBy = void 0;
|
|
26
26
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
27
27
|
const ent_1 = require("../ent");
|
|
28
28
|
const clause = __importStar(require("../clause"));
|
|
@@ -30,13 +30,17 @@ const logger_1 = require("../logger");
|
|
|
30
30
|
const loader_1 = require("./loader");
|
|
31
31
|
const memoizee_1 = __importDefault(require("memoizee"));
|
|
32
32
|
function getOrderBy(sortCol, orderby) {
|
|
33
|
+
if (orderby) {
|
|
34
|
+
return orderby;
|
|
35
|
+
}
|
|
33
36
|
let sortColLower = sortCol.toLowerCase();
|
|
34
37
|
let orderbyDirection = " DESC";
|
|
35
38
|
if (sortColLower.endsWith("asc") || sortCol.endsWith("desc")) {
|
|
36
39
|
orderbyDirection = "";
|
|
37
40
|
}
|
|
38
|
-
return
|
|
41
|
+
return `${sortCol}${orderbyDirection}`;
|
|
39
42
|
}
|
|
43
|
+
exports.getOrderBy = getOrderBy;
|
|
40
44
|
async function simpleCase(options, id, queryOptions) {
|
|
41
45
|
let cls;
|
|
42
46
|
if (options.groupCol) {
|
|
@@ -120,16 +124,47 @@ function createLoader(options, queryOptions) {
|
|
|
120
124
|
}, loaderOptions);
|
|
121
125
|
}
|
|
122
126
|
class QueryDirectLoader {
|
|
123
|
-
constructor(options, queryOptions) {
|
|
127
|
+
constructor(options, queryOptions, context) {
|
|
124
128
|
this.options = options;
|
|
125
129
|
this.queryOptions = queryOptions;
|
|
130
|
+
this.context = context;
|
|
131
|
+
this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
|
|
132
|
+
}
|
|
133
|
+
initPrime() {
|
|
134
|
+
if (!this.context || !this.options?.toPrime) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
let primedLoaders = new Map();
|
|
138
|
+
this.options.toPrime.forEach((prime) => {
|
|
139
|
+
const l2 = prime.createLoader(this.context);
|
|
140
|
+
if (l2.prime === undefined) {
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
primedLoaders.set(prime.options.key, l2);
|
|
144
|
+
});
|
|
145
|
+
this.primedLoaders = primedLoaders;
|
|
126
146
|
}
|
|
127
147
|
async load(id) {
|
|
128
|
-
|
|
148
|
+
const rows = await simpleCase(this.options, id, this.queryOptions);
|
|
149
|
+
if (this.context) {
|
|
150
|
+
this.memoizedInitPrime();
|
|
151
|
+
if (this.primedLoaders) {
|
|
152
|
+
for (const row of rows) {
|
|
153
|
+
for (const [key, loader] of this.primedLoaders) {
|
|
154
|
+
const value = row[key];
|
|
155
|
+
if (value !== undefined) {
|
|
156
|
+
loader.prime(row);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return rows;
|
|
129
163
|
}
|
|
130
164
|
clearAll() { }
|
|
131
165
|
}
|
|
132
|
-
|
|
166
|
+
// note, you should never call this directly
|
|
167
|
+
// there's scenarios where QueryDirectLoader is needed instead of this...
|
|
133
168
|
class QueryLoader {
|
|
134
169
|
constructor(options, context, queryOptions) {
|
|
135
170
|
this.options = options;
|
|
@@ -176,7 +211,6 @@ class QueryLoader {
|
|
|
176
211
|
this.loader && this.loader.clearAll();
|
|
177
212
|
}
|
|
178
213
|
}
|
|
179
|
-
exports.QueryLoader = QueryLoader;
|
|
180
214
|
class QueryLoaderFactory {
|
|
181
215
|
constructor(options) {
|
|
182
216
|
this.options = options;
|
|
@@ -194,11 +228,14 @@ class QueryLoaderFactory {
|
|
|
194
228
|
return (0, loader_1.getLoader)(this, () => new QueryLoader(this.options, context), context);
|
|
195
229
|
}
|
|
196
230
|
createConfigurableLoader(options, context) {
|
|
197
|
-
|
|
198
|
-
|
|
231
|
+
return QueryLoaderFactory.createConfigurableLoader(this.name, this.options, options, context);
|
|
232
|
+
}
|
|
233
|
+
static createConfigurableLoader(name, queryOptions, options, context) {
|
|
234
|
+
if (options.clause || !context) {
|
|
235
|
+
return new QueryDirectLoader(queryOptions, options, context);
|
|
199
236
|
}
|
|
200
|
-
const key = `${
|
|
201
|
-
return (0, loader_1.getCustomLoader)(key, () => new QueryLoader(
|
|
237
|
+
const key = `${name}:limit:${options.limit}:orderby:${options.orderby}`;
|
|
238
|
+
return (0, loader_1.getCustomLoader)(key, () => new QueryLoader(queryOptions, context, options), context);
|
|
202
239
|
}
|
|
203
240
|
}
|
|
204
241
|
exports.QueryLoaderFactory = QueryLoaderFactory;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Data, EdgeQueryableDataOptions, Ent, ID, LoadEntOptions, Viewer } from "../base";
|
|
2
|
+
import { Clause } from "../clause";
|
|
3
|
+
import { BaseEdgeQuery, IDInfo } from "./query";
|
|
4
|
+
interface CustomClauseQueryOptions<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
|
|
5
|
+
loadEntOptions: LoadEntOptions<TDest, TViewer>;
|
|
6
|
+
clause: Clause;
|
|
7
|
+
name: string;
|
|
8
|
+
sortColumn?: string;
|
|
9
|
+
disableTransformations?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare class CustomClauseQuery<TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> extends BaseEdgeQuery<any, TDest, Data> {
|
|
12
|
+
viewer: TViewer;
|
|
13
|
+
private options;
|
|
14
|
+
private clause;
|
|
15
|
+
constructor(viewer: TViewer, options: CustomClauseQueryOptions<TDest, TViewer>);
|
|
16
|
+
sourceEnt(_id: ID): Promise<null>;
|
|
17
|
+
queryRawCount(): Promise<number>;
|
|
18
|
+
queryAllRawCount(): Promise<Map<ID, number>>;
|
|
19
|
+
protected loadRawIDs(_addID: (src: ID) => void): Promise<void>;
|
|
20
|
+
protected loadRawData(_infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
|
|
21
|
+
dataToID(edge: Data): ID;
|
|
22
|
+
protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CustomClauseQuery = void 0;
|
|
4
|
+
const clause_1 = require("../clause");
|
|
5
|
+
const ent_1 = require("../ent");
|
|
6
|
+
const query_loader_1 = require("../loaders/query_loader");
|
|
7
|
+
const query_1 = require("./query");
|
|
8
|
+
function getClause(opts) {
|
|
9
|
+
let cls = opts.clause;
|
|
10
|
+
if (opts.disableTransformations) {
|
|
11
|
+
return cls;
|
|
12
|
+
}
|
|
13
|
+
let optClause = opts.loadEntOptions.loaderFactory?.options?.clause;
|
|
14
|
+
if (typeof optClause === "function") {
|
|
15
|
+
optClause = optClause();
|
|
16
|
+
}
|
|
17
|
+
if (!optClause) {
|
|
18
|
+
return cls;
|
|
19
|
+
}
|
|
20
|
+
return (0, clause_1.AndOptional)(cls, optClause);
|
|
21
|
+
}
|
|
22
|
+
class CustomClauseQuery extends query_1.BaseEdgeQuery {
|
|
23
|
+
constructor(viewer, options) {
|
|
24
|
+
super(viewer, options.sortColumn || "created_at");
|
|
25
|
+
this.viewer = viewer;
|
|
26
|
+
this.options = options;
|
|
27
|
+
this.clause = getClause(options);
|
|
28
|
+
}
|
|
29
|
+
async sourceEnt(_id) {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
async queryRawCount() {
|
|
33
|
+
const row = await (0, ent_1.loadRow)({
|
|
34
|
+
tableName: this.options.loadEntOptions.tableName,
|
|
35
|
+
// sqlite needs as count otherwise it returns count(1)
|
|
36
|
+
fields: ["count(1) as count"],
|
|
37
|
+
clause: this.clause,
|
|
38
|
+
context: this.viewer.context,
|
|
39
|
+
});
|
|
40
|
+
return parseInt(row?.count, 10) || 0;
|
|
41
|
+
}
|
|
42
|
+
async queryAllRawCount() {
|
|
43
|
+
throw new Error(`queryAllRawCount doesn't make sense in CustomClauseQuery`);
|
|
44
|
+
}
|
|
45
|
+
// nothing to do here
|
|
46
|
+
async loadRawIDs(_addID) { }
|
|
47
|
+
async loadRawData(_infos, options) {
|
|
48
|
+
if (!options.orderby) {
|
|
49
|
+
options.orderby = `${this.options.sortColumn} DESC`;
|
|
50
|
+
}
|
|
51
|
+
if (!options.limit) {
|
|
52
|
+
options.limit = ent_1.DefaultLimit;
|
|
53
|
+
}
|
|
54
|
+
let sortCol = this.options.sortColumn || "created_at";
|
|
55
|
+
const rows = await (0, ent_1.loadRows)({
|
|
56
|
+
tableName: this.options.loadEntOptions.tableName,
|
|
57
|
+
fields: this.options.loadEntOptions.fields,
|
|
58
|
+
clause: (0, clause_1.AndOptional)(this.clause, options.clause),
|
|
59
|
+
orderby: (0, query_loader_1.getOrderBy)(sortCol, options?.orderby),
|
|
60
|
+
limit: options?.limit || ent_1.DefaultLimit,
|
|
61
|
+
context: this.viewer.context,
|
|
62
|
+
});
|
|
63
|
+
this.edges.set(1, rows);
|
|
64
|
+
}
|
|
65
|
+
dataToID(edge) {
|
|
66
|
+
return edge.id;
|
|
67
|
+
}
|
|
68
|
+
async loadEntsFromEdges(id, rows) {
|
|
69
|
+
return (0, ent_1.applyPrivacyPolicyForRows)(this.viewer, rows, this.options.loadEntOptions);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
exports.CustomClauseQuery = CustomClauseQuery;
|
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
import { Data, Ent, ID, EdgeQueryableDataOptions, LoadEntOptions, Viewer, LoaderFactory, ConfigurableLoaderFactory } from "../base";
|
|
2
|
+
import { Clause } from "../clause";
|
|
2
3
|
import { BaseEdgeQuery, IDInfo, EdgeQuery } from "./query";
|
|
3
|
-
export interface
|
|
4
|
+
export interface CustomEdgeQueryOptionsDeprecated<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
|
|
4
5
|
src: TSource | ID;
|
|
5
6
|
countLoaderFactory: LoaderFactory<ID, number>;
|
|
6
7
|
dataLoaderFactory: ConfigurableLoaderFactory<ID, Data[]>;
|
|
7
8
|
options: LoadEntOptions<TDest, TViewer>;
|
|
8
9
|
sortColumn?: string;
|
|
9
10
|
}
|
|
11
|
+
export interface CustomEdgeQueryOptions<TSource extends Ent<TViewer>, TDest extends Ent<TViewer>, TViewer extends Viewer = Viewer> {
|
|
12
|
+
src: TSource | ID;
|
|
13
|
+
loadEntOptions: LoadEntOptions<TDest, TViewer>;
|
|
14
|
+
groupCol?: string;
|
|
15
|
+
clause?: Clause;
|
|
16
|
+
name: string;
|
|
17
|
+
sortColumn?: string;
|
|
18
|
+
disableTransformations?: boolean;
|
|
19
|
+
}
|
|
10
20
|
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> {
|
|
11
21
|
viewer: TViewer;
|
|
12
22
|
private options;
|
|
13
23
|
private id;
|
|
14
|
-
|
|
24
|
+
private opts;
|
|
25
|
+
constructor(viewer: TViewer, options: CustomEdgeQueryOptionsDeprecated<TSource, TDest, TViewer> | CustomEdgeQueryOptions<TSource, TDest, TViewer>);
|
|
15
26
|
abstract sourceEnt(id: ID): Promise<Ent | null>;
|
|
16
27
|
private idVisible;
|
|
28
|
+
private isDeprecatedOptions;
|
|
29
|
+
private getCountLoader;
|
|
30
|
+
private getQueryLoader;
|
|
17
31
|
queryRawCount(): Promise<number>;
|
|
18
32
|
queryAllRawCount(): Promise<Map<ID, number>>;
|
|
19
33
|
protected loadRawIDs(addID: (src: ID | TSource) => void): Promise<void>;
|
|
34
|
+
private getLoadEntOptions;
|
|
20
35
|
protected loadRawData(infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
|
|
21
36
|
dataToID(edge: Data): ID;
|
|
22
37
|
protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
|