@snowtop/ent 0.1.0-alpha15 → 0.1.0-alpha151

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.
Files changed (171) hide show
  1. package/action/action.d.ts +27 -16
  2. package/action/action.js +22 -7
  3. package/action/executor.d.ts +16 -3
  4. package/action/executor.js +90 -23
  5. package/action/experimental_action.d.ts +25 -16
  6. package/action/experimental_action.js +35 -9
  7. package/action/index.d.ts +3 -1
  8. package/action/index.js +7 -1
  9. package/action/operations.d.ts +125 -0
  10. package/action/operations.js +684 -0
  11. package/action/orchestrator.d.ts +38 -12
  12. package/action/orchestrator.js +427 -102
  13. package/action/relative_value.d.ts +47 -0
  14. package/action/relative_value.js +125 -0
  15. package/action/transaction.d.ts +10 -0
  16. package/action/transaction.js +23 -0
  17. package/auth/auth.d.ts +1 -1
  18. package/core/base.d.ts +52 -21
  19. package/core/base.js +7 -1
  20. package/core/clause.d.ts +95 -40
  21. package/core/clause.js +395 -64
  22. package/core/config.d.ts +15 -1
  23. package/core/config.js +10 -1
  24. package/core/const.d.ts +3 -0
  25. package/core/const.js +6 -0
  26. package/core/context.d.ts +4 -2
  27. package/core/context.js +20 -2
  28. package/core/convert.d.ts +1 -1
  29. package/core/date.js +1 -5
  30. package/core/db.d.ts +12 -8
  31. package/core/db.js +18 -8
  32. package/core/ent.d.ts +68 -94
  33. package/core/ent.js +538 -587
  34. package/core/global_schema.d.ts +7 -0
  35. package/core/global_schema.js +51 -0
  36. package/core/loaders/assoc_count_loader.d.ts +1 -0
  37. package/core/loaders/assoc_count_loader.js +10 -2
  38. package/core/loaders/assoc_edge_loader.d.ts +1 -1
  39. package/core/loaders/assoc_edge_loader.js +10 -13
  40. package/core/loaders/index.d.ts +1 -1
  41. package/core/loaders/index.js +1 -3
  42. package/core/loaders/index_loader.d.ts +3 -3
  43. package/core/loaders/loader.d.ts +2 -2
  44. package/core/loaders/loader.js +5 -5
  45. package/core/loaders/object_loader.d.ts +30 -9
  46. package/core/loaders/object_loader.js +225 -78
  47. package/core/loaders/query_loader.d.ts +6 -12
  48. package/core/loaders/query_loader.js +54 -13
  49. package/core/loaders/raw_count_loader.d.ts +1 -0
  50. package/core/loaders/raw_count_loader.js +7 -2
  51. package/core/logger.d.ts +1 -1
  52. package/core/logger.js +1 -0
  53. package/core/privacy.d.ts +7 -6
  54. package/core/privacy.js +21 -25
  55. package/core/query/assoc_query.d.ts +3 -2
  56. package/core/query/assoc_query.js +9 -1
  57. package/core/query/custom_clause_query.d.ts +27 -0
  58. package/core/query/custom_clause_query.js +88 -0
  59. package/core/query/custom_query.d.ts +17 -2
  60. package/core/query/custom_query.js +88 -13
  61. package/core/query/index.d.ts +1 -0
  62. package/core/query/index.js +3 -1
  63. package/core/query/query.d.ts +15 -3
  64. package/core/query/query.js +128 -53
  65. package/core/query/shared_assoc_test.d.ts +2 -1
  66. package/core/query/shared_assoc_test.js +44 -54
  67. package/core/query/shared_test.d.ts +8 -1
  68. package/core/query/shared_test.js +532 -236
  69. package/core/viewer.d.ts +2 -0
  70. package/core/viewer.js +3 -1
  71. package/graphql/graphql.d.ts +52 -19
  72. package/graphql/graphql.js +174 -136
  73. package/graphql/graphql_field_helpers.d.ts +7 -1
  74. package/graphql/graphql_field_helpers.js +21 -1
  75. package/graphql/index.d.ts +2 -2
  76. package/graphql/index.js +3 -5
  77. package/graphql/query/connection_type.d.ts +9 -9
  78. package/graphql/query/shared_assoc_test.js +1 -1
  79. package/graphql/query/shared_edge_connection.js +1 -19
  80. package/graphql/scalars/orderby_direction.d.ts +2 -0
  81. package/graphql/scalars/orderby_direction.js +15 -0
  82. package/imports/dataz/example1/_auth.js +128 -47
  83. package/imports/dataz/example1/_viewer.js +87 -39
  84. package/imports/index.d.ts +7 -2
  85. package/imports/index.js +20 -5
  86. package/index.d.ts +18 -5
  87. package/index.js +30 -10
  88. package/package.json +18 -17
  89. package/parse_schema/parse.d.ts +31 -9
  90. package/parse_schema/parse.js +179 -32
  91. package/schema/base_schema.d.ts +13 -3
  92. package/schema/base_schema.js +13 -0
  93. package/schema/field.d.ts +78 -21
  94. package/schema/field.js +231 -71
  95. package/schema/index.d.ts +2 -2
  96. package/schema/index.js +7 -2
  97. package/schema/json_field.d.ts +16 -4
  98. package/schema/json_field.js +32 -2
  99. package/schema/schema.d.ts +109 -20
  100. package/schema/schema.js +42 -53
  101. package/schema/struct_field.d.ts +15 -3
  102. package/schema/struct_field.js +117 -22
  103. package/schema/union_field.d.ts +1 -1
  104. package/scripts/custom_compiler.js +12 -8
  105. package/scripts/custom_graphql.js +145 -34
  106. package/scripts/migrate_v0.1.js +36 -0
  107. package/scripts/move_types.js +120 -0
  108. package/scripts/read_schema.js +22 -7
  109. package/testutils/action/complex_schemas.d.ts +69 -0
  110. package/testutils/action/complex_schemas.js +405 -0
  111. package/testutils/builder.d.ts +39 -43
  112. package/testutils/builder.js +75 -49
  113. package/testutils/db/fixture.d.ts +10 -0
  114. package/testutils/db/fixture.js +26 -0
  115. package/testutils/db/{test_db.d.ts → temp_db.d.ts} +32 -8
  116. package/testutils/db/{test_db.js → temp_db.js} +244 -48
  117. package/testutils/db/value.d.ts +7 -0
  118. package/testutils/db/value.js +251 -0
  119. package/testutils/db_mock.d.ts +16 -4
  120. package/testutils/db_mock.js +52 -9
  121. package/testutils/db_time_zone.d.ts +4 -0
  122. package/testutils/db_time_zone.js +41 -0
  123. package/testutils/ent-graphql-tests/index.d.ts +7 -1
  124. package/testutils/ent-graphql-tests/index.js +56 -26
  125. package/testutils/fake_comms.js +1 -1
  126. package/testutils/fake_data/const.d.ts +2 -1
  127. package/testutils/fake_data/const.js +3 -0
  128. package/testutils/fake_data/fake_contact.d.ts +7 -3
  129. package/testutils/fake_data/fake_contact.js +13 -7
  130. package/testutils/fake_data/fake_event.d.ts +4 -1
  131. package/testutils/fake_data/fake_event.js +7 -6
  132. package/testutils/fake_data/fake_tag.d.ts +36 -0
  133. package/testutils/fake_data/fake_tag.js +89 -0
  134. package/testutils/fake_data/fake_user.d.ts +8 -5
  135. package/testutils/fake_data/fake_user.js +16 -15
  136. package/testutils/fake_data/index.js +5 -1
  137. package/testutils/fake_data/internal.d.ts +2 -0
  138. package/testutils/fake_data/internal.js +7 -1
  139. package/testutils/fake_data/tag_query.d.ts +13 -0
  140. package/testutils/fake_data/tag_query.js +43 -0
  141. package/testutils/fake_data/test_helpers.d.ts +11 -4
  142. package/testutils/fake_data/test_helpers.js +29 -13
  143. package/testutils/fake_data/user_query.d.ts +11 -4
  144. package/testutils/fake_data/user_query.js +54 -22
  145. package/testutils/fake_log.js +1 -1
  146. package/testutils/parse_sql.d.ts +6 -0
  147. package/testutils/parse_sql.js +16 -2
  148. package/testutils/test_edge_global_schema.d.ts +15 -0
  149. package/testutils/test_edge_global_schema.js +62 -0
  150. package/testutils/write.d.ts +2 -2
  151. package/testutils/write.js +33 -7
  152. package/tsc/ast.d.ts +25 -2
  153. package/tsc/ast.js +141 -17
  154. package/tsc/compilerOptions.js +5 -1
  155. package/tsc/move_generated.d.ts +1 -0
  156. package/tsc/move_generated.js +164 -0
  157. package/tsc/transform.d.ts +22 -0
  158. package/tsc/transform.js +182 -0
  159. package/tsc/transform_action.d.ts +22 -0
  160. package/tsc/transform_action.js +183 -0
  161. package/tsc/transform_ent.d.ts +17 -0
  162. package/tsc/transform_ent.js +60 -0
  163. package/tsc/transform_schema.d.ts +27 -0
  164. package/{scripts → tsc}/transform_schema.js +146 -117
  165. package/graphql/enums.d.ts +0 -3
  166. package/graphql/enums.js +0 -25
  167. package/scripts/move_generated.js +0 -142
  168. package/scripts/transform_code.js +0 -113
  169. package/scripts/transform_schema.d.ts +0 -1
  170. /package/scripts/{move_generated.d.ts → migrate_v0.1.d.ts} +0 -0
  171. /package/scripts/{transform_code.d.ts → move_types.d.ts} +0 -0
@@ -1,4 +1,27 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
2
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
27
  };
@@ -6,11 +29,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
29
  exports.EntChangeset = exports.Orchestrator = exports.edgeDirection = void 0;
7
30
  const ent_1 = require("../core/ent");
8
31
  const schema_1 = require("../schema/schema");
32
+ const operations_1 = require("./operations");
9
33
  const action_1 = require("../action");
10
34
  const privacy_1 = require("../core/privacy");
11
35
  const executor_1 = require("./executor");
12
36
  const logger_1 = require("../core/logger");
13
37
  const memoizee_1 = __importDefault(require("memoizee"));
38
+ const clause = __importStar(require("../core/clause"));
39
+ const util_1 = require("util");
40
+ const operations_2 = require("./operations");
14
41
  var edgeDirection;
15
42
  (function (edgeDirection) {
16
43
  edgeDirection[edgeDirection["inboundEdge"] = 0] = "inboundEdge";
@@ -24,31 +51,38 @@ class edgeInputData {
24
51
  return id.placeholderID !== undefined;
25
52
  }
26
53
  }
27
- function getViewer(action) {
28
- if (!action.viewer.viewerID) {
54
+ function getViewer(viewer) {
55
+ if (!viewer.viewerID) {
29
56
  return "Logged out Viewer";
30
57
  }
31
58
  else {
32
- return `Viewer with ID ${action.viewer.viewerID}`;
59
+ return `Viewer with ID ${viewer.viewerID}`;
33
60
  }
34
61
  }
35
62
  class EntCannotCreateEntError extends Error {
36
63
  constructor(privacyPolicy, action) {
37
- let msg = `${getViewer(action)} does not have permission to create ${action.builder.ent.name}`;
64
+ let msg = `${getViewer(action.viewer)} does not have permission to create ${action.builder.ent.name}`;
38
65
  super(msg);
39
66
  this.privacyPolicy = privacyPolicy;
40
67
  }
41
68
  }
42
69
  class EntCannotEditEntError extends Error {
43
70
  constructor(privacyPolicy, action, ent) {
44
- let msg = `${getViewer(action)} does not have permission to edit ${ent.constructor.name}`;
71
+ let msg = `${getViewer(action.viewer)} does not have permission to edit ${ent.constructor.name}`;
72
+ super(msg);
73
+ this.privacyPolicy = privacyPolicy;
74
+ }
75
+ }
76
+ class EntCannotEditEntFieldError extends Error {
77
+ constructor(privacyPolicy, viewer, field, ent) {
78
+ let msg = `${getViewer(viewer)} does not have permission to edit field ${field} in ${ent.constructor.name}`;
45
79
  super(msg);
46
80
  this.privacyPolicy = privacyPolicy;
47
81
  }
48
82
  }
49
83
  class EntCannotDeleteEntError extends Error {
50
84
  constructor(privacyPolicy, action, ent) {
51
- let msg = `${getViewer(action)} does not have permission to delete ${ent.constructor.name}`;
85
+ let msg = `${getViewer(action.viewer)} does not have permission to delete ${ent.constructor.name}`;
52
86
  super(msg);
53
87
  this.privacyPolicy = privacyPolicy;
54
88
  }
@@ -58,6 +92,7 @@ class Orchestrator {
58
92
  this.options = options;
59
93
  this.edgeSet = new Set();
60
94
  this.edges = new Map();
95
+ this.conditionalEdges = new Map();
61
96
  this.changesets = [];
62
97
  this.dependencies = new Map();
63
98
  this.fieldsToResolve = [];
@@ -68,7 +103,11 @@ class Orchestrator {
68
103
  this.existingEnt = this.options.builder.existingEnt;
69
104
  this.memoizedGetFields = (0, memoizee_1.default)(this.getFieldsInfo.bind(this));
70
105
  }
71
- addEdge(edge, op) {
106
+ // don't type this because we don't care
107
+ __getOptions() {
108
+ return this.options;
109
+ }
110
+ addEdge(edge, op, conditional) {
72
111
  this.edgeSet.add(edge.edgeType);
73
112
  let m1 = this.edges.get(edge.edgeType) || new Map();
74
113
  let m2 = m1.get(op) || new Map();
@@ -83,11 +122,22 @@ class Orchestrator {
83
122
  // set or overwrite the new edge data for said id
84
123
  m2.set(id, edge);
85
124
  m1.set(op, m2);
86
- this.edges.set(edge.edgeType, m1);
125
+ if (conditional && this.onConflict) {
126
+ this.conditionalEdges.set(edge.edgeType, m1);
127
+ }
128
+ else {
129
+ this.edges.set(edge.edgeType, m1);
130
+ }
87
131
  }
88
132
  setDisableTransformations(val) {
89
133
  this.disableTransformations = val;
90
134
  }
135
+ setOnConflictOptions(onConflict) {
136
+ if (onConflict?.onConflictConstraint && !onConflict.updateCols) {
137
+ throw new Error(`cannot set onConflictConstraint without updateCols`);
138
+ }
139
+ this.onConflict = onConflict;
140
+ }
91
141
  addInboundEdge(id1, edgeType, nodeType, options) {
92
142
  this.addEdge(new edgeInputData({
93
143
  id: id1,
@@ -95,7 +145,7 @@ class Orchestrator {
95
145
  nodeType,
96
146
  options,
97
147
  direction: edgeDirection.inboundEdge,
98
- }), action_1.WriteOperation.Insert);
148
+ }), action_1.WriteOperation.Insert, options?.conditional);
99
149
  }
100
150
  addOutboundEdge(id2, edgeType, nodeType, options) {
101
151
  this.addEdge(new edgeInputData({
@@ -104,21 +154,21 @@ class Orchestrator {
104
154
  nodeType,
105
155
  options,
106
156
  direction: edgeDirection.outboundEdge,
107
- }), action_1.WriteOperation.Insert);
157
+ }), action_1.WriteOperation.Insert, options?.conditional);
108
158
  }
109
- removeInboundEdge(id1, edgeType) {
159
+ removeInboundEdge(id1, edgeType, options) {
110
160
  this.addEdge(new edgeInputData({
111
161
  id: id1,
112
162
  edgeType,
113
163
  direction: edgeDirection.inboundEdge,
114
- }), action_1.WriteOperation.Delete);
164
+ }), action_1.WriteOperation.Delete, options?.conditional);
115
165
  }
116
- removeOutboundEdge(id2, edgeType) {
166
+ removeOutboundEdge(id2, edgeType, options) {
117
167
  this.addEdge(new edgeInputData({
118
168
  id: id2,
119
169
  edgeType,
120
170
  direction: edgeDirection.outboundEdge,
121
- }), action_1.WriteOperation.Delete);
171
+ }), action_1.WriteOperation.Delete, options?.conditional);
122
172
  }
123
173
  // this doesn't take a direction as that's an implementation detail
124
174
  // it doesn't make any sense to use the same edgeType for inbound and outbound edges
@@ -141,29 +191,39 @@ class Orchestrator {
141
191
  m.clear();
142
192
  }
143
193
  }
144
- buildMainOp() {
194
+ buildMainOp(conditionalBuilder) {
145
195
  // this assumes we have validated fields
146
196
  switch (this.actualOperation) {
147
197
  case action_1.WriteOperation.Delete:
148
- return new ent_1.DeleteNodeOperation(this.existingEnt.id, {
198
+ return new operations_1.DeleteNodeOperation(this.existingEnt.id, this.options.builder, {
149
199
  tableName: this.options.tableName,
150
200
  });
151
201
  default:
152
202
  if (this.actualOperation === action_1.WriteOperation.Edit && !this.existingEnt) {
153
203
  throw new Error(`existing ent required with operation ${this.actualOperation}`);
154
204
  }
205
+ if (this.options.expressions &&
206
+ this.actualOperation !== action_1.WriteOperation.Edit) {
207
+ throw new Error(`expressions are only supported in edit operations for now`);
208
+ }
155
209
  const opts = {
156
210
  fields: this.validatedFields,
157
211
  tableName: this.options.tableName,
158
212
  fieldsToResolve: this.fieldsToResolve,
159
213
  key: this.options.key,
160
214
  loadEntOptions: this.options.loaderOptions,
161
- placeholderID: this.options.builder.placeholderID,
215
+ whereClause: clause.Eq(this.options.key, this.existingEnt?.id),
216
+ expressions: this.options.expressions,
217
+ onConflict: this.onConflict,
218
+ builder: this.options.builder,
162
219
  };
163
220
  if (this.logValues) {
164
221
  opts.fieldsToLog = this.logValues;
165
222
  }
166
- this.mainOp = new ent_1.EditNodeOperation(opts, this.existingEnt);
223
+ this.mainOp = new operations_1.EditNodeOperation(opts, this.existingEnt);
224
+ if (conditionalBuilder) {
225
+ this.mainOp = new operations_1.ConditionalNodeOperation(this.mainOp, conditionalBuilder);
226
+ }
167
227
  return this.mainOp;
168
228
  }
169
229
  }
@@ -183,10 +243,10 @@ class Orchestrator {
183
243
  throw new Error(`no nodeType for edge when adding outboundEdge`);
184
244
  }
185
245
  if (edge.direction === edgeDirection.outboundEdge) {
186
- return ent_1.EdgeOperation.outboundEdge(this.options.builder, edgeType, edge.id, edge.nodeType, edge.options);
246
+ return operations_1.EdgeOperation.outboundEdge(this.options.builder, edgeType, edge.id, edge.nodeType, edge.options);
187
247
  }
188
248
  else {
189
- return ent_1.EdgeOperation.inboundEdge(this.options.builder, edgeType, edge.id, edge.nodeType, edge.options);
249
+ return operations_1.EdgeOperation.inboundEdge(this.options.builder, edgeType, edge.id, edge.nodeType, edge.options);
190
250
  }
191
251
  }
192
252
  else if (op === action_1.WriteOperation.Delete) {
@@ -195,30 +255,53 @@ class Orchestrator {
195
255
  }
196
256
  let id2 = edge.id;
197
257
  if (edge.direction === edgeDirection.outboundEdge) {
198
- return ent_1.EdgeOperation.removeOutboundEdge(this.options.builder, edgeType, id2);
258
+ return operations_1.EdgeOperation.removeOutboundEdge(this.options.builder, edgeType, id2);
199
259
  }
200
260
  else {
201
- return ent_1.EdgeOperation.removeInboundEdge(this.options.builder, edgeType, id2);
261
+ return operations_1.EdgeOperation.removeInboundEdge(this.options.builder, edgeType, id2);
202
262
  }
203
263
  }
204
264
  throw new Error("could not find an edge operation from the given parameters");
205
265
  }
206
- async buildEdgeOps(ops) {
266
+ async buildEdgeOps(ops, conditionalBuilder, conditionalOverride) {
207
267
  const edgeDatas = await (0, ent_1.loadEdgeDatas)(...Array.from(this.edgeSet.values()));
208
- for (const [edgeType, m] of this.edges) {
209
- for (const [op, m2] of m) {
210
- for (const [_, edge] of m2) {
211
- let edgeOp = this.getEdgeOperation(edgeType, op, edge);
212
- ops.push(edgeOp);
213
- const edgeData = edgeDatas.get(edgeType);
214
- if (!edgeData) {
215
- throw new Error(`could not load edge data for ${edgeType}`);
216
- }
217
- if (edgeData.symmetricEdge) {
218
- ops.push(edgeOp.symmetricEdge());
219
- }
220
- if (edgeData.inverseEdgeType) {
221
- ops.push(edgeOp.inverseEdge(edgeData));
268
+ const edges = [
269
+ [this.edges, false],
270
+ [this.conditionalEdges, true],
271
+ ];
272
+ // conditional should only apply if onconflict...
273
+ // if no upsert and just create, nothing to do here
274
+ for (const edgeInfo of edges) {
275
+ const [edges, conditionalEdge] = edgeInfo;
276
+ const conditional = conditionalOverride || conditionalEdge;
277
+ for (const [edgeType, m] of edges) {
278
+ for (const [op, m2] of m) {
279
+ for (const [_, edge] of m2) {
280
+ let edgeOp = this.getEdgeOperation(edgeType, op, edge);
281
+ if (conditional) {
282
+ ops.push(new operations_1.ConditionalOperation(edgeOp, conditionalBuilder));
283
+ }
284
+ else {
285
+ ops.push(edgeOp);
286
+ }
287
+ const edgeData = edgeDatas.get(edgeType);
288
+ if (!edgeData) {
289
+ throw new Error(`could not load edge data for '${edgeType}'`);
290
+ }
291
+ if (edgeData.symmetricEdge) {
292
+ let symmetric = edgeOp.symmetricEdge();
293
+ if (conditional) {
294
+ symmetric = new operations_1.ConditionalOperation(symmetric, conditionalBuilder);
295
+ }
296
+ ops.push(symmetric);
297
+ }
298
+ if (edgeData.inverseEdgeType) {
299
+ let inverse = edgeOp.inverseEdge(edgeData);
300
+ if (conditional) {
301
+ inverse = new operations_1.ConditionalOperation(inverse, conditionalBuilder);
302
+ }
303
+ ops.push(inverse);
304
+ }
222
305
  }
223
306
  }
224
307
  }
@@ -238,12 +321,50 @@ class Orchestrator {
238
321
  }
239
322
  return new EntCannotDeleteEntError(privacyPolicy, action, this.existingEnt);
240
323
  }
241
- getEntForPrivacyPolicyImpl(editedData) {
324
+ async getRowForPrivacyPolicyImpl(schemaFields, editedData) {
325
+ // need to format fields if possible because ent constructors expect data that's
326
+ // in the format that's coming from the db
327
+ // required for object fields...
328
+ const formatted = { ...editedData };
329
+ for (const [fieldName, field] of schemaFields) {
330
+ if (!field.format) {
331
+ continue;
332
+ }
333
+ let dbKey = this.getStorageKey(fieldName);
334
+ let val = formatted[dbKey];
335
+ if (!val) {
336
+ continue;
337
+ }
338
+ if (field.valid) {
339
+ let valid = field.valid(val);
340
+ if (util_1.types.isPromise(valid)) {
341
+ valid = await valid;
342
+ }
343
+ // if not valid, don't format and don't pass to ent?
344
+ // or just early throw here
345
+ if (!valid) {
346
+ continue;
347
+ // throw new Error(`invalid field ${fieldName} with value ${val}`);
348
+ }
349
+ }
350
+ // nested so it's not JSON stringified or anything like that
351
+ val = field.format(formatted[dbKey], true);
352
+ if (util_1.types.isPromise(val)) {
353
+ val = await val;
354
+ }
355
+ formatted[dbKey] = val;
356
+ }
357
+ return formatted;
358
+ }
359
+ async getEntForPrivacyPolicyImpl(schemaFields, editedData, viewerToUse, rowToUse) {
242
360
  if (this.actualOperation !== action_1.WriteOperation.Insert) {
243
361
  return this.existingEnt;
244
362
  }
363
+ if (!rowToUse) {
364
+ rowToUse = await this.getRowForPrivacyPolicyImpl(schemaFields, editedData);
365
+ }
245
366
  // we create an unsafe ent to be used for privacy policies
246
- return new this.options.builder.ent(this.options.builder.viewer, editedData);
367
+ return new this.options.builder.ent(viewerToUse, rowToUse);
247
368
  }
248
369
  getSQLStatementOperation() {
249
370
  switch (this.actualOperation) {
@@ -273,8 +394,8 @@ class Orchestrator {
273
394
  if (this.actualOperation !== action_1.WriteOperation.Insert) {
274
395
  return this.existingEnt;
275
396
  }
276
- const { editedData } = await this.memoizedGetFields();
277
- return this.getEntForPrivacyPolicyImpl(editedData);
397
+ const { schemaFields, editedData } = await this.memoizedGetFields();
398
+ return this.getEntForPrivacyPolicyImpl(schemaFields, editedData, this.options.viewer);
278
399
  }
279
400
  // this gets the fields that were explicitly set plus any default or transformed values
280
401
  // mainly exists to get default fields e.g. default id to be used in triggers
@@ -284,15 +405,41 @@ class Orchestrator {
284
405
  const { editedData } = await this.memoizedGetFields();
285
406
  return editedData;
286
407
  }
408
+ /**
409
+ * @returns validated and formatted fields that would be written to the db
410
+ * throws an error if called before valid() or validX() has been called
411
+ */
412
+ getValidatedFields() {
413
+ if (this.validatedFields === null) {
414
+ throw new Error(`trying to call getValidatedFields before validating fields`);
415
+ }
416
+ return this.validatedFields;
417
+ }
287
418
  // Note: this is memoized. call memoizedGetFields instead
288
419
  async getFieldsInfo() {
289
420
  const action = this.options.action;
290
421
  const builder = this.options.builder;
291
422
  // future optimization: can get schemaFields to memoize based on different values
292
423
  const schemaFields = (0, schema_1.getFields)(this.options.schema);
424
+ // also future optimization, no need to go through the list of fields multiple times
425
+ let editPrivacyFields = new Map();
426
+ switch (this.actualOperation) {
427
+ case action_1.WriteOperation.Edit:
428
+ editPrivacyFields = (0, schema_1.getFieldsWithEditPrivacy)(this.options.schema, this.options.fieldInfo);
429
+ break;
430
+ case action_1.WriteOperation.Insert:
431
+ editPrivacyFields = (0, schema_1.getFieldsForCreateAction)(this.options.schema, this.options.fieldInfo);
432
+ break;
433
+ }
293
434
  const editedFields = await this.options.editedFields();
294
- let editedData = await this.getFieldsWithDefaultValues(builder, schemaFields, editedFields, action);
295
- return { editedData, editedFields, schemaFields };
435
+ let { data: editedData, userDefinedKeys } = await this.getFieldsWithDefaultValues(builder, schemaFields, editedFields, action);
436
+ return {
437
+ editedData,
438
+ editedFields,
439
+ schemaFields,
440
+ userDefinedKeys,
441
+ editPrivacyFields,
442
+ };
296
443
  }
297
444
  async validate() {
298
445
  // existing ent required for edit or delete operations
@@ -303,7 +450,7 @@ class Orchestrator {
303
450
  throw new Error(`existing ent required with operation ${this.actualOperation}`);
304
451
  }
305
452
  }
306
- const { schemaFields, editedData } = await this.memoizedGetFields();
453
+ const { schemaFields, editedData, userDefinedKeys, editPrivacyFields } = await this.memoizedGetFields();
307
454
  const action = this.options.action;
308
455
  const builder = this.options.builder;
309
456
  // this runs in following phases:
@@ -312,51 +459,117 @@ class Orchestrator {
312
459
  // * triggers
313
460
  // * validators
314
461
  let privacyPolicy = action?.getPrivacyPolicy();
462
+ const errors = [];
315
463
  if (privacyPolicy) {
316
- await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, this.getEntForPrivacyPolicyImpl(editedData), this.throwError.bind(this));
464
+ const ent = await this.getEntForPrivacyPolicyImpl(schemaFields, editedData, this.options.viewer);
465
+ try {
466
+ await (0, privacy_1.applyPrivacyPolicyX)(this.options.viewer, privacyPolicy, ent, () => this.throwError());
467
+ }
468
+ catch (err) {
469
+ errors.push(err);
470
+ }
471
+ }
472
+ // we have edit privacy fields, so we need to apply privacy policy on those
473
+ const promises = [];
474
+ if (editPrivacyFields.size) {
475
+ // get row based on edited data
476
+ const row = await this.getRowForPrivacyPolicyImpl(schemaFields, editedData);
477
+ // get viewer for ent load based on formatted row
478
+ const viewer = await this.viewerForEntLoad(row);
479
+ const ent = await this.getEntForPrivacyPolicyImpl(schemaFields, editedData, viewer, row);
480
+ for (const [k, policy] of editPrivacyFields) {
481
+ if (editedData[k] === undefined || !userDefinedKeys.has(k)) {
482
+ continue;
483
+ }
484
+ promises.push((async () => {
485
+ const r = await (0, privacy_1.applyPrivacyPolicy)(viewer, policy, ent);
486
+ if (!r) {
487
+ errors.push(new EntCannotEditEntFieldError(policy, viewer, k, ent));
488
+ }
489
+ })());
490
+ }
491
+ await Promise.all(promises);
492
+ }
493
+ // privacy or field errors should return first so it's less confusing
494
+ if (errors.length) {
495
+ return errors;
317
496
  }
318
497
  // have to run triggers which update fields first before field and other validators
319
498
  // so running this first to build things up
320
- let triggers = action?.triggers;
321
- if (triggers) {
322
- await this.triggers(action, builder, triggers);
499
+ if (action?.getTriggers) {
500
+ await this.triggers(action, builder, action.getTriggers());
501
+ }
502
+ let validators = [];
503
+ if (action?.getValidators) {
504
+ validators = action.getValidators();
323
505
  }
324
- let validators = action?.validators || [];
325
506
  // not ideal we're calling this twice. fix...
326
507
  // needed for now. may need to rewrite some of this?
327
508
  const editedFields2 = await this.options.editedFields();
328
- await Promise.all([
509
+ const [errs2, errs3] = await Promise.all([
329
510
  this.formatAndValidateFields(schemaFields, editedFields2),
330
511
  this.validators(validators, action, builder),
331
512
  ]);
513
+ errors.push(...errs2);
514
+ errors.push(...errs3);
515
+ return errors;
332
516
  }
333
517
  async triggers(action, builder, triggers) {
334
- await Promise.all(triggers.map(async (trigger) => {
335
- let ret = await trigger.changeset(builder, action.getInput());
336
- if (Array.isArray(ret)) {
337
- ret = await Promise.all(ret);
338
- }
339
- if (Array.isArray(ret)) {
340
- for (const v of ret) {
341
- if (typeof v === "object") {
342
- this.changesets.push(v);
343
- }
518
+ let groups = [];
519
+ let lastArray = 0;
520
+ let prevWasArray = false;
521
+ for (let i = 0; i < triggers.length; i++) {
522
+ let t = triggers[i];
523
+ if (Array.isArray(t)) {
524
+ if (!prevWasArray) {
525
+ // @ts-ignore
526
+ groups.push(triggers.slice(lastArray, i));
344
527
  }
528
+ groups.push(t);
529
+ prevWasArray = true;
530
+ lastArray++;
345
531
  }
346
- else if (ret) {
347
- this.changesets.push(ret);
532
+ else {
533
+ if (i === triggers.length - 1) {
534
+ // @ts-ignore
535
+ groups.push(triggers.slice(lastArray, i + 1));
536
+ }
537
+ prevWasArray = false;
348
538
  }
349
- }));
539
+ }
540
+ for (const triggers of groups) {
541
+ await Promise.all(triggers.map(async (trigger) => {
542
+ let ret = await trigger.changeset(builder, action.getInput());
543
+ if (Array.isArray(ret)) {
544
+ ret = await Promise.all(ret);
545
+ }
546
+ if (Array.isArray(ret)) {
547
+ for (const v of ret) {
548
+ if (typeof v === "object") {
549
+ this.changesets.push(v);
550
+ }
551
+ }
552
+ }
553
+ else if (ret) {
554
+ this.changesets.push(ret);
555
+ }
556
+ }));
557
+ }
350
558
  }
351
559
  async validators(validators, action, builder) {
352
- let promises = [];
353
- validators.forEach((validator) => {
354
- let res = validator.validate(builder, action.getInput());
355
- if (res) {
356
- promises.push(res);
560
+ const errors = [];
561
+ await Promise.all(validators.map(async (v) => {
562
+ try {
563
+ const r = await v.validate(builder, action.getInput());
564
+ if (r instanceof Error) {
565
+ errors.push(r);
566
+ }
357
567
  }
358
- });
359
- await Promise.all(promises);
568
+ catch (err) {
569
+ errors.push(err);
570
+ }
571
+ }));
572
+ return errors;
360
573
  }
361
574
  isBuilder(val) {
362
575
  return val.placeholderID !== undefined;
@@ -377,23 +590,31 @@ class Orchestrator {
377
590
  // if disable transformations set, don't do schema transform and just do the right thing
378
591
  // else apply schema tranformation if it exists
379
592
  let transformed = null;
593
+ const sqlOp = this.getSQLStatementOperation();
594
+ // why is transform write technically different from upsert?
595
+ // it's create -> update just at the db level...
380
596
  if (action?.transformWrite) {
381
597
  transformed = await action.transformWrite({
382
- viewer: builder.viewer,
383
- op: this.getSQLStatementOperation(),
598
+ builder,
599
+ input,
600
+ op: sqlOp,
384
601
  data: editedFields,
385
- existingEnt: this.existingEnt,
386
602
  });
387
603
  }
388
604
  else if (!this.disableTransformations) {
389
605
  transformed = (0, schema_1.getTransformedUpdateOp)(this.options.schema, {
390
- viewer: builder.viewer,
391
- op: this.getSQLStatementOperation(),
606
+ builder,
607
+ input,
608
+ op: sqlOp,
392
609
  data: editedFields,
393
- existingEnt: this.existingEnt,
394
610
  });
395
611
  }
396
612
  if (transformed) {
613
+ if (sqlOp === schema_1.SQLStatementOperation.Insert && sqlOp !== transformed.op) {
614
+ if (!transformed.existingEnt) {
615
+ throw new Error(`cannot transform an insert operation without providing an existing ent`);
616
+ }
617
+ }
397
618
  if (transformed.data) {
398
619
  updateInput = true;
399
620
  for (const k in transformed.data) {
@@ -412,18 +633,29 @@ class Orchestrator {
412
633
  // this.defaultFieldsByFieldName[k] = val;
413
634
  }
414
635
  }
636
+ if (transformed.changeset) {
637
+ const changeset = await transformed.changeset();
638
+ this.changesets.push(changeset);
639
+ }
415
640
  this.actualOperation = this.getWriteOpForSQLStamentOp(transformed.op);
416
641
  if (transformed.existingEnt) {
417
642
  // @ts-ignore
418
643
  this.existingEnt = transformed.existingEnt;
644
+ // modify existing ent in builder. it's readonly in generated ents but doesn't apply here
645
+ builder.existingEnt = transformed.existingEnt;
419
646
  }
420
647
  }
421
648
  // transforming before doing default fields so that we don't create a new id
422
649
  // and anything that depends on the type of operations knows what it is
650
+ const userDefinedKeys = new Set();
423
651
  for (const [fieldName, field] of schemaFields) {
424
652
  let value = editedFields.get(fieldName);
425
653
  let defaultValue = undefined;
426
654
  let dbKey = this.getStorageKey(fieldName);
655
+ let updateOnlyIfOther = field.onlyUpdateIfOtherFieldsBeingSet_BETA;
656
+ if (value !== undefined) {
657
+ userDefinedKeys.add(dbKey);
658
+ }
427
659
  if (value === undefined) {
428
660
  if (this.actualOperation === action_1.WriteOperation.Insert) {
429
661
  if (field.defaultToViewerOnCreate && field.defaultValueOnCreate) {
@@ -437,11 +669,17 @@ class Orchestrator {
437
669
  if (defaultValue === undefined) {
438
670
  throw new Error(`defaultValueOnCreate() returned undefined for field ${fieldName}`);
439
671
  }
672
+ if (util_1.types.isPromise(defaultValue)) {
673
+ defaultValue = await defaultValue;
674
+ }
440
675
  }
441
676
  }
442
677
  if (field.defaultValueOnEdit &&
443
678
  this.actualOperation === action_1.WriteOperation.Edit) {
444
679
  defaultValue = field.defaultValueOnEdit(builder, input);
680
+ if (util_1.types.isPromise(defaultValue)) {
681
+ defaultValue = await defaultValue;
682
+ }
445
683
  }
446
684
  }
447
685
  if (value !== undefined) {
@@ -449,7 +687,12 @@ class Orchestrator {
449
687
  }
450
688
  if (defaultValue !== undefined) {
451
689
  updateInput = true;
452
- defaultData[dbKey] = defaultValue;
690
+ if (updateOnlyIfOther) {
691
+ defaultData[dbKey] = defaultValue;
692
+ }
693
+ else {
694
+ data[dbKey] = defaultValue;
695
+ }
453
696
  this.defaultFieldsByFieldName[fieldName] = defaultValue;
454
697
  this.defaultFieldsByTSName[this.getInputKey(fieldName)] = defaultValue;
455
698
  }
@@ -465,7 +708,7 @@ class Orchestrator {
465
708
  this.options.updateInput(this.defaultFieldsByTSName);
466
709
  }
467
710
  }
468
- return data;
711
+ return { data, userDefinedKeys };
469
712
  }
470
713
  hasData(data) {
471
714
  for (const _k in data) {
@@ -477,7 +720,7 @@ class Orchestrator {
477
720
  // now format and validate...
478
721
  if (value === null) {
479
722
  if (!field.nullable) {
480
- throw new Error(`field ${fieldName} set to null for non-nullable field`);
723
+ return new Error(`field ${fieldName} set to null for non-nullable field`);
481
724
  }
482
725
  }
483
726
  else if (value === undefined) {
@@ -488,14 +731,14 @@ class Orchestrator {
488
731
  // server default allowed
489
732
  field.serverDefault === undefined &&
490
733
  this.actualOperation === action_1.WriteOperation.Insert) {
491
- throw new Error(`required field ${fieldName} not set`);
734
+ return new Error(`required field ${fieldName} not set`);
492
735
  }
493
736
  }
494
737
  else if (this.isBuilder(value)) {
495
738
  if (field.valid) {
496
739
  const valid = await field.valid(value);
497
740
  if (!valid) {
498
- throw new Error(`invalid field ${fieldName} with value ${value}`);
741
+ return new Error(`invalid field ${fieldName} with value ${value}`);
499
742
  }
500
743
  }
501
744
  // keep track of dependencies to resolve
@@ -508,7 +751,7 @@ class Orchestrator {
508
751
  // TODO this could be async. handle this better
509
752
  const valid = await field.valid(value);
510
753
  if (!valid) {
511
- throw new Error(`invalid field ${fieldName} with value ${value}`);
754
+ return new Error(`invalid field ${fieldName} with value ${value}`);
512
755
  }
513
756
  }
514
757
  if (field.format) {
@@ -518,26 +761,52 @@ class Orchestrator {
518
761
  return value;
519
762
  }
520
763
  async formatAndValidateFields(schemaFields, editedFields) {
764
+ const errors = [];
521
765
  const op = this.actualOperation;
522
766
  if (op === action_1.WriteOperation.Delete) {
523
- return;
767
+ return [];
524
768
  }
525
769
  // build up data to be saved...
526
770
  let data = {};
527
771
  let logValues = {};
772
+ let needsFullDataChecks = [];
528
773
  for (const [fieldName, field] of schemaFields) {
529
774
  let value = editedFields.get(fieldName);
775
+ if (field.validateWithFullData) {
776
+ needsFullDataChecks.push(fieldName);
777
+ }
530
778
  if (value === undefined && op === action_1.WriteOperation.Insert) {
531
779
  // null allowed
532
780
  value = this.defaultFieldsByFieldName[fieldName];
533
781
  }
534
782
  let dbKey = this.getStorageKey(fieldName);
535
- value = await this.transformFieldValue(fieldName, field, dbKey, value);
783
+ let ret = await this.transformFieldValue(fieldName, field, dbKey, value);
784
+ if (ret instanceof Error) {
785
+ errors.push(ret);
786
+ }
787
+ else {
788
+ value = ret;
789
+ }
536
790
  if (value !== undefined) {
537
791
  data[dbKey] = value;
538
792
  logValues[dbKey] = field.logValue(value);
539
793
  }
540
794
  }
795
+ for (const fieldName of needsFullDataChecks) {
796
+ const field = schemaFields.get(fieldName);
797
+ let value = editedFields.get(fieldName);
798
+ // @ts-ignore...
799
+ // type hackery because it's hard
800
+ const v = await field.validateWithFullData(value, this.options.builder);
801
+ if (!v) {
802
+ if (value === undefined) {
803
+ errors.push(new Error(`field ${fieldName} set to undefined when it can't be nullable`));
804
+ }
805
+ else {
806
+ errors.push(new Error(`field ${fieldName} set to null when it can't be nullable`));
807
+ }
808
+ }
809
+ }
541
810
  // we ignored default values while editing.
542
811
  // if we're editing and there's data, add default values
543
812
  if (op === action_1.WriteOperation.Edit && this.hasData(data)) {
@@ -547,41 +816,73 @@ class Orchestrator {
547
816
  let dbKey = this.getStorageKey(fieldName);
548
817
  // no value, let's just default
549
818
  if (data[dbKey] === undefined) {
550
- const value = await this.transformFieldValue(fieldName, field, dbKey, defaultValue);
551
- data[dbKey] = value;
552
- logValues[dbKey] = field.logValue(value);
819
+ const ret = await this.transformFieldValue(fieldName, field, dbKey, defaultValue);
820
+ if (ret instanceof Error) {
821
+ errors.push(ret);
822
+ }
823
+ else {
824
+ data[dbKey] = ret;
825
+ logValues[dbKey] = field.logValue(ret);
826
+ }
553
827
  }
554
828
  }
555
829
  }
556
830
  this.validatedFields = data;
557
831
  this.logValues = logValues;
832
+ return errors;
558
833
  }
559
834
  async valid() {
560
- try {
561
- await this.validate();
562
- }
563
- catch (e) {
564
- (0, logger_1.log)("error", e);
835
+ const errors = await this.validate();
836
+ if (errors.length) {
837
+ errors.map((err) => (0, logger_1.log)("error", err));
565
838
  return false;
566
839
  }
567
840
  return true;
568
841
  }
569
842
  async validX() {
843
+ const errors = await this.validate();
844
+ if (errors.length) {
845
+ // just throw the first one...
846
+ // TODO we should ideally throw all of them
847
+ throw errors[0];
848
+ }
849
+ }
850
+ /**
851
+ * @experimental API that's not guaranteed to remain in the future which returns
852
+ * a list of errors encountered
853
+ * 0 errors indicates valid
854
+ * NOTE that this currently doesn't catch errors returned by validators().
855
+ * If those throws, this still throws and doesn't return them
856
+ */
857
+ async validWithErrors() {
570
858
  return this.validate();
571
859
  }
572
- async build() {
860
+ async buildPlusChangeset(conditionalBuilder, conditionalOverride) {
573
861
  // validate everything first
574
862
  await this.validX();
575
- let ops = [this.buildMainOp()];
576
- await this.buildEdgeOps(ops);
577
- return new EntChangeset(this.options.viewer, this.options.builder.placeholderID, this.options.loaderOptions.ent, ops, this.dependencies, this.changesets, this.options);
863
+ let ops = [
864
+ this.buildMainOp(conditionalOverride ? conditionalBuilder : undefined),
865
+ ];
866
+ await this.buildEdgeOps(ops, conditionalBuilder, conditionalOverride);
867
+ // TODO throw if we try and create a new changeset after previously creating one
868
+ // TODO test actualOperation value
869
+ // observers is fine since they're run after and we have the actualOperation value...
870
+ return new EntChangeset(this.options.viewer, this.options.builder, this.options.builder.placeholderID, conditionalOverride, ops, this.dependencies, this.changesets, this.options);
871
+ }
872
+ async build() {
873
+ return this.buildPlusChangeset(this.options.builder, false);
874
+ }
875
+ async buildWithOptions_BETA(options) {
876
+ // set as dependency so that we do the right order of operations
877
+ this.dependencies.set(options.conditionalBuilder.placeholderID, options.conditionalBuilder);
878
+ return this.buildPlusChangeset(options.conditionalBuilder, true);
578
879
  }
579
880
  async viewerForEntLoad(data) {
580
881
  const action = this.options.action;
581
882
  if (!action || !action.viewerForEntLoad) {
582
883
  return this.options.viewer;
583
884
  }
584
- return action.viewerForEntLoad(data);
885
+ return action.viewerForEntLoad(data, action.builder.viewer.context);
585
886
  }
586
887
  async returnedRow() {
587
888
  if (this.mainOp && this.mainOp.returnedRow) {
@@ -616,16 +917,34 @@ class Orchestrator {
616
917
  }
617
918
  }
618
919
  exports.Orchestrator = Orchestrator;
920
+ function randomNum() {
921
+ return Math.random().toString(10).substring(2);
922
+ }
923
+ // each changeset is required to have a unique placeholderID
924
+ // used in executor. if we end up creating multiple changesets from a builder, we need
925
+ // different placeholders
926
+ // in practice, only applies to Entchangeset::changesetFrom()
619
927
  class EntChangeset {
620
- constructor(viewer, placeholderID, ent, operations, dependencies, changesets, options) {
928
+ constructor(viewer, builder, placeholderID, conditionalOverride, operations, dependencies, changesets, options) {
621
929
  this.viewer = viewer;
930
+ this.builder = builder;
622
931
  this.placeholderID = placeholderID;
623
- this.ent = ent;
932
+ this.conditionalOverride = conditionalOverride;
624
933
  this.operations = operations;
625
934
  this.dependencies = dependencies;
626
935
  this.changesets = changesets;
627
936
  this.options = options;
628
937
  }
938
+ static changesetFrom(builder, ops) {
939
+ return new EntChangeset(builder.viewer, builder,
940
+ // need unique placeholderID different from the builder. see comment above EntChangeset
941
+ `$ent.idPlaceholderID$ ${randomNum()}-${builder.ent.name}`, false, ops);
942
+ }
943
+ static changesetFromQueries(builder, queries) {
944
+ return new EntChangeset(builder.viewer, builder,
945
+ // need unique placeholderID different from the builder. see comment above EntChangeset
946
+ `$ent.idPlaceholderID$ ${randomNum()}-${builder.ent.name}`, false, [new operations_2.RawQueryOperation(builder, queries)]);
947
+ }
629
948
  executor() {
630
949
  if (this._executor) {
631
950
  return this._executor;
@@ -635,9 +954,15 @@ class EntChangeset {
635
954
  // executor and depend on something else in the stack to handle this correctly
636
955
  // ComplexExecutor which could be a parent of this should make sure the dependency
637
956
  // is resolved beforehand
638
- return (this._executor = new executor_1.ListBasedExecutor(this.viewer, this.placeholderID, this.operations, this.options));
639
- }
640
- return (this._executor = new executor_1.ComplexExecutor(this.viewer, this.placeholderID, this.operations, this.dependencies || new Map(), this.changesets || [], this.options));
957
+ return (this._executor = new executor_1.ListBasedExecutor(this.viewer, this.placeholderID, this.operations, this.options, {
958
+ conditionalOverride: this.conditionalOverride,
959
+ builder: this.builder,
960
+ }));
961
+ }
962
+ return (this._executor = new executor_1.ComplexExecutor(this.viewer, this.placeholderID, this.operations, this.dependencies || new Map(), this.changesets || [], this.options, {
963
+ conditionalOverride: this.conditionalOverride,
964
+ builder: this.builder,
965
+ }));
641
966
  }
642
967
  }
643
968
  exports.EntChangeset = EntChangeset;