@snowtop/ent 0.1.0-alpha47 → 0.1.0-alpha53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/action/executor.d.ts +2 -2
- package/action/experimental_action.d.ts +22 -16
- package/action/experimental_action.js +19 -2
- package/action/orchestrator.d.ts +16 -3
- package/action/orchestrator.js +65 -16
- package/package.json +1 -1
- package/schema/field.js +4 -0
- package/testutils/builder.d.ts +5 -4
- package/testutils/builder.js +3 -0
package/action/executor.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ export declare class ListBasedExecutor<T extends Ent> implements Executor {
|
|
|
10
10
|
private operations;
|
|
11
11
|
private options?;
|
|
12
12
|
private idx;
|
|
13
|
-
constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation<T>[], options?: OrchestratorOptions<T, Viewer<Ent<any> | null, ID | null>,
|
|
13
|
+
constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation<T>[], options?: OrchestratorOptions<T, Data, Viewer<Ent<any> | null, ID | null>, T | null> | undefined);
|
|
14
14
|
private lastOp;
|
|
15
15
|
private createdEnt;
|
|
16
16
|
resolveValue(val: ID): Ent | null;
|
|
@@ -29,7 +29,7 @@ export declare class ComplexExecutor<T extends Ent> implements Executor {
|
|
|
29
29
|
private lastOp;
|
|
30
30
|
private allOperations;
|
|
31
31
|
private executors;
|
|
32
|
-
constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset[], options?: OrchestratorOptions<T,
|
|
32
|
+
constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset[], options?: OrchestratorOptions<T, Data, Viewer>);
|
|
33
33
|
[Symbol.iterator](): this;
|
|
34
34
|
private handleCreatedEnt;
|
|
35
35
|
next(): IteratorResult<DataOperation<Ent>>;
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { Orchestrator } from "@snowtop/ent/action";
|
|
1
2
|
import { Viewer, Ent, Data } from "../core/base";
|
|
2
3
|
import { Action, WriteOperation, Builder, Trigger, Observer, Changeset, Validator } from "./action";
|
|
3
|
-
export interface ActionOptions<
|
|
4
|
-
existingEnt
|
|
4
|
+
export interface ActionOptions<TEnt extends Ent<TViewer>, TViewer extends Viewer, TData extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
|
|
5
|
+
existingEnt: TExistingEnt;
|
|
5
6
|
input?: TData;
|
|
6
7
|
operation?: WriteOperation;
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
+
declare type MaybeNull<T extends Ent> = T | null;
|
|
10
|
+
declare type TMaybleNullableEnt<T extends Ent> = T | MaybeNull<T>;
|
|
11
|
+
export interface EntBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> extends Builder<TEnt, TViewer, TExistingEnt> {
|
|
9
12
|
valid(): Promise<boolean>;
|
|
10
13
|
validX(): Promise<void>;
|
|
11
14
|
save(): Promise<void>;
|
|
@@ -13,19 +16,20 @@ interface EntBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput e
|
|
|
13
16
|
editedEnt(): Promise<TEnt | null>;
|
|
14
17
|
editedEntX(): Promise<TEnt>;
|
|
15
18
|
getInput(): TInput;
|
|
19
|
+
orchestrator: Orchestrator<TEnt, TInput, TViewer, TExistingEnt>;
|
|
16
20
|
}
|
|
17
|
-
export declare class BaseAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data> implements Action<TEnt, EntBuilder<TEnt, TViewer, TInput>, TViewer, TInput> {
|
|
21
|
+
export declare class BaseAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> implements Action<TEnt, EntBuilder<TEnt, TViewer, TInput, TExistingEnt>, TViewer, TInput, TExistingEnt> {
|
|
18
22
|
viewer: TViewer;
|
|
19
|
-
builderCtr: BuilderConstructor<TEnt, TViewer, TInput>;
|
|
20
|
-
builder: EntBuilder<TEnt, TViewer, TInput>;
|
|
23
|
+
builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TExistingEnt>;
|
|
24
|
+
builder: EntBuilder<TEnt, TViewer, TInput, TExistingEnt>;
|
|
21
25
|
private input;
|
|
22
26
|
getPrivacyPolicy(): import("../core/base").PrivacyPolicy<Ent<Viewer<Ent<any> | null, import("../core/base").ID | null>>, Viewer<Ent<any> | null, import("../core/base").ID | null>>;
|
|
23
|
-
getTriggers(): Trigger<TEnt, EntBuilder<TEnt, TViewer, TInput>, TViewer, TInput>[];
|
|
24
|
-
getObservers(): Observer<TEnt, EntBuilder<TEnt, TViewer, TInput>, TViewer, TInput>[];
|
|
25
|
-
getValidators(): Validator<TEnt, EntBuilder<TEnt, TViewer, TInput>, TViewer, TInput>[];
|
|
26
|
-
constructor(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, options
|
|
27
|
-
static createBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: Viewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, options
|
|
28
|
-
static bulkAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(ent: TEnt, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, ...actions: Action<Ent, Builder<Ent, any>>[]): BaseAction<TEnt, TViewer, TInput>;
|
|
27
|
+
getTriggers(): Trigger<TEnt, EntBuilder<TEnt, TViewer, TInput, TExistingEnt>, TViewer, TInput, TExistingEnt>[];
|
|
28
|
+
getObservers(): Observer<TEnt, EntBuilder<TEnt, TViewer, TInput, TExistingEnt>, TViewer, TInput, TExistingEnt>[];
|
|
29
|
+
getValidators(): Validator<TEnt, EntBuilder<TEnt, TViewer, TInput, TExistingEnt>, TViewer, TInput, TExistingEnt>[];
|
|
30
|
+
constructor(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TExistingEnt>, options: ActionOptions<TEnt, TViewer, TInput, TExistingEnt>);
|
|
31
|
+
static createBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>>(viewer: Viewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TExistingEnt>, options: ActionOptions<TEnt, TViewer, TInput, TExistingEnt>): Builder<TEnt>;
|
|
32
|
+
static bulkAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(ent: TEnt, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TEnt>, ...actions: Action<Ent, Builder<Ent, any>>[]): BaseAction<TEnt, TViewer, TInput, TEnt>;
|
|
29
33
|
changeset(): Promise<Changeset>;
|
|
30
34
|
valid(): Promise<boolean>;
|
|
31
35
|
validX(): Promise<void>;
|
|
@@ -33,9 +37,11 @@ export declare class BaseAction<TEnt extends Ent<TViewer>, TViewer extends Viewe
|
|
|
33
37
|
saveX(): Promise<TEnt>;
|
|
34
38
|
getInput(): TInput;
|
|
35
39
|
}
|
|
36
|
-
interface BuilderConstructor<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data> {
|
|
37
|
-
new (viewer: TViewer, operation: WriteOperation, action: Action<TEnt,
|
|
40
|
+
export interface BuilderConstructor<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
|
|
41
|
+
new (viewer: TViewer, operation: WriteOperation, action: Action<TEnt, any, TViewer, TInput, TExistingEnt>, existingEnt: TExistingEnt): EntBuilder<TEnt, TViewer, TInput, TExistingEnt>;
|
|
38
42
|
}
|
|
39
|
-
export declare function updateRawObject<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, existingEnt: TEnt, input: TInput): Promise<TEnt>;
|
|
40
|
-
export declare function getSimpleEditAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, existingEnt: TEnt, input: TInput):
|
|
43
|
+
export declare function updateRawObject<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TEnt>, existingEnt: TEnt, input: TInput): Promise<TEnt>;
|
|
44
|
+
export declare function getSimpleEditAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TEnt>, existingEnt: TEnt, input: TInput): BaseAction<TEnt, TViewer, TInput, TEnt>;
|
|
45
|
+
export declare function getSimpleDeleteAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, TEnt>, existingEnt: TEnt, input: TInput): BaseAction<TEnt, TViewer, TInput, TEnt>;
|
|
46
|
+
export declare function getSimpleInsertAction<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: TViewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput, null>, input: TInput): BaseAction<TEnt, TViewer, TInput, null>;
|
|
41
47
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getSimpleEditAction = exports.updateRawObject = exports.BaseAction = void 0;
|
|
3
|
+
exports.getSimpleInsertAction = exports.getSimpleDeleteAction = exports.getSimpleEditAction = exports.updateRawObject = exports.BaseAction = void 0;
|
|
4
4
|
const privacy_1 = require("../core/privacy");
|
|
5
5
|
const action_1 = require("./action");
|
|
6
6
|
class BaseAction {
|
|
@@ -17,7 +17,7 @@ class BaseAction {
|
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
19
|
this.input = options?.input || {};
|
|
20
|
-
this.builder = new builderCtr(viewer, operation, this, options
|
|
20
|
+
this.builder = new builderCtr(viewer, operation, this, options.existingEnt);
|
|
21
21
|
}
|
|
22
22
|
getPrivacyPolicy() {
|
|
23
23
|
return privacy_1.AlwaysAllowPrivacyPolicy;
|
|
@@ -85,6 +85,7 @@ async function updateRawObject(viewer, builderCtr, existingEnt, input) {
|
|
|
85
85
|
return action.saveX();
|
|
86
86
|
}
|
|
87
87
|
exports.updateRawObject = updateRawObject;
|
|
88
|
+
// TODO need to fix types for all these
|
|
88
89
|
// creates an action which has no privacy, triggers, observers etc
|
|
89
90
|
// does do field validation
|
|
90
91
|
// useful to batch a bunch of writes together with BaseAction.bulkAction
|
|
@@ -97,3 +98,19 @@ function getSimpleEditAction(viewer, builderCtr, existingEnt, input) {
|
|
|
97
98
|
});
|
|
98
99
|
}
|
|
99
100
|
exports.getSimpleEditAction = getSimpleEditAction;
|
|
101
|
+
function getSimpleDeleteAction(viewer, builderCtr, existingEnt, input) {
|
|
102
|
+
return new BaseAction(viewer, builderCtr, {
|
|
103
|
+
existingEnt: existingEnt,
|
|
104
|
+
operation: action_1.WriteOperation.Delete,
|
|
105
|
+
input,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
exports.getSimpleDeleteAction = getSimpleDeleteAction;
|
|
109
|
+
function getSimpleInsertAction(viewer, builderCtr, input) {
|
|
110
|
+
return new BaseAction(viewer, builderCtr, {
|
|
111
|
+
operation: action_1.WriteOperation.Insert,
|
|
112
|
+
input,
|
|
113
|
+
existingEnt: null,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
exports.getSimpleInsertAction = getSimpleInsertAction;
|
package/action/orchestrator.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { Changeset, Executor } from "../action/action";
|
|
|
5
5
|
import { WriteOperation, Builder, Action } from "../action";
|
|
6
6
|
declare type MaybeNull<T extends Ent> = T | null;
|
|
7
7
|
declare type TMaybleNullableEnt<T extends Ent> = T | MaybeNull<T>;
|
|
8
|
-
export interface OrchestratorOptions<TEnt extends Ent<TViewer>,
|
|
8
|
+
export interface OrchestratorOptions<TEnt extends Ent<TViewer>, TInput extends Data, TViewer extends Viewer, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
|
|
9
9
|
viewer: Viewer;
|
|
10
10
|
operation: WriteOperation;
|
|
11
11
|
tableName: string;
|
|
@@ -48,7 +48,7 @@ export declare class Orchestrator<TEnt extends Ent<TViewer>, TInput extends Data
|
|
|
48
48
|
private existingEnt;
|
|
49
49
|
private disableTransformations;
|
|
50
50
|
private memoizedGetFields;
|
|
51
|
-
constructor(options: OrchestratorOptions<TEnt,
|
|
51
|
+
constructor(options: OrchestratorOptions<TEnt, TInput, TViewer, TExistingEnt>);
|
|
52
52
|
private addEdge;
|
|
53
53
|
setDisableTransformations(val: boolean): void;
|
|
54
54
|
addInboundEdge<T2 extends Ent>(id1: ID | Builder<T2, any>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
|
|
@@ -66,6 +66,11 @@ export declare class Orchestrator<TEnt extends Ent<TViewer>, TInput extends Data
|
|
|
66
66
|
private getWriteOpForSQLStamentOp;
|
|
67
67
|
getPossibleUnsafeEntForPrivacy(): Promise<TEnt>;
|
|
68
68
|
getEditedData(): Promise<Data>;
|
|
69
|
+
/**
|
|
70
|
+
* @returns validated and formatted fields that would be written to the db
|
|
71
|
+
* throws an error if called before valid() or validX() has been called
|
|
72
|
+
*/
|
|
73
|
+
getValidatedFields(): Data;
|
|
69
74
|
private getFieldsInfo;
|
|
70
75
|
private validate;
|
|
71
76
|
private triggers;
|
|
@@ -79,6 +84,14 @@ export declare class Orchestrator<TEnt extends Ent<TViewer>, TInput extends Data
|
|
|
79
84
|
private formatAndValidateFields;
|
|
80
85
|
valid(): Promise<boolean>;
|
|
81
86
|
validX(): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* @experimental API that's not guaranteed to remain in the future which returns
|
|
89
|
+
* a list of errors encountered
|
|
90
|
+
* 0 errors indicates valid
|
|
91
|
+
* NOTE that this currently doesn't catch errors returned by validators().
|
|
92
|
+
* If those throws, this still throws and doesn't return them
|
|
93
|
+
*/
|
|
94
|
+
validWithErrors(): Promise<Error[]>;
|
|
82
95
|
build(): Promise<EntChangeset<TEnt>>;
|
|
83
96
|
private viewerForEntLoad;
|
|
84
97
|
returnedRow(): Promise<Data | null>;
|
|
@@ -94,7 +107,7 @@ export declare class EntChangeset<T extends Ent> implements Changeset {
|
|
|
94
107
|
changesets?: Changeset[] | undefined;
|
|
95
108
|
private options?;
|
|
96
109
|
private _executor;
|
|
97
|
-
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>, Ent<Viewer<Ent<any> | null, ID | null>> | null>> | undefined, changesets?: Changeset[] | undefined, options?: OrchestratorOptions<T, Viewer<Ent<any> | null, ID | null>,
|
|
110
|
+
constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<Ent<Viewer<Ent<any> | null, ID | null>>, Viewer<Ent<any> | null, ID | null>, Ent<Viewer<Ent<any> | null, ID | null>> | null>> | undefined, changesets?: Changeset[] | undefined, options?: OrchestratorOptions<T, Data, Viewer<Ent<any> | null, ID | null>, MaybeNull<T>> | undefined);
|
|
98
111
|
executor(): Executor;
|
|
99
112
|
}
|
|
100
113
|
export {};
|
package/action/orchestrator.js
CHANGED
|
@@ -284,6 +284,16 @@ class Orchestrator {
|
|
|
284
284
|
const { editedData } = await this.memoizedGetFields();
|
|
285
285
|
return editedData;
|
|
286
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* @returns validated and formatted fields that would be written to the db
|
|
289
|
+
* throws an error if called before valid() or validX() has been called
|
|
290
|
+
*/
|
|
291
|
+
getValidatedFields() {
|
|
292
|
+
if (this.validatedFields === null) {
|
|
293
|
+
throw new Error(`trying to call getValidatedFields before validating fields`);
|
|
294
|
+
}
|
|
295
|
+
return this.validatedFields;
|
|
296
|
+
}
|
|
287
297
|
// Note: this is memoized. call memoizedGetFields instead
|
|
288
298
|
async getFieldsInfo() {
|
|
289
299
|
const action = this.options.action;
|
|
@@ -312,8 +322,14 @@ class Orchestrator {
|
|
|
312
322
|
// * triggers
|
|
313
323
|
// * validators
|
|
314
324
|
let privacyPolicy = action?.getPrivacyPolicy();
|
|
325
|
+
let privacyError = null;
|
|
315
326
|
if (privacyPolicy) {
|
|
316
|
-
|
|
327
|
+
try {
|
|
328
|
+
await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, this.getEntForPrivacyPolicyImpl(editedData), this.throwError.bind(this));
|
|
329
|
+
}
|
|
330
|
+
catch (err) {
|
|
331
|
+
privacyError = err;
|
|
332
|
+
}
|
|
317
333
|
}
|
|
318
334
|
// have to run triggers which update fields first before field and other validators
|
|
319
335
|
// so running this first to build things up
|
|
@@ -327,10 +343,14 @@ class Orchestrator {
|
|
|
327
343
|
// not ideal we're calling this twice. fix...
|
|
328
344
|
// needed for now. may need to rewrite some of this?
|
|
329
345
|
const editedFields2 = await this.options.editedFields();
|
|
330
|
-
await Promise.all([
|
|
346
|
+
const [errors, _] = await Promise.all([
|
|
331
347
|
this.formatAndValidateFields(schemaFields, editedFields2),
|
|
332
348
|
this.validators(validators, action, builder),
|
|
333
349
|
]);
|
|
350
|
+
if (privacyError !== null) {
|
|
351
|
+
errors.unshift(privacyError);
|
|
352
|
+
}
|
|
353
|
+
return errors;
|
|
334
354
|
}
|
|
335
355
|
async triggers(action, builder, triggers) {
|
|
336
356
|
let groups = [];
|
|
@@ -375,6 +395,8 @@ class Orchestrator {
|
|
|
375
395
|
}
|
|
376
396
|
}
|
|
377
397
|
async validators(validators, action, builder) {
|
|
398
|
+
// TODO need to catch errors and return it...
|
|
399
|
+
// don't need it initially since what we need this for doesn't have the errors
|
|
378
400
|
let promises = [];
|
|
379
401
|
validators.forEach((validator) => {
|
|
380
402
|
let res = validator.validate(builder, action.getInput());
|
|
@@ -511,7 +533,7 @@ class Orchestrator {
|
|
|
511
533
|
// now format and validate...
|
|
512
534
|
if (value === null) {
|
|
513
535
|
if (!field.nullable) {
|
|
514
|
-
|
|
536
|
+
return new Error(`field ${fieldName} set to null for non-nullable field`);
|
|
515
537
|
}
|
|
516
538
|
}
|
|
517
539
|
else if (value === undefined) {
|
|
@@ -522,14 +544,14 @@ class Orchestrator {
|
|
|
522
544
|
// server default allowed
|
|
523
545
|
field.serverDefault === undefined &&
|
|
524
546
|
this.actualOperation === action_1.WriteOperation.Insert) {
|
|
525
|
-
|
|
547
|
+
return new Error(`required field ${fieldName} not set`);
|
|
526
548
|
}
|
|
527
549
|
}
|
|
528
550
|
else if (this.isBuilder(value)) {
|
|
529
551
|
if (field.valid) {
|
|
530
552
|
const valid = await field.valid(value);
|
|
531
553
|
if (!valid) {
|
|
532
|
-
|
|
554
|
+
return new Error(`invalid field ${fieldName} with value ${value}`);
|
|
533
555
|
}
|
|
534
556
|
}
|
|
535
557
|
// keep track of dependencies to resolve
|
|
@@ -542,7 +564,7 @@ class Orchestrator {
|
|
|
542
564
|
// TODO this could be async. handle this better
|
|
543
565
|
const valid = await field.valid(value);
|
|
544
566
|
if (!valid) {
|
|
545
|
-
|
|
567
|
+
return new Error(`invalid field ${fieldName} with value ${value}`);
|
|
546
568
|
}
|
|
547
569
|
}
|
|
548
570
|
if (field.format) {
|
|
@@ -552,9 +574,10 @@ class Orchestrator {
|
|
|
552
574
|
return value;
|
|
553
575
|
}
|
|
554
576
|
async formatAndValidateFields(schemaFields, editedFields) {
|
|
577
|
+
const errors = [];
|
|
555
578
|
const op = this.actualOperation;
|
|
556
579
|
if (op === action_1.WriteOperation.Delete) {
|
|
557
|
-
return;
|
|
580
|
+
return [];
|
|
558
581
|
}
|
|
559
582
|
// build up data to be saved...
|
|
560
583
|
let data = {};
|
|
@@ -566,7 +589,13 @@ class Orchestrator {
|
|
|
566
589
|
value = this.defaultFieldsByFieldName[fieldName];
|
|
567
590
|
}
|
|
568
591
|
let dbKey = this.getStorageKey(fieldName);
|
|
569
|
-
|
|
592
|
+
let ret = await this.transformFieldValue(fieldName, field, dbKey, value);
|
|
593
|
+
if (ret instanceof Error) {
|
|
594
|
+
errors.push(ret);
|
|
595
|
+
}
|
|
596
|
+
else {
|
|
597
|
+
value = ret;
|
|
598
|
+
}
|
|
570
599
|
if (value !== undefined) {
|
|
571
600
|
data[dbKey] = value;
|
|
572
601
|
logValues[dbKey] = field.logValue(value);
|
|
@@ -581,28 +610,48 @@ class Orchestrator {
|
|
|
581
610
|
let dbKey = this.getStorageKey(fieldName);
|
|
582
611
|
// no value, let's just default
|
|
583
612
|
if (data[dbKey] === undefined) {
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
613
|
+
const ret = await this.transformFieldValue(fieldName, field, dbKey, defaultValue);
|
|
614
|
+
if (ret instanceof Error) {
|
|
615
|
+
errors.push(ret);
|
|
616
|
+
}
|
|
617
|
+
else {
|
|
618
|
+
data[dbKey] = ret;
|
|
619
|
+
logValues[dbKey] = field.logValue(ret);
|
|
620
|
+
}
|
|
587
621
|
}
|
|
588
622
|
}
|
|
589
623
|
}
|
|
590
624
|
this.validatedFields = data;
|
|
591
625
|
this.logValues = logValues;
|
|
626
|
+
return errors;
|
|
592
627
|
}
|
|
593
628
|
async valid() {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
catch (e) {
|
|
598
|
-
(0, logger_1.log)("error", e);
|
|
629
|
+
const errors = await this.validate();
|
|
630
|
+
if (errors.length) {
|
|
631
|
+
errors.map((err) => (0, logger_1.log)("error", err));
|
|
599
632
|
return false;
|
|
600
633
|
}
|
|
601
634
|
return true;
|
|
602
635
|
}
|
|
603
636
|
async validX() {
|
|
637
|
+
const errors = await this.validate();
|
|
638
|
+
if (errors.length) {
|
|
639
|
+
// just throw the first one...
|
|
640
|
+
// TODO we should ideally throw all of them
|
|
641
|
+
throw errors[0];
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
/**
|
|
645
|
+
* @experimental API that's not guaranteed to remain in the future which returns
|
|
646
|
+
* a list of errors encountered
|
|
647
|
+
* 0 errors indicates valid
|
|
648
|
+
* NOTE that this currently doesn't catch errors returned by validators().
|
|
649
|
+
* If those throws, this still throws and doesn't return them
|
|
650
|
+
*/
|
|
651
|
+
async validWithErrors() {
|
|
604
652
|
return this.validate();
|
|
605
653
|
}
|
|
654
|
+
// TODO validWithErrors
|
|
606
655
|
async build() {
|
|
607
656
|
// validate everything first
|
|
608
657
|
await this.validX();
|
package/package.json
CHANGED
package/schema/field.js
CHANGED
package/testutils/builder.d.ts
CHANGED
|
@@ -70,18 +70,18 @@ export declare function getTableName(value: BuilderSchema<Ent>): string;
|
|
|
70
70
|
export declare function getFieldInfo(value: BuilderSchema<Ent>): FieldInfoMap;
|
|
71
71
|
declare type MaybeNull<T extends Ent> = T | null;
|
|
72
72
|
declare type TMaybleNullableEnt<T extends Ent> = T | MaybeNull<T>;
|
|
73
|
-
export declare class SimpleBuilder<T extends Ent, TExistingEnt extends TMaybleNullableEnt<T> = MaybeNull<T>> implements Builder<T> {
|
|
73
|
+
export declare class SimpleBuilder<T extends Ent, TExistingEnt extends TMaybleNullableEnt<T> = MaybeNull<T>> implements Builder<T, Viewer, TExistingEnt> {
|
|
74
74
|
viewer: Viewer;
|
|
75
75
|
private schema;
|
|
76
76
|
operation: WriteOperation;
|
|
77
77
|
existingEnt: TExistingEnt;
|
|
78
|
-
ent: EntConstructor<T>;
|
|
78
|
+
ent: EntConstructor<T, Viewer>;
|
|
79
79
|
placeholderID: ID;
|
|
80
|
-
orchestrator: Orchestrator<T, Data, Viewer>;
|
|
80
|
+
orchestrator: Orchestrator<T, Data, Viewer, TExistingEnt>;
|
|
81
81
|
fields: Map<string, any>;
|
|
82
82
|
nodeType: string;
|
|
83
83
|
m: Map<string, any>;
|
|
84
|
-
constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation: WriteOperation, existingEnt: TExistingEnt, action?: Action<T, SimpleBuilder<T>, Viewer, Data> | undefined);
|
|
84
|
+
constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation: WriteOperation, existingEnt: TExistingEnt, action?: Action<T, SimpleBuilder<T, TExistingEnt>, Viewer, Data, TExistingEnt> | undefined);
|
|
85
85
|
getInput(): Data;
|
|
86
86
|
updateInput(input: Data): void;
|
|
87
87
|
storeData(k: string, v: any): void;
|
|
@@ -111,6 +111,7 @@ export declare class SimpleAction<T extends Ent, TExistingEnt extends TMaybleNul
|
|
|
111
111
|
changeset(): Promise<Changeset>;
|
|
112
112
|
valid(): Promise<boolean>;
|
|
113
113
|
validX(): Promise<void>;
|
|
114
|
+
validWithErrors(): Promise<Error[]>;
|
|
114
115
|
save(): Promise<T | null>;
|
|
115
116
|
saveX(): Promise<T>;
|
|
116
117
|
editedEnt(): Promise<T | null>;
|
package/testutils/builder.js
CHANGED
|
@@ -296,6 +296,9 @@ class SimpleAction {
|
|
|
296
296
|
validX() {
|
|
297
297
|
return this.builder.orchestrator.validX();
|
|
298
298
|
}
|
|
299
|
+
validWithErrors() {
|
|
300
|
+
return this.builder.orchestrator.validWithErrors();
|
|
301
|
+
}
|
|
299
302
|
async save() {
|
|
300
303
|
await (0, action_1.saveBuilder)(this.builder);
|
|
301
304
|
if (this.builder.operation !== action_1.WriteOperation.Delete) {
|