@snowtop/ent 0.2.14 → 0.2.15

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.
@@ -17,7 +17,7 @@ export interface OrchestratorOptions<TEnt extends Ent<TViewer>, TInput extends D
17
17
  action?: Action<TEnt, Builder<TEnt, TViewer>, TViewer, TInput>;
18
18
  schema: SchemaInputType;
19
19
  editedFields(): Map<string, any> | Promise<Map<string, any>>;
20
- updateInput?: (data: TInput, operation?: WriteOperation) => void;
20
+ updateInput?: (data: TInput, operation?: WriteOperation, defaultKeys?: ReadonlySet<string>) => void;
21
21
  expressions?: Map<string, clause.Clause>;
22
22
  fieldInfo: FieldInfoMap;
23
23
  }
@@ -708,6 +708,8 @@ class Orchestrator {
708
708
  async getFieldsWithDefaultValues(builder, schemaFields, editedFields, action) {
709
709
  let data = {};
710
710
  let defaultData = {};
711
+ const defaultKeys = new Set();
712
+ const transformedFields = new Set();
711
713
  let input = action?.getInput() || {};
712
714
  let updateInput = false;
713
715
  // transformations
@@ -760,6 +762,7 @@ class Orchestrator {
760
762
  }
761
763
  data[this.getStorageKey(k)] = dbVal;
762
764
  if (!field.immutable) {
765
+ transformedFields.add(k);
763
766
  this.defaultFieldsByTSName[this.getInputKey(k)] = inputVal;
764
767
  }
765
768
  // hmm do we need this?
@@ -797,7 +800,7 @@ class Orchestrator {
797
800
  if (value !== undefined) {
798
801
  userDefinedKeys.add(dbKey);
799
802
  }
800
- if (value === undefined) {
803
+ if (value === undefined && !transformedFields.has(fieldName)) {
801
804
  if (this.actualOperation === action_1.WriteOperation.Insert) {
802
805
  if (field.defaultToViewerOnCreate && field.defaultValueOnCreate) {
803
806
  throw new Error(`cannot set both defaultToViewerOnCreate and defaultValueOnCreate`);
@@ -836,6 +839,9 @@ class Orchestrator {
836
839
  }
837
840
  this.defaultFieldsByFieldName[fieldName] = defaultValue;
838
841
  this.defaultFieldsByTSName[this.getInputKey(fieldName)] = defaultValue;
842
+ if (field.disableUserEditable || updateOnlyIfOther) {
843
+ defaultKeys.add(this.getInputKey(fieldName));
844
+ }
839
845
  }
840
846
  }
841
847
  // if there's data changing, add data
@@ -846,7 +852,7 @@ class Orchestrator {
846
852
  };
847
853
  if (updateInput && this.options.updateInput) {
848
854
  // this basically fixes #605. just needs to be exposed correctly
849
- this.options.updateInput(this.defaultFieldsByTSName, this.actualOperation);
855
+ this.options.updateInput(this.defaultFieldsByTSName, this.actualOperation, defaultKeys);
850
856
  }
851
857
  }
852
858
  return { data, userDefinedKeys };
@@ -941,6 +947,12 @@ class Orchestrator {
941
947
  for (const fieldName of needsFullDataChecks) {
942
948
  const field = schemaFields.get(fieldName);
943
949
  let value = editedFields.get(fieldName);
950
+ // Deferred defaults are absent from editedFields, but validators must
951
+ // still receive the value that will be saved when this operation writes.
952
+ if (value === undefined &&
953
+ (op === action_1.WriteOperation.Insert || this.hasData(data))) {
954
+ value = this.defaultFieldsByFieldName[fieldName];
955
+ }
944
956
  // @ts-ignore...
945
957
  // type hackery because it's hard
946
958
  const v = await field.validateWithFullData(value, this.options.builder);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.2.14",
3
+ "version": "0.2.15",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -3,26 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BaseEntSchemaWithTZ = exports.BaseEntSchema = exports.EntSchemaWithTZ = exports.EntSchema = exports.Node = exports.Timestamps = void 0;
4
4
  const uuid_1 = require("uuid");
5
5
  const field_1 = require("./field");
6
- let tsFields = {
7
- createdAt: (0, field_1.TimestampType)({
8
- hideFromGraphQL: true,
9
- disableUserEditable: true,
10
- defaultValueOnCreate: () => {
11
- return new Date();
12
- },
13
- }),
14
- updatedAt: (0, field_1.TimestampType)({
15
- hideFromGraphQL: true,
16
- disableUserEditable: true,
17
- defaultValueOnCreate: () => {
18
- return new Date();
19
- },
20
- onlyUpdateIfOtherFieldsBeingSet_BETA: true,
21
- defaultValueOnEdit: () => {
22
- return new Date();
23
- },
24
- }),
25
- };
6
+ function timestampFields(withTimezone) {
7
+ return {
8
+ createdAt: (0, field_1.TimestampType)({
9
+ withTimezone,
10
+ hideFromGraphQL: true,
11
+ disableUserEditable: true,
12
+ defaultValueOnCreate: () => {
13
+ return new Date();
14
+ },
15
+ }),
16
+ updatedAt: (0, field_1.TimestampType)({
17
+ withTimezone,
18
+ hideFromGraphQL: true,
19
+ disableUserEditable: true,
20
+ defaultValueOnCreate: () => {
21
+ return new Date();
22
+ },
23
+ onlyUpdateIfOtherFieldsBeingSet_BETA: true,
24
+ defaultValueOnEdit: () => {
25
+ return new Date();
26
+ },
27
+ }),
28
+ };
29
+ }
30
+ let tsFields = timestampFields(false);
26
31
  // Timestamps is a Pattern that adds a createdAt and updatedAt timestamp fields to the ent
27
32
  exports.Timestamps = {
28
33
  name: "timestamps",
@@ -43,25 +48,7 @@ let nodeFields = {
43
48
  let nodeFieldsWithTZ = {
44
49
  // inconsistent naming :(
45
50
  id: nodeField,
46
- createdAt: (0, field_1.TimestampType)({
47
- hideFromGraphQL: true,
48
- disableUserEditable: true,
49
- defaultValueOnCreate: () => {
50
- return new Date();
51
- },
52
- withTimezone: true,
53
- }),
54
- updatedAt: (0, field_1.TimestampType)({
55
- hideFromGraphQL: true,
56
- disableUserEditable: true,
57
- defaultValueOnCreate: () => {
58
- return new Date();
59
- },
60
- defaultValueOnEdit: () => {
61
- return new Date();
62
- },
63
- withTimezone: true,
64
- }),
51
+ ...timestampFields(true),
65
52
  };
66
53
  // Node is a Pattern that adds 3 fields to the ent: (id, createdAt, and updatedAt timestamps)
67
54
  exports.Node = {
@@ -81,6 +81,7 @@ export declare class SimpleBuilder<T extends Ent, TExistingEnt extends TMaybleNu
81
81
  placeholderID: ID;
82
82
  orchestrator: Orchestrator<T, Data, Viewer, TExistingEnt>;
83
83
  fields: Map<string, any>;
84
+ private defaultInput;
84
85
  nodeType: string;
85
86
  m: Map<string, any>;
86
87
  constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation: WriteOperation | undefined, existingEnt: TExistingEnt, action?: Action<T, SimpleBuilder<T, TExistingEnt>, Viewer, Data, TExistingEnt> | undefined, expressions?: Map<string, Clause>);
@@ -191,6 +191,7 @@ class SimpleBuilder {
191
191
  this.schema = schema;
192
192
  this.operation = operation;
193
193
  this.existingEnt = existingEnt;
194
+ this.defaultInput = new Map();
194
195
  this.m = new Map();
195
196
  // create dynamic placeholder
196
197
  // TODO: do we need to use this as the node when there's an existingEnt
@@ -247,11 +248,18 @@ class SimpleBuilder {
247
248
  // to simulate what we do in generated builders where we return a new Map
248
249
  const m = new Map();
249
250
  for (const [k, v] of this.fields) {
250
- m.set(k, v);
251
+ if (!this.defaultInput.has(k) || this.defaultInput.get(k) !== v) {
252
+ m.set(k, v);
253
+ }
251
254
  }
252
255
  return m;
253
256
  },
254
- updateInput: this.updateInput.bind(this),
257
+ updateInput: (input, _operation, defaultKeys) => {
258
+ this.updateInput(input);
259
+ for (const key of defaultKeys ?? []) {
260
+ this.defaultInput.set(key, input[key]);
261
+ }
262
+ },
255
263
  });
256
264
  }
257
265
  getInput() {
@@ -264,6 +272,7 @@ class SimpleBuilder {
264
272
  updateInput(input) {
265
273
  const knownFields = (0, schema_1.getFields)(this.schema);
266
274
  for (const k in input) {
275
+ this.defaultInput.delete(k);
267
276
  if (knownFields.has(k)) {
268
277
  this.fields.set(k, input[k]);
269
278
  }