@snowtop/ent 0.1.0-alpha80 → 0.1.0-alpha85

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.
@@ -1,14 +1,16 @@
1
- import { Ent, EntConstructor, Viewer, ID, Data, PrivacyPolicy, Context } from "../core/base";
1
+ import { Ent, EntConstructor, Viewer, ID, Data, PrivacyPolicy, Context, WriteOperation } from "../core/base";
2
2
  import { DataOperation, AssocEdgeInputOptions } from "../core/ent";
3
3
  import { Queryer } from "../core/db";
4
4
  import { TransformedUpdateOperation, UpdateOperation } from "../schema";
5
- export declare enum WriteOperation {
6
- Insert = "insert",
7
- Edit = "edit",
8
- Delete = "delete"
9
- }
5
+ import { FieldInfoMap } from "../schema/schema";
6
+ export { WriteOperation };
10
7
  declare type MaybeNull<T extends Ent> = T | null;
11
8
  declare type TMaybleNullableEnt<T extends Ent> = T | MaybeNull<T>;
9
+ interface BuilderOrchestrator {
10
+ __getOptions(): {
11
+ fieldInfo: FieldInfoMap;
12
+ };
13
+ }
12
14
  export interface Builder<TEnt extends Ent<TViewer>, TViewer extends Viewer = Viewer, TExistingEnt extends TMaybleNullableEnt<TEnt> = MaybeNull<TEnt>> {
13
15
  existingEnt: TExistingEnt;
14
16
  ent: EntConstructor<TEnt, TViewer>;
@@ -18,6 +20,8 @@ export interface Builder<TEnt extends Ent<TViewer>, TViewer extends Viewer = Vie
18
20
  operation: WriteOperation;
19
21
  editedEnt?(): Promise<TEnt | null>;
20
22
  nodeType: string;
23
+ getInput(): Data;
24
+ orchestrator: BuilderOrchestrator;
21
25
  }
22
26
  export interface Executor extends Iterable<DataOperation>, Iterator<DataOperation> {
23
27
  placeholderID: ID;
@@ -66,4 +70,3 @@ interface Orchestrator {
66
70
  viewer: Viewer;
67
71
  }
68
72
  export declare function setEdgeTypeInGroup<T extends string>(orchestrator: Orchestrator, inputEnumValue: string, id1: ID, id2: ID, nodeType: string, m: Map<T, string>): Promise<void>;
69
- export {};
package/action/action.js CHANGED
@@ -1,14 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.setEdgeTypeInGroup = exports.saveBuilderX = exports.saveBuilder = exports.WriteOperation = void 0;
4
+ const base_1 = require("../core/base");
5
+ Object.defineProperty(exports, "WriteOperation", { enumerable: true, get: function () { return base_1.WriteOperation; } });
4
6
  const ent_1 = require("../core/ent");
5
7
  const logger_1 = require("../core/logger");
6
- var WriteOperation;
7
- (function (WriteOperation) {
8
- WriteOperation["Insert"] = "insert";
9
- WriteOperation["Edit"] = "edit";
10
- WriteOperation["Delete"] = "delete";
11
- })(WriteOperation = exports.WriteOperation || (exports.WriteOperation = {}));
12
8
  async function saveBuilder(builder) {
13
9
  await saveBuilderImpl(builder, false);
14
10
  }
@@ -49,6 +49,7 @@ export declare class Orchestrator<TEnt extends Ent<TViewer>, TInput extends Data
49
49
  private disableTransformations;
50
50
  private memoizedGetFields;
51
51
  constructor(options: OrchestratorOptions<TEnt, TInput, TViewer, TExistingEnt>);
52
+ __getOptions(): OrchestratorOptions<any, any, any, any>;
52
53
  private addEdge;
53
54
  setDisableTransformations(val: boolean): void;
54
55
  addInboundEdge<T2 extends Ent>(id1: ID | Builder<T2, any>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
@@ -88,6 +88,10 @@ class Orchestrator {
88
88
  this.existingEnt = this.options.builder.existingEnt;
89
89
  this.memoizedGetFields = (0, memoizee_1.default)(this.getFieldsInfo.bind(this));
90
90
  }
91
+ // don't type this because we don't care
92
+ __getOptions() {
93
+ return this.options;
94
+ }
91
95
  addEdge(edge, op) {
92
96
  this.edgeSet.add(edge.edgeType);
93
97
  let m1 = this.edges.get(edge.edgeType) || new Map();
@@ -607,8 +611,12 @@ class Orchestrator {
607
611
  // build up data to be saved...
608
612
  let data = {};
609
613
  let logValues = {};
614
+ let needsFullDataChecks = [];
610
615
  for (const [fieldName, field] of schemaFields) {
611
616
  let value = editedFields.get(fieldName);
617
+ if (field.validateWithFullData) {
618
+ needsFullDataChecks.push(fieldName);
619
+ }
612
620
  if (value === undefined && op === action_1.WriteOperation.Insert) {
613
621
  // null allowed
614
622
  value = this.defaultFieldsByFieldName[fieldName];
@@ -626,6 +634,21 @@ class Orchestrator {
626
634
  logValues[dbKey] = field.logValue(value);
627
635
  }
628
636
  }
637
+ for (const fieldName of needsFullDataChecks) {
638
+ const field = schemaFields.get(fieldName);
639
+ let value = editedFields.get(fieldName);
640
+ // @ts-ignore...
641
+ // type hackery because it's hard
642
+ const v = await field.validateWithFullData(value, this.options.builder);
643
+ if (!v) {
644
+ if (value === undefined) {
645
+ errors.push(new Error(`field ${fieldName} set to undefined when it can't be nullable`));
646
+ }
647
+ else {
648
+ errors.push(new Error(`field ${fieldName} set to null when it can't be nullable`));
649
+ }
650
+ }
651
+ }
629
652
  // we ignored default values while editing.
630
653
  // if we're editing and there's data, add default values
631
654
  if (op === action_1.WriteOperation.Edit && this.hasData(data)) {
package/core/base.d.ts CHANGED
@@ -143,4 +143,9 @@ export interface PrivacyPolicyRule<TEnt extends Ent = Ent, TViewer = Viewer> {
143
143
  export interface PrivacyPolicy<TEnt extends Ent = Ent, TViewer = Viewer> {
144
144
  rules: PrivacyPolicyRule<TEnt, TViewer>[];
145
145
  }
146
+ export declare enum WriteOperation {
147
+ Insert = "insert",
148
+ Edit = "edit",
149
+ Delete = "delete"
150
+ }
146
151
  export {};
package/core/base.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DenyWithReason = exports.Deny = exports.Skip = exports.Allow = void 0;
3
+ exports.WriteOperation = exports.DenyWithReason = exports.Deny = exports.Skip = exports.Allow = void 0;
4
4
  // Privacy
5
5
  var privacyResult;
6
6
  (function (privacyResult) {
@@ -53,3 +53,9 @@ function DenyWithReason(e) {
53
53
  };
54
54
  }
55
55
  exports.DenyWithReason = DenyWithReason;
56
+ var WriteOperation;
57
+ (function (WriteOperation) {
58
+ WriteOperation["Insert"] = "insert";
59
+ WriteOperation["Edit"] = "edit";
60
+ WriteOperation["Delete"] = "delete";
61
+ })(WriteOperation = exports.WriteOperation || (exports.WriteOperation = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.1.0-alpha80",
3
+ "version": "0.1.0-alpha85",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
package/schema/field.d.ts CHANGED
@@ -131,8 +131,6 @@ export interface EnumOptions extends FieldOptions {
131
131
  graphQLType?: string;
132
132
  createEnumType?: boolean;
133
133
  }
134
- export interface StringEnumOptions extends EnumOptions {
135
- }
136
134
  /**
137
135
  * @deprecated Use StringEnumField
138
136
  */
@@ -147,6 +145,11 @@ export declare class EnumField extends BaseField implements Field {
147
145
  }
148
146
  export declare class StringEnumField extends EnumField {
149
147
  }
148
+ export interface PolymorphicStringEnumOptions extends EnumOptions {
149
+ parentFieldToValidate: string;
150
+ }
151
+ export interface StringEnumOptions extends EnumOptions {
152
+ }
150
153
  export declare function EnumType(options: StringEnumOptions): EnumField;
151
154
  declare type IntEnumMap = {
152
155
  [key: string]: number;
@@ -165,11 +168,15 @@ export declare class IntegerEnumField extends BaseField implements Field {
165
168
  format(val: any): any;
166
169
  }
167
170
  export declare function IntegerEnumType(options: IntegerEnumOptions): IntegerEnumField;
171
+ interface ListOptions extends FieldOptions {
172
+ disableJSONStringify?: boolean;
173
+ }
168
174
  export declare class ListField extends BaseField {
169
175
  private field;
176
+ private options?;
170
177
  type: Type;
171
178
  private validators;
172
- constructor(field: Field, options?: FieldOptions);
179
+ constructor(field: Field, options?: ListOptions | undefined);
173
180
  __getElemField(): Field;
174
181
  validate(validator: (val: any[]) => boolean): this;
175
182
  valid(val: any): Promise<boolean>;
package/schema/field.js CHANGED
@@ -22,10 +22,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.UUIDListType = exports.IntegerEnumListType = exports.EnumListType = exports.DateListType = exports.TimetzListType = exports.TimeListType = exports.TimestamptzListType = exports.TimestampListType = exports.BooleanListType = exports.BigIntegerListType = exports.FloatListType = exports.IntegerListType = exports.IntListType = exports.StringListType = exports.ListField = exports.IntegerEnumType = exports.IntegerEnumField = exports.EnumType = exports.StringEnumField = exports.EnumField = exports.DateType = exports.DateField = exports.TimetzType = exports.TimeType = exports.TimeField = exports.leftPad = exports.TimestamptzType = exports.TimestampType = exports.TimestampField = exports.StringType = exports.StringField = exports.BooleanType = exports.BooleanField = exports.FloatType = exports.FloatField = exports.BigIntegerType = exports.BigIntegerField = exports.IntegerType = exports.IntegerField = exports.UUIDType = exports.UUIDField = exports.BaseField = void 0;
23
23
  const luxon_1 = require("luxon");
24
24
  const snake_case_1 = require("snake-case");
25
- const db_1 = __importStar(require("../core/db"));
26
- const schema_1 = require("./schema");
27
25
  const util_1 = require("util");
28
26
  const uuid_1 = require("uuid");
27
+ const base_1 = require("../core/base");
28
+ const db_1 = __importStar(require("../core/db"));
29
+ const schema_1 = require("./schema");
29
30
  class BaseField {
30
31
  logValue(val) {
31
32
  if (this.sensitive) {
@@ -68,21 +69,22 @@ class UUIDField extends BaseField {
68
69
  if (typeof polymorphic === "object" && polymorphic.types) {
69
70
  // an enum with types validated here
70
71
  return {
71
- [name]: EnumType({
72
+ [name]: PolymorphicStringEnumType({
72
73
  values: polymorphic.types,
73
74
  hideFromGraphQL: true,
74
75
  derivedWhenEmbedded: true,
75
76
  nullable: this.options?.nullable,
77
+ parentFieldToValidate: fieldName,
76
78
  }),
77
79
  };
78
80
  }
79
81
  else {
80
- // just a string field...
81
82
  return {
82
- [name]: StringType({
83
+ [name]: PolymorphicStringType({
83
84
  hideFromGraphQL: true,
84
85
  derivedWhenEmbedded: true,
85
86
  nullable: this.options?.nullable,
87
+ parentFieldToValidate: fieldName,
86
88
  }),
87
89
  };
88
90
  }
@@ -311,6 +313,33 @@ class StringField extends BaseField {
311
313
  }
312
314
  }
313
315
  exports.StringField = StringField;
316
+ function validatePolymorphicTypeWithFullData(val, b, field) {
317
+ const input = b.getInput();
318
+ const inputKey = b.orchestrator.__getOptions().fieldInfo[field].inputKey;
319
+ const v = input[inputKey];
320
+ if (val === null) {
321
+ // if this is being set to null, ok if v is also null
322
+ return v === null;
323
+ }
324
+ // if this is not being set, ok if v is not being set
325
+ if (val === undefined && b.operation === base_1.WriteOperation.Insert) {
326
+ return v === undefined;
327
+ }
328
+ return true;
329
+ }
330
+ class PolymorphicStringField extends StringField {
331
+ constructor(opts) {
332
+ super(opts);
333
+ this.opts = opts;
334
+ }
335
+ validateWithFullData(val, b) {
336
+ return validatePolymorphicTypeWithFullData(val, b, this.opts.parentFieldToValidate);
337
+ }
338
+ }
339
+ function PolymorphicStringType(opts) {
340
+ let result = new PolymorphicStringField(opts);
341
+ return Object.assign(result, opts);
342
+ }
314
343
  function StringType(options) {
315
344
  let result = new StringField(options);
316
345
  const options2 = { ...options };
@@ -556,6 +585,19 @@ exports.EnumField = EnumField;
556
585
  class StringEnumField extends EnumField {
557
586
  }
558
587
  exports.StringEnumField = StringEnumField;
588
+ class PolymorphicStringEnumField extends StringEnumField {
589
+ constructor(opts) {
590
+ super(opts);
591
+ this.opts = opts;
592
+ }
593
+ validateWithFullData(val, b) {
594
+ return validatePolymorphicTypeWithFullData(val, b, this.opts.parentFieldToValidate);
595
+ }
596
+ }
597
+ function PolymorphicStringEnumType(options) {
598
+ let result = new PolymorphicStringEnumField(options);
599
+ return Object.assign(result, options);
600
+ }
559
601
  function EnumType(options) {
560
602
  let result = new StringEnumField(options);
561
603
  return Object.assign(result, options);
@@ -608,6 +650,7 @@ class ListField extends BaseField {
608
650
  constructor(field, options) {
609
651
  super();
610
652
  this.field = field;
653
+ this.options = options;
611
654
  this.validators = [];
612
655
  if (field.type.dbType === schema_1.DBType.List) {
613
656
  throw new Error(`nested lists not currently supported`);
@@ -648,11 +691,12 @@ class ListField extends BaseField {
648
691
  return result;
649
692
  }
650
693
  postgresVal(val, jsonType) {
651
- if (!jsonType) {
694
+ if (!jsonType && val === "") {
652
695
  // support empty strings in list
653
- if (val === "") {
654
- val = '"' + val + '"';
655
- }
696
+ val = '"' + val + '"';
697
+ return val;
698
+ }
699
+ if (this.options?.disableJSONStringify) {
656
700
  return val;
657
701
  }
658
702
  return JSON.stringify(val);
@@ -789,6 +833,9 @@ function IntegerEnumListType(options) {
789
833
  }
790
834
  exports.IntegerEnumListType = IntegerEnumListType;
791
835
  function UUIDListType(options) {
792
- return new ListField(UUIDType(options), options);
836
+ return new ListField(UUIDType(options), {
837
+ ...options,
838
+ disableJSONStringify: true,
839
+ });
793
840
  }
794
841
  exports.UUIDListType = UUIDListType;
@@ -217,6 +217,7 @@ export interface PolymorphicOptions {
217
217
  export interface Field extends FieldOptions {
218
218
  type: Type;
219
219
  valid?(val: any): Promise<boolean> | boolean;
220
+ validateWithFullData?(val: any, builder: Builder<any>): boolean | Promise<boolean>;
220
221
  format?(val: any, nested?: boolean): any;
221
222
  logValue(val: any): any;
222
223
  }
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.StructTypeAsList = exports.StructListType = exports.StructType = exports.StructField = void 0;
4
+ const camel_case_1 = require("camel-case");
4
5
  const field_1 = require("./field");
5
6
  const schema_1 = require("./schema");
6
- const camel_case_1 = require("camel-case");
7
7
  class StructField extends field_1.BaseField {
8
8
  constructor(options) {
9
9
  super();
@@ -26,10 +26,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const glob_1 = __importDefault(require("glob"));
27
27
  const json5_1 = __importDefault(require("json5"));
28
28
  const minimist_1 = __importDefault(require("minimist"));
29
- const graphql_1 = require("../graphql/graphql");
30
- const readline = __importStar(require("readline"));
31
29
  const path = __importStar(require("path"));
32
30
  const fs = __importStar(require("fs"));
31
+ const graphql_1 = require("../graphql/graphql");
32
+ const readline = __importStar(require("readline"));
33
33
  const imports_1 = require("../imports");
34
34
  const process_1 = require("process");
35
35
  // need to use the GQLCapture from the package so that when we call GQLCapture.enable()
@@ -3,12 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
+ const minimist_1 = __importDefault(require("minimist"));
6
7
  const transform_1 = require("../tsc/transform");
7
8
  const transform_schema_1 = require("../tsc/transform_schema");
8
9
  const transform_ent_1 = require("../tsc/transform_ent");
9
10
  const move_generated_1 = require("../tsc/move_generated");
10
11
  const transform_action_1 = require("../tsc/transform_action");
11
- const minimist_1 = __importDefault(require("minimist"));
12
12
  const ast_1 = require("../tsc/ast");
13
13
  // todo-sqlite
14
14
  // ts-node-script --swc --project ./tsconfig.json -r tsconfig-paths/register ../../ts/src/scripts/migrate_v0.1.ts --transform_schema --old_base_class BaseEntTodoSchema --new_schema_class TodoEntSchema --transform_path src/schema/patterns/base
@@ -137,7 +137,8 @@ function getFieldInfo(value) {
137
137
  for (const [k, f] of fields) {
138
138
  ret[k] = {
139
139
  dbCol: (0, schema_2.getStorageKey)(f, k),
140
- inputKey: (0, camel_case_1.camelCase)(k),
140
+ // in tests (anything using SimpleBuilder), make it be the same as the fieldName
141
+ inputKey: k,
141
142
  };
142
143
  }
143
144
  return ret;