@snowtop/ent 0.0.22 → 0.0.28-alpha
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/executor.d.ts +3 -3
- package/action/orchestrator.d.ts +9 -4
- package/action/orchestrator.js +70 -30
- package/core/base.js +12 -9
- package/core/config.d.ts +2 -0
- package/core/convert.js +2 -1
- package/core/privacy.d.ts +21 -1
- package/core/privacy.js +45 -1
- package/core/query/assoc_query.d.ts +10 -12
- package/core/query/assoc_query.js +52 -49
- package/core/query/custom_query.d.ts +10 -7
- package/core/query/custom_query.js +28 -2
- package/core/query/query.d.ts +19 -3
- package/core/query/query.js +39 -2
- package/core/query/shared_assoc_test.js +104 -0
- package/core/viewer.js +1 -0
- package/imports/index.d.ts +1 -1
- package/imports/index.js +3 -5
- package/index.d.ts +1 -1
- package/index.js +5 -2
- package/package.json +3 -5
- package/schema/field.d.ts +28 -14
- package/schema/field.js +46 -6
- package/scripts/custom_graphql.js +28 -8
- package/testutils/builder.d.ts +1 -0
- package/testutils/builder.js +1 -0
- package/testutils/fake_data/events_query.d.ts +16 -11
- package/testutils/fake_data/events_query.js +15 -0
- package/testutils/fake_data/test_helpers.d.ts +5 -1
- package/testutils/fake_data/test_helpers.js +35 -1
- package/testutils/fake_data/user_query.d.ts +22 -10
- package/testutils/fake_data/user_query.js +37 -0
package/action/executor.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ID, Ent, Viewer, EntConstructor, Context } from "../core/base";
|
|
1
|
+
import { ID, Data, Ent, Viewer, EntConstructor, Context } from "../core/base";
|
|
2
2
|
import { DataOperation } from "../core/ent";
|
|
3
3
|
import { Changeset, Executor } from "../action";
|
|
4
4
|
import { Builder } from "../action";
|
|
@@ -11,7 +11,7 @@ export declare class ListBasedExecutor<T extends Ent> implements Executor {
|
|
|
11
11
|
private operations;
|
|
12
12
|
private options?;
|
|
13
13
|
private idx;
|
|
14
|
-
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], options?: OrchestratorOptions<T> | undefined);
|
|
14
|
+
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], options?: OrchestratorOptions<T, Data> | undefined);
|
|
15
15
|
private lastOp;
|
|
16
16
|
private createdEnt;
|
|
17
17
|
resolveValue(val: ID): Ent | null;
|
|
@@ -34,7 +34,7 @@ export declare class ComplexExecutor<T extends Ent> implements Executor {
|
|
|
34
34
|
private changesetMap;
|
|
35
35
|
private nodeOpMap;
|
|
36
36
|
private executors;
|
|
37
|
-
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset<T>[], options?: OrchestratorOptions<T> | undefined);
|
|
37
|
+
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset<T>[], options?: OrchestratorOptions<T, Data> | undefined);
|
|
38
38
|
[Symbol.iterator](): this;
|
|
39
39
|
private handleCreatedEnt;
|
|
40
40
|
next(): IteratorResult<DataOperation>;
|
package/action/orchestrator.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { AssocEdgeInputOptions, DataOperation } from "../core/ent";
|
|
|
3
3
|
import { SchemaInputType } from "../schema/schema";
|
|
4
4
|
import { Changeset, Executor } from "../action";
|
|
5
5
|
import { WriteOperation, Builder, Action } from "../action";
|
|
6
|
-
export interface OrchestratorOptions<T extends Ent> {
|
|
6
|
+
export interface OrchestratorOptions<T extends Ent, TData extends Data> {
|
|
7
7
|
viewer: Viewer;
|
|
8
8
|
operation: WriteOperation;
|
|
9
9
|
tableName: string;
|
|
@@ -13,6 +13,7 @@ export interface OrchestratorOptions<T extends Ent> {
|
|
|
13
13
|
action?: Action<T>;
|
|
14
14
|
schema: SchemaInputType;
|
|
15
15
|
editedFields(): Map<string, any>;
|
|
16
|
+
updateInput?: (data: TData) => void;
|
|
16
17
|
}
|
|
17
18
|
interface edgeInputDataOpts {
|
|
18
19
|
edgeType: string;
|
|
@@ -38,7 +39,9 @@ export declare class Orchestrator<T extends Ent> {
|
|
|
38
39
|
private fieldsToResolve;
|
|
39
40
|
private mainOp;
|
|
40
41
|
viewer: Viewer;
|
|
41
|
-
|
|
42
|
+
private defaultFieldsByFieldName;
|
|
43
|
+
private defaultFieldsByTSName;
|
|
44
|
+
constructor(options: OrchestratorOptions<T, Data>);
|
|
42
45
|
private addEdge;
|
|
43
46
|
addInboundEdge<T2 extends Ent>(id1: ID | Builder<T2>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
|
|
44
47
|
addOutboundEdge<T2 extends Ent>(id2: ID | Builder<T2>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
|
|
@@ -50,11 +53,13 @@ export declare class Orchestrator<T extends Ent> {
|
|
|
50
53
|
private getEdgeOperation;
|
|
51
54
|
private buildEdgeOps;
|
|
52
55
|
private throwError;
|
|
56
|
+
private getEntForPrivacyPolicy;
|
|
53
57
|
private validate;
|
|
54
58
|
private triggers;
|
|
55
59
|
private validators;
|
|
56
60
|
private isBuilder;
|
|
57
|
-
private
|
|
61
|
+
private getFieldsWithDefaultValues;
|
|
62
|
+
private formatAndValidateFields;
|
|
58
63
|
valid(): Promise<boolean>;
|
|
59
64
|
validX(): Promise<void>;
|
|
60
65
|
build(): Promise<EntChangeset<T>>;
|
|
@@ -71,7 +76,7 @@ export declare class EntChangeset<T extends Ent> implements Changeset<T> {
|
|
|
71
76
|
dependencies?: Map<ID, Builder<T>> | undefined;
|
|
72
77
|
changesets?: Changeset<Ent>[] | undefined;
|
|
73
78
|
private options?;
|
|
74
|
-
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<T>> | undefined, changesets?: Changeset<Ent>[] | undefined, options?: OrchestratorOptions<T> | undefined);
|
|
79
|
+
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<T>> | undefined, changesets?: Changeset<Ent>[] | undefined, options?: OrchestratorOptions<T, Data> | undefined);
|
|
75
80
|
executor(): Executor;
|
|
76
81
|
}
|
|
77
82
|
export {};
|
package/action/orchestrator.js
CHANGED
|
@@ -5,6 +5,7 @@ const ent_1 = require("../core/ent");
|
|
|
5
5
|
const schema_1 = require("../schema/schema");
|
|
6
6
|
const action_1 = require("../action");
|
|
7
7
|
const snake_case_1 = require("snake-case");
|
|
8
|
+
const camel_case_1 = require("camel-case");
|
|
8
9
|
const privacy_1 = require("../core/privacy");
|
|
9
10
|
const executor_1 = require("./executor");
|
|
10
11
|
const logger_1 = require("../core/logger");
|
|
@@ -58,6 +59,8 @@ class Orchestrator {
|
|
|
58
59
|
this.changesets = [];
|
|
59
60
|
this.dependencies = new Map();
|
|
60
61
|
this.fieldsToResolve = [];
|
|
62
|
+
this.defaultFieldsByFieldName = {};
|
|
63
|
+
this.defaultFieldsByTSName = {};
|
|
61
64
|
this.viewer = options.viewer;
|
|
62
65
|
}
|
|
63
66
|
addEdge(edge, op) {
|
|
@@ -222,16 +225,35 @@ class Orchestrator {
|
|
|
222
225
|
}
|
|
223
226
|
return new EntCannotDeleteEntError(privacyPolicy, action, this.options.builder.existingEnt);
|
|
224
227
|
}
|
|
228
|
+
getEntForPrivacyPolicy(editedData) {
|
|
229
|
+
if (this.options.operation !== action_1.WriteOperation.Insert) {
|
|
230
|
+
return this.options.builder.existingEnt;
|
|
231
|
+
}
|
|
232
|
+
// we create an unsafe ent to be used for privacy policies
|
|
233
|
+
return new this.options.builder.ent(this.options.builder.viewer, editedData);
|
|
234
|
+
}
|
|
225
235
|
async validate() {
|
|
236
|
+
// existing ent required for edit or delete operations
|
|
237
|
+
switch (this.options.operation) {
|
|
238
|
+
case action_1.WriteOperation.Delete:
|
|
239
|
+
case action_1.WriteOperation.Edit:
|
|
240
|
+
if (!this.options.builder.existingEnt) {
|
|
241
|
+
throw new Error("existing ent required with operation");
|
|
242
|
+
}
|
|
243
|
+
}
|
|
226
244
|
const action = this.options.action;
|
|
227
245
|
const builder = this.options.builder;
|
|
228
|
-
//
|
|
229
|
-
|
|
246
|
+
// future optimization: can get schemaFields to memoize based on different values
|
|
247
|
+
const schemaFields = (0, schema_1.getFields)(this.options.schema);
|
|
248
|
+
let editedData = this.getFieldsWithDefaultValues(builder, schemaFields, action);
|
|
249
|
+
// this runs in following phases:
|
|
250
|
+
// * set default fields and pass to builder so the value can be checked by triggers/observers/validators
|
|
251
|
+
// * privacy policy (use unsafe ent if we have it)
|
|
230
252
|
// * triggers
|
|
231
253
|
// * validators
|
|
232
254
|
let privacyPolicy = action?.getPrivacyPolicy();
|
|
233
255
|
if (privacyPolicy) {
|
|
234
|
-
await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy,
|
|
256
|
+
await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, this.getEntForPrivacyPolicy(editedData), this.throwError.bind(this));
|
|
235
257
|
}
|
|
236
258
|
// have to run triggers which update fields first before field and other validators
|
|
237
259
|
// so running this first to build things up
|
|
@@ -241,7 +263,7 @@ class Orchestrator {
|
|
|
241
263
|
}
|
|
242
264
|
let validators = action?.validators || [];
|
|
243
265
|
await Promise.all([
|
|
244
|
-
this.
|
|
266
|
+
this.formatAndValidateFields(schemaFields),
|
|
245
267
|
this.validators(validators, action, builder),
|
|
246
268
|
]);
|
|
247
269
|
}
|
|
@@ -276,29 +298,14 @@ class Orchestrator {
|
|
|
276
298
|
isBuilder(val) {
|
|
277
299
|
return val.placeholderID !== undefined;
|
|
278
300
|
}
|
|
279
|
-
|
|
280
|
-
// existing ent required for edit or delete operations
|
|
281
|
-
switch (this.options.operation) {
|
|
282
|
-
case action_1.WriteOperation.Delete:
|
|
283
|
-
case action_1.WriteOperation.Edit:
|
|
284
|
-
if (!this.options.builder.existingEnt) {
|
|
285
|
-
throw new Error("existing ent required with operation");
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
if (this.options.operation == action_1.WriteOperation.Delete) {
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
301
|
+
getFieldsWithDefaultValues(builder, schemaFields, action) {
|
|
291
302
|
const editedFields = this.options.editedFields();
|
|
292
|
-
// build up data to be saved...
|
|
293
303
|
let data = {};
|
|
294
|
-
let
|
|
295
|
-
|
|
296
|
-
let input = {};
|
|
297
|
-
if (action !== undefined) {
|
|
298
|
-
input = action.getInput();
|
|
299
|
-
}
|
|
304
|
+
let input = action?.getInput() || {};
|
|
305
|
+
let updateInput = false;
|
|
300
306
|
for (const [fieldName, field] of schemaFields) {
|
|
301
307
|
let value = editedFields.get(fieldName);
|
|
308
|
+
let defaultValue = undefined;
|
|
302
309
|
let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
|
|
303
310
|
if (value === undefined) {
|
|
304
311
|
if (this.options.operation === action_1.WriteOperation.Insert) {
|
|
@@ -306,18 +313,52 @@ class Orchestrator {
|
|
|
306
313
|
throw new Error(`cannot set both defaultToViewerOnCreate and defaultValueOnCreate`);
|
|
307
314
|
}
|
|
308
315
|
if (field.defaultToViewerOnCreate) {
|
|
309
|
-
|
|
316
|
+
defaultValue = builder.viewer.viewerID;
|
|
310
317
|
}
|
|
311
318
|
if (field.defaultValueOnCreate) {
|
|
312
|
-
|
|
319
|
+
defaultValue = field.defaultValueOnCreate(builder, input);
|
|
320
|
+
if (defaultValue === undefined) {
|
|
321
|
+
throw new Error(`defaultValueOnCreate() returned undefined for field ${field.name}`);
|
|
322
|
+
}
|
|
313
323
|
}
|
|
314
324
|
}
|
|
315
325
|
if (field.defaultValueOnEdit &&
|
|
316
326
|
this.options.operation === action_1.WriteOperation.Edit) {
|
|
317
|
-
|
|
318
|
-
// TODO special case this if this is the
|
|
327
|
+
defaultValue = field.defaultValueOnEdit(builder, input);
|
|
328
|
+
// TODO special case this if this is the only thing changing and don't do the write.
|
|
319
329
|
}
|
|
320
330
|
}
|
|
331
|
+
data[dbKey] = value;
|
|
332
|
+
if (defaultValue !== undefined) {
|
|
333
|
+
updateInput = true;
|
|
334
|
+
data[dbKey] = defaultValue;
|
|
335
|
+
this.defaultFieldsByFieldName[fieldName] = defaultValue;
|
|
336
|
+
// TODO related to #510. we need this logic to be consistent so do this all in TypeScript or get it from go somehow
|
|
337
|
+
this.defaultFieldsByTSName[(0, camel_case_1.camelCase)(fieldName)] = defaultValue;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
if (updateInput && this.options.updateInput) {
|
|
341
|
+
// this basically fixes #605. just needs to be exposed correctly
|
|
342
|
+
this.options.updateInput(this.defaultFieldsByTSName);
|
|
343
|
+
}
|
|
344
|
+
return data;
|
|
345
|
+
}
|
|
346
|
+
async formatAndValidateFields(schemaFields) {
|
|
347
|
+
if (this.options.operation == action_1.WriteOperation.Delete) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const editedFields = this.options.editedFields();
|
|
351
|
+
// build up data to be saved...
|
|
352
|
+
let data = {};
|
|
353
|
+
let logValues = {};
|
|
354
|
+
for (const [fieldName, field] of schemaFields) {
|
|
355
|
+
let value = editedFields.get(fieldName);
|
|
356
|
+
if (value === undefined) {
|
|
357
|
+
// null allowed
|
|
358
|
+
value = this.defaultFieldsByFieldName[fieldName];
|
|
359
|
+
}
|
|
360
|
+
let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
|
|
361
|
+
// now format and validate...
|
|
321
362
|
if (value === null) {
|
|
322
363
|
if (!field.nullable) {
|
|
323
364
|
throw new Error(`field ${field.name} set to null for non-nullable field`);
|
|
@@ -361,7 +402,6 @@ class Orchestrator {
|
|
|
361
402
|
}
|
|
362
403
|
this.validatedFields = data;
|
|
363
404
|
this.logValues = logValues;
|
|
364
|
-
// console.log(this.validatedFields);
|
|
365
405
|
}
|
|
366
406
|
async valid() {
|
|
367
407
|
try {
|
|
@@ -389,7 +429,7 @@ class Orchestrator {
|
|
|
389
429
|
if (!action || !action.viewerForEntLoad) {
|
|
390
430
|
return this.options.viewer;
|
|
391
431
|
}
|
|
392
|
-
return
|
|
432
|
+
return action.viewerForEntLoad(data);
|
|
393
433
|
}
|
|
394
434
|
async returnedRow() {
|
|
395
435
|
if (this.mainOp && this.mainOp.returnedEntRow) {
|
|
@@ -403,7 +443,7 @@ class Orchestrator {
|
|
|
403
443
|
return null;
|
|
404
444
|
}
|
|
405
445
|
const viewer = await this.viewerForEntLoad(row);
|
|
406
|
-
return
|
|
446
|
+
return (0, ent_1.applyPrivacyPolicyForRow)(viewer, this.options.loaderOptions, row);
|
|
407
447
|
}
|
|
408
448
|
async editedEntX() {
|
|
409
449
|
const row = await this.returnedRow();
|
package/core/base.js
CHANGED
|
@@ -9,22 +9,25 @@ var privacyResult;
|
|
|
9
9
|
privacyResult[privacyResult["Deny"] = 401] = "Deny";
|
|
10
10
|
privacyResult[privacyResult["Skip"] = 307] = "Skip";
|
|
11
11
|
})(privacyResult || (privacyResult = {}));
|
|
12
|
+
const allow = {
|
|
13
|
+
result: privacyResult.Allow,
|
|
14
|
+
};
|
|
12
15
|
function Allow() {
|
|
13
|
-
return
|
|
14
|
-
result: privacyResult.Allow,
|
|
15
|
-
};
|
|
16
|
+
return allow;
|
|
16
17
|
}
|
|
17
18
|
exports.Allow = Allow;
|
|
19
|
+
const skip = {
|
|
20
|
+
result: privacyResult.Skip,
|
|
21
|
+
};
|
|
18
22
|
function Skip() {
|
|
19
|
-
return
|
|
20
|
-
result: privacyResult.Skip,
|
|
21
|
-
};
|
|
23
|
+
return skip;
|
|
22
24
|
}
|
|
23
25
|
exports.Skip = Skip;
|
|
26
|
+
const deny = {
|
|
27
|
+
result: privacyResult.Deny,
|
|
28
|
+
};
|
|
24
29
|
function Deny() {
|
|
25
|
-
return
|
|
26
|
-
result: privacyResult.Deny,
|
|
27
|
-
};
|
|
30
|
+
return deny;
|
|
28
31
|
}
|
|
29
32
|
exports.Deny = Deny;
|
|
30
33
|
function DenyWithReason(e) {
|
package/core/config.d.ts
CHANGED
package/core/convert.js
CHANGED
|
@@ -59,7 +59,8 @@ function convertList(val, conv) {
|
|
|
59
59
|
}
|
|
60
60
|
exports.convertList = convertList;
|
|
61
61
|
function convertNullableList(val, conv) {
|
|
62
|
-
|
|
62
|
+
// undefined can happen with unsafe ents
|
|
63
|
+
if (val === null || val === undefined) {
|
|
63
64
|
return null;
|
|
64
65
|
}
|
|
65
66
|
return convertList(val, conv);
|
package/core/privacy.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Ent, ID, LoadEntOptions, PrivacyError, PrivacyPolicy, PrivacyPolicyRule, PrivacyResult, Viewer } from "./base";
|
|
2
2
|
export declare class EntPrivacyError extends Error implements PrivacyError {
|
|
3
3
|
privacyPolicy: PrivacyPolicy;
|
|
4
4
|
privacyRule: PrivacyPolicyRule;
|
|
@@ -46,11 +46,31 @@ export declare class DenyIfFuncRule implements PrivacyPolicyRule {
|
|
|
46
46
|
constructor(fn: FuncRule);
|
|
47
47
|
apply(v: Viewer, ent?: Ent): Promise<PrivacyResult>;
|
|
48
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated use AllowIfViewerIsEntPropertyRule
|
|
51
|
+
*/
|
|
49
52
|
export declare class AllowIfViewerIsRule implements PrivacyPolicyRule {
|
|
50
53
|
private property;
|
|
51
54
|
constructor(property: string);
|
|
52
55
|
apply(v: Viewer, ent?: Ent): Promise<PrivacyResult>;
|
|
53
56
|
}
|
|
57
|
+
export declare class AllowIfViewerIsEntPropertyRule<T extends Ent> implements PrivacyPolicyRule {
|
|
58
|
+
private property;
|
|
59
|
+
constructor(property: keyof T);
|
|
60
|
+
apply(v: Viewer, ent?: T): Promise<PrivacyResult>;
|
|
61
|
+
}
|
|
62
|
+
export declare class AllowIfEntPropertyIsRule<T extends Ent> implements PrivacyPolicyRule {
|
|
63
|
+
private property;
|
|
64
|
+
private val;
|
|
65
|
+
constructor(property: keyof T, val: any);
|
|
66
|
+
apply(v: Viewer, ent?: T): Promise<PrivacyResult>;
|
|
67
|
+
}
|
|
68
|
+
export declare class DenyIfEntPropertyIsRule<T extends Ent> implements PrivacyPolicyRule {
|
|
69
|
+
private property;
|
|
70
|
+
private val;
|
|
71
|
+
constructor(property: keyof T, val: any);
|
|
72
|
+
apply(v: Viewer, ent?: T): Promise<PrivacyResult>;
|
|
73
|
+
}
|
|
54
74
|
export declare class AllowIfEntIsVisibleRule<T extends Ent> implements PrivacyPolicyRule {
|
|
55
75
|
private id;
|
|
56
76
|
private options;
|
package/core/privacy.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = 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.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;
|
|
3
|
+
exports.AllowIfViewerHasIdentityPrivacyPolicy = exports.AllowIfViewerPrivacyPolicy = exports.AlwaysDenyPrivacyPolicy = exports.AlwaysAllowPrivacyPolicy = 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
4
|
const base_1 = require("./base");
|
|
5
5
|
const ent_1 = require("./ent");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
@@ -124,6 +124,9 @@ class DenyIfFuncRule {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
exports.DenyIfFuncRule = DenyIfFuncRule;
|
|
127
|
+
/**
|
|
128
|
+
* @deprecated use AllowIfViewerIsEntPropertyRule
|
|
129
|
+
*/
|
|
127
130
|
class AllowIfViewerIsRule {
|
|
128
131
|
constructor(property) {
|
|
129
132
|
this.property = property;
|
|
@@ -140,6 +143,47 @@ class AllowIfViewerIsRule {
|
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
exports.AllowIfViewerIsRule = AllowIfViewerIsRule;
|
|
146
|
+
class AllowIfViewerIsEntPropertyRule {
|
|
147
|
+
constructor(property) {
|
|
148
|
+
this.property = property;
|
|
149
|
+
}
|
|
150
|
+
async apply(v, ent) {
|
|
151
|
+
const result = ent && ent[this.property];
|
|
152
|
+
if (result === v.viewerID) {
|
|
153
|
+
return (0, base_1.Allow)();
|
|
154
|
+
}
|
|
155
|
+
return (0, base_1.Skip)();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
exports.AllowIfViewerIsEntPropertyRule = AllowIfViewerIsEntPropertyRule;
|
|
159
|
+
class AllowIfEntPropertyIsRule {
|
|
160
|
+
constructor(property, val) {
|
|
161
|
+
this.property = property;
|
|
162
|
+
this.val = val;
|
|
163
|
+
}
|
|
164
|
+
async apply(v, ent) {
|
|
165
|
+
const result = ent && ent[this.property];
|
|
166
|
+
if (result === this.val) {
|
|
167
|
+
return (0, base_1.Allow)();
|
|
168
|
+
}
|
|
169
|
+
return (0, base_1.Skip)();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
exports.AllowIfEntPropertyIsRule = AllowIfEntPropertyIsRule;
|
|
173
|
+
class DenyIfEntPropertyIsRule {
|
|
174
|
+
constructor(property, val) {
|
|
175
|
+
this.property = property;
|
|
176
|
+
this.val = val;
|
|
177
|
+
}
|
|
178
|
+
async apply(v, ent) {
|
|
179
|
+
const result = ent && ent[this.property];
|
|
180
|
+
if (result === this.val) {
|
|
181
|
+
return (0, base_1.Deny)();
|
|
182
|
+
}
|
|
183
|
+
return (0, base_1.Skip)();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
exports.DenyIfEntPropertyIsRule = DenyIfEntPropertyIsRule;
|
|
143
187
|
class AllowIfEntIsVisibleRule {
|
|
144
188
|
constructor(id, options) {
|
|
145
189
|
this.id = id;
|
|
@@ -2,31 +2,29 @@ import { ID, Ent, Viewer, LoadEntOptions, EdgeQueryableDataOptions } from "../ba
|
|
|
2
2
|
import { AssocEdge } from "../ent";
|
|
3
3
|
import { AssocEdgeCountLoaderFactory } from "../loaders/assoc_count_loader";
|
|
4
4
|
import { AssocEdgeLoaderFactory } from "../loaders/assoc_edge_loader";
|
|
5
|
-
import { EdgeQuery, BaseEdgeQuery } from "./query";
|
|
6
|
-
export declare type EdgeQuerySource<
|
|
5
|
+
import { EdgeQuery, BaseEdgeQuery, IDInfo } from "./query";
|
|
6
|
+
export declare type EdgeQuerySource<TSource extends Ent, TDest extends Ent = Ent> = TSource | TSource[] | ID | ID[] | EdgeQuery<TDest, Ent, AssocEdge>;
|
|
7
7
|
declare type loaderOptionsFunc = (type: string) => LoadEntOptions<Ent>;
|
|
8
|
-
export declare class AssocEdgeQueryBase<TSource extends Ent, TDest extends Ent, TEdge extends AssocEdge> extends BaseEdgeQuery<TDest, TEdge> {
|
|
8
|
+
export declare abstract class AssocEdgeQueryBase<TSource extends Ent, TDest extends Ent, TEdge extends AssocEdge> extends BaseEdgeQuery<TSource, TDest, TEdge> implements EdgeQuery<TSource, TDest, TEdge> {
|
|
9
9
|
viewer: Viewer;
|
|
10
|
-
src: EdgeQuerySource<TSource>;
|
|
10
|
+
src: EdgeQuerySource<TSource, TDest>;
|
|
11
11
|
private countLoaderFactory;
|
|
12
12
|
private dataLoaderFactory;
|
|
13
13
|
private options;
|
|
14
|
-
|
|
15
|
-
private resolvedIDs;
|
|
16
|
-
constructor(viewer: Viewer, src: EdgeQuerySource<TSource>, countLoaderFactory: AssocEdgeCountLoaderFactory, dataLoaderFactory: AssocEdgeLoaderFactory<TEdge>, options: LoadEntOptions<TDest> | loaderOptionsFunc);
|
|
17
|
-
private resolveIDs;
|
|
14
|
+
constructor(viewer: Viewer, src: EdgeQuerySource<TSource, TDest>, countLoaderFactory: AssocEdgeCountLoaderFactory, dataLoaderFactory: AssocEdgeLoaderFactory<TEdge>, options: LoadEntOptions<TDest> | loaderOptionsFunc);
|
|
18
15
|
private isEdgeQuery;
|
|
19
|
-
|
|
16
|
+
abstract sourceEnt(id: ID): Promise<Ent | null>;
|
|
20
17
|
private getSingleID;
|
|
21
18
|
queryRawCount(): Promise<number>;
|
|
22
19
|
queryAllRawCount(): Promise<Map<ID, number>>;
|
|
23
20
|
protected loadEntsFromEdges(id: ID, edges: AssocEdge[]): Promise<TDest[]>;
|
|
24
21
|
dataToID(edge: AssocEdge): ID;
|
|
25
|
-
protected
|
|
22
|
+
protected loadRawIDs(addID: (src: ID | TSource) => void): Promise<void>;
|
|
23
|
+
protected loadRawData(infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
|
|
26
24
|
queryID2(id2: ID): Promise<TEdge | undefined>;
|
|
27
25
|
queryAllID2(id2: ID): Promise<Map<ID, TEdge>>;
|
|
28
26
|
}
|
|
29
|
-
export interface EdgeQueryCtr<
|
|
30
|
-
new (viewer: Viewer, src: EdgeQuerySource<
|
|
27
|
+
export interface EdgeQueryCtr<TSource extends Ent, TDest extends Ent, TEdge extends AssocEdge> {
|
|
28
|
+
new (viewer: Viewer, src: EdgeQuerySource<TSource>): EdgeQuery<TSource, TDest, TEdge>;
|
|
31
29
|
}
|
|
32
30
|
export {};
|
|
@@ -14,27 +14,6 @@ class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
|
|
|
14
14
|
this.countLoaderFactory = countLoaderFactory;
|
|
15
15
|
this.dataLoaderFactory = dataLoaderFactory;
|
|
16
16
|
this.options = options;
|
|
17
|
-
this.resolvedIDs = [];
|
|
18
|
-
}
|
|
19
|
-
// TODO memoization...
|
|
20
|
-
async resolveIDs() {
|
|
21
|
-
if (this.idsResolved) {
|
|
22
|
-
return this.resolvedIDs;
|
|
23
|
-
}
|
|
24
|
-
if (Array.isArray(this.src)) {
|
|
25
|
-
this.src.forEach((obj) => this.addID(obj));
|
|
26
|
-
}
|
|
27
|
-
else if (this.isEdgeQuery(this.src)) {
|
|
28
|
-
const idsMap = await this.src.queryAllIDs();
|
|
29
|
-
for (const [_, ids] of idsMap) {
|
|
30
|
-
ids.forEach((id) => this.resolvedIDs.push(id));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
this.addID(this.src);
|
|
35
|
-
}
|
|
36
|
-
this.idsResolved = true;
|
|
37
|
-
return this.resolvedIDs;
|
|
38
17
|
}
|
|
39
18
|
isEdgeQuery(obj) {
|
|
40
19
|
if (obj.queryIDs !== undefined) {
|
|
@@ -42,33 +21,34 @@ class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
|
|
|
42
21
|
}
|
|
43
22
|
return false;
|
|
44
23
|
}
|
|
45
|
-
addID(obj) {
|
|
46
|
-
if (typeof obj === "object") {
|
|
47
|
-
this.resolvedIDs.push(obj.id);
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
this.resolvedIDs.push(obj);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
24
|
async getSingleID() {
|
|
54
|
-
const
|
|
55
|
-
if (
|
|
25
|
+
const infos = await this.genIDInfosToFetch();
|
|
26
|
+
if (infos.length !== 1) {
|
|
56
27
|
throw new Error("cannot call queryRawCount when more than one id is requested");
|
|
57
28
|
}
|
|
58
|
-
return
|
|
29
|
+
return infos[0];
|
|
59
30
|
}
|
|
60
31
|
// doesn't work with filters...
|
|
61
32
|
async queryRawCount() {
|
|
62
|
-
const
|
|
63
|
-
|
|
33
|
+
const info = await this.getSingleID();
|
|
34
|
+
if (info.invalidated) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
return this.countLoaderFactory
|
|
38
|
+
.createLoader(this.viewer.context)
|
|
39
|
+
.load(info.id);
|
|
64
40
|
}
|
|
65
41
|
async queryAllRawCount() {
|
|
66
42
|
let results = new Map();
|
|
67
|
-
const
|
|
43
|
+
const infos = await this.genIDInfosToFetch();
|
|
68
44
|
const loader = this.countLoaderFactory.createLoader(this.viewer.context);
|
|
69
|
-
await Promise.all(
|
|
70
|
-
|
|
71
|
-
|
|
45
|
+
await Promise.all(infos.map(async (info) => {
|
|
46
|
+
if (info.invalidated) {
|
|
47
|
+
results.set(info.id, 0);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const count = await loader.load(info.id);
|
|
51
|
+
results.set(info.id, count);
|
|
72
52
|
}));
|
|
73
53
|
return results;
|
|
74
54
|
}
|
|
@@ -108,33 +88,56 @@ class AssocEdgeQueryBase extends query_1.BaseEdgeQuery {
|
|
|
108
88
|
dataToID(edge) {
|
|
109
89
|
return edge.id2;
|
|
110
90
|
}
|
|
111
|
-
async
|
|
112
|
-
|
|
91
|
+
async loadRawIDs(addID) {
|
|
92
|
+
if (Array.isArray(this.src)) {
|
|
93
|
+
this.src.forEach((obj) => addID(obj));
|
|
94
|
+
}
|
|
95
|
+
else if (this.isEdgeQuery(this.src)) {
|
|
96
|
+
const idsMap = await this.src.queryAllIDs();
|
|
97
|
+
for (const [_, ids] of idsMap) {
|
|
98
|
+
ids.forEach((id) => addID(id));
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
addID(this.src);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
async loadRawData(infos, options) {
|
|
113
106
|
const loader = this.dataLoaderFactory.createConfigurableLoader(options, this.viewer.context);
|
|
114
|
-
await Promise.all(
|
|
107
|
+
await Promise.all(infos.map(async (info) => {
|
|
108
|
+
if (info.invalidated) {
|
|
109
|
+
this.edges.set(info.id, []);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
115
112
|
// there'll be filters for special edges here...
|
|
116
113
|
// and then depending on that, we use this
|
|
117
114
|
// what happens if you do first(10).id2(XX)
|
|
118
115
|
// doesn't make sense
|
|
119
116
|
// so only makes sense if one of these...
|
|
120
117
|
// Id2 needs to be an option
|
|
121
|
-
const edges = await loader.load(id);
|
|
122
|
-
this.edges.set(id, edges);
|
|
118
|
+
const edges = await loader.load(info.id);
|
|
119
|
+
this.edges.set(info.id, edges);
|
|
123
120
|
}));
|
|
124
121
|
}
|
|
125
122
|
async queryID2(id2) {
|
|
126
|
-
const
|
|
123
|
+
const info = await this.getSingleID();
|
|
124
|
+
if (info.invalidated) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
127
|
const loader = this.dataLoaderFactory.createLoader(this.viewer.context);
|
|
128
|
-
return loader.loadEdgeForID2(id, id2);
|
|
128
|
+
return loader.loadEdgeForID2(info.id, id2);
|
|
129
129
|
}
|
|
130
130
|
async queryAllID2(id2) {
|
|
131
|
-
const
|
|
131
|
+
const infos = await this.genIDInfosToFetch();
|
|
132
132
|
const loader = this.dataLoaderFactory.createLoader(this.viewer.context);
|
|
133
133
|
const m = new Map();
|
|
134
|
-
await Promise.all(
|
|
135
|
-
|
|
134
|
+
await Promise.all(infos.map(async (info) => {
|
|
135
|
+
if (info.invalidated) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const edge = await loader.loadEdgeForID2(info.id, id2);
|
|
136
139
|
if (edge) {
|
|
137
|
-
m.set(id, edge);
|
|
140
|
+
m.set(info.id, edge);
|
|
138
141
|
}
|
|
139
142
|
}));
|
|
140
143
|
return m;
|
|
@@ -1,20 +1,23 @@
|
|
|
1
1
|
import { Data, Ent, ID, EdgeQueryableDataOptions, LoadEntOptions, Viewer, LoaderFactory, ConfigurableLoaderFactory } from "../base";
|
|
2
|
-
import { BaseEdgeQuery } from "./query";
|
|
3
|
-
export interface CustomEdgeQueryOptions<
|
|
4
|
-
src:
|
|
2
|
+
import { BaseEdgeQuery, IDInfo, EdgeQuery } from "./query";
|
|
3
|
+
export interface CustomEdgeQueryOptions<TSource extends Ent, TDest extends Ent> {
|
|
4
|
+
src: TSource | ID;
|
|
5
5
|
countLoaderFactory: LoaderFactory<ID, number>;
|
|
6
6
|
dataLoaderFactory: ConfigurableLoaderFactory<ID, Data[]>;
|
|
7
|
-
options: LoadEntOptions<
|
|
7
|
+
options: LoadEntOptions<TDest>;
|
|
8
8
|
sortColumn?: string;
|
|
9
9
|
}
|
|
10
|
-
export declare class CustomEdgeQueryBase<TDest extends Ent> extends BaseEdgeQuery<TDest, Data> {
|
|
10
|
+
export declare abstract class CustomEdgeQueryBase<TSource extends Ent, TDest extends Ent> extends BaseEdgeQuery<TSource, TDest, Data> implements EdgeQuery<TSource, TDest, Data> {
|
|
11
11
|
viewer: Viewer;
|
|
12
12
|
private options;
|
|
13
13
|
private id;
|
|
14
|
-
constructor(viewer: Viewer, options: CustomEdgeQueryOptions<TDest>);
|
|
14
|
+
constructor(viewer: Viewer, options: CustomEdgeQueryOptions<TSource, TDest>);
|
|
15
|
+
abstract sourceEnt(id: ID): Promise<Ent | null>;
|
|
16
|
+
private idVisible;
|
|
15
17
|
queryRawCount(): Promise<number>;
|
|
16
18
|
queryAllRawCount(): Promise<Map<ID, number>>;
|
|
17
|
-
protected
|
|
19
|
+
protected loadRawIDs(addID: (src: ID | TSource) => void): Promise<void>;
|
|
20
|
+
protected loadRawData(infos: IDInfo[], options: EdgeQueryableDataOptions): Promise<void>;
|
|
18
21
|
dataToID(edge: Data): ID;
|
|
19
22
|
protected loadEntsFromEdges(id: ID, rows: Data[]): Promise<TDest[]>;
|
|
20
23
|
}
|