@snowtop/ent 0.1.0-alpha12 → 0.1.0-alpha121
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 +37 -31
- package/action/action.js +22 -7
- package/action/executor.d.ts +3 -3
- package/action/executor.js +8 -3
- package/action/experimental_action.d.ts +32 -22
- package/action/experimental_action.js +35 -9
- package/action/index.d.ts +2 -0
- package/action/index.js +7 -1
- package/action/orchestrator.d.ts +33 -14
- package/action/orchestrator.js +251 -54
- package/action/privacy.d.ts +2 -2
- package/action/relative_value.d.ts +47 -0
- package/action/relative_value.js +125 -0
- package/action/transaction.d.ts +10 -0
- package/action/transaction.js +23 -0
- package/auth/auth.d.ts +1 -1
- package/core/base.d.ts +60 -37
- package/core/base.js +7 -1
- package/core/clause.d.ts +84 -40
- package/core/clause.js +358 -64
- package/core/config.d.ts +12 -1
- package/core/config.js +7 -1
- package/core/const.d.ts +3 -0
- package/core/const.js +6 -0
- package/core/context.d.ts +6 -4
- package/core/context.js +20 -2
- package/core/convert.d.ts +1 -1
- package/core/date.js +1 -5
- package/core/db.d.ts +11 -8
- package/core/db.js +20 -8
- package/core/ent.d.ts +82 -30
- package/core/ent.js +632 -193
- package/core/global_schema.d.ts +7 -0
- package/core/global_schema.js +51 -0
- package/core/loaders/assoc_count_loader.d.ts +3 -2
- package/core/loaders/assoc_count_loader.js +10 -2
- package/core/loaders/assoc_edge_loader.d.ts +2 -2
- package/core/loaders/assoc_edge_loader.js +8 -11
- package/core/loaders/index.d.ts +1 -1
- package/core/loaders/index.js +1 -3
- package/core/loaders/index_loader.d.ts +3 -3
- package/core/loaders/loader.d.ts +2 -2
- package/core/loaders/loader.js +5 -5
- package/core/loaders/object_loader.d.ts +11 -10
- package/core/loaders/object_loader.js +70 -60
- package/core/loaders/query_loader.d.ts +7 -13
- package/core/loaders/query_loader.js +52 -11
- package/core/loaders/raw_count_loader.d.ts +2 -2
- package/core/loaders/raw_count_loader.js +5 -1
- package/core/logger.d.ts +1 -1
- package/core/logger.js +1 -0
- package/core/privacy.d.ts +25 -24
- package/core/privacy.js +21 -25
- package/core/query/assoc_query.d.ts +7 -6
- package/core/query/assoc_query.js +9 -1
- package/core/query/custom_clause_query.d.ts +27 -0
- package/core/query/custom_clause_query.js +84 -0
- package/core/query/custom_query.d.ts +20 -5
- package/core/query/custom_query.js +87 -12
- package/core/query/index.d.ts +1 -0
- package/core/query/index.js +3 -1
- package/core/query/query.d.ts +8 -4
- package/core/query/query.js +101 -53
- package/core/query/shared_assoc_test.d.ts +2 -1
- package/core/query/shared_assoc_test.js +35 -45
- package/core/query/shared_test.d.ts +8 -1
- package/core/query/shared_test.js +470 -236
- package/core/viewer.d.ts +3 -3
- package/core/viewer.js +1 -1
- package/graphql/graphql.d.ts +15 -7
- package/graphql/graphql.js +23 -7
- package/graphql/index.d.ts +1 -1
- package/graphql/index.js +3 -4
- package/graphql/query/connection_type.d.ts +9 -9
- package/graphql/query/edge_connection.d.ts +9 -9
- package/graphql/query/page_info.d.ts +1 -1
- package/graphql/query/shared_assoc_test.js +1 -1
- package/graphql/query/shared_edge_connection.js +1 -19
- package/graphql/scalars/orderby_direction.d.ts +2 -0
- package/graphql/scalars/orderby_direction.js +15 -0
- package/imports/index.d.ts +6 -1
- package/imports/index.js +19 -4
- package/index.d.ts +13 -5
- package/index.js +21 -7
- package/package.json +17 -16
- package/parse_schema/parse.d.ts +31 -9
- package/parse_schema/parse.js +152 -12
- package/schema/base_schema.d.ts +5 -3
- package/schema/base_schema.js +6 -0
- package/schema/field.d.ts +78 -21
- package/schema/field.js +219 -72
- package/schema/index.d.ts +2 -2
- package/schema/index.js +5 -1
- package/schema/json_field.d.ts +16 -4
- package/schema/json_field.js +32 -2
- package/schema/schema.d.ts +89 -20
- package/schema/schema.js +13 -14
- package/schema/struct_field.d.ts +15 -3
- package/schema/struct_field.js +71 -22
- package/schema/union_field.d.ts +1 -1
- package/scripts/custom_compiler.js +10 -6
- package/scripts/custom_graphql.js +124 -31
- package/scripts/migrate_v0.1.js +36 -0
- package/scripts/move_types.js +117 -0
- package/scripts/read_schema.js +20 -5
- package/testutils/action/complex_schemas.d.ts +69 -0
- package/testutils/action/complex_schemas.js +398 -0
- package/testutils/builder.d.ts +43 -47
- package/testutils/builder.js +76 -49
- package/testutils/db/fixture.d.ts +10 -0
- package/testutils/db/fixture.js +26 -0
- package/testutils/db/{test_db.d.ts → temp_db.d.ts} +24 -8
- package/testutils/db/{test_db.js → temp_db.js} +182 -45
- package/testutils/db/value.d.ts +7 -0
- package/testutils/db/value.js +251 -0
- package/testutils/db_mock.d.ts +16 -4
- package/testutils/db_mock.js +51 -6
- package/testutils/db_time_zone.d.ts +4 -0
- package/testutils/db_time_zone.js +41 -0
- package/testutils/ent-graphql-tests/index.d.ts +7 -1
- package/testutils/ent-graphql-tests/index.js +52 -23
- package/testutils/fake_data/const.d.ts +2 -1
- package/testutils/fake_data/const.js +3 -0
- package/testutils/fake_data/fake_contact.d.ts +8 -4
- package/testutils/fake_data/fake_contact.js +15 -8
- package/testutils/fake_data/fake_event.d.ts +5 -2
- package/testutils/fake_data/fake_event.js +9 -7
- package/testutils/fake_data/fake_tag.d.ts +36 -0
- package/testutils/fake_data/fake_tag.js +89 -0
- package/testutils/fake_data/fake_user.d.ts +10 -7
- package/testutils/fake_data/fake_user.js +18 -16
- package/testutils/fake_data/index.js +5 -1
- package/testutils/fake_data/internal.d.ts +2 -0
- package/testutils/fake_data/internal.js +7 -1
- package/testutils/fake_data/tag_query.d.ts +13 -0
- package/testutils/fake_data/tag_query.js +43 -0
- package/testutils/fake_data/test_helpers.d.ts +11 -4
- package/testutils/fake_data/test_helpers.js +28 -12
- package/testutils/fake_data/user_query.d.ts +13 -6
- package/testutils/fake_data/user_query.js +54 -22
- package/testutils/fake_log.d.ts +3 -3
- package/testutils/parse_sql.d.ts +6 -0
- package/testutils/parse_sql.js +16 -2
- package/testutils/test_edge_global_schema.d.ts +15 -0
- package/testutils/test_edge_global_schema.js +62 -0
- package/testutils/write.d.ts +2 -2
- package/testutils/write.js +33 -7
- package/tsc/ast.d.ts +25 -2
- package/tsc/ast.js +141 -17
- package/tsc/compilerOptions.js +5 -1
- package/tsc/move_generated.d.ts +1 -0
- package/tsc/move_generated.js +164 -0
- package/tsc/transform.d.ts +22 -0
- package/tsc/transform.js +181 -0
- package/tsc/transform_action.d.ts +22 -0
- package/tsc/transform_action.js +183 -0
- package/tsc/transform_ent.d.ts +17 -0
- package/tsc/transform_ent.js +60 -0
- package/tsc/transform_schema.d.ts +27 -0
- package/{scripts → tsc}/transform_schema.js +146 -117
- package/graphql/enums.d.ts +0 -3
- package/graphql/enums.js +0 -25
- package/scripts/move_generated.js +0 -142
- package/scripts/transform_code.js +0 -113
- package/scripts/transform_schema.d.ts +0 -1
- /package/scripts/{move_generated.d.ts → migrate_v0.1.d.ts} +0 -0
- /package/scripts/{transform_code.d.ts → move_types.d.ts} +0 -0
package/core/ent.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -22,13 +26,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
22
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
23
27
|
};
|
|
24
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
29
|
+
exports.loadNodesByEdge = exports.loadEdgeForID2 = exports.loadRawEdgeCountX = exports.loadUniqueNode = exports.loadUniqueEdge = exports.loadCustomEdges = exports.getEdgeClauseAndFields = exports.loadEdges = 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.EditNodeOperation = exports.RawQueryOperation = exports.buildGroupQuery = exports.buildQuery = exports.loadRows = exports.performRawQuery = exports.___setLogQueryErrorWithError = exports.loadRow = exports.loadRowX = exports.logQuery = exports.loadDerivedEntX = exports.loadDerivedEnt = exports.loadCustomCount = 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;
|
|
30
|
+
exports.getEdgeTypeInGroup = exports.applyPrivacyPolicyForRows = exports.applyPrivacyPolicyForRow = void 0;
|
|
26
31
|
const db_1 = __importStar(require("./db"));
|
|
27
32
|
const privacy_1 = require("./privacy");
|
|
28
33
|
const clause = __importStar(require("./clause"));
|
|
29
34
|
const action_1 = require("../action");
|
|
30
35
|
const logger_1 = require("./logger");
|
|
31
36
|
const dataloader_1 = __importDefault(require("dataloader"));
|
|
37
|
+
const schema_1 = require("../schema/schema");
|
|
38
|
+
const global_schema_1 = require("./global_schema");
|
|
32
39
|
// TODO kill this and createDataLoader
|
|
33
40
|
class cacheMap {
|
|
34
41
|
constructor(options) {
|
|
@@ -38,7 +45,7 @@ class cacheMap {
|
|
|
38
45
|
get(key) {
|
|
39
46
|
const ret = this.m.get(key);
|
|
40
47
|
if (ret) {
|
|
41
|
-
(0, logger_1.log)("
|
|
48
|
+
(0, logger_1.log)("cache", {
|
|
42
49
|
"dataloader-cache-hit": key,
|
|
43
50
|
"tableName": this.options.tableName,
|
|
44
51
|
});
|
|
@@ -55,12 +62,41 @@ class cacheMap {
|
|
|
55
62
|
return this.m.clear();
|
|
56
63
|
}
|
|
57
64
|
}
|
|
65
|
+
class entCacheMap {
|
|
66
|
+
constructor(viewer, options) {
|
|
67
|
+
this.viewer = viewer;
|
|
68
|
+
this.options = options;
|
|
69
|
+
this.m = new Map();
|
|
70
|
+
this.logEnabled = false;
|
|
71
|
+
this.logEnabled = (0, logger_1.logEnabled)("cache");
|
|
72
|
+
}
|
|
73
|
+
get(id) {
|
|
74
|
+
const ret = this.m.get(id);
|
|
75
|
+
if (this.logEnabled && ret) {
|
|
76
|
+
const key = getEntKey(this.viewer, id, this.options);
|
|
77
|
+
(0, logger_1.log)("cache", {
|
|
78
|
+
"ent-cache-hit": key,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return ret;
|
|
82
|
+
}
|
|
83
|
+
set(key, value) {
|
|
84
|
+
return this.m.set(key, value);
|
|
85
|
+
}
|
|
86
|
+
delete(key) {
|
|
87
|
+
return this.m.delete(key);
|
|
88
|
+
}
|
|
89
|
+
clear() {
|
|
90
|
+
return this.m.clear();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
58
93
|
function createDataLoader(options) {
|
|
59
94
|
const loaderOptions = {};
|
|
60
95
|
// if query logging is enabled, we should log what's happening with loader
|
|
61
96
|
if ((0, logger_1.logEnabled)("query")) {
|
|
62
97
|
loaderOptions.cacheMap = new cacheMap(options);
|
|
63
98
|
}
|
|
99
|
+
// something here brokwn with strict:true
|
|
64
100
|
return new dataloader_1.default(async (ids) => {
|
|
65
101
|
if (!ids.length) {
|
|
66
102
|
return [];
|
|
@@ -84,28 +120,151 @@ function createDataLoader(options) {
|
|
|
84
120
|
return result;
|
|
85
121
|
}, loaderOptions);
|
|
86
122
|
}
|
|
87
|
-
//
|
|
123
|
+
// used to wrap errors that would eventually be thrown in ents
|
|
124
|
+
// not an Error because DataLoader automatically rejects that
|
|
125
|
+
class ErrorWrapper {
|
|
126
|
+
constructor(error) {
|
|
127
|
+
this.error = error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function createEntLoader(viewer, options, map) {
|
|
131
|
+
// share the cache across loaders even if we create a new instance
|
|
132
|
+
const loaderOptions = {};
|
|
133
|
+
loaderOptions.cacheMap = map;
|
|
134
|
+
return new dataloader_1.default(async (ids) => {
|
|
135
|
+
if (!ids.length) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
let result = [];
|
|
139
|
+
const tableName = options.loaderFactory.options?.tableName;
|
|
140
|
+
const loader = options.loaderFactory.createLoader(viewer.context);
|
|
141
|
+
const rows = await loader.loadMany(ids);
|
|
142
|
+
// this is a loader which should return the same order based on passed-in ids
|
|
143
|
+
// so let's depend on that...
|
|
144
|
+
for (let idx = 0; idx < rows.length; idx++) {
|
|
145
|
+
const row = rows[idx];
|
|
146
|
+
// db error
|
|
147
|
+
if (row instanceof Error) {
|
|
148
|
+
result[idx] = row;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
else if (!row) {
|
|
152
|
+
if (tableName) {
|
|
153
|
+
result[idx] = new ErrorWrapper(new Error(`couldn't find row for value ${ids[idx]} in table ${tableName}`));
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
result[idx] = new ErrorWrapper(new Error(`couldn't find row for value ${ids[idx]}`));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
161
|
+
if (r instanceof Error) {
|
|
162
|
+
result[idx] = new ErrorWrapper(r);
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
result[idx] = r;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return result;
|
|
170
|
+
}, loaderOptions);
|
|
171
|
+
}
|
|
172
|
+
class EntLoader {
|
|
173
|
+
constructor(viewer, options) {
|
|
174
|
+
this.viewer = viewer;
|
|
175
|
+
this.options = options;
|
|
176
|
+
this.map = new entCacheMap(viewer, options);
|
|
177
|
+
this.loader = createEntLoader(this.viewer, this.options, this.map);
|
|
178
|
+
}
|
|
179
|
+
getMap() {
|
|
180
|
+
return this.map;
|
|
181
|
+
}
|
|
182
|
+
async load(id) {
|
|
183
|
+
return this.loader.load(id);
|
|
184
|
+
}
|
|
185
|
+
async loadMany(ids) {
|
|
186
|
+
return this.loader.loadMany(ids);
|
|
187
|
+
}
|
|
188
|
+
prime(id, ent) {
|
|
189
|
+
this.loader.prime(id, ent);
|
|
190
|
+
}
|
|
191
|
+
clear(id) {
|
|
192
|
+
this.loader.clear(id);
|
|
193
|
+
}
|
|
194
|
+
clearAll() {
|
|
195
|
+
this.loader.clearAll();
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function getEntLoader(viewer, options) {
|
|
199
|
+
if (!viewer.context?.cache) {
|
|
200
|
+
return new EntLoader(viewer, options);
|
|
201
|
+
}
|
|
202
|
+
const name = `ent-loader:${viewer.instanceKey()}:${options.loaderFactory.name}`;
|
|
203
|
+
return viewer.context.cache.getLoaderWithLoadMany(name, () => new EntLoader(viewer, options));
|
|
204
|
+
}
|
|
205
|
+
function getEntKey(viewer, id, options) {
|
|
206
|
+
return `${viewer.instanceKey()}:${options.loaderFactory.name}:${id}`;
|
|
207
|
+
}
|
|
208
|
+
exports.getEntKey = getEntKey;
|
|
88
209
|
async function loadEnt(viewer, id, options) {
|
|
89
|
-
|
|
90
|
-
|
|
210
|
+
if (typeof id !== "string" &&
|
|
211
|
+
typeof id !== "number" &&
|
|
212
|
+
typeof id !== "bigint") {
|
|
213
|
+
throw new Error(`invalid id ${id} passed to loadEnt`);
|
|
214
|
+
}
|
|
215
|
+
const r = await getEntLoader(viewer, options).load(id);
|
|
216
|
+
return r instanceof ErrorWrapper ? null : r;
|
|
91
217
|
}
|
|
92
218
|
exports.loadEnt = loadEnt;
|
|
219
|
+
async function applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options,
|
|
220
|
+
// can pass in loader when calling this for multi-id cases...
|
|
221
|
+
loader) {
|
|
222
|
+
if (!loader) {
|
|
223
|
+
loader = getEntLoader(viewer, options);
|
|
224
|
+
}
|
|
225
|
+
// TODO every row.id needs to be audited...
|
|
226
|
+
// https://github.com/lolopinto/ent/issues/1064
|
|
227
|
+
const id = row.id;
|
|
228
|
+
// we should check the ent loader cache to see if this is already there
|
|
229
|
+
// TODO hmm... we eventually need a custom data-loader for this too so that it's all done correctly if there's a complicated fetch deep down in graphql
|
|
230
|
+
const result = loader.getMap().get(id);
|
|
231
|
+
if (result !== undefined) {
|
|
232
|
+
return result;
|
|
233
|
+
}
|
|
234
|
+
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
235
|
+
if (r instanceof Error) {
|
|
236
|
+
loader.prime(id, new ErrorWrapper(r));
|
|
237
|
+
return new ErrorWrapper(r);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
loader.prime(id, r);
|
|
241
|
+
return r;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
93
244
|
// this is the same implementation-wise (right now) as loadEnt. it's just clearer that it's not loaded via ID.
|
|
94
245
|
// used for load via email address etc
|
|
95
246
|
async function loadEntViaKey(viewer, key, options) {
|
|
96
247
|
const row = await options.loaderFactory
|
|
97
248
|
.createLoader(viewer.context)
|
|
98
249
|
.load(key);
|
|
99
|
-
|
|
250
|
+
if (!row) {
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const r = await applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options);
|
|
254
|
+
return r instanceof ErrorWrapper ? null : r;
|
|
100
255
|
}
|
|
101
256
|
exports.loadEntViaKey = loadEntViaKey;
|
|
102
257
|
async function loadEntX(viewer, id, options) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
throw new Error(
|
|
258
|
+
if (typeof id !== "string" &&
|
|
259
|
+
typeof id !== "number" &&
|
|
260
|
+
typeof id !== "bigint") {
|
|
261
|
+
throw new Error(`invalid id ${id} passed to loadEntX`);
|
|
107
262
|
}
|
|
108
|
-
|
|
263
|
+
const r = await getEntLoader(viewer, options).load(id);
|
|
264
|
+
if (r instanceof ErrorWrapper) {
|
|
265
|
+
throw r.error;
|
|
266
|
+
}
|
|
267
|
+
return r;
|
|
109
268
|
}
|
|
110
269
|
exports.loadEntX = loadEntX;
|
|
111
270
|
async function loadEntXViaKey(viewer, key, options) {
|
|
@@ -116,9 +275,16 @@ async function loadEntXViaKey(viewer, key, options) {
|
|
|
116
275
|
// todo make this better
|
|
117
276
|
throw new Error(`${options.loaderFactory.name}: couldn't find row for value ${key}`);
|
|
118
277
|
}
|
|
119
|
-
|
|
278
|
+
const r = await applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options);
|
|
279
|
+
if (r instanceof ErrorWrapper) {
|
|
280
|
+
throw r.error;
|
|
281
|
+
}
|
|
282
|
+
return r;
|
|
120
283
|
}
|
|
121
284
|
exports.loadEntXViaKey = loadEntXViaKey;
|
|
285
|
+
/**
|
|
286
|
+
* @deprecated use loadCustomEnts
|
|
287
|
+
*/
|
|
122
288
|
async function loadEntFromClause(viewer, options, clause) {
|
|
123
289
|
const rowOptions = {
|
|
124
290
|
...options,
|
|
@@ -126,12 +292,18 @@ async function loadEntFromClause(viewer, options, clause) {
|
|
|
126
292
|
context: viewer.context,
|
|
127
293
|
};
|
|
128
294
|
const row = await loadRow(rowOptions);
|
|
129
|
-
|
|
295
|
+
if (row === null) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
return applyPrivacyPolicyForRow(viewer, options, row);
|
|
130
299
|
}
|
|
131
300
|
exports.loadEntFromClause = loadEntFromClause;
|
|
132
301
|
// same as loadEntFromClause
|
|
133
302
|
// only works for ents where primary key is "id"
|
|
134
303
|
// use loadEnt with a loaderFactory if different
|
|
304
|
+
/**
|
|
305
|
+
* @deprecated use loadCustomEnts
|
|
306
|
+
*/
|
|
135
307
|
async function loadEntXFromClause(viewer, options, clause) {
|
|
136
308
|
const rowOptions = {
|
|
137
309
|
...options,
|
|
@@ -146,37 +318,19 @@ async function loadEnts(viewer, options, ...ids) {
|
|
|
146
318
|
if (!ids.length) {
|
|
147
319
|
return new Map();
|
|
148
320
|
}
|
|
149
|
-
|
|
150
|
-
let rows = [];
|
|
151
|
-
// TODO loadMany everywhere
|
|
152
|
-
const l = options.loaderFactory.createLoader(viewer.context);
|
|
153
|
-
if (l.loadMany) {
|
|
154
|
-
loaded = true;
|
|
155
|
-
rows = await l.loadMany(ids);
|
|
156
|
-
}
|
|
157
|
-
// TODO rewrite all of this
|
|
321
|
+
// result
|
|
158
322
|
let m = new Map();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
continue;
|
|
164
|
-
}
|
|
165
|
-
if (row instanceof Error) {
|
|
166
|
-
throw row;
|
|
167
|
-
}
|
|
168
|
-
rows2.push(row);
|
|
323
|
+
const ret = await getEntLoader(viewer, options).loadMany(ids);
|
|
324
|
+
for (const r of ret) {
|
|
325
|
+
if (r instanceof Error) {
|
|
326
|
+
throw r;
|
|
169
327
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
m
|
|
174
|
-
// this is always "id" if not using an ObjectLoaderFactory
|
|
175
|
-
clause.In("id", ...ids), options);
|
|
328
|
+
if (r instanceof ErrorWrapper) {
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
m.set(r.id, r);
|
|
176
332
|
}
|
|
177
333
|
return m;
|
|
178
|
-
// TODO do we want to change this to be a map not a list so that it's easy to check for existence?
|
|
179
|
-
// TODO eventually this should be doing a cache then db queyr and maybe depend on dataloader to get all the results at once
|
|
180
334
|
}
|
|
181
335
|
exports.loadEnts = loadEnts;
|
|
182
336
|
// calls loadEnts and returns the results sorted in the order they were passed in
|
|
@@ -195,6 +349,9 @@ async function loadEntsList(viewer, options, ...ids) {
|
|
|
195
349
|
exports.loadEntsList = loadEntsList;
|
|
196
350
|
// we return a map here so that any sorting for queries that exist
|
|
197
351
|
// can be done in O(N) time
|
|
352
|
+
/**
|
|
353
|
+
* @deperecated use loadCustomEnts
|
|
354
|
+
*/
|
|
198
355
|
async function loadEntsFromClause(viewer, clause, options) {
|
|
199
356
|
const rowOptions = {
|
|
200
357
|
...options,
|
|
@@ -202,65 +359,139 @@ async function loadEntsFromClause(viewer, clause, options) {
|
|
|
202
359
|
context: viewer.context,
|
|
203
360
|
};
|
|
204
361
|
const rows = await loadRows(rowOptions);
|
|
205
|
-
return
|
|
362
|
+
return applyPrivacyPolicyForRowsDeprecated(viewer, rows, options);
|
|
206
363
|
}
|
|
207
364
|
exports.loadEntsFromClause = loadEntsFromClause;
|
|
208
365
|
async function loadCustomEnts(viewer, options, query) {
|
|
209
366
|
const rows = await loadCustomData(options, query, viewer.context);
|
|
210
|
-
|
|
211
|
-
await Promise.all(rows.map(async (row, idx) => {
|
|
212
|
-
const ent = new options.ent(viewer, row);
|
|
213
|
-
let privacyEnt = await applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
214
|
-
if (privacyEnt) {
|
|
215
|
-
result[idx] = privacyEnt;
|
|
216
|
-
}
|
|
217
|
-
}));
|
|
218
|
-
// filter ents that aren't visible because of privacy
|
|
219
|
-
return result.filter((r) => r !== undefined);
|
|
367
|
+
return applyPrivacyPolicyForRows(viewer, rows, options);
|
|
220
368
|
}
|
|
221
369
|
exports.loadCustomEnts = loadCustomEnts;
|
|
222
370
|
function isClause(opts) {
|
|
223
371
|
const cls = opts;
|
|
224
372
|
return cls.clause !== undefined && cls.values !== undefined;
|
|
225
373
|
}
|
|
226
|
-
function
|
|
374
|
+
function isParameterizedQuery(opts) {
|
|
227
375
|
return opts.query !== undefined;
|
|
228
376
|
}
|
|
377
|
+
/**
|
|
378
|
+
* Note that if there's default read transformations (e.g. soft delete) and a clause is passed in
|
|
379
|
+
* either as Clause or QueryDataOptions without {disableTransformations: true}, the default transformation
|
|
380
|
+
* (e.g. soft delete) is applied.
|
|
381
|
+
*
|
|
382
|
+
* Passing a full SQL string or Paramterized SQL string doesn't apply it and the given string is sent to the
|
|
383
|
+
* database as written.
|
|
384
|
+
*
|
|
385
|
+
* e.g.
|
|
386
|
+
* Foo.loadCustom(opts, 'SELECT * FROM foo') // doesn't change the query
|
|
387
|
+
* Foo.loadCustom(opts, { query: 'SELECT * FROM foo WHERE id = ?', values: [1]}) // doesn't change the query
|
|
388
|
+
* Foo.loadCustom(opts, query.Eq('time', Date.now())) // changes the query
|
|
389
|
+
* Foo.loadCustom(opts, {
|
|
390
|
+
* clause: query.LessEq('time', Date.now()),
|
|
391
|
+
* limit: 100,
|
|
392
|
+
* orderby: 'time',
|
|
393
|
+
* }) // changes the query
|
|
394
|
+
* Foo.loadCustom(opts, {
|
|
395
|
+
* clause: query.LessEq('time', Date.now()),
|
|
396
|
+
* limit: 100,
|
|
397
|
+
* orderby: 'time',
|
|
398
|
+
* disableTransformations: false
|
|
399
|
+
* }) // doesn't change the query
|
|
400
|
+
*/
|
|
229
401
|
async function loadCustomData(options, query, context) {
|
|
402
|
+
const rows = await loadCustomDataImpl(options, query, context);
|
|
403
|
+
// prime the data so that subsequent fetches of the row with this id are a cache hit.
|
|
404
|
+
if (options.prime) {
|
|
405
|
+
const loader = options.loaderFactory.createLoader(context);
|
|
406
|
+
if (isPrimableLoader(loader) && loader.primeAll !== undefined) {
|
|
407
|
+
for (const row of rows) {
|
|
408
|
+
loader.primeAll(row);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return rows;
|
|
413
|
+
}
|
|
414
|
+
exports.loadCustomData = loadCustomData;
|
|
415
|
+
// NOTE: if you use a raw query or paramterized query with this,
|
|
416
|
+
// you should use `SELECT count(*) as count...`
|
|
417
|
+
async function loadCustomCount(options, query, context) {
|
|
418
|
+
// TODO also need to loaderify this in case we're querying for this a lot...
|
|
419
|
+
const rows = await loadCustomDataImpl({
|
|
420
|
+
...options,
|
|
421
|
+
fields: ["count(1) as count"],
|
|
422
|
+
}, query, context);
|
|
423
|
+
if (rows.length) {
|
|
424
|
+
return parseInt(rows[0].count);
|
|
425
|
+
}
|
|
426
|
+
return 0;
|
|
427
|
+
}
|
|
428
|
+
exports.loadCustomCount = loadCustomCount;
|
|
429
|
+
function isPrimableLoader(loader) {
|
|
430
|
+
return loader != undefined;
|
|
431
|
+
}
|
|
432
|
+
async function loadCustomDataImpl(options, query, context) {
|
|
433
|
+
function getClause(cls) {
|
|
434
|
+
let optClause = options.loaderFactory?.options?.clause;
|
|
435
|
+
if (typeof optClause === "function") {
|
|
436
|
+
optClause = optClause();
|
|
437
|
+
}
|
|
438
|
+
if (!optClause) {
|
|
439
|
+
return cls;
|
|
440
|
+
}
|
|
441
|
+
// @ts-expect-error string|ID mismatch
|
|
442
|
+
return clause.And(cls, optClause);
|
|
443
|
+
}
|
|
230
444
|
if (typeof query === "string") {
|
|
231
445
|
// no caching, perform raw query
|
|
232
|
-
return
|
|
446
|
+
return performRawQuery(query, [], []);
|
|
447
|
+
// @ts-ignore
|
|
233
448
|
}
|
|
234
449
|
else if (isClause(query)) {
|
|
450
|
+
// if a Clause is passed in and we have a default clause
|
|
451
|
+
// associated with the query, pass that in
|
|
452
|
+
// if we want to disableTransformations, need to indicate that with
|
|
453
|
+
// disableTransformations option
|
|
235
454
|
// this will have rudimentary caching but nothing crazy
|
|
236
|
-
return
|
|
455
|
+
return loadRows({
|
|
237
456
|
...options,
|
|
238
|
-
|
|
457
|
+
// @ts-ignore
|
|
458
|
+
clause: getClause(query),
|
|
239
459
|
context: context,
|
|
240
460
|
});
|
|
241
461
|
}
|
|
242
|
-
else if (
|
|
462
|
+
else if (isParameterizedQuery(query)) {
|
|
243
463
|
// no caching, perform raw query
|
|
244
|
-
return
|
|
464
|
+
return performRawQuery(query.query, query.values || [], query.logValues);
|
|
245
465
|
}
|
|
246
466
|
else {
|
|
467
|
+
let cls = query.clause;
|
|
468
|
+
if (!query.disableTransformations) {
|
|
469
|
+
// @ts-ignore
|
|
470
|
+
cls = getClause(cls);
|
|
471
|
+
}
|
|
247
472
|
// this will have rudimentary caching but nothing crazy
|
|
248
|
-
return
|
|
473
|
+
return loadRows({
|
|
249
474
|
...query,
|
|
250
475
|
...options,
|
|
251
476
|
context: context,
|
|
477
|
+
clause: cls,
|
|
252
478
|
});
|
|
253
479
|
}
|
|
254
480
|
}
|
|
255
|
-
exports.loadCustomData = loadCustomData;
|
|
256
481
|
// Derived ents
|
|
482
|
+
// no ent caching
|
|
257
483
|
async function loadDerivedEnt(viewer, data, loader) {
|
|
258
484
|
const ent = new loader(viewer, data);
|
|
259
|
-
|
|
485
|
+
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, {
|
|
260
486
|
ent: loader,
|
|
261
487
|
});
|
|
488
|
+
if (r instanceof Error) {
|
|
489
|
+
return null;
|
|
490
|
+
}
|
|
491
|
+
return r;
|
|
262
492
|
}
|
|
263
493
|
exports.loadDerivedEnt = loadDerivedEnt;
|
|
494
|
+
// won't have caching yet either
|
|
264
495
|
async function loadDerivedEntX(viewer, data, loader) {
|
|
265
496
|
const ent = new loader(viewer, data);
|
|
266
497
|
return await applyPrivacyPolicyForEntX(viewer, ent, data, { ent: loader });
|
|
@@ -269,19 +500,21 @@ exports.loadDerivedEntX = loadDerivedEntX;
|
|
|
269
500
|
// everything calls into this two so should be fine
|
|
270
501
|
// TODO is there a smarter way to not instantiate two objects here?
|
|
271
502
|
async function applyPrivacyPolicyForEnt(viewer, ent, data, fieldPrivacyOptions) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (!visible) {
|
|
275
|
-
return null;
|
|
276
|
-
}
|
|
503
|
+
const error = await (0, privacy_1.applyPrivacyPolicyImpl)(viewer, ent.getPrivacyPolicy(), ent);
|
|
504
|
+
if (error === null) {
|
|
277
505
|
return doFieldPrivacy(viewer, ent, data, fieldPrivacyOptions);
|
|
278
506
|
}
|
|
279
|
-
return
|
|
507
|
+
return error;
|
|
280
508
|
}
|
|
281
509
|
async function applyPrivacyPolicyForEntX(viewer, ent, data, options) {
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
510
|
+
const r = await applyPrivacyPolicyForEnt(viewer, ent, data, options);
|
|
511
|
+
if (r instanceof Error) {
|
|
512
|
+
throw r;
|
|
513
|
+
}
|
|
514
|
+
if (r === null) {
|
|
515
|
+
throw new Error(`couldn't apply privacyPoliy for ent ${ent.id}`);
|
|
516
|
+
}
|
|
517
|
+
return r;
|
|
285
518
|
}
|
|
286
519
|
async function doFieldPrivacy(viewer, ent, data, options) {
|
|
287
520
|
if (!options.fieldPrivacy) {
|
|
@@ -289,13 +522,16 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
289
522
|
}
|
|
290
523
|
const promises = [];
|
|
291
524
|
let somethingChanged = false;
|
|
525
|
+
const origData = {
|
|
526
|
+
...data,
|
|
527
|
+
};
|
|
292
528
|
for (const [k, policy] of options.fieldPrivacy) {
|
|
529
|
+
const curr = data[k];
|
|
530
|
+
if (curr === null || curr === undefined) {
|
|
531
|
+
continue;
|
|
532
|
+
}
|
|
293
533
|
promises.push((async () => {
|
|
294
534
|
// don't do anything if key is null or for some reason missing
|
|
295
|
-
const curr = data[k];
|
|
296
|
-
if (curr === null || curr === undefined) {
|
|
297
|
-
return;
|
|
298
|
-
}
|
|
299
535
|
const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
|
|
300
536
|
if (!r) {
|
|
301
537
|
data[k] = null;
|
|
@@ -306,8 +542,11 @@ async function doFieldPrivacy(viewer, ent, data, options) {
|
|
|
306
542
|
await Promise.all(promises);
|
|
307
543
|
if (somethingChanged) {
|
|
308
544
|
// have to create new instance
|
|
309
|
-
|
|
545
|
+
const ent = new options.ent(viewer, data);
|
|
546
|
+
ent.__setRawDBData(origData);
|
|
547
|
+
return ent;
|
|
310
548
|
}
|
|
549
|
+
ent.__setRawDBData(origData);
|
|
311
550
|
return ent;
|
|
312
551
|
}
|
|
313
552
|
function logQuery(query, logValues) {
|
|
@@ -317,6 +556,7 @@ function logQuery(query, logValues) {
|
|
|
317
556
|
});
|
|
318
557
|
(0, logger_1.logTrace)();
|
|
319
558
|
}
|
|
559
|
+
exports.logQuery = logQuery;
|
|
320
560
|
// TODO long term figure out if this API should be exposed
|
|
321
561
|
async function loadRowX(options) {
|
|
322
562
|
const result = await loadRow(options);
|
|
@@ -339,29 +579,26 @@ async function loadRow(options) {
|
|
|
339
579
|
}
|
|
340
580
|
const query = buildQuery(options);
|
|
341
581
|
logQuery(query, options.clause.logValues());
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (res.rowCount
|
|
346
|
-
|
|
347
|
-
(0, logger_1.log)("error", "got more than one row for query " + query);
|
|
348
|
-
}
|
|
349
|
-
return null;
|
|
350
|
-
}
|
|
351
|
-
// put the row in the cache...
|
|
352
|
-
if (cache) {
|
|
353
|
-
cache.primeCache(options, res.rows[0]);
|
|
582
|
+
const pool = db_1.default.getInstance().getPool();
|
|
583
|
+
const res = await pool.query(query, options.clause.values());
|
|
584
|
+
if (res.rowCount != 1) {
|
|
585
|
+
if (res.rowCount > 1) {
|
|
586
|
+
(0, logger_1.log)("error", "got more than one row for query " + query);
|
|
354
587
|
}
|
|
355
|
-
return res.rows[0];
|
|
356
|
-
}
|
|
357
|
-
catch (e) {
|
|
358
|
-
// an example of an error being suppressed
|
|
359
|
-
// another one. TODO https://github.com/lolopinto/ent/issues/862
|
|
360
|
-
(0, logger_1.log)("error", e);
|
|
361
588
|
return null;
|
|
362
589
|
}
|
|
590
|
+
// put the row in the cache...
|
|
591
|
+
if (cache) {
|
|
592
|
+
cache.primeCache(options, res.rows[0]);
|
|
593
|
+
}
|
|
594
|
+
return res.rows[0];
|
|
363
595
|
}
|
|
364
596
|
exports.loadRow = loadRow;
|
|
597
|
+
var _logQueryWithError = false;
|
|
598
|
+
function ___setLogQueryErrorWithError(val) {
|
|
599
|
+
_logQueryWithError = val || false;
|
|
600
|
+
}
|
|
601
|
+
exports.___setLogQueryErrorWithError = ___setLogQueryErrorWithError;
|
|
365
602
|
// this always goes to the db, no cache, nothing
|
|
366
603
|
async function performRawQuery(query, values, logValues) {
|
|
367
604
|
const pool = db_1.default.getInstance().getPool();
|
|
@@ -371,9 +608,11 @@ async function performRawQuery(query, values, logValues) {
|
|
|
371
608
|
return res.rows;
|
|
372
609
|
}
|
|
373
610
|
catch (e) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
611
|
+
if (_logQueryWithError) {
|
|
612
|
+
const msg = e.message;
|
|
613
|
+
throw new Error(`error \`${msg}\` running query: \`${query}\` with values: \`${logValues}\``);
|
|
614
|
+
}
|
|
615
|
+
throw e;
|
|
377
616
|
}
|
|
378
617
|
}
|
|
379
618
|
exports.performRawQuery = performRawQuery;
|
|
@@ -432,10 +671,41 @@ function buildGroupQuery(options) {
|
|
|
432
671
|
];
|
|
433
672
|
}
|
|
434
673
|
exports.buildGroupQuery = buildGroupQuery;
|
|
674
|
+
class RawQueryOperation {
|
|
675
|
+
constructor(queries) {
|
|
676
|
+
this.queries = queries;
|
|
677
|
+
}
|
|
678
|
+
async performWrite(queryer, context) {
|
|
679
|
+
for (const q of this.queries) {
|
|
680
|
+
if (typeof q === "string") {
|
|
681
|
+
logQuery(q, []);
|
|
682
|
+
await queryer.query(q);
|
|
683
|
+
}
|
|
684
|
+
else {
|
|
685
|
+
logQuery(q.query, q.logValues || []);
|
|
686
|
+
await queryer.query(q.query, q.values);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
performWriteSync(queryer, context) {
|
|
691
|
+
for (const q of this.queries) {
|
|
692
|
+
if (typeof q === "string") {
|
|
693
|
+
logQuery(q, []);
|
|
694
|
+
queryer.execSync(q);
|
|
695
|
+
}
|
|
696
|
+
else {
|
|
697
|
+
logQuery(q.query, q.logValues || []);
|
|
698
|
+
queryer.execSync(q.query, q.values);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
exports.RawQueryOperation = RawQueryOperation;
|
|
435
704
|
class EditNodeOperation {
|
|
436
705
|
constructor(options, existingEnt = null) {
|
|
437
706
|
this.options = options;
|
|
438
707
|
this.existingEnt = existingEnt;
|
|
708
|
+
this.row = null;
|
|
439
709
|
this.placeholderID = options.placeholderID;
|
|
440
710
|
}
|
|
441
711
|
resolve(executor) {
|
|
@@ -471,9 +741,10 @@ class EditNodeOperation {
|
|
|
471
741
|
if (this.hasData(options.fields)) {
|
|
472
742
|
// even this with returning * may not always work if transformed...
|
|
473
743
|
// we can have a transformed flag to see if it should be returned?
|
|
474
|
-
this.row = await editRow(queryer, options,
|
|
744
|
+
this.row = await editRow(queryer, options, "RETURNING *");
|
|
475
745
|
}
|
|
476
746
|
else {
|
|
747
|
+
// @ts-ignore
|
|
477
748
|
this.row = this.existingEnt["data"];
|
|
478
749
|
}
|
|
479
750
|
}
|
|
@@ -496,7 +767,8 @@ class EditNodeOperation {
|
|
|
496
767
|
optionClause = opts.clause;
|
|
497
768
|
}
|
|
498
769
|
if (optionClause) {
|
|
499
|
-
|
|
770
|
+
// @ts-expect-error ID|string mismatch
|
|
771
|
+
cls = clause.And(cls, optionClause);
|
|
500
772
|
}
|
|
501
773
|
}
|
|
502
774
|
const query = buildQuery({
|
|
@@ -520,10 +792,11 @@ class EditNodeOperation {
|
|
|
520
792
|
};
|
|
521
793
|
if (this.existingEnt) {
|
|
522
794
|
if (this.hasData(this.options.fields)) {
|
|
523
|
-
editRowSync(queryer, options,
|
|
795
|
+
editRowSync(queryer, options, "RETURNING *");
|
|
524
796
|
this.reloadRow(queryer, this.existingEnt.id, options);
|
|
525
797
|
}
|
|
526
798
|
else {
|
|
799
|
+
// @ts-ignore
|
|
527
800
|
this.row = this.existingEnt["data"];
|
|
528
801
|
}
|
|
529
802
|
}
|
|
@@ -545,7 +818,8 @@ class EditNodeOperation {
|
|
|
545
818
|
}
|
|
546
819
|
exports.EditNodeOperation = EditNodeOperation;
|
|
547
820
|
class EdgeOperation {
|
|
548
|
-
constructor(edgeInput, options) {
|
|
821
|
+
constructor(builder, edgeInput, options) {
|
|
822
|
+
this.builder = builder;
|
|
549
823
|
this.edgeInput = edgeInput;
|
|
550
824
|
this.options = options;
|
|
551
825
|
}
|
|
@@ -581,7 +855,32 @@ class EdgeOperation {
|
|
|
581
855
|
}
|
|
582
856
|
}
|
|
583
857
|
getDeleteRowParams(edgeData, edge, context) {
|
|
858
|
+
let transformed = null;
|
|
859
|
+
let op = schema_1.SQLStatementOperation.Delete;
|
|
860
|
+
let updateData = null;
|
|
861
|
+
// TODO respect disableTransformations
|
|
862
|
+
const transformedEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
863
|
+
if (transformedEdgeWrite) {
|
|
864
|
+
transformed = transformedEdgeWrite({
|
|
865
|
+
op: schema_1.SQLStatementOperation.Delete,
|
|
866
|
+
edge,
|
|
867
|
+
});
|
|
868
|
+
if (transformed) {
|
|
869
|
+
op = transformed.op;
|
|
870
|
+
if (transformed.op === schema_1.SQLStatementOperation.Insert) {
|
|
871
|
+
throw new Error(`cannot currently transform a delete into an insert`);
|
|
872
|
+
}
|
|
873
|
+
if (transformed.op === schema_1.SQLStatementOperation.Update) {
|
|
874
|
+
if (!transformed.data) {
|
|
875
|
+
throw new Error(`cannot transform a delete into an update without providing data`);
|
|
876
|
+
}
|
|
877
|
+
updateData = transformed.data;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
584
881
|
return {
|
|
882
|
+
op,
|
|
883
|
+
updateData,
|
|
585
884
|
options: {
|
|
586
885
|
tableName: edgeData.edgeTable,
|
|
587
886
|
context,
|
|
@@ -591,11 +890,36 @@ class EdgeOperation {
|
|
|
591
890
|
}
|
|
592
891
|
async performDeleteWrite(q, edgeData, edge, context) {
|
|
593
892
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
594
|
-
|
|
893
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
894
|
+
return deleteRows(q, params.options, params.clause);
|
|
895
|
+
}
|
|
896
|
+
else {
|
|
897
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
898
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
899
|
+
}
|
|
900
|
+
await editRow(q, {
|
|
901
|
+
tableName: params.options.tableName,
|
|
902
|
+
whereClause: params.clause,
|
|
903
|
+
fields: params.updateData,
|
|
904
|
+
fieldsToLog: params.updateData,
|
|
905
|
+
});
|
|
906
|
+
}
|
|
595
907
|
}
|
|
596
908
|
performDeleteWriteSync(q, edgeData, edge, context) {
|
|
597
909
|
const params = this.getDeleteRowParams(edgeData, edge, context);
|
|
598
|
-
|
|
910
|
+
if (params.op === schema_1.SQLStatementOperation.Delete) {
|
|
911
|
+
return deleteRowsSync(q, params.options, params.clause);
|
|
912
|
+
}
|
|
913
|
+
else {
|
|
914
|
+
if (params.op !== schema_1.SQLStatementOperation.Update) {
|
|
915
|
+
throw new Error(`invalid operation ${params.op}`);
|
|
916
|
+
}
|
|
917
|
+
editRowSync(q, {
|
|
918
|
+
tableName: params.options.tableName,
|
|
919
|
+
whereClause: params.clause,
|
|
920
|
+
fields: params.updateData,
|
|
921
|
+
});
|
|
922
|
+
}
|
|
599
923
|
}
|
|
600
924
|
getInsertRowParams(edgeData, edge, context) {
|
|
601
925
|
const fields = {
|
|
@@ -614,6 +938,32 @@ class EdgeOperation {
|
|
|
614
938
|
// maybe when actions exist?
|
|
615
939
|
fields["time"] = new Date().toISOString();
|
|
616
940
|
}
|
|
941
|
+
const onConflictFields = ["data"];
|
|
942
|
+
const extraEdgeFields = (0, global_schema_1.__getGlobalSchema)()?.extraEdgeFields;
|
|
943
|
+
if (extraEdgeFields) {
|
|
944
|
+
for (const name in extraEdgeFields) {
|
|
945
|
+
const f = extraEdgeFields[name];
|
|
946
|
+
if (f.defaultValueOnCreate) {
|
|
947
|
+
const storageKey = (0, schema_1.getStorageKey)(f, name);
|
|
948
|
+
fields[storageKey] = f.defaultValueOnCreate(this.builder, {});
|
|
949
|
+
// onconflict make sure we override the default values
|
|
950
|
+
// e.g. setting deleted_at = null for soft delete
|
|
951
|
+
onConflictFields.push(storageKey);
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
// TODO respect disableTransformations
|
|
956
|
+
let transformed = null;
|
|
957
|
+
const transformEdgeWrite = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeWrite;
|
|
958
|
+
if (transformEdgeWrite) {
|
|
959
|
+
transformed = transformEdgeWrite({
|
|
960
|
+
op: schema_1.SQLStatementOperation.Insert,
|
|
961
|
+
edge,
|
|
962
|
+
});
|
|
963
|
+
if (transformed) {
|
|
964
|
+
throw new Error(`transforming an insert edge not currently supported`);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
617
967
|
return [
|
|
618
968
|
{
|
|
619
969
|
tableName: edgeData.edgeTable,
|
|
@@ -621,7 +971,9 @@ class EdgeOperation {
|
|
|
621
971
|
fieldsToLog: fields,
|
|
622
972
|
context,
|
|
623
973
|
},
|
|
624
|
-
|
|
974
|
+
`ON CONFLICT(id1, edge_type, id2) DO UPDATE SET ${onConflictFields
|
|
975
|
+
.map((f) => `${f} = EXCLUDED.${f}`)
|
|
976
|
+
.join(", ")}`,
|
|
625
977
|
];
|
|
626
978
|
}
|
|
627
979
|
async performInsertWrite(q, edgeData, edge, context) {
|
|
@@ -658,7 +1010,7 @@ class EdgeOperation {
|
|
|
658
1010
|
}
|
|
659
1011
|
}
|
|
660
1012
|
symmetricEdge() {
|
|
661
|
-
return new EdgeOperation({
|
|
1013
|
+
return new EdgeOperation(this.builder, {
|
|
662
1014
|
id1: this.edgeInput.id2,
|
|
663
1015
|
id1Type: this.edgeInput.id2Type,
|
|
664
1016
|
id2: this.edgeInput.id1,
|
|
@@ -674,7 +1026,7 @@ class EdgeOperation {
|
|
|
674
1026
|
});
|
|
675
1027
|
}
|
|
676
1028
|
inverseEdge(edgeData) {
|
|
677
|
-
return new EdgeOperation({
|
|
1029
|
+
return new EdgeOperation(this.builder, {
|
|
678
1030
|
id1: this.edgeInput.id2,
|
|
679
1031
|
id1Type: this.edgeInput.id2Type,
|
|
680
1032
|
id2: this.edgeInput.id1,
|
|
@@ -742,7 +1094,7 @@ class EdgeOperation {
|
|
|
742
1094
|
if (data) {
|
|
743
1095
|
edge.data = data;
|
|
744
1096
|
}
|
|
745
|
-
return new EdgeOperation(edge, {
|
|
1097
|
+
return new EdgeOperation(builder, edge, {
|
|
746
1098
|
operation: action_1.WriteOperation.Insert,
|
|
747
1099
|
id2Placeholder,
|
|
748
1100
|
id1Placeholder,
|
|
@@ -763,7 +1115,7 @@ class EdgeOperation {
|
|
|
763
1115
|
if (data) {
|
|
764
1116
|
edge.data = data;
|
|
765
1117
|
}
|
|
766
|
-
return new EdgeOperation(edge, {
|
|
1118
|
+
return new EdgeOperation(builder, edge, {
|
|
767
1119
|
operation: action_1.WriteOperation.Insert,
|
|
768
1120
|
id1Placeholder,
|
|
769
1121
|
id2Placeholder,
|
|
@@ -781,7 +1133,7 @@ class EdgeOperation {
|
|
|
781
1133
|
id2Type: "",
|
|
782
1134
|
id1Type: "",
|
|
783
1135
|
};
|
|
784
|
-
return new EdgeOperation(edge, {
|
|
1136
|
+
return new EdgeOperation(builder, edge, {
|
|
785
1137
|
operation: action_1.WriteOperation.Delete,
|
|
786
1138
|
});
|
|
787
1139
|
}
|
|
@@ -796,7 +1148,7 @@ class EdgeOperation {
|
|
|
796
1148
|
id2Type: "",
|
|
797
1149
|
id1Type: "",
|
|
798
1150
|
};
|
|
799
|
-
return new EdgeOperation(edge, {
|
|
1151
|
+
return new EdgeOperation(builder, edge, {
|
|
800
1152
|
operation: action_1.WriteOperation.Delete,
|
|
801
1153
|
});
|
|
802
1154
|
}
|
|
@@ -808,24 +1160,26 @@ function isSyncQueryer(queryer) {
|
|
|
808
1160
|
async function mutateRow(queryer, query, values, logValues, options) {
|
|
809
1161
|
logQuery(query, logValues);
|
|
810
1162
|
let cache = options.context?.cache;
|
|
1163
|
+
let res;
|
|
811
1164
|
try {
|
|
812
|
-
let res;
|
|
813
1165
|
if (isSyncQueryer(queryer)) {
|
|
814
1166
|
res = queryer.execSync(query, values);
|
|
815
1167
|
}
|
|
816
1168
|
else {
|
|
817
1169
|
res = await queryer.exec(query, values);
|
|
818
1170
|
}
|
|
819
|
-
|
|
820
|
-
|
|
1171
|
+
}
|
|
1172
|
+
catch (e) {
|
|
1173
|
+
if (_logQueryWithError) {
|
|
1174
|
+
const msg = e.message;
|
|
1175
|
+
throw new Error(`error \`${msg}\` running query: \`${query}\``);
|
|
821
1176
|
}
|
|
822
|
-
|
|
1177
|
+
throw e;
|
|
823
1178
|
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
(0, logger_1.log)("error", err);
|
|
827
|
-
throw err;
|
|
1179
|
+
if (cache) {
|
|
1180
|
+
cache.clearCache();
|
|
828
1181
|
}
|
|
1182
|
+
return res;
|
|
829
1183
|
}
|
|
830
1184
|
function mutateRowSync(queryer, query, values, logValues, options) {
|
|
831
1185
|
logQuery(query, logValues);
|
|
@@ -837,10 +1191,12 @@ function mutateRowSync(queryer, query, values, logValues, options) {
|
|
|
837
1191
|
}
|
|
838
1192
|
return res;
|
|
839
1193
|
}
|
|
840
|
-
catch (
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
1194
|
+
catch (e) {
|
|
1195
|
+
if (_logQueryWithError) {
|
|
1196
|
+
const msg = e.message;
|
|
1197
|
+
throw new Error(`error \`${msg}\` running query: \`${query}\``);
|
|
1198
|
+
}
|
|
1199
|
+
throw e;
|
|
844
1200
|
}
|
|
845
1201
|
}
|
|
846
1202
|
function buildInsertQuery(options, suffix) {
|
|
@@ -893,32 +1249,47 @@ function createRowSync(queryer, options, suffix) {
|
|
|
893
1249
|
return null;
|
|
894
1250
|
}
|
|
895
1251
|
exports.createRowSync = createRowSync;
|
|
896
|
-
function buildUpdateQuery(options,
|
|
1252
|
+
function buildUpdateQuery(options, suffix) {
|
|
897
1253
|
let valsString = [];
|
|
898
1254
|
let values = [];
|
|
899
1255
|
let logValues = [];
|
|
900
1256
|
const dialect = db_1.default.getDialect();
|
|
901
1257
|
let idx = 1;
|
|
902
1258
|
for (const key in options.fields) {
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1259
|
+
if (options.expressions && options.expressions.has(key)) {
|
|
1260
|
+
const cls = options.expressions.get(key);
|
|
1261
|
+
valsString.push(`${key} = ${cls.clause(idx)}`);
|
|
1262
|
+
// TODO need to test a clause with more than one value...
|
|
1263
|
+
const newVals = cls.values();
|
|
1264
|
+
idx += newVals.length;
|
|
1265
|
+
values.push(...newVals);
|
|
1266
|
+
logValues.push(...cls.logValues());
|
|
910
1267
|
}
|
|
911
1268
|
else {
|
|
912
|
-
|
|
1269
|
+
const val = options.fields[key];
|
|
1270
|
+
values.push(val);
|
|
1271
|
+
if (options.fieldsToLog) {
|
|
1272
|
+
logValues.push(options.fieldsToLog[key]);
|
|
1273
|
+
}
|
|
1274
|
+
// TODO would be nice to use clause here. need update version of the queries so that
|
|
1275
|
+
// we don't have to handle dialect specifics here
|
|
1276
|
+
// can't use clause because of IS NULL
|
|
1277
|
+
// valsString.push(clause.Eq(key, val).clause(idx));
|
|
1278
|
+
if (dialect === db_1.Dialect.Postgres) {
|
|
1279
|
+
valsString.push(`${key} = $${idx}`);
|
|
1280
|
+
}
|
|
1281
|
+
else {
|
|
1282
|
+
valsString.push(`${key} = ?`);
|
|
1283
|
+
}
|
|
1284
|
+
idx++;
|
|
913
1285
|
}
|
|
914
1286
|
}
|
|
915
1287
|
const vals = valsString.join(", ");
|
|
916
1288
|
let query = `UPDATE ${options.tableName} SET ${vals} WHERE `;
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
query = query + `${options.key} = ?`;
|
|
1289
|
+
query = query + options.whereClause.clause(idx);
|
|
1290
|
+
values.push(...options.whereClause.values());
|
|
1291
|
+
if (options.fieldsToLog) {
|
|
1292
|
+
logValues.push(...options.whereClause.logValues());
|
|
922
1293
|
}
|
|
923
1294
|
if (suffix) {
|
|
924
1295
|
query = query + " " + suffix;
|
|
@@ -926,10 +1297,8 @@ function buildUpdateQuery(options, id, suffix) {
|
|
|
926
1297
|
return [query, values, logValues];
|
|
927
1298
|
}
|
|
928
1299
|
exports.buildUpdateQuery = buildUpdateQuery;
|
|
929
|
-
async function editRow(queryer, options,
|
|
930
|
-
const [query, values, logValues] = buildUpdateQuery(options,
|
|
931
|
-
// add id as value to prepared query
|
|
932
|
-
values.push(id);
|
|
1300
|
+
async function editRow(queryer, options, suffix) {
|
|
1301
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
933
1302
|
const res = await mutateRow(queryer, query, values, logValues, options);
|
|
934
1303
|
if (res?.rowCount == 1) {
|
|
935
1304
|
// for now assume id primary key
|
|
@@ -940,10 +1309,8 @@ async function editRow(queryer, options, id, suffix) {
|
|
|
940
1309
|
return null;
|
|
941
1310
|
}
|
|
942
1311
|
exports.editRow = editRow;
|
|
943
|
-
function editRowSync(queryer, options,
|
|
944
|
-
const [query, values, logValues] = buildUpdateQuery(options,
|
|
945
|
-
// add id as value to prepared query
|
|
946
|
-
values.push(id);
|
|
1312
|
+
function editRowSync(queryer, options, suffix) {
|
|
1313
|
+
const [query, values, logValues] = buildUpdateQuery(options, suffix);
|
|
947
1314
|
const res = mutateRowSync(queryer, query, values, logValues, options);
|
|
948
1315
|
if (res?.rowCount == 1) {
|
|
949
1316
|
// for now assume id primary key
|
|
@@ -994,21 +1361,22 @@ class AssocEdge {
|
|
|
994
1361
|
this.edgeType = data.edge_type;
|
|
995
1362
|
this.time = data.time;
|
|
996
1363
|
this.data = data.data;
|
|
1364
|
+
this.rawData = data;
|
|
1365
|
+
}
|
|
1366
|
+
__getRawData() {
|
|
1367
|
+
// incase there's extra db fields. useful for tests
|
|
1368
|
+
// in production, a subclass of this should be in use so we won't need this...
|
|
1369
|
+
return this.rawData;
|
|
997
1370
|
}
|
|
998
1371
|
getCursor() {
|
|
999
1372
|
return getCursor({
|
|
1000
1373
|
row: this,
|
|
1001
|
-
col: "
|
|
1002
|
-
conv: (t) => {
|
|
1003
|
-
if (typeof t === "string") {
|
|
1004
|
-
return Date.parse(t);
|
|
1005
|
-
}
|
|
1006
|
-
return t.getTime();
|
|
1007
|
-
},
|
|
1374
|
+
col: "id2",
|
|
1008
1375
|
});
|
|
1009
1376
|
}
|
|
1010
1377
|
}
|
|
1011
1378
|
exports.AssocEdge = AssocEdge;
|
|
1379
|
+
// TODO eventually update this for sortCol time unique keys
|
|
1012
1380
|
function getCursor(opts) {
|
|
1013
1381
|
const { row, col, conv } = opts;
|
|
1014
1382
|
// row: Data, col: string, conv?: (any) => any) {
|
|
@@ -1088,52 +1456,80 @@ const edgeFields = [
|
|
|
1088
1456
|
];
|
|
1089
1457
|
exports.DefaultLimit = 1000;
|
|
1090
1458
|
// TODO default limit from somewhere
|
|
1091
|
-
function defaultEdgeQueryOptions(id1, edgeType) {
|
|
1459
|
+
function defaultEdgeQueryOptions(id1, edgeType, id2) {
|
|
1460
|
+
let cls = clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType));
|
|
1461
|
+
if (id2) {
|
|
1462
|
+
cls = clause.And(cls, clause.Eq("id2", id2));
|
|
1463
|
+
}
|
|
1092
1464
|
return {
|
|
1093
|
-
clause:
|
|
1465
|
+
clause: cls,
|
|
1094
1466
|
orderby: "time DESC",
|
|
1095
1467
|
limit: exports.DefaultLimit,
|
|
1096
1468
|
};
|
|
1097
1469
|
}
|
|
1098
|
-
exports.defaultEdgeQueryOptions = defaultEdgeQueryOptions;
|
|
1099
1470
|
async function loadEdges(options) {
|
|
1100
1471
|
return loadCustomEdges({ ...options, ctr: AssocEdge });
|
|
1101
1472
|
}
|
|
1102
1473
|
exports.loadEdges = loadEdges;
|
|
1474
|
+
function getEdgeClauseAndFields(cls, options) {
|
|
1475
|
+
let fields = edgeFields;
|
|
1476
|
+
const transformEdgeRead = (0, global_schema_1.__getGlobalSchema)()?.transformEdgeRead;
|
|
1477
|
+
if (transformEdgeRead) {
|
|
1478
|
+
const transformClause = transformEdgeRead();
|
|
1479
|
+
if (!options.disableTransformations) {
|
|
1480
|
+
cls = clause.And(cls, transformClause);
|
|
1481
|
+
}
|
|
1482
|
+
fields = edgeFields.concat(transformClause.columns());
|
|
1483
|
+
}
|
|
1484
|
+
return {
|
|
1485
|
+
cls,
|
|
1486
|
+
fields,
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
exports.getEdgeClauseAndFields = getEdgeClauseAndFields;
|
|
1103
1490
|
async function loadCustomEdges(options) {
|
|
1104
|
-
const {
|
|
1491
|
+
const { cls: actualClause, fields, defaultOptions, tableName, } = await loadEgesInfo(options);
|
|
1492
|
+
const rows = await loadRows({
|
|
1493
|
+
tableName,
|
|
1494
|
+
fields: fields,
|
|
1495
|
+
clause: actualClause,
|
|
1496
|
+
orderby: options.queryOptions?.orderby || defaultOptions.orderby,
|
|
1497
|
+
limit: options.queryOptions?.limit || defaultOptions.limit,
|
|
1498
|
+
context: options.context,
|
|
1499
|
+
});
|
|
1500
|
+
return rows.map((row) => {
|
|
1501
|
+
return new options.ctr(row);
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1504
|
+
exports.loadCustomEdges = loadCustomEdges;
|
|
1505
|
+
async function loadEgesInfo(options, id2) {
|
|
1506
|
+
const { id1, edgeType } = options;
|
|
1105
1507
|
const edgeData = await loadEdgeData(edgeType);
|
|
1106
1508
|
if (!edgeData) {
|
|
1107
1509
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1108
1510
|
}
|
|
1109
|
-
const defaultOptions = defaultEdgeQueryOptions(id1, edgeType);
|
|
1511
|
+
const defaultOptions = defaultEdgeQueryOptions(id1, edgeType, id2);
|
|
1110
1512
|
let cls = defaultOptions.clause;
|
|
1111
1513
|
if (options.queryOptions?.clause) {
|
|
1112
1514
|
cls = clause.And(cls, options.queryOptions.clause);
|
|
1113
1515
|
}
|
|
1114
|
-
|
|
1516
|
+
return {
|
|
1517
|
+
...getEdgeClauseAndFields(cls, options),
|
|
1518
|
+
defaultOptions,
|
|
1115
1519
|
tableName: edgeData.edgeTable,
|
|
1116
|
-
|
|
1117
|
-
clause: cls,
|
|
1118
|
-
orderby: options.queryOptions?.orderby || defaultOptions.orderby,
|
|
1119
|
-
limit: options.queryOptions?.limit || defaultOptions.limit,
|
|
1120
|
-
context,
|
|
1121
|
-
});
|
|
1122
|
-
return rows.map((row) => {
|
|
1123
|
-
return new options.ctr(row);
|
|
1124
|
-
});
|
|
1520
|
+
};
|
|
1125
1521
|
}
|
|
1126
|
-
exports.loadCustomEdges = loadCustomEdges;
|
|
1127
1522
|
async function loadUniqueEdge(options) {
|
|
1128
1523
|
const { id1, edgeType, context } = options;
|
|
1129
1524
|
const edgeData = await loadEdgeData(edgeType);
|
|
1130
1525
|
if (!edgeData) {
|
|
1131
1526
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1132
1527
|
}
|
|
1528
|
+
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1133
1529
|
const row = await loadRow({
|
|
1134
1530
|
tableName: edgeData.edgeTable,
|
|
1135
|
-
fields:
|
|
1136
|
-
clause:
|
|
1531
|
+
fields: fields,
|
|
1532
|
+
clause: cls,
|
|
1137
1533
|
context,
|
|
1138
1534
|
});
|
|
1139
1535
|
if (!row) {
|
|
@@ -1160,21 +1556,28 @@ async function loadRawEdgeCountX(options) {
|
|
|
1160
1556
|
if (!edgeData) {
|
|
1161
1557
|
throw new Error(`error loading edge data for ${edgeType}`);
|
|
1162
1558
|
}
|
|
1559
|
+
const { cls } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.Eq("edge_type", edgeType)), options);
|
|
1163
1560
|
const row = await loadRowX({
|
|
1164
1561
|
tableName: edgeData.edgeTable,
|
|
1165
1562
|
// sqlite needs as count otherwise it returns count(1)
|
|
1166
1563
|
fields: ["count(1) as count"],
|
|
1167
|
-
clause:
|
|
1564
|
+
clause: cls,
|
|
1168
1565
|
context,
|
|
1169
1566
|
});
|
|
1170
1567
|
return parseInt(row["count"], 10) || 0;
|
|
1171
1568
|
}
|
|
1172
1569
|
exports.loadRawEdgeCountX = loadRawEdgeCountX;
|
|
1173
1570
|
async function loadEdgeForID2(options) {
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1571
|
+
const { cls: actualClause, fields, tableName, } = await loadEgesInfo(options, options.id2);
|
|
1572
|
+
const row = await loadRow({
|
|
1573
|
+
tableName,
|
|
1574
|
+
fields: fields,
|
|
1575
|
+
clause: actualClause,
|
|
1576
|
+
context: options.context,
|
|
1577
|
+
});
|
|
1578
|
+
if (row) {
|
|
1579
|
+
return new options.ctr(row);
|
|
1580
|
+
}
|
|
1178
1581
|
}
|
|
1179
1582
|
exports.loadEdgeForID2 = loadEdgeForID2;
|
|
1180
1583
|
async function loadNodesByEdge(viewer, id1, edgeType, options) {
|
|
@@ -1190,19 +1593,20 @@ async function loadNodesByEdge(viewer, id1, edgeType, options) {
|
|
|
1190
1593
|
}
|
|
1191
1594
|
exports.loadNodesByEdge = loadNodesByEdge;
|
|
1192
1595
|
async function applyPrivacyPolicyForRow(viewer, options, row) {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
}
|
|
1196
|
-
const ent = new options.ent(viewer, row);
|
|
1197
|
-
return await applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
1596
|
+
const r = await applyPrivacyPolicyForRowImpl(viewer, options, row);
|
|
1597
|
+
return r instanceof Error ? null : r;
|
|
1198
1598
|
}
|
|
1199
1599
|
exports.applyPrivacyPolicyForRow = applyPrivacyPolicyForRow;
|
|
1600
|
+
async function applyPrivacyPolicyForRowImpl(viewer, options, row) {
|
|
1601
|
+
const ent = new options.ent(viewer, row);
|
|
1602
|
+
return applyPrivacyPolicyForEnt(viewer, ent, row, options);
|
|
1603
|
+
}
|
|
1200
1604
|
async function applyPrivacyPolicyForRowX(viewer, options, row) {
|
|
1201
1605
|
const ent = new options.ent(viewer, row);
|
|
1202
1606
|
return await applyPrivacyPolicyForEntX(viewer, ent, row, options);
|
|
1203
1607
|
}
|
|
1204
|
-
|
|
1205
|
-
async function
|
|
1608
|
+
// deprecated. doesn't use entcache
|
|
1609
|
+
async function applyPrivacyPolicyForRowsDeprecated(viewer, rows, options) {
|
|
1206
1610
|
let m = new Map();
|
|
1207
1611
|
// apply privacy logic
|
|
1208
1612
|
await Promise.all(rows.map(async (row) => {
|
|
@@ -1213,27 +1617,62 @@ async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
|
1213
1617
|
}));
|
|
1214
1618
|
return m;
|
|
1215
1619
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1620
|
+
async function applyPrivacyPolicyForRows(viewer, rows, options) {
|
|
1621
|
+
const result = new Array(rows.length);
|
|
1622
|
+
if (!rows.length) {
|
|
1623
|
+
return [];
|
|
1624
|
+
}
|
|
1625
|
+
const entLoader = getEntLoader(viewer, options);
|
|
1626
|
+
await Promise.all(rows.map(async (row, idx) => {
|
|
1627
|
+
const r = await applyPrivacyPolicyForRowAndStoreInEntLoader(viewer, row, options, entLoader);
|
|
1628
|
+
if (r instanceof ErrorWrapper) {
|
|
1629
|
+
return;
|
|
1630
|
+
}
|
|
1631
|
+
result[idx] = r;
|
|
1632
|
+
}));
|
|
1633
|
+
// filter ents that aren't visible because of privacy
|
|
1634
|
+
return result.filter((r) => r !== undefined);
|
|
1226
1635
|
}
|
|
1636
|
+
exports.applyPrivacyPolicyForRows = applyPrivacyPolicyForRows;
|
|
1227
1637
|
// given a viewer, an id pair, and a map of edgeEnum to EdgeType
|
|
1228
1638
|
// return the edgeEnum that's set in the group
|
|
1229
1639
|
async function getEdgeTypeInGroup(viewer, id1, id2, m) {
|
|
1230
1640
|
let promises = [];
|
|
1231
|
-
|
|
1232
|
-
|
|
1641
|
+
const edgeDatas = await loadEdgeDatas(...Array.from(m.values()));
|
|
1642
|
+
let tableToEdgeEnumMap = new Map();
|
|
1643
|
+
for (const [edgeEnum, edgeType] of m) {
|
|
1644
|
+
const edgeData = edgeDatas.get(edgeType);
|
|
1645
|
+
if (!edgeData) {
|
|
1646
|
+
throw new Error(`could not load edge data for '${edgeType}'`);
|
|
1647
|
+
}
|
|
1648
|
+
const l = tableToEdgeEnumMap.get(edgeData.edgeTable) ?? [];
|
|
1649
|
+
l.push(edgeEnum);
|
|
1650
|
+
tableToEdgeEnumMap.set(edgeData.edgeTable, l);
|
|
1233
1651
|
}
|
|
1652
|
+
tableToEdgeEnumMap.forEach((edgeEnums, tableName) => {
|
|
1653
|
+
promises.push((async () => {
|
|
1654
|
+
const edgeTypes = edgeEnums.map((edgeEnum) => m.get(edgeEnum));
|
|
1655
|
+
const { cls, fields } = getEdgeClauseAndFields(clause.And(clause.Eq("id1", id1), clause.In("edge_type", edgeTypes), clause.Eq("id2", id2)), {});
|
|
1656
|
+
const rows = await loadRows({
|
|
1657
|
+
tableName,
|
|
1658
|
+
fields,
|
|
1659
|
+
clause: cls,
|
|
1660
|
+
context: viewer.context,
|
|
1661
|
+
});
|
|
1662
|
+
const row = rows[0];
|
|
1663
|
+
if (row) {
|
|
1664
|
+
const edgeType = row.edge_type;
|
|
1665
|
+
for (const [k, v] of m) {
|
|
1666
|
+
if (v === edgeType) {
|
|
1667
|
+
return [k, new AssocEdge(row)];
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
})());
|
|
1672
|
+
});
|
|
1234
1673
|
const results = await Promise.all(promises);
|
|
1235
1674
|
for (const res of results) {
|
|
1236
|
-
if (res[1]) {
|
|
1675
|
+
if (res && res[1]) {
|
|
1237
1676
|
return [res[0], res[1]];
|
|
1238
1677
|
}
|
|
1239
1678
|
}
|