@snowtop/ent 0.1.0-alpha74 → 0.1.0-alpha75
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/core/base.d.ts +11 -3
- package/core/clause.d.ts +13 -0
- package/core/clause.js +44 -23
- package/core/context.d.ts +3 -1
- package/core/context.js +5 -0
- package/core/ent.d.ts +10 -1
- package/core/ent.js +207 -55
- package/core/loaders/object_loader.d.ts +1 -0
- package/core/loaders/object_loader.js +15 -3
- package/core/privacy.d.ts +1 -0
- package/core/privacy.js +19 -20
- package/core/viewer.js +1 -1
- package/package.json +1 -1
- package/schema/schema.d.ts +1 -0
package/core/base.d.ts
CHANGED
|
@@ -5,16 +5,23 @@ export interface Loader<T, V> {
|
|
|
5
5
|
loadMany?(keys: T[]): Promise<(V | null)[]>;
|
|
6
6
|
clearAll(): any;
|
|
7
7
|
}
|
|
8
|
+
interface LoaderWithLoadMany<T, V> extends Loader<T, V> {
|
|
9
|
+
loadMany(keys: T[]): Promise<(V | null)[]>;
|
|
10
|
+
}
|
|
8
11
|
export interface LoaderFactory<T, V> {
|
|
9
12
|
name: string;
|
|
10
13
|
createLoader(context?: Context): Loader<T, V>;
|
|
11
14
|
}
|
|
15
|
+
interface LoaderFactoryWithLoaderMany<T, V> extends LoaderFactory<T, V> {
|
|
16
|
+
createLoader(context?: Context): LoaderWithLoadMany<T, V>;
|
|
17
|
+
}
|
|
12
18
|
export interface ConfigurableLoaderFactory<T, V> extends LoaderFactory<T, V> {
|
|
13
19
|
createConfigurableLoader(options: EdgeQueryableDataOptions, context?: Context): Loader<T, V>;
|
|
14
20
|
}
|
|
15
21
|
export declare type EdgeQueryableDataOptions = Partial<Pick<QueryableDataOptions, "limit" | "orderby" | "clause">>;
|
|
16
22
|
export interface PrimableLoader<T, V> extends Loader<T, V> {
|
|
17
23
|
prime(d: Data): void;
|
|
24
|
+
primeAll?(d: Data): void;
|
|
18
25
|
}
|
|
19
26
|
interface cache {
|
|
20
27
|
getLoader<T, V>(name: string, create: () => Loader<T, V>): Loader<T, V>;
|
|
@@ -23,6 +30,7 @@ interface cache {
|
|
|
23
30
|
primeCache(options: queryOptions, rows: Data[]): void;
|
|
24
31
|
primeCache(options: queryOptions, rows: Data): void;
|
|
25
32
|
clearCache(): void;
|
|
33
|
+
getEntCache(): Map<string, Ent | Error | null>;
|
|
26
34
|
}
|
|
27
35
|
interface queryOptions {
|
|
28
36
|
fields: string[];
|
|
@@ -89,15 +97,15 @@ interface LoadableEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer>
|
|
|
89
97
|
loaderFactory: LoaderFactoryWithOptions;
|
|
90
98
|
ent: EntConstructor<TEnt, TViewer>;
|
|
91
99
|
}
|
|
92
|
-
interface LoaderFactoryWithOptions extends
|
|
100
|
+
interface LoaderFactoryWithOptions extends LoaderFactoryWithLoaderMany<any, Data | null> {
|
|
93
101
|
options?: SelectDataOptions;
|
|
94
102
|
}
|
|
95
103
|
export interface LoadEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer> extends LoadableEntOptions<TEnt, TViewer>, SelectBaseDataOptions {
|
|
96
104
|
fieldPrivacy?: Map<string, PrivacyPolicy>;
|
|
97
105
|
}
|
|
98
106
|
export interface SelectCustomDataOptions extends SelectBaseDataOptions {
|
|
99
|
-
|
|
100
|
-
|
|
107
|
+
loaderFactory: LoaderFactoryWithOptions;
|
|
108
|
+
prime?: boolean;
|
|
101
109
|
}
|
|
102
110
|
export interface LoadCustomEntOptions<TEnt extends Ent, TViewer extends Viewer = Viewer> extends SelectCustomDataOptions {
|
|
103
111
|
ent: EntConstructor<TEnt, TViewer>;
|
package/core/clause.d.ts
CHANGED
|
@@ -22,6 +22,18 @@ declare class simpleClause implements Clause {
|
|
|
22
22
|
logValues(): any[];
|
|
23
23
|
instanceKey(): string;
|
|
24
24
|
}
|
|
25
|
+
export declare class inClause implements Clause {
|
|
26
|
+
private col;
|
|
27
|
+
private value;
|
|
28
|
+
private type;
|
|
29
|
+
static getPostgresInClauseValuesThreshold(): number;
|
|
30
|
+
constructor(col: string, value: any[], type?: string);
|
|
31
|
+
clause(idx: number): string;
|
|
32
|
+
columns(): string[];
|
|
33
|
+
values(): any[];
|
|
34
|
+
logValues(): any[];
|
|
35
|
+
instanceKey(): string;
|
|
36
|
+
}
|
|
25
37
|
declare class compositeClause implements Clause {
|
|
26
38
|
private clauses;
|
|
27
39
|
private sep;
|
|
@@ -86,6 +98,7 @@ export declare function And(...args: Clause[]): compositeClause;
|
|
|
86
98
|
export declare function AndOptional(...args: (Clause | undefined)[]): Clause;
|
|
87
99
|
export declare function Or(...args: Clause[]): compositeClause;
|
|
88
100
|
export declare function In(col: string, ...values: any): Clause;
|
|
101
|
+
export declare function In(col: string, values: any[], type?: string): Clause;
|
|
89
102
|
interface TsQuery {
|
|
90
103
|
language: "english" | "french" | "german" | "simple";
|
|
91
104
|
value: string;
|
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 = 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.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 &&
|
|
@@ -213,17 +213,37 @@ class postgresArrayOperatorList extends postgresArrayOperator {
|
|
|
213
213
|
}
|
|
214
214
|
}
|
|
215
215
|
class inClause {
|
|
216
|
-
constructor(col, value) {
|
|
216
|
+
constructor(col, value, type = "uuid") {
|
|
217
217
|
this.col = col;
|
|
218
218
|
this.value = value;
|
|
219
|
+
this.type = type;
|
|
220
|
+
}
|
|
221
|
+
static getPostgresInClauseValuesThreshold() {
|
|
222
|
+
return 70;
|
|
219
223
|
}
|
|
220
224
|
clause(idx) {
|
|
221
|
-
|
|
225
|
+
// do a simple = when only one item
|
|
226
|
+
if (this.value.length === 1) {
|
|
227
|
+
return new simpleClause(this.col, this.value[0], "=").clause(idx);
|
|
228
|
+
}
|
|
229
|
+
const postgres = db_1.default.getDialect() === db_1.Dialect.Postgres;
|
|
230
|
+
const postgresValuesList = postgres &&
|
|
231
|
+
this.value.length >= inClause.getPostgresInClauseValuesThreshold();
|
|
222
232
|
let indices;
|
|
223
|
-
if (
|
|
233
|
+
if (postgres) {
|
|
224
234
|
indices = [];
|
|
225
235
|
for (let i = 0; i < this.value.length; i++) {
|
|
226
|
-
|
|
236
|
+
if (postgresValuesList) {
|
|
237
|
+
if (i === 0) {
|
|
238
|
+
indices.push(`($${idx}::${this.type})`);
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
indices.push(`($${idx})`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
indices.push(`$${idx}`);
|
|
246
|
+
}
|
|
227
247
|
idx++;
|
|
228
248
|
}
|
|
229
249
|
}
|
|
@@ -231,7 +251,11 @@ class inClause {
|
|
|
231
251
|
indices = new Array(this.value.length);
|
|
232
252
|
indices.fill("?", 0);
|
|
233
253
|
}
|
|
234
|
-
|
|
254
|
+
let inValue = indices.join(", ");
|
|
255
|
+
// wrap in VALUES list for postgres...
|
|
256
|
+
if (postgresValuesList) {
|
|
257
|
+
inValue = `VALUES${inValue}`;
|
|
258
|
+
}
|
|
235
259
|
return `${this.col} IN (${inValue})`;
|
|
236
260
|
// TODO we need to return idx at end to query builder...
|
|
237
261
|
// or anything that's doing a composite query so next clause knows where to start
|
|
@@ -243,25 +267,15 @@ class inClause {
|
|
|
243
267
|
}
|
|
244
268
|
values() {
|
|
245
269
|
const result = [];
|
|
246
|
-
for (
|
|
247
|
-
|
|
248
|
-
result.push(value.value());
|
|
249
|
-
}
|
|
250
|
-
else {
|
|
251
|
-
result.push(value);
|
|
252
|
-
}
|
|
270
|
+
for (let value of this.value) {
|
|
271
|
+
result.push(rawValue(value));
|
|
253
272
|
}
|
|
254
273
|
return result;
|
|
255
274
|
}
|
|
256
275
|
logValues() {
|
|
257
276
|
const result = [];
|
|
258
|
-
for (
|
|
259
|
-
|
|
260
|
-
result.push(value.logValue());
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
result.push(value);
|
|
264
|
-
}
|
|
277
|
+
for (let value of this.value) {
|
|
278
|
+
result.push(isSensitive(value) ? value.logValue() : value);
|
|
265
279
|
}
|
|
266
280
|
return result;
|
|
267
281
|
}
|
|
@@ -269,6 +283,7 @@ class inClause {
|
|
|
269
283
|
return `in:${this.col}:${this.values().join(",")}`;
|
|
270
284
|
}
|
|
271
285
|
}
|
|
286
|
+
exports.inClause = inClause;
|
|
272
287
|
class compositeClause {
|
|
273
288
|
constructor(clauses, sep) {
|
|
274
289
|
this.clauses = clauses;
|
|
@@ -486,9 +501,15 @@ function Or(...args) {
|
|
|
486
501
|
return new compositeClause(args, " OR ");
|
|
487
502
|
}
|
|
488
503
|
exports.Or = Or;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
504
|
+
function In(...args) {
|
|
505
|
+
if (args.length < 2) {
|
|
506
|
+
throw new Error(`invalid args passed to In`);
|
|
507
|
+
}
|
|
508
|
+
// 2nd overload
|
|
509
|
+
if (Array.isArray(args[1])) {
|
|
510
|
+
return new inClause(args[0], args[1], args[2]);
|
|
511
|
+
}
|
|
512
|
+
return new inClause(args[0], args.slice(1));
|
|
492
513
|
}
|
|
493
514
|
exports.In = In;
|
|
494
515
|
// if string defaults to english
|
package/core/context.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { Viewer, Data, Loader } from "./base";
|
|
2
|
+
import { Viewer, Data, Loader, Ent } from "./base";
|
|
3
3
|
import { IncomingMessage, ServerResponse } from "http";
|
|
4
4
|
import * as clause from "./clause";
|
|
5
5
|
import { Context } from "./base";
|
|
@@ -14,12 +14,14 @@ export declare class ContextCache {
|
|
|
14
14
|
getLoader<T, V>(name: string, create: () => Loader<T, V>): Loader<T, V>;
|
|
15
15
|
private itemMap;
|
|
16
16
|
private listMap;
|
|
17
|
+
private entCache;
|
|
17
18
|
private getkey;
|
|
18
19
|
getCachedRows(options: queryOptions): Data[] | null;
|
|
19
20
|
getCachedRow(options: queryOptions): Data | null;
|
|
20
21
|
primeCache(options: queryOptions, rows: Data[]): void;
|
|
21
22
|
primeCache(options: queryOptions, rows: Data): void;
|
|
22
23
|
clearCache(): void;
|
|
24
|
+
getEntCache(): Map<string, Error | Ent<any> | null>;
|
|
23
25
|
}
|
|
24
26
|
interface queryOptions {
|
|
25
27
|
fields: string[];
|
package/core/context.js
CHANGED
|
@@ -8,6 +8,7 @@ class ContextCache {
|
|
|
8
8
|
// we have a per-table map to make it easier to purge and have less things to compare with
|
|
9
9
|
this.itemMap = new Map();
|
|
10
10
|
this.listMap = new Map();
|
|
11
|
+
this.entCache = new Map();
|
|
11
12
|
}
|
|
12
13
|
getLoader(name, create) {
|
|
13
14
|
let l = this.loaders.get(name);
|
|
@@ -82,6 +83,10 @@ class ContextCache {
|
|
|
82
83
|
this.loaders.clear();
|
|
83
84
|
this.itemMap.clear();
|
|
84
85
|
this.listMap.clear();
|
|
86
|
+
this.entCache.clear();
|
|
87
|
+
}
|
|
88
|
+
getEntCache() {
|
|
89
|
+
return this.entCache;
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
exports.ContextCache = ContextCache;
|
package/core/ent.d.ts
CHANGED
|
@@ -5,14 +5,24 @@ import * as clause from "./clause";
|
|
|
5
5
|
import { Builder } from "../action";
|
|
6
6
|
import DataLoader from "dataloader";
|
|
7
7
|
import { GlobalSchema } from "../schema/";
|
|
8
|
+
export declare function getEntKey<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, id: ID, options: LoadEntOptions<TEnt, TViewer>): string;
|
|
8
9
|
export declare function loadEnt<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, id: ID, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt | null>;
|
|
9
10
|
export declare function loadEntViaKey<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, key: any, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt | null>;
|
|
10
11
|
export declare function loadEntX<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, id: ID, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt>;
|
|
11
12
|
export declare function loadEntXViaKey<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, key: any, options: LoadEntOptions<TEnt, TViewer>): Promise<TEnt>;
|
|
13
|
+
/**
|
|
14
|
+
* @deprecated use loadCustomEnts
|
|
15
|
+
*/
|
|
12
16
|
export declare function loadEntFromClause<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, clause: clause.Clause): Promise<TEnt | null>;
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated use loadCustomEnts
|
|
19
|
+
*/
|
|
13
20
|
export declare function loadEntXFromClause<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, clause: clause.Clause): Promise<TEnt>;
|
|
14
21
|
export declare function loadEnts<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, ...ids: ID[]): Promise<Map<ID, TEnt>>;
|
|
15
22
|
export declare function loadEntsList<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, ...ids: ID[]): Promise<TEnt[]>;
|
|
23
|
+
/**
|
|
24
|
+
* @deperecated use loadCustomEnts
|
|
25
|
+
*/
|
|
16
26
|
export declare function loadEntsFromClause<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, clause: clause.Clause, options: LoadEntOptions<TEnt, TViewer>): Promise<Map<ID, TEnt>>;
|
|
17
27
|
export declare function loadCustomEnts<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadCustomEntOptions<TEnt, TViewer>, query: CustomQuery): Promise<TEnt[]>;
|
|
18
28
|
interface parameterizedQueryOptions {
|
|
@@ -210,7 +220,6 @@ interface loadEdgeForIDOptions<T extends AssocEdge> extends loadCustomEdgesOptio
|
|
|
210
220
|
export declare function loadEdgeForID2<T extends AssocEdge>(options: loadEdgeForIDOptions<T>): Promise<T | undefined>;
|
|
211
221
|
export declare function loadNodesByEdge<T extends Ent>(viewer: Viewer, id1: ID, edgeType: string, options: LoadEntOptions<T>): Promise<T[]>;
|
|
212
222
|
export declare function applyPrivacyPolicyForRow<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, row: Data | null): Promise<TEnt | null>;
|
|
213
|
-
export declare function applyPrivacyPolicyForRowX<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, options: LoadEntOptions<TEnt, TViewer>, row: Data): Promise<TEnt>;
|
|
214
223
|
export declare function applyPrivacyPolicyForRows<TEnt extends Ent<TViewer>, TViewer extends Viewer>(viewer: TViewer, rows: Data[], options: LoadEntOptions<TEnt, TViewer>): Promise<Map<ID, TEnt>>;
|
|
215
224
|
export declare function getEdgeTypeInGroup<T extends string>(viewer: Viewer, id1: ID, id2: ID, m: Map<T, string>): Promise<[T, AssocEdge] | undefined>;
|
|
216
225
|
export {};
|
package/core/ent.js
CHANGED
|
@@ -22,8 +22,8 @@ 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.
|
|
26
|
-
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.
|
|
25
|
+
exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = exports.defaultEdgeQueryOptions = exports.DefaultLimit = exports.loadEdgeDatas = exports.loadEdgeData = exports.assocEdgeLoader = exports.AssocEdgeData = exports.getCursor = exports.AssocEdge = exports.DeleteNodeOperation = exports.deleteRowsSync = exports.deleteRows = exports.editRowSync = exports.editRow = exports.buildUpdateQuery = exports.createRowSync = exports.createRow = exports.buildInsertQuery = exports.EdgeOperation = exports.__hasGlobalSchema = exports.clearGlobalSchema = exports.setGlobalSchema = exports.EditNodeOperation = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.loadRow = exports.loadRowX = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadCustomData = exports.loadCustomEnts = exports.loadEntsFromClause = exports.loadEntsList = exports.loadEnts = exports.loadEntXFromClause = exports.loadEntFromClause = exports.loadEntXViaKey = exports.loadEntX = exports.loadEntViaKey = exports.loadEnt = exports.getEntKey = void 0;
|
|
26
|
+
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRow = void 0;
|
|
27
27
|
const db_1 = __importStar(require("./db"));
|
|
28
28
|
const privacy_1 = require("./privacy");
|
|
29
29
|
const clause = __importStar(require("./clause"));
|
|
@@ -87,10 +87,58 @@ function createDataLoader(options) {
|
|
|
87
87
|
return result;
|
|
88
88
|
}, loaderOptions);
|
|
89
89
|
}
|
|
90
|
+
function getEntKey(viewer, id, options) {
|
|
91
|
+
return `${viewer.instanceKey()}:${options.loaderFactory.name}:${id}`;
|
|
92
|
+
}
|
|
93
|
+
exports.getEntKey = getEntKey;
|
|
94
|
+
// fetches the ent from cache if cache exists.
|
|
95
|
+
function entFromCacheMaybe(viewer, id, options) {
|
|
96
|
+
const cache = viewer.context?.cache?.getEntCache();
|
|
97
|
+
if (!cache) {
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
const key = getEntKey(viewer, id, options);
|
|
101
|
+
const r = cache.get(key);
|
|
102
|
+
if (r !== undefined) {
|
|
103
|
+
(0, logger_1.log)("cache", {
|
|
104
|
+
"ent-cache-hit": key,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
key,
|
|
109
|
+
ent: r instanceof Error ? undefined : r,
|
|
110
|
+
error: r instanceof Error ? r : undefined,
|
|
111
|
+
cache,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
90
114
|
// Ent accessors
|
|
115
|
+
async function applyPrivacyPolicyForRowAndStoreInCache(viewer, options, row, info) {
|
|
116
|
+
const ent = await applyPrivacyPolicyForRow(viewer, options, row);
|
|
117
|
+
if (info.cache && info.key) {
|
|
118
|
+
info.cache.set(info.key, ent);
|
|
119
|
+
}
|
|
120
|
+
return ent instanceof Error ? null : ent;
|
|
121
|
+
}
|
|
122
|
+
async function applyPrivacyPolicyForRowAndStoreInCacheX(viewer, options, row, info) {
|
|
123
|
+
const ent = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
124
|
+
if (info.cache && info.key) {
|
|
125
|
+
info.cache.set(info.key, ent);
|
|
126
|
+
}
|
|
127
|
+
if (ent instanceof Error) {
|
|
128
|
+
throw ent;
|
|
129
|
+
}
|
|
130
|
+
if (ent === null) {
|
|
131
|
+
throw new Error(`TODO`);
|
|
132
|
+
}
|
|
133
|
+
return ent;
|
|
134
|
+
}
|
|
91
135
|
async function loadEnt(viewer, id, options) {
|
|
136
|
+
const info = entFromCacheMaybe(viewer, id, options);
|
|
137
|
+
if (info.ent !== undefined) {
|
|
138
|
+
return info.ent;
|
|
139
|
+
}
|
|
92
140
|
const row = await options.loaderFactory.createLoader(viewer.context).load(id);
|
|
93
|
-
return
|
|
141
|
+
return applyPrivacyPolicyForRowAndStoreInCache(viewer, options, row, info);
|
|
94
142
|
}
|
|
95
143
|
exports.loadEnt = loadEnt;
|
|
96
144
|
// this is the same implementation-wise (right now) as loadEnt. it's just clearer that it's not loaded via ID.
|
|
@@ -99,18 +147,36 @@ async function loadEntViaKey(viewer, key, options) {
|
|
|
99
147
|
const row = await options.loaderFactory
|
|
100
148
|
.createLoader(viewer.context)
|
|
101
149
|
.load(key);
|
|
102
|
-
|
|
150
|
+
if (!row) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
// TODO every row.id needs to be audited...
|
|
154
|
+
const info = entFromCacheMaybe(viewer, row.id, options);
|
|
155
|
+
if (info.ent !== undefined) {
|
|
156
|
+
return info.ent;
|
|
157
|
+
}
|
|
158
|
+
return applyPrivacyPolicyForRowAndStoreInCache(viewer, options, row, info);
|
|
103
159
|
}
|
|
104
160
|
exports.loadEntViaKey = loadEntViaKey;
|
|
161
|
+
// need a cached error...
|
|
105
162
|
async function loadEntX(viewer, id, options) {
|
|
163
|
+
const info = entFromCacheMaybe(viewer, id, options);
|
|
164
|
+
if (info.error !== undefined) {
|
|
165
|
+
throw info.error;
|
|
166
|
+
}
|
|
167
|
+
if (info.ent !== undefined && info.ent !== null) {
|
|
168
|
+
return info.ent;
|
|
169
|
+
}
|
|
106
170
|
const row = await options.loaderFactory.createLoader(viewer.context).load(id);
|
|
107
171
|
if (!row) {
|
|
108
172
|
// todo make this better
|
|
109
173
|
throw new Error(`${options.loaderFactory.name}: couldn't find row for value ${id}`);
|
|
110
174
|
}
|
|
111
|
-
return
|
|
175
|
+
return applyPrivacyPolicyForRowAndStoreInCacheX(viewer, options, row, info);
|
|
112
176
|
}
|
|
113
177
|
exports.loadEntX = loadEntX;
|
|
178
|
+
// TODO test this and loadEntViaKey
|
|
179
|
+
// replace loadEntViaClause??
|
|
114
180
|
async function loadEntXViaKey(viewer, key, options) {
|
|
115
181
|
const row = await options.loaderFactory
|
|
116
182
|
.createLoader(viewer.context)
|
|
@@ -119,9 +185,19 @@ async function loadEntXViaKey(viewer, key, options) {
|
|
|
119
185
|
// todo make this better
|
|
120
186
|
throw new Error(`${options.loaderFactory.name}: couldn't find row for value ${key}`);
|
|
121
187
|
}
|
|
122
|
-
|
|
188
|
+
const info = entFromCacheMaybe(viewer, row.id, options);
|
|
189
|
+
if (info.error !== undefined) {
|
|
190
|
+
throw info.error;
|
|
191
|
+
}
|
|
192
|
+
if (info.ent !== undefined && info.ent !== null) {
|
|
193
|
+
return info.ent;
|
|
194
|
+
}
|
|
195
|
+
return applyPrivacyPolicyForRowAndStoreInCacheX(viewer, options, row, info);
|
|
123
196
|
}
|
|
124
197
|
exports.loadEntXViaKey = loadEntXViaKey;
|
|
198
|
+
/**
|
|
199
|
+
* @deprecated use loadCustomEnts
|
|
200
|
+
*/
|
|
125
201
|
async function loadEntFromClause(viewer, options, clause) {
|
|
126
202
|
const rowOptions = {
|
|
127
203
|
...options,
|
|
@@ -129,12 +205,15 @@ async function loadEntFromClause(viewer, options, clause) {
|
|
|
129
205
|
context: viewer.context,
|
|
130
206
|
};
|
|
131
207
|
const row = await loadRow(rowOptions);
|
|
132
|
-
return
|
|
208
|
+
return applyPrivacyPolicyForRow(viewer, options, row);
|
|
133
209
|
}
|
|
134
210
|
exports.loadEntFromClause = loadEntFromClause;
|
|
135
211
|
// same as loadEntFromClause
|
|
136
212
|
// only works for ents where primary key is "id"
|
|
137
213
|
// use loadEnt with a loaderFactory if different
|
|
214
|
+
/**
|
|
215
|
+
* @deprecated use loadCustomEnts
|
|
216
|
+
*/
|
|
138
217
|
async function loadEntXFromClause(viewer, options, clause) {
|
|
139
218
|
const rowOptions = {
|
|
140
219
|
...options,
|
|
@@ -149,33 +228,62 @@ async function loadEnts(viewer, options, ...ids) {
|
|
|
149
228
|
if (!ids.length) {
|
|
150
229
|
return new Map();
|
|
151
230
|
}
|
|
152
|
-
|
|
153
|
-
let rows = [];
|
|
154
|
-
// TODO loadMany everywhere
|
|
155
|
-
const l = options.loaderFactory.createLoader(viewer.context);
|
|
156
|
-
if (l.loadMany) {
|
|
157
|
-
loaded = true;
|
|
158
|
-
rows = await l.loadMany(ids);
|
|
159
|
-
}
|
|
160
|
-
// TODO rewrite all of this
|
|
231
|
+
// result
|
|
161
232
|
let m = new Map();
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
233
|
+
const cache = viewer.context?.cache?.getEntCache();
|
|
234
|
+
let toFetch = [];
|
|
235
|
+
if (cache) {
|
|
236
|
+
for (const id of ids) {
|
|
237
|
+
const key = getEntKey(viewer, id, options);
|
|
238
|
+
const ent = cache.get(key);
|
|
239
|
+
if (ent !== undefined) {
|
|
240
|
+
(0, logger_1.log)("cache", {
|
|
241
|
+
"ent-cache-hit": key,
|
|
242
|
+
});
|
|
243
|
+
if (ent === null) {
|
|
244
|
+
// TODO this should return null if not loadable...
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
// @ts-ignore
|
|
248
|
+
m.set(id, ent);
|
|
167
249
|
}
|
|
168
|
-
|
|
169
|
-
|
|
250
|
+
else {
|
|
251
|
+
toFetch.push(id);
|
|
170
252
|
}
|
|
171
|
-
rows2.push(row);
|
|
172
253
|
}
|
|
173
|
-
m = await applyPrivacyPolicyForRows(viewer, rows2, options);
|
|
174
254
|
}
|
|
175
255
|
else {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
256
|
+
toFetch = ids;
|
|
257
|
+
}
|
|
258
|
+
// all in ent cache!
|
|
259
|
+
if (!toFetch.length) {
|
|
260
|
+
return m;
|
|
261
|
+
}
|
|
262
|
+
const l = options.loaderFactory.createLoader(viewer.context);
|
|
263
|
+
const rows = await l.loadMany(toFetch);
|
|
264
|
+
let rows2 = [];
|
|
265
|
+
for (const row of rows) {
|
|
266
|
+
if (!row) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (row instanceof Error) {
|
|
270
|
+
throw row;
|
|
271
|
+
}
|
|
272
|
+
rows2.push(row);
|
|
273
|
+
}
|
|
274
|
+
const m2 = await applyPrivacyPolicyForRows(viewer, rows2, options);
|
|
275
|
+
for (const row of rows2) {
|
|
276
|
+
const id = row[options.loaderFactory.options?.key || "id"];
|
|
277
|
+
const ent = m2.get(id);
|
|
278
|
+
if (cache) {
|
|
279
|
+
// put back in cache...
|
|
280
|
+
// store null for rows that can't be seen
|
|
281
|
+
cache.set(getEntKey(viewer, id, options), ent ?? null);
|
|
282
|
+
}
|
|
283
|
+
if (ent !== undefined) {
|
|
284
|
+
// TODO this should return null if not loadable...?
|
|
285
|
+
m.set(id, ent);
|
|
286
|
+
}
|
|
179
287
|
}
|
|
180
288
|
return m;
|
|
181
289
|
// TODO do we want to change this to be a map not a list so that it's easy to check for existence?
|
|
@@ -198,6 +306,9 @@ async function loadEntsList(viewer, options, ...ids) {
|
|
|
198
306
|
exports.loadEntsList = loadEntsList;
|
|
199
307
|
// we return a map here so that any sorting for queries that exist
|
|
200
308
|
// can be done in O(N) time
|
|
309
|
+
/**
|
|
310
|
+
* @deperecated use loadCustomEnts
|
|
311
|
+
*/
|
|
201
312
|
async function loadEntsFromClause(viewer, clause, options) {
|
|
202
313
|
const rowOptions = {
|
|
203
314
|
...options,
|
|
@@ -212,8 +323,18 @@ async function loadCustomEnts(viewer, options, query) {
|
|
|
212
323
|
const rows = await loadCustomData(options, query, viewer.context);
|
|
213
324
|
const result = new Array(rows.length);
|
|
214
325
|
await Promise.all(rows.map(async (row, idx) => {
|
|
215
|
-
|
|
216
|
-
|
|
326
|
+
// TODO what if key is different
|
|
327
|
+
const info = entFromCacheMaybe(viewer, row.id, options);
|
|
328
|
+
if (info.ent !== undefined) {
|
|
329
|
+
if (info.ent === null) {
|
|
330
|
+
// we're done here
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
// @ts-ignore
|
|
334
|
+
result[idx] = info.ent;
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
const privacyEnt = await applyPrivacyPolicyForRowAndStoreInCache(viewer, options, row, info);
|
|
217
338
|
if (privacyEnt) {
|
|
218
339
|
result[idx] = privacyEnt;
|
|
219
340
|
}
|
|
@@ -254,11 +375,25 @@ function isParameterizedQuery(opts) {
|
|
|
254
375
|
* }) // doesn't change the query
|
|
255
376
|
*/
|
|
256
377
|
async function loadCustomData(options, query, context) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
378
|
+
const rows = await loadCustomDataImpl(options, query, context);
|
|
379
|
+
// prime the data so that subsequent fetches of the row with this id are a cache hit.
|
|
380
|
+
if (options.prime) {
|
|
381
|
+
const loader = options.loaderFactory.createLoader(context);
|
|
382
|
+
if (isPrimableLoader(loader) && loader.primeAll !== undefined) {
|
|
383
|
+
for (const row of rows) {
|
|
384
|
+
loader.primeAll(row);
|
|
385
|
+
}
|
|
260
386
|
}
|
|
261
|
-
|
|
387
|
+
}
|
|
388
|
+
return rows;
|
|
389
|
+
}
|
|
390
|
+
exports.loadCustomData = loadCustomData;
|
|
391
|
+
function isPrimableLoader(loader) {
|
|
392
|
+
return loader != undefined;
|
|
393
|
+
}
|
|
394
|
+
async function loadCustomDataImpl(options, query, context) {
|
|
395
|
+
function getClause(cls) {
|
|
396
|
+
let optClause = options.loaderFactory?.options?.clause;
|
|
262
397
|
if (typeof optClause === "function") {
|
|
263
398
|
optClause = optClause();
|
|
264
399
|
}
|
|
@@ -269,7 +404,7 @@ async function loadCustomData(options, query, context) {
|
|
|
269
404
|
}
|
|
270
405
|
if (typeof query === "string") {
|
|
271
406
|
// no caching, perform raw query
|
|
272
|
-
return
|
|
407
|
+
return performRawQuery(query, [], []);
|
|
273
408
|
}
|
|
274
409
|
else if (isClause(query)) {
|
|
275
410
|
// if a Clause is passed in and we have a default clause
|
|
@@ -277,7 +412,7 @@ async function loadCustomData(options, query, context) {
|
|
|
277
412
|
// if we want to disableTransformations, need to indicate that with
|
|
278
413
|
// disableTransformations option
|
|
279
414
|
// this will have rudimentary caching but nothing crazy
|
|
280
|
-
return
|
|
415
|
+
return loadRows({
|
|
281
416
|
...options,
|
|
282
417
|
clause: getClause(query),
|
|
283
418
|
context: context,
|
|
@@ -285,7 +420,7 @@ async function loadCustomData(options, query, context) {
|
|
|
285
420
|
}
|
|
286
421
|
else if (isParameterizedQuery(query)) {
|
|
287
422
|
// no caching, perform raw query
|
|
288
|
-
return
|
|
423
|
+
return performRawQuery(query.query, query.values || [], query.logValues);
|
|
289
424
|
}
|
|
290
425
|
else {
|
|
291
426
|
let cls = query.clause;
|
|
@@ -293,7 +428,7 @@ async function loadCustomData(options, query, context) {
|
|
|
293
428
|
cls = getClause(cls);
|
|
294
429
|
}
|
|
295
430
|
// this will have rudimentary caching but nothing crazy
|
|
296
|
-
return
|
|
431
|
+
return loadRows({
|
|
297
432
|
...query,
|
|
298
433
|
...options,
|
|
299
434
|
context: context,
|
|
@@ -301,15 +436,20 @@ async function loadCustomData(options, query, context) {
|
|
|
301
436
|
});
|
|
302
437
|
}
|
|
303
438
|
}
|
|
304
|
-
exports.loadCustomData = loadCustomData;
|
|
305
439
|
// Derived ents
|
|
440
|
+
// no ent caching
|
|
306
441
|
async function loadDerivedEnt(viewer, data, loader) {
|
|
307
442
|
const ent = new loader(viewer, data);
|
|
308
|
-
|
|
443
|
+
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, {
|
|
309
444
|
ent: loader,
|
|
310
445
|
});
|
|
446
|
+
if (r instanceof Error) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
return r;
|
|
311
450
|
}
|
|
312
451
|
exports.loadDerivedEnt = loadDerivedEnt;
|
|
452
|
+
// won't have caching yet either
|
|
313
453
|
async function loadDerivedEntX(viewer, data, loader) {
|
|
314
454
|
const ent = new loader(viewer, data);
|
|
315
455
|
return await applyPrivacyPolicyForEntX(viewer, ent, data, { ent: loader });
|
|
@@ -319,18 +459,23 @@ exports.loadDerivedEntX = loadDerivedEntX;
|
|
|
319
459
|
// TODO is there a smarter way to not instantiate two objects here?
|
|
320
460
|
async function applyPrivacyPolicyForEnt(viewer, ent, data, fieldPrivacyOptions) {
|
|
321
461
|
if (ent) {
|
|
322
|
-
const
|
|
323
|
-
if (
|
|
324
|
-
return
|
|
462
|
+
const error = await (0, privacy_1.applyPrivacyPolicyImpl)(viewer, ent.getPrivacyPolicy(), ent);
|
|
463
|
+
if (error === null) {
|
|
464
|
+
return doFieldPrivacy(viewer, ent, data, fieldPrivacyOptions);
|
|
325
465
|
}
|
|
326
|
-
return
|
|
466
|
+
return error;
|
|
327
467
|
}
|
|
328
468
|
return null;
|
|
329
469
|
}
|
|
330
470
|
async function applyPrivacyPolicyForEntX(viewer, ent, data, options) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
471
|
+
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, options);
|
|
472
|
+
if (r instanceof Error) {
|
|
473
|
+
throw r;
|
|
474
|
+
}
|
|
475
|
+
if (r === null) {
|
|
476
|
+
throw new Error(`couldn't apply privacyPoliy for ent ${ent.id}`);
|
|
477
|
+
}
|
|
478
|
+
return r;
|
|
334
479
|
}
|
|
335
480
|
async function doFieldPrivacy(viewer, ent, data, options) {
|
|
336
481
|
if (!options.fieldPrivacy) {
|
|
@@ -339,12 +484,12 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
339
484
|
const promises = [];
|
|
340
485
|
let somethingChanged = false;
|
|
341
486
|
for (const [k, policy] of options.fieldPrivacy) {
|
|
487
|
+
const curr = data[k];
|
|
488
|
+
if (curr === null || curr === undefined) {
|
|
489
|
+
continue;
|
|
490
|
+
}
|
|
342
491
|
promises.push((async () => {
|
|
343
492
|
// don't do anything if key is null or for some reason missing
|
|
344
|
-
const curr = data[k];
|
|
345
|
-
if (curr === null || curr === undefined) {
|
|
346
|
-
return;
|
|
347
|
-
}
|
|
348
493
|
const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
|
|
349
494
|
if (!r) {
|
|
350
495
|
data[k] = null;
|
|
@@ -547,7 +692,7 @@ class EditNodeOperation {
|
|
|
547
692
|
optionClause = opts.clause;
|
|
548
693
|
}
|
|
549
694
|
if (optionClause) {
|
|
550
|
-
cls = clause.And(
|
|
695
|
+
cls = clause.And(cls, optionClause);
|
|
551
696
|
}
|
|
552
697
|
}
|
|
553
698
|
const query = buildQuery({
|
|
@@ -1062,6 +1207,9 @@ function buildUpdateQuery(options, suffix) {
|
|
|
1062
1207
|
let query = `UPDATE ${options.tableName} SET ${vals} WHERE `;
|
|
1063
1208
|
query = query + options.whereClause.clause(idx);
|
|
1064
1209
|
values.push(...options.whereClause.values());
|
|
1210
|
+
if (options.fieldsToLog) {
|
|
1211
|
+
logValues.push(...options.whereClause.logValues());
|
|
1212
|
+
}
|
|
1065
1213
|
if (suffix) {
|
|
1066
1214
|
query = query + " " + suffix;
|
|
1067
1215
|
}
|
|
@@ -1352,18 +1500,22 @@ async function loadNodesByEdge(viewer, id1, edgeType, options) {
|
|
|
1352
1500
|
}
|
|
1353
1501
|
exports.loadNodesByEdge = loadNodesByEdge;
|
|
1354
1502
|
async function applyPrivacyPolicyForRow(viewer, options, row) {
|
|
1503
|
+
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
1504
|
+
return r instanceof Error ? null : r;
|
|
1505
|
+
}
|
|
1506
|
+
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1507
|
+
async function applyPrivacyPolicyForRowImpl(viewer, options, row) {
|
|
1355
1508
|
if (!row) {
|
|
1356
1509
|
return null;
|
|
1357
1510
|
}
|
|
1358
1511
|
const ent = new options.ent(viewer, row);
|
|
1359
|
-
return
|
|
1512
|
+
return applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
1360
1513
|
}
|
|
1361
|
-
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1362
1514
|
async function applyPrivacyPolicyForRowX(viewer, options, row) {
|
|
1363
1515
|
const ent = new options.ent(viewer, row);
|
|
1364
1516
|
return await applyPrivacyPolicyForEntX(viewer, ent, row, options);
|
|
1365
1517
|
}
|
|
1366
|
-
|
|
1518
|
+
// TODO this needs to be changed to use ent cache as needed...
|
|
1367
1519
|
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1368
1520
|
let m = new Map();
|
|
1369
1521
|
// apply privacy logic
|
|
@@ -13,6 +13,7 @@ export declare class ObjectLoader<T> implements Loader<T, Data | null> {
|
|
|
13
13
|
clearAll(): void;
|
|
14
14
|
loadMany(keys: T[]): Promise<Data[]>;
|
|
15
15
|
prime(data: Data): void;
|
|
16
|
+
primeAll(data: Data): void;
|
|
16
17
|
}
|
|
17
18
|
interface ObjectLoaderOptions extends SelectDataOptions {
|
|
18
19
|
instanceKey?: string;
|
|
@@ -53,7 +53,7 @@ function createDataLoader(options) {
|
|
|
53
53
|
optionClause = options.clause;
|
|
54
54
|
}
|
|
55
55
|
if (optionClause) {
|
|
56
|
-
cls = clause.And(
|
|
56
|
+
cls = clause.And(cls, optionClause);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
const rowOptions = {
|
|
@@ -136,7 +136,7 @@ class ObjectLoader {
|
|
|
136
136
|
optionClause = this.options.clause;
|
|
137
137
|
}
|
|
138
138
|
if (optionClause) {
|
|
139
|
-
cls = clause.And(
|
|
139
|
+
cls = clause.And(cls, optionClause);
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
142
|
const rowOptions = {
|
|
@@ -163,7 +163,7 @@ class ObjectLoader {
|
|
|
163
163
|
optionClause = this.options.clause;
|
|
164
164
|
}
|
|
165
165
|
if (optionClause) {
|
|
166
|
-
cls = clause.And(
|
|
166
|
+
cls = clause.And(cls, optionClause);
|
|
167
167
|
}
|
|
168
168
|
}
|
|
169
169
|
const rowOptions = {
|
|
@@ -181,6 +181,18 @@ class ObjectLoader {
|
|
|
181
181
|
this.loader.prime(key, data);
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
+
// prime this loader and any other loaders it's aware of
|
|
185
|
+
primeAll(data) {
|
|
186
|
+
this.prime(data);
|
|
187
|
+
if (this.primedLoaders) {
|
|
188
|
+
for (const [key, loader] of this.primedLoaders) {
|
|
189
|
+
const value = data[key];
|
|
190
|
+
if (value !== undefined) {
|
|
191
|
+
loader.prime(data);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
184
196
|
}
|
|
185
197
|
exports.ObjectLoader = ObjectLoader;
|
|
186
198
|
class ObjectLoaderFactory {
|
package/core/privacy.d.ts
CHANGED
|
@@ -183,6 +183,7 @@ export declare class AllowIfSubPolicyAllowsRule implements PrivacyPolicyRule {
|
|
|
183
183
|
}
|
|
184
184
|
export declare function applyPrivacyPolicy(v: Viewer, policy: PrivacyPolicy, ent: Ent | undefined): Promise<boolean>;
|
|
185
185
|
export declare function applyPrivacyPolicyX(v: Viewer, policy: PrivacyPolicy, ent: Ent | undefined, throwErr?: () => Error): Promise<boolean>;
|
|
186
|
+
export declare function applyPrivacyPolicyImpl(v: Viewer, policy: PrivacyPolicy, ent: Ent | undefined, throwErr?: () => Error): Promise<Error | null>;
|
|
186
187
|
export declare const AlwaysAllowPrivacyPolicy: PrivacyPolicy;
|
|
187
188
|
export declare const AlwaysDenyPrivacyPolicy: PrivacyPolicy;
|
|
188
189
|
export declare const AllowIfViewerPrivacyPolicy: PrivacyPolicy;
|
package/core/privacy.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
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.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;
|
|
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
4
|
const base_1 = require("./base");
|
|
5
5
|
const ent_1 = require("./ent");
|
|
6
|
-
const logger_1 = require("./logger");
|
|
7
6
|
// copied from ./base
|
|
8
7
|
var privacyResult;
|
|
9
8
|
(function (privacyResult) {
|
|
@@ -437,42 +436,42 @@ class AllowIfSubPolicyAllowsRule {
|
|
|
437
436
|
}
|
|
438
437
|
exports.AllowIfSubPolicyAllowsRule = AllowIfSubPolicyAllowsRule;
|
|
439
438
|
async function applyPrivacyPolicy(v, policy, ent) {
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
catch (e) {
|
|
444
|
-
// TODO privacy errors should not throw
|
|
445
|
-
// but other expected errors should throw...
|
|
446
|
-
// we shouldn't just hide them
|
|
447
|
-
(0, logger_1.log)("debug", e);
|
|
448
|
-
return false;
|
|
449
|
-
}
|
|
439
|
+
const err = await applyPrivacyPolicyImpl(v, policy, ent);
|
|
440
|
+
return err === null;
|
|
450
441
|
}
|
|
451
442
|
exports.applyPrivacyPolicy = applyPrivacyPolicy;
|
|
452
|
-
// this will throw an exception if fails or return error | null?
|
|
453
443
|
async function applyPrivacyPolicyX(v, policy, ent, throwErr) {
|
|
444
|
+
const err = await applyPrivacyPolicyImpl(v, policy, ent, throwErr);
|
|
445
|
+
if (err !== null) {
|
|
446
|
+
throw err;
|
|
447
|
+
}
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
exports.applyPrivacyPolicyX = applyPrivacyPolicyX;
|
|
451
|
+
// this will throw an exception if fails or return error | null?
|
|
452
|
+
async function applyPrivacyPolicyImpl(v, policy, ent, throwErr) {
|
|
454
453
|
for (const rule of policy.rules) {
|
|
455
454
|
const res = await rule.apply(v, ent);
|
|
456
455
|
if (res.result == privacyResult.Allow) {
|
|
457
|
-
return
|
|
456
|
+
return null;
|
|
458
457
|
}
|
|
459
458
|
else if (res.result == privacyResult.Deny) {
|
|
460
459
|
// specific error throw that
|
|
461
460
|
if (res.error) {
|
|
462
|
-
|
|
461
|
+
return res.error;
|
|
463
462
|
}
|
|
464
463
|
if (res.getError) {
|
|
465
|
-
|
|
464
|
+
return res.getError(policy, rule, ent);
|
|
466
465
|
}
|
|
467
466
|
if (throwErr) {
|
|
468
|
-
|
|
467
|
+
return throwErr();
|
|
469
468
|
}
|
|
470
|
-
|
|
469
|
+
return new EntPrivacyError(policy, rule, ent);
|
|
471
470
|
}
|
|
472
471
|
}
|
|
473
|
-
|
|
472
|
+
return new EntInvalidPrivacyPolicyError(policy, ent);
|
|
474
473
|
}
|
|
475
|
-
exports.
|
|
474
|
+
exports.applyPrivacyPolicyImpl = applyPrivacyPolicyImpl;
|
|
476
475
|
exports.AlwaysAllowPrivacyPolicy = {
|
|
477
476
|
rules: [exports.AlwaysAllowRule],
|
|
478
477
|
};
|
package/core/viewer.js
CHANGED
package/package.json
CHANGED
package/schema/schema.d.ts
CHANGED
|
@@ -205,6 +205,7 @@ export interface FieldOptions {
|
|
|
205
205
|
privacyPolicy?: PrivacyPolicy | (() => PrivacyPolicy);
|
|
206
206
|
getDerivedFields?(name: string): FieldMap;
|
|
207
207
|
convert?: ConvertType;
|
|
208
|
+
fetchOnDemand?: boolean;
|
|
208
209
|
[x: string]: any;
|
|
209
210
|
}
|
|
210
211
|
export interface PolymorphicOptions {
|