@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.
@@ -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>, Data, T | null> | undefined);
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, Viewer, Data>);
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<T extends Ent, TData extends Data> {
4
- existingEnt?: T | null;
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
- interface EntBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data> extends Builder<TEnt, TViewer> {
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?: ActionOptions<TEnt, TInput> | null);
27
- static createBuilder<TEnt extends Ent<TViewer>, TViewer extends Viewer, TInput extends Data>(viewer: Viewer, builderCtr: BuilderConstructor<TEnt, TViewer, TInput>, options?: ActionOptions<TEnt, TInput> | null): Builder<TEnt>;
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, EntBuilder<TEnt, TViewer, TInput>, TViewer, TInput>, existingEnt: TEnt | null): EntBuilder<TEnt, TViewer, TInput>;
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): Action<TEnt, Builder<TEnt, TViewer>, TViewer, 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?.existingEnt || null);
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;
@@ -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>, TViewer extends Viewer, TInput extends Data, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
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, TViewer, TInput, TExistingEnt>);
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>, Data, MaybeNull<T>> | undefined);
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 {};
@@ -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
- await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, this.getEntForPrivacyPolicyImpl(editedData), this.throwError.bind(this));
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
- throw new Error(`field ${fieldName} set to null for non-nullable field`);
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
- throw new Error(`required field ${fieldName} not set`);
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
- throw new Error(`invalid field ${fieldName} with value ${value}`);
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
- throw new Error(`invalid field ${fieldName} with value ${value}`);
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
- value = await this.transformFieldValue(fieldName, field, dbKey, value);
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 value = await this.transformFieldValue(fieldName, field, dbKey, defaultValue);
585
- data[dbKey] = value;
586
- logValues[dbKey] = field.logValue(value);
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
- try {
595
- await this.validate();
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.1.0-alpha47",
3
+ "version": "0.1.0-alpha53",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/schema/field.js CHANGED
@@ -642,6 +642,10 @@ class ListField extends BaseField {
642
642
  }
643
643
  postgresVal(val, jsonType) {
644
644
  if (!jsonType) {
645
+ // support empty strings in list
646
+ if (val === "") {
647
+ val = '"' + val + '"';
648
+ }
645
649
  return val;
646
650
  }
647
651
  return JSON.stringify(val);
@@ -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>;
@@ -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) {