@snowtop/ent 0.0.2 → 0.0.3-4.alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/action/action.d.ts +6 -6
- package/action/action.js +2 -2
- package/action/executor.d.ts +7 -12
- package/action/executor.js +39 -33
- package/action/experimental_action.d.ts +4 -2
- package/action/experimental_action.js +27 -2
- package/action/index.d.ts +1 -1
- package/action/orchestrator.d.ts +14 -6
- package/action/orchestrator.js +188 -99
- package/action/privacy.js +4 -4
- package/auth/auth.js +2 -2
- package/core/base.js +12 -9
- package/core/clause.d.ts +1 -0
- package/core/clause.js +6 -2
- package/core/config.d.ts +20 -0
- package/core/config.js +2 -2
- package/core/context.js +3 -3
- package/core/convert.d.ts +4 -0
- package/core/convert.js +25 -2
- package/core/db.d.ts +18 -1
- package/core/db.js +4 -7
- package/core/ent.d.ts +17 -10
- package/core/ent.js +38 -15
- package/core/loaders/assoc_count_loader.js +5 -5
- package/core/loaders/assoc_edge_loader.js +10 -10
- package/core/loaders/loader.js +3 -3
- package/core/loaders/object_loader.js +6 -6
- package/core/loaders/query_loader.js +7 -7
- package/core/loaders/raw_count_loader.js +4 -4
- package/core/logger.js +2 -2
- package/core/privacy.d.ts +21 -1
- package/core/privacy.js +91 -47
- package/core/query/assoc_query.d.ts +12 -12
- package/core/query/assoc_query.js +86 -51
- package/core/query/custom_query.d.ts +10 -7
- package/core/query/custom_query.js +29 -3
- package/core/query/query.d.ts +24 -8
- package/core/query/query.js +41 -4
- package/core/query/shared_assoc_test.js +257 -13
- package/core/query/shared_test.d.ts +1 -1
- package/core/query/shared_test.js +11 -11
- package/core/viewer.js +1 -0
- package/graphql/builtins/connection.js +4 -3
- package/graphql/builtins/edge.js +3 -2
- package/graphql/builtins/node.js +2 -1
- package/graphql/graphql.d.ts +2 -0
- package/graphql/graphql.js +83 -61
- package/graphql/index.d.ts +1 -1
- package/graphql/index.js +2 -1
- package/graphql/node_resolver.d.ts +1 -0
- package/graphql/node_resolver.js +14 -1
- package/graphql/query/connection_type.d.ts +5 -4
- package/graphql/query/connection_type.js +6 -6
- package/graphql/query/edge_connection.d.ts +7 -7
- package/graphql/query/page_info.js +5 -4
- package/graphql/query/shared_assoc_test.js +9 -9
- package/graphql/query/shared_edge_connection.d.ts +1 -1
- package/graphql/query/shared_edge_connection.js +4 -4
- package/graphql/scalars/time.js +1 -1
- package/imports/dataz/example1/_auth.js +8 -8
- package/imports/dataz/example1/_viewer.js +4 -4
- package/imports/index.d.ts +1 -1
- package/imports/index.js +3 -5
- package/index.d.ts +2 -1
- package/index.js +6 -2
- package/package.json +17 -10
- package/parse_schema/parse.d.ts +41 -0
- package/parse_schema/parse.js +147 -0
- package/schema/base_schema.d.ts +2 -0
- package/schema/base_schema.js +17 -7
- package/schema/field.d.ts +52 -15
- package/schema/field.js +252 -47
- package/schema/index.d.ts +1 -0
- package/schema/index.js +1 -0
- package/schema/json_field.d.ts +17 -0
- package/schema/json_field.js +48 -0
- package/schema/schema.d.ts +39 -4
- package/schema/schema.js +2 -0
- package/scripts/custom_compiler.js +8 -10
- package/scripts/custom_graphql.js +45 -10
- package/scripts/read_schema.js +6 -108
- package/testutils/builder.d.ts +6 -3
- package/testutils/builder.js +31 -15
- package/testutils/db/test_db.d.ts +16 -8
- package/testutils/db/test_db.js +65 -9
- package/testutils/db_mock.js +5 -5
- package/testutils/ent-graphql-tests/index.d.ts +1 -0
- package/testutils/ent-graphql-tests/index.js +13 -13
- package/testutils/fake_comms.d.ts +1 -0
- package/testutils/fake_comms.js +4 -0
- package/testutils/fake_data/const.d.ts +5 -1
- package/testutils/fake_data/const.js +19 -1
- package/testutils/fake_data/events_query.d.ts +16 -11
- package/testutils/fake_data/events_query.js +15 -0
- package/testutils/fake_data/fake_contact.js +9 -9
- package/testutils/fake_data/fake_event.js +14 -14
- package/testutils/fake_data/fake_user.js +12 -10
- package/testutils/fake_data/test_helpers.d.ts +5 -1
- package/testutils/fake_data/test_helpers.js +49 -16
- package/testutils/fake_data/user_query.d.ts +25 -9
- package/testutils/fake_data/user_query.js +52 -5
- package/testutils/parse_sql.js +19 -3
- package/testutils/write.js +6 -6
package/action/orchestrator.js
CHANGED
|
@@ -5,6 +5,7 @@ const ent_1 = require("../core/ent");
|
|
|
5
5
|
const schema_1 = require("../schema/schema");
|
|
6
6
|
const action_1 = require("../action");
|
|
7
7
|
const snake_case_1 = require("snake-case");
|
|
8
|
+
const camel_case_1 = require("camel-case");
|
|
8
9
|
const privacy_1 = require("../core/privacy");
|
|
9
10
|
const executor_1 = require("./executor");
|
|
10
11
|
const logger_1 = require("../core/logger");
|
|
@@ -58,6 +59,8 @@ class Orchestrator {
|
|
|
58
59
|
this.changesets = [];
|
|
59
60
|
this.dependencies = new Map();
|
|
60
61
|
this.fieldsToResolve = [];
|
|
62
|
+
this.defaultFieldsByFieldName = {};
|
|
63
|
+
this.defaultFieldsByTSName = {};
|
|
61
64
|
this.viewer = options.viewer;
|
|
62
65
|
}
|
|
63
66
|
addEdge(edge, op) {
|
|
@@ -143,6 +146,8 @@ class Orchestrator {
|
|
|
143
146
|
tableName: this.options.tableName,
|
|
144
147
|
fieldsToResolve: this.fieldsToResolve,
|
|
145
148
|
key: this.options.key,
|
|
149
|
+
ent: this.options.loaderOptions.ent,
|
|
150
|
+
placeholderID: this.options.builder.placeholderID,
|
|
146
151
|
};
|
|
147
152
|
if (this.logValues) {
|
|
148
153
|
opts.fieldsToLog = this.logValues;
|
|
@@ -188,7 +193,7 @@ class Orchestrator {
|
|
|
188
193
|
throw new Error("could not find an edge operation from the given parameters");
|
|
189
194
|
}
|
|
190
195
|
async buildEdgeOps(ops) {
|
|
191
|
-
const edgeDatas = await ent_1.loadEdgeDatas(...Array.from(this.edgeSet.values()));
|
|
196
|
+
const edgeDatas = await (0, ent_1.loadEdgeDatas)(...Array.from(this.edgeSet.values()));
|
|
192
197
|
for (const [edgeType, m] of this.edges) {
|
|
193
198
|
for (const [op, m2] of m) {
|
|
194
199
|
for (const [_, edge] of m2) {
|
|
@@ -222,53 +227,65 @@ class Orchestrator {
|
|
|
222
227
|
}
|
|
223
228
|
return new EntCannotDeleteEntError(privacyPolicy, action, this.options.builder.existingEnt);
|
|
224
229
|
}
|
|
230
|
+
getEntForPrivacyPolicy(editedData) {
|
|
231
|
+
if (this.options.operation !== action_1.WriteOperation.Insert) {
|
|
232
|
+
return this.options.builder.existingEnt;
|
|
233
|
+
}
|
|
234
|
+
// we create an unsafe ent to be used for privacy policies
|
|
235
|
+
return new this.options.builder.ent(this.options.builder.viewer, editedData);
|
|
236
|
+
}
|
|
225
237
|
async validate() {
|
|
238
|
+
// existing ent required for edit or delete operations
|
|
239
|
+
switch (this.options.operation) {
|
|
240
|
+
case action_1.WriteOperation.Delete:
|
|
241
|
+
case action_1.WriteOperation.Edit:
|
|
242
|
+
if (!this.options.builder.existingEnt) {
|
|
243
|
+
throw new Error("existing ent required with operation");
|
|
244
|
+
}
|
|
245
|
+
}
|
|
226
246
|
const action = this.options.action;
|
|
227
|
-
let privacyPolicy = action?.getPrivacyPolicy();
|
|
228
247
|
const builder = this.options.builder;
|
|
229
|
-
|
|
248
|
+
// future optimization: can get schemaFields to memoize based on different values
|
|
249
|
+
const schemaFields = (0, schema_1.getFields)(this.options.schema);
|
|
250
|
+
let editedData = this.getFieldsWithDefaultValues(builder, schemaFields, action);
|
|
251
|
+
// this runs in following phases:
|
|
252
|
+
// * set default fields and pass to builder so the value can be checked by triggers/observers/validators
|
|
253
|
+
// * privacy policy (use unsafe ent if we have it)
|
|
254
|
+
// * triggers
|
|
255
|
+
// * validators
|
|
256
|
+
let privacyPolicy = action?.getPrivacyPolicy();
|
|
230
257
|
if (privacyPolicy) {
|
|
231
|
-
|
|
258
|
+
await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, this.getEntForPrivacyPolicy(editedData), this.throwError.bind(this));
|
|
232
259
|
}
|
|
233
260
|
// have to run triggers which update fields first before field and other validators
|
|
234
261
|
// so running this first to build things up
|
|
235
262
|
let triggers = action?.triggers;
|
|
236
263
|
if (triggers) {
|
|
237
|
-
|
|
238
|
-
triggers.forEach((trigger) => {
|
|
239
|
-
let c = trigger.changeset(builder, action.getInput());
|
|
240
|
-
if (c) {
|
|
241
|
-
triggerPromises.push(c);
|
|
242
|
-
}
|
|
243
|
-
});
|
|
244
|
-
// TODO right now trying to parallelize this with validateFields below
|
|
245
|
-
// may need to run triggers first to be deterministic
|
|
246
|
-
// TODO: see https://github.com/lolopinto/ent/pull/50
|
|
247
|
-
promises.push(this.triggers(triggerPromises));
|
|
264
|
+
await this.triggers(action, builder, triggers);
|
|
248
265
|
}
|
|
249
|
-
promises.push(this.validateFields());
|
|
250
266
|
let validators = action?.validators || [];
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
256
|
-
async triggers(
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
if (Array.isArray(
|
|
260
|
-
|
|
267
|
+
await Promise.all([
|
|
268
|
+
this.formatAndValidateFields(schemaFields),
|
|
269
|
+
this.validators(validators, action, builder),
|
|
270
|
+
]);
|
|
271
|
+
}
|
|
272
|
+
async triggers(action, builder, triggers) {
|
|
273
|
+
await Promise.all(triggers.map(async (trigger) => {
|
|
274
|
+
let ret = await trigger.changeset(builder, action.getInput());
|
|
275
|
+
if (Array.isArray(ret)) {
|
|
276
|
+
ret = await Promise.all(ret);
|
|
261
277
|
}
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
278
|
+
if (Array.isArray(ret)) {
|
|
279
|
+
for (const v of ret) {
|
|
280
|
+
if (typeof v === "object") {
|
|
281
|
+
this.changesets.push(v);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
267
284
|
}
|
|
268
|
-
else if (
|
|
269
|
-
this.changesets.push(
|
|
285
|
+
else if (ret) {
|
|
286
|
+
this.changesets.push(ret);
|
|
270
287
|
}
|
|
271
|
-
});
|
|
288
|
+
}));
|
|
272
289
|
}
|
|
273
290
|
async validators(validators, action, builder) {
|
|
274
291
|
let promises = [];
|
|
@@ -283,88 +300,157 @@ class Orchestrator {
|
|
|
283
300
|
isBuilder(val) {
|
|
284
301
|
return val.placeholderID !== undefined;
|
|
285
302
|
}
|
|
286
|
-
|
|
287
|
-
// existing ent required for edit or delete operations
|
|
288
|
-
switch (this.options.operation) {
|
|
289
|
-
case action_1.WriteOperation.Delete:
|
|
290
|
-
case action_1.WriteOperation.Edit:
|
|
291
|
-
if (!this.options.builder.existingEnt) {
|
|
292
|
-
throw new Error("existing ent required with operation");
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
if (this.options.operation == action_1.WriteOperation.Delete) {
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
303
|
+
getFieldsWithDefaultValues(builder, schemaFields, action) {
|
|
298
304
|
const editedFields = this.options.editedFields();
|
|
299
|
-
// build up data to be saved...
|
|
300
305
|
let data = {};
|
|
301
|
-
let
|
|
302
|
-
|
|
306
|
+
let defaultData = {};
|
|
307
|
+
let input = action?.getInput() || {};
|
|
308
|
+
let updateInput = false;
|
|
303
309
|
for (const [fieldName, field] of schemaFields) {
|
|
304
310
|
let value = editedFields.get(fieldName);
|
|
305
|
-
let
|
|
311
|
+
let defaultValue = undefined;
|
|
312
|
+
let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
|
|
306
313
|
if (value === undefined) {
|
|
307
|
-
if (
|
|
308
|
-
|
|
309
|
-
|
|
314
|
+
if (this.options.operation === action_1.WriteOperation.Insert) {
|
|
315
|
+
if (field.defaultToViewerOnCreate && field.defaultValueOnCreate) {
|
|
316
|
+
throw new Error(`cannot set both defaultToViewerOnCreate and defaultValueOnCreate`);
|
|
317
|
+
}
|
|
318
|
+
if (field.defaultToViewerOnCreate) {
|
|
319
|
+
defaultValue = builder.viewer.viewerID;
|
|
320
|
+
}
|
|
321
|
+
if (field.defaultValueOnCreate) {
|
|
322
|
+
defaultValue = field.defaultValueOnCreate(builder, input);
|
|
323
|
+
if (defaultValue === undefined) {
|
|
324
|
+
throw new Error(`defaultValueOnCreate() returned undefined for field ${field.name}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
310
327
|
}
|
|
311
328
|
if (field.defaultValueOnEdit &&
|
|
312
329
|
this.options.operation === action_1.WriteOperation.Edit) {
|
|
313
|
-
|
|
314
|
-
// TODO special case this if this is the onlything changing and don't do the write.
|
|
330
|
+
defaultValue = field.defaultValueOnEdit(builder, input);
|
|
315
331
|
}
|
|
316
332
|
}
|
|
317
|
-
if (value
|
|
318
|
-
|
|
319
|
-
throw new Error(`field ${field.name} set to null for non-nullable field`);
|
|
320
|
-
}
|
|
333
|
+
if (value !== undefined) {
|
|
334
|
+
data[dbKey] = value;
|
|
321
335
|
}
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
field.serverDefault === undefined &&
|
|
329
|
-
this.options.operation === action_1.WriteOperation.Insert) {
|
|
330
|
-
throw new Error(`required field ${field.name} not set`);
|
|
331
|
-
}
|
|
336
|
+
if (defaultValue !== undefined) {
|
|
337
|
+
updateInput = true;
|
|
338
|
+
defaultData[dbKey] = defaultValue;
|
|
339
|
+
this.defaultFieldsByFieldName[fieldName] = defaultValue;
|
|
340
|
+
// TODO related to #510. we need this logic to be consistent so do this all in TypeScript or get it from go somehow
|
|
341
|
+
this.defaultFieldsByTSName[(0, camel_case_1.camelCase)(fieldName)] = defaultValue;
|
|
332
342
|
}
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
343
|
+
}
|
|
344
|
+
// if there's data changing, add data
|
|
345
|
+
if (this.hasData(data)) {
|
|
346
|
+
data = {
|
|
347
|
+
...data,
|
|
348
|
+
...defaultData,
|
|
349
|
+
};
|
|
350
|
+
if (updateInput && this.options.updateInput) {
|
|
351
|
+
// this basically fixes #605. just needs to be exposed correctly
|
|
352
|
+
this.options.updateInput(this.defaultFieldsByTSName);
|
|
339
353
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
354
|
+
}
|
|
355
|
+
return data;
|
|
356
|
+
}
|
|
357
|
+
hasData(data) {
|
|
358
|
+
for (const _k in data) {
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
async transformFieldValue(field, dbKey, value) {
|
|
364
|
+
// now format and validate...
|
|
365
|
+
if (value === null) {
|
|
366
|
+
if (!field.nullable) {
|
|
367
|
+
throw new Error(`field ${field.name} set to null for non-nullable field`);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else if (value === undefined) {
|
|
371
|
+
if (!field.nullable &&
|
|
372
|
+
// required field can be skipped if server default set
|
|
373
|
+
// not checking defaultValueOnCreate() or defaultValueOnEdit() as that's set above
|
|
374
|
+
// not setting server default as we're depending on the database handling that.
|
|
375
|
+
// server default allowed
|
|
376
|
+
field.serverDefault === undefined &&
|
|
377
|
+
this.options.operation === action_1.WriteOperation.Insert) {
|
|
378
|
+
throw new Error(`required field ${field.name} not set`);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
else if (this.isBuilder(value)) {
|
|
382
|
+
if (field.valid) {
|
|
383
|
+
const valid = await Promise.resolve(field.valid(value));
|
|
384
|
+
if (!valid) {
|
|
385
|
+
throw new Error(`invalid field ${field.name} with value ${value}`);
|
|
347
386
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
387
|
+
}
|
|
388
|
+
// keep track of dependencies to resolve
|
|
389
|
+
this.dependencies.set(value.placeholderID, value);
|
|
390
|
+
// keep track of fields to resolve
|
|
391
|
+
this.fieldsToResolve.push(dbKey);
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
if (field.valid) {
|
|
395
|
+
// TODO this could be async. handle this better
|
|
396
|
+
const valid = await Promise.resolve(field.valid(value));
|
|
397
|
+
if (!valid) {
|
|
398
|
+
throw new Error(`invalid field ${field.name} with value ${value}`);
|
|
351
399
|
}
|
|
352
400
|
}
|
|
401
|
+
if (field.format) {
|
|
402
|
+
// TODO this could be async e.g. password. handle this better
|
|
403
|
+
value = await Promise.resolve(field.format(value));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
return value;
|
|
407
|
+
}
|
|
408
|
+
async formatAndValidateFields(schemaFields) {
|
|
409
|
+
const op = this.options.operation;
|
|
410
|
+
if (op === action_1.WriteOperation.Delete) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
const editedFields = this.options.editedFields();
|
|
414
|
+
// build up data to be saved...
|
|
415
|
+
let data = {};
|
|
416
|
+
let logValues = {};
|
|
417
|
+
for (const [fieldName, field] of schemaFields) {
|
|
418
|
+
let value = editedFields.get(fieldName);
|
|
419
|
+
if (value === undefined && op === action_1.WriteOperation.Insert) {
|
|
420
|
+
// null allowed
|
|
421
|
+
value = this.defaultFieldsByFieldName[fieldName];
|
|
422
|
+
}
|
|
423
|
+
let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
|
|
424
|
+
value = await this.transformFieldValue(field, dbKey, value);
|
|
353
425
|
if (value !== undefined) {
|
|
354
426
|
data[dbKey] = value;
|
|
355
427
|
logValues[dbKey] = field.logValue(value);
|
|
356
428
|
}
|
|
357
429
|
}
|
|
430
|
+
// we ignored default values while editing.
|
|
431
|
+
// if we're editing and there's data, add default values
|
|
432
|
+
if (op === action_1.WriteOperation.Edit && this.hasData(data)) {
|
|
433
|
+
for (const fieldName in this.defaultFieldsByFieldName) {
|
|
434
|
+
const defaultValue = this.defaultFieldsByFieldName[fieldName];
|
|
435
|
+
let field = schemaFields.get(fieldName);
|
|
436
|
+
let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
|
|
437
|
+
// no value, let's just default
|
|
438
|
+
if (data[dbKey] === undefined) {
|
|
439
|
+
const value = await this.transformFieldValue(field, dbKey, defaultValue);
|
|
440
|
+
data[dbKey] = value;
|
|
441
|
+
logValues[dbKey] = field.logValue(value);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
358
445
|
this.validatedFields = data;
|
|
359
446
|
this.logValues = logValues;
|
|
360
|
-
// console.log(this.validatedFields);
|
|
361
447
|
}
|
|
362
448
|
async valid() {
|
|
363
449
|
try {
|
|
364
450
|
await this.validate();
|
|
365
451
|
}
|
|
366
452
|
catch (e) {
|
|
367
|
-
logger_1.log("error", e);
|
|
453
|
+
(0, logger_1.log)("error", e);
|
|
368
454
|
return false;
|
|
369
455
|
}
|
|
370
456
|
return true;
|
|
@@ -377,7 +463,6 @@ class Orchestrator {
|
|
|
377
463
|
await this.validX();
|
|
378
464
|
let ops = [this.buildMainOp()];
|
|
379
465
|
await this.buildEdgeOps(ops);
|
|
380
|
-
// console.log("post build");
|
|
381
466
|
return new EntChangeset(this.options.viewer, this.options.builder.placeholderID, this.options.loaderOptions.ent, ops, this.dependencies, this.changesets, this.options);
|
|
382
467
|
}
|
|
383
468
|
async viewerForEntLoad(data) {
|
|
@@ -385,11 +470,11 @@ class Orchestrator {
|
|
|
385
470
|
if (!action || !action.viewerForEntLoad) {
|
|
386
471
|
return this.options.viewer;
|
|
387
472
|
}
|
|
388
|
-
return
|
|
473
|
+
return action.viewerForEntLoad(data);
|
|
389
474
|
}
|
|
390
475
|
async returnedRow() {
|
|
391
|
-
if (this.mainOp && this.mainOp.
|
|
392
|
-
return this.mainOp.
|
|
476
|
+
if (this.mainOp && this.mainOp.returnedRow) {
|
|
477
|
+
return this.mainOp.returnedRow();
|
|
393
478
|
}
|
|
394
479
|
return null;
|
|
395
480
|
}
|
|
@@ -399,7 +484,7 @@ class Orchestrator {
|
|
|
399
484
|
return null;
|
|
400
485
|
}
|
|
401
486
|
const viewer = await this.viewerForEntLoad(row);
|
|
402
|
-
return
|
|
487
|
+
return (0, ent_1.applyPrivacyPolicyForRow)(viewer, this.options.loaderOptions, row);
|
|
403
488
|
}
|
|
404
489
|
async editedEntX() {
|
|
405
490
|
const row = await this.returnedRow();
|
|
@@ -407,7 +492,7 @@ class Orchestrator {
|
|
|
407
492
|
throw new Error(`ent was not created`);
|
|
408
493
|
}
|
|
409
494
|
const viewer = await this.viewerForEntLoad(row);
|
|
410
|
-
const ent = await ent_1.applyPrivacyPolicyForRow(viewer, this.options.loaderOptions, row);
|
|
495
|
+
const ent = await (0, ent_1.applyPrivacyPolicyForRow)(viewer, this.options.loaderOptions, row);
|
|
411
496
|
if (!ent) {
|
|
412
497
|
if (this.options.operation == action_1.WriteOperation.Insert) {
|
|
413
498
|
throw new Error(`was able to create ent but not load it`);
|
|
@@ -431,13 +516,17 @@ class EntChangeset {
|
|
|
431
516
|
this.options = options;
|
|
432
517
|
}
|
|
433
518
|
executor() {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
if (this.changesets?.length) {
|
|
438
|
-
|
|
519
|
+
if (this._executor) {
|
|
520
|
+
return this._executor;
|
|
521
|
+
}
|
|
522
|
+
if (!this.changesets?.length) {
|
|
523
|
+
// if we have dependencies but no changesets, we just need a simple
|
|
524
|
+
// executor and depend on something else in the stack to handle this correctly
|
|
525
|
+
// ComplexExecutor which could be a parent of this should make sure the dependency
|
|
526
|
+
// is resolved beforehand
|
|
527
|
+
return (this._executor = new executor_1.ListBasedExecutor(this.viewer, this.placeholderID, this.operations, this.options));
|
|
439
528
|
}
|
|
440
|
-
return new executor_1.
|
|
529
|
+
return (this._executor = new executor_1.ComplexExecutor(this.viewer, this.placeholderID, this.operations, this.dependencies || new Map(), this.changesets || [], this.options));
|
|
441
530
|
}
|
|
442
531
|
}
|
|
443
532
|
exports.EntChangeset = EntChangeset;
|
package/action/privacy.js
CHANGED
|
@@ -11,9 +11,9 @@ class DenyIfBuilder {
|
|
|
11
11
|
}
|
|
12
12
|
async apply(_v, _ent) {
|
|
13
13
|
if (this.id && isBuilder(this.id)) {
|
|
14
|
-
return base_1.Deny();
|
|
14
|
+
return (0, base_1.Deny)();
|
|
15
15
|
}
|
|
16
|
-
return base_1.Skip();
|
|
16
|
+
return (0, base_1.Skip)();
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
exports.DenyIfBuilder = DenyIfBuilder;
|
|
@@ -23,9 +23,9 @@ class AllowIfBuilder {
|
|
|
23
23
|
}
|
|
24
24
|
async apply(_v, _ent) {
|
|
25
25
|
if (this.id && isBuilder(this.id)) {
|
|
26
|
-
return base_1.Allow();
|
|
26
|
+
return (0, base_1.Allow)();
|
|
27
27
|
}
|
|
28
|
-
return base_1.Skip();
|
|
28
|
+
return (0, base_1.Skip)();
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
exports.AllowIfBuilder = AllowIfBuilder;
|
package/auth/auth.js
CHANGED
|
@@ -17,11 +17,11 @@ async function getLoggedInViewer(context) {
|
|
|
17
17
|
for (const [name, authHandler] of handlers) {
|
|
18
18
|
let v = await authHandler.authViewer(context);
|
|
19
19
|
if (v !== null) {
|
|
20
|
-
logger_1.log("info", `auth handler \`${name}\` authenticated user \`${v.viewerID}\``);
|
|
20
|
+
(0, logger_1.log)("info", `auth handler \`${name}\` authenticated user \`${v.viewerID}\``);
|
|
21
21
|
return v;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
logger_1.log("info", "no auth handler returned viewer. default to logged out viewer");
|
|
24
|
+
(0, logger_1.log)("info", "no auth handler returned viewer. default to logged out viewer");
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
27
|
exports.getLoggedInViewer = getLoggedInViewer;
|
package/core/base.js
CHANGED
|
@@ -9,22 +9,25 @@ var privacyResult;
|
|
|
9
9
|
privacyResult[privacyResult["Deny"] = 401] = "Deny";
|
|
10
10
|
privacyResult[privacyResult["Skip"] = 307] = "Skip";
|
|
11
11
|
})(privacyResult || (privacyResult = {}));
|
|
12
|
+
const allow = {
|
|
13
|
+
result: privacyResult.Allow,
|
|
14
|
+
};
|
|
12
15
|
function Allow() {
|
|
13
|
-
return
|
|
14
|
-
result: privacyResult.Allow,
|
|
15
|
-
};
|
|
16
|
+
return allow;
|
|
16
17
|
}
|
|
17
18
|
exports.Allow = Allow;
|
|
19
|
+
const skip = {
|
|
20
|
+
result: privacyResult.Skip,
|
|
21
|
+
};
|
|
18
22
|
function Skip() {
|
|
19
|
-
return
|
|
20
|
-
result: privacyResult.Skip,
|
|
21
|
-
};
|
|
23
|
+
return skip;
|
|
22
24
|
}
|
|
23
25
|
exports.Skip = Skip;
|
|
26
|
+
const deny = {
|
|
27
|
+
result: privacyResult.Deny,
|
|
28
|
+
};
|
|
24
29
|
function Deny() {
|
|
25
|
-
return
|
|
26
|
-
result: privacyResult.Deny,
|
|
27
|
-
};
|
|
30
|
+
return deny;
|
|
28
31
|
}
|
|
29
32
|
exports.Deny = Deny;
|
|
30
33
|
function DenyWithReason(e) {
|
package/core/clause.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ declare class compositeClause implements Clause {
|
|
|
28
28
|
instanceKey(): string;
|
|
29
29
|
}
|
|
30
30
|
export declare function Eq(col: string, value: any): simpleClause;
|
|
31
|
+
export declare function NotEq(col: string, value: any): simpleClause;
|
|
31
32
|
export declare function Greater(col: string, value: any): simpleClause;
|
|
32
33
|
export declare function Less(col: string, value: any): simpleClause;
|
|
33
34
|
export declare function GreaterEq(col: string, value: any): simpleClause;
|
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.sensitiveValue = exports.In = exports.Or = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.Eq = void 0;
|
|
22
|
+
exports.sensitiveValue = exports.In = exports.Or = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = void 0;
|
|
23
23
|
const db_1 = __importStar(require("./db"));
|
|
24
24
|
function isSensitive(val) {
|
|
25
25
|
return (typeof val === "object" && val.logValue !== undefined);
|
|
@@ -149,6 +149,10 @@ function Eq(col, value) {
|
|
|
149
149
|
return new simpleClause(col, value, "=");
|
|
150
150
|
}
|
|
151
151
|
exports.Eq = Eq;
|
|
152
|
+
function NotEq(col, value) {
|
|
153
|
+
return new simpleClause(col, value, "!=");
|
|
154
|
+
}
|
|
155
|
+
exports.NotEq = NotEq;
|
|
152
156
|
function Greater(col, value) {
|
|
153
157
|
return new simpleClause(col, value, ">");
|
|
154
158
|
}
|
|
@@ -173,7 +177,7 @@ function Or(...args) {
|
|
|
173
177
|
return new compositeClause(args, " OR ");
|
|
174
178
|
}
|
|
175
179
|
exports.Or = Or;
|
|
176
|
-
// todo
|
|
180
|
+
// TODO this breaks if values.length ===1 and array. todo fix
|
|
177
181
|
function In(col, ...values) {
|
|
178
182
|
return new inClause(col, values);
|
|
179
183
|
}
|
package/core/config.d.ts
CHANGED
|
@@ -6,6 +6,26 @@ export interface Config {
|
|
|
6
6
|
dbFile?: string;
|
|
7
7
|
db?: Database | DBDict;
|
|
8
8
|
log?: logType | logType[];
|
|
9
|
+
codegen?: CodegenConfig;
|
|
10
|
+
}
|
|
11
|
+
interface CodegenConfig {
|
|
12
|
+
defaultEntPolicy?: PrivacyConfig;
|
|
13
|
+
defaultActionPolicy?: PrivacyConfig;
|
|
14
|
+
prettier?: PrettierConfig;
|
|
15
|
+
relativeImports?: boolean;
|
|
16
|
+
disableGraphQLRoot?: boolean;
|
|
17
|
+
generatedHeader?: string;
|
|
18
|
+
disableBase64Encoding?: boolean;
|
|
19
|
+
generateRootResolvers?: boolean;
|
|
20
|
+
}
|
|
21
|
+
interface PrettierConfig {
|
|
22
|
+
custom?: boolean;
|
|
23
|
+
glob?: string;
|
|
24
|
+
}
|
|
25
|
+
interface PrivacyConfig {
|
|
26
|
+
path: string;
|
|
27
|
+
policyName: string;
|
|
28
|
+
class?: boolean;
|
|
9
29
|
}
|
|
10
30
|
export declare function loadConfig(file?: string | Buffer | Config): void;
|
|
11
31
|
export {};
|
package/core/config.js
CHANGED
|
@@ -30,7 +30,7 @@ const path = __importStar(require("path"));
|
|
|
30
30
|
const logger_1 = require("./logger");
|
|
31
31
|
function setConfig(cfg) {
|
|
32
32
|
if (cfg.log) {
|
|
33
|
-
logger_1.setLogLevels(cfg.log);
|
|
33
|
+
(0, logger_1.setLogLevels)(cfg.log);
|
|
34
34
|
}
|
|
35
35
|
if (cfg.dbConnectionString || cfg.dbFile || cfg.db) {
|
|
36
36
|
db_1.default.initDB({
|
|
@@ -68,7 +68,7 @@ function loadConfig(file) {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
try {
|
|
71
|
-
let yaml = js_yaml_1.load(data);
|
|
71
|
+
let yaml = (0, js_yaml_1.load)(data);
|
|
72
72
|
if (typeof yaml !== "object") {
|
|
73
73
|
throw new Error(`invalid yaml passed`);
|
|
74
74
|
}
|
package/core/context.js
CHANGED
|
@@ -14,7 +14,7 @@ class ContextCache {
|
|
|
14
14
|
if (l) {
|
|
15
15
|
return l;
|
|
16
16
|
}
|
|
17
|
-
logger_1.log("debug", `new context-aware loader created for ${name}`);
|
|
17
|
+
(0, logger_1.log)("debug", `new context-aware loader created for ${name}`);
|
|
18
18
|
l = create();
|
|
19
19
|
this.loaders.set(name, l);
|
|
20
20
|
return l;
|
|
@@ -39,7 +39,7 @@ class ContextCache {
|
|
|
39
39
|
const key = this.getkey(options);
|
|
40
40
|
let rows = m.get(key);
|
|
41
41
|
if (rows) {
|
|
42
|
-
logger_1.log("query", {
|
|
42
|
+
(0, logger_1.log)("query", {
|
|
43
43
|
"cache-hit": key,
|
|
44
44
|
"tableName": options.tableName,
|
|
45
45
|
});
|
|
@@ -54,7 +54,7 @@ class ContextCache {
|
|
|
54
54
|
const key = this.getkey(options);
|
|
55
55
|
let row = m.get(key);
|
|
56
56
|
if (row) {
|
|
57
|
-
logger_1.log("query", {
|
|
57
|
+
(0, logger_1.log)("query", {
|
|
58
58
|
"cache-hit": key,
|
|
59
59
|
"tableName": options.tableName,
|
|
60
60
|
});
|
package/core/convert.d.ts
CHANGED
|
@@ -8,3 +8,7 @@ export declare function convertDateList(val: any): Date[];
|
|
|
8
8
|
export declare function convertNullableDateList(val: any): Date[] | null;
|
|
9
9
|
export declare function convertBoolList(val: any): boolean[];
|
|
10
10
|
export declare function convertNullableBoolList(val: any): boolean[] | null;
|
|
11
|
+
export declare function convertJSON(val: any): any;
|
|
12
|
+
export declare function convertNullableJSON(val: any): any | null;
|
|
13
|
+
export declare function convertJSONList(val: any): boolean[];
|
|
14
|
+
export declare function convertNullableJSONList(val: any): any[] | null;
|
package/core/convert.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.convertNullableBoolList = exports.convertBoolList = exports.convertNullableDateList = exports.convertDateList = exports.convertNullableList = exports.convertList = exports.convertNullableBool = exports.convertBool = exports.convertNullableDate = exports.convertDate = void 0;
|
|
3
|
+
exports.convertNullableJSONList = exports.convertJSONList = exports.convertNullableJSON = exports.convertJSON = exports.convertNullableBoolList = exports.convertBoolList = exports.convertNullableDateList = exports.convertDateList = exports.convertNullableList = exports.convertList = exports.convertNullableBool = exports.convertBool = exports.convertNullableDate = exports.convertDate = void 0;
|
|
4
4
|
const luxon_1 = require("luxon");
|
|
5
5
|
// these are needed to deal with SQLite having different types stored in the db vs the representation
|
|
6
6
|
// gotten back from the db/needed in ent land
|
|
@@ -59,7 +59,8 @@ function convertList(val, conv) {
|
|
|
59
59
|
}
|
|
60
60
|
exports.convertList = convertList;
|
|
61
61
|
function convertNullableList(val, conv) {
|
|
62
|
-
|
|
62
|
+
// undefined can happen with unsafe ents
|
|
63
|
+
if (val === null || val === undefined) {
|
|
63
64
|
return null;
|
|
64
65
|
}
|
|
65
66
|
return convertList(val, conv);
|
|
@@ -81,3 +82,25 @@ function convertNullableBoolList(val) {
|
|
|
81
82
|
return convertNullableList(val, convertBool);
|
|
82
83
|
}
|
|
83
84
|
exports.convertNullableBoolList = convertNullableBoolList;
|
|
85
|
+
function convertJSON(val) {
|
|
86
|
+
if (typeof val === "string") {
|
|
87
|
+
return JSON.parse(val);
|
|
88
|
+
}
|
|
89
|
+
return val;
|
|
90
|
+
}
|
|
91
|
+
exports.convertJSON = convertJSON;
|
|
92
|
+
function convertNullableJSON(val) {
|
|
93
|
+
if (val === null) {
|
|
94
|
+
return val;
|
|
95
|
+
}
|
|
96
|
+
return convertJSON(val);
|
|
97
|
+
}
|
|
98
|
+
exports.convertNullableJSON = convertNullableJSON;
|
|
99
|
+
function convertJSONList(val) {
|
|
100
|
+
return convertList(val, convertJSON);
|
|
101
|
+
}
|
|
102
|
+
exports.convertJSONList = convertJSONList;
|
|
103
|
+
function convertNullableJSONList(val) {
|
|
104
|
+
return convertNullableList(val, convertJSON);
|
|
105
|
+
}
|
|
106
|
+
exports.convertNullableJSONList = convertNullableJSONList;
|