@snowtop/ent 0.0.38 → 0.0.39-alpha4

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,6 +1,7 @@
1
1
  import { Ent, EntConstructor, Viewer, ID, Data, PrivacyPolicy, Context } from "../core/base";
2
2
  import { DataOperation, AssocEdgeInputOptions } from "../core/ent";
3
3
  import { Queryer } from "../core/db";
4
+ import { TransformedUpdateOperation, UpdateOperation } from "../schema";
4
5
  export declare enum WriteOperation {
5
6
  Insert = "insert",
6
7
  Edit = "edit",
@@ -50,6 +51,7 @@ export interface Action<T extends Ent> {
50
51
  observers?: Observer<T>[];
51
52
  validators?: Validator<T>[];
52
53
  getInput(): Data;
54
+ transformWrite?: (stmt: UpdateOperation<T>) => Promise<TransformedUpdateOperation<T>> | TransformedUpdateOperation<T> | undefined;
53
55
  valid(): Promise<boolean>;
54
56
  validX(): Promise<void>;
55
57
  viewerForEntLoad?(data: Data): Viewer | Promise<Viewer>;
@@ -41,8 +41,12 @@ export declare class Orchestrator<T extends Ent> {
41
41
  viewer: Viewer;
42
42
  private defaultFieldsByFieldName;
43
43
  private defaultFieldsByTSName;
44
+ private actualOperation;
45
+ private existingEnt?;
46
+ private disableTransformations;
44
47
  constructor(options: OrchestratorOptions<T, Data>);
45
48
  private addEdge;
49
+ setDisableTransformations(val: boolean): void;
46
50
  addInboundEdge<T2 extends Ent>(id1: ID | Builder<T2>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
47
51
  addOutboundEdge<T2 extends Ent>(id2: ID | Builder<T2>, edgeType: string, nodeType: string, options?: AssocEdgeInputOptions): void;
48
52
  removeInboundEdge(id1: ID, edgeType: string): void;
@@ -54,6 +58,8 @@ export declare class Orchestrator<T extends Ent> {
54
58
  private buildEdgeOps;
55
59
  private throwError;
56
60
  private getEntForPrivacyPolicy;
61
+ private getSQLStatementOperation;
62
+ private getWriteOpForSQLStamentOp;
57
63
  private validate;
58
64
  private triggers;
59
65
  private validators;
@@ -62,6 +62,8 @@ class Orchestrator {
62
62
  this.defaultFieldsByFieldName = {};
63
63
  this.defaultFieldsByTSName = {};
64
64
  this.viewer = options.viewer;
65
+ this.actualOperation = this.options.operation;
66
+ this.existingEnt = this.options.builder.existingEnt;
65
67
  }
66
68
  addEdge(edge, op) {
67
69
  this.edgeSet.add(edge.edgeType);
@@ -80,6 +82,9 @@ class Orchestrator {
80
82
  m1.set(op, m2);
81
83
  this.edges.set(edge.edgeType, m1);
82
84
  }
85
+ setDisableTransformations(val) {
86
+ this.disableTransformations = val;
87
+ }
83
88
  addInboundEdge(id1, edgeType, nodeType, options) {
84
89
  this.addEdge(new edgeInputData({
85
90
  id: id1,
@@ -135,24 +140,27 @@ class Orchestrator {
135
140
  }
136
141
  buildMainOp() {
137
142
  // this assumes we have validated fields
138
- switch (this.options.operation) {
143
+ switch (this.actualOperation) {
139
144
  case action_1.WriteOperation.Delete:
140
- return new ent_1.DeleteNodeOperation(this.options.builder.existingEnt.id, {
145
+ return new ent_1.DeleteNodeOperation(this.existingEnt.id, {
141
146
  tableName: this.options.tableName,
142
147
  });
143
148
  default:
149
+ if (this.actualOperation === action_1.WriteOperation.Edit && !this.existingEnt) {
150
+ throw new Error(`existing ent required with operation ${this.actualOperation}`);
151
+ }
144
152
  const opts = {
145
153
  fields: this.validatedFields,
146
154
  tableName: this.options.tableName,
147
155
  fieldsToResolve: this.fieldsToResolve,
148
156
  key: this.options.key,
149
- ent: this.options.loaderOptions.ent,
157
+ loadEntOptions: this.options.loaderOptions,
150
158
  placeholderID: this.options.builder.placeholderID,
151
159
  };
152
160
  if (this.logValues) {
153
161
  opts.fieldsToLog = this.logValues;
154
162
  }
155
- this.mainOp = new ent_1.EditNodeOperation(opts, this.options.builder.existingEnt);
163
+ this.mainOp = new ent_1.EditNodeOperation(opts, this.existingEnt);
156
164
  return this.mainOp;
157
165
  }
158
166
  }
@@ -219,35 +227,57 @@ class Orchestrator {
219
227
  if (!privacyPolicy || !action) {
220
228
  throw new Error(`shouldn't get here if no privacyPolicy for action`);
221
229
  }
222
- if (this.options.operation === action_1.WriteOperation.Insert) {
230
+ if (this.actualOperation === action_1.WriteOperation.Insert) {
223
231
  return new EntCannotCreateEntError(privacyPolicy, action);
224
232
  }
225
- else if (this.options.operation === action_1.WriteOperation.Edit) {
226
- return new EntCannotEditEntError(privacyPolicy, action, this.options.builder.existingEnt);
233
+ else if (this.actualOperation === action_1.WriteOperation.Edit) {
234
+ return new EntCannotEditEntError(privacyPolicy, action, this.existingEnt);
227
235
  }
228
- return new EntCannotDeleteEntError(privacyPolicy, action, this.options.builder.existingEnt);
236
+ return new EntCannotDeleteEntError(privacyPolicy, action, this.existingEnt);
229
237
  }
230
238
  getEntForPrivacyPolicy(editedData) {
231
- if (this.options.operation !== action_1.WriteOperation.Insert) {
232
- return this.options.builder.existingEnt;
239
+ if (this.actualOperation !== action_1.WriteOperation.Insert) {
240
+ return this.existingEnt;
233
241
  }
234
242
  // we create an unsafe ent to be used for privacy policies
235
243
  return new this.options.builder.ent(this.options.builder.viewer, editedData);
236
244
  }
245
+ getSQLStatementOperation() {
246
+ switch (this.actualOperation) {
247
+ case action_1.WriteOperation.Edit:
248
+ return schema_1.SQLStatementOperation.Update;
249
+ case action_1.WriteOperation.Insert:
250
+ return schema_1.SQLStatementOperation.Insert;
251
+ case action_1.WriteOperation.Delete:
252
+ return schema_1.SQLStatementOperation.Delete;
253
+ }
254
+ }
255
+ getWriteOpForSQLStamentOp(op) {
256
+ switch (op) {
257
+ case schema_1.SQLStatementOperation.Update:
258
+ return action_1.WriteOperation.Edit;
259
+ case schema_1.SQLStatementOperation.Insert:
260
+ return action_1.WriteOperation.Insert;
261
+ case schema_1.SQLStatementOperation.Update:
262
+ return action_1.WriteOperation.Delete;
263
+ default:
264
+ throw new Error("invalid path");
265
+ }
266
+ }
237
267
  async validate() {
238
268
  // existing ent required for edit or delete operations
239
- switch (this.options.operation) {
269
+ switch (this.actualOperation) {
240
270
  case action_1.WriteOperation.Delete:
241
271
  case action_1.WriteOperation.Edit:
242
- if (!this.options.builder.existingEnt) {
243
- throw new Error("existing ent required with operation");
272
+ if (!this.existingEnt) {
273
+ throw new Error(`existing ent required with operation ${this.actualOperation}`);
244
274
  }
245
275
  }
246
276
  const action = this.options.action;
247
277
  const builder = this.options.builder;
248
278
  // future optimization: can get schemaFields to memoize based on different values
249
279
  const schemaFields = (0, schema_1.getFields)(this.options.schema);
250
- let editedData = this.getFieldsWithDefaultValues(builder, schemaFields, action);
280
+ let editedData = await this.getFieldsWithDefaultValues(builder, schemaFields, action);
251
281
  // this runs in following phases:
252
282
  // * set default fields and pass to builder so the value can be checked by triggers/observers/validators
253
283
  // * privacy policy (use unsafe ent if we have it)
@@ -300,18 +330,66 @@ class Orchestrator {
300
330
  isBuilder(val) {
301
331
  return val.placeholderID !== undefined;
302
332
  }
303
- getFieldsWithDefaultValues(builder, schemaFields, action) {
333
+ async getFieldsWithDefaultValues(builder, schemaFields, action) {
304
334
  const editedFields = this.options.editedFields();
305
335
  let data = {};
306
336
  let defaultData = {};
307
337
  let input = action?.getInput() || {};
308
338
  let updateInput = false;
339
+ // transformations
340
+ // if action transformations. always do it
341
+ // if disable transformations set, don't do schema transform and just do the right thing
342
+ // else apply schema tranformation if it exists
343
+ let transformed;
344
+ if (action?.transformWrite) {
345
+ transformed = await action.transformWrite({
346
+ viewer: builder.viewer,
347
+ op: this.getSQLStatementOperation(),
348
+ data: editedFields,
349
+ existingEnt: this.existingEnt,
350
+ });
351
+ }
352
+ else if (!this.disableTransformations) {
353
+ transformed = (0, schema_1.getTransformedUpdateOp)(this.options.schema, {
354
+ viewer: builder.viewer,
355
+ op: this.getSQLStatementOperation(),
356
+ data: editedFields,
357
+ existingEnt: this.existingEnt,
358
+ });
359
+ }
360
+ if (transformed) {
361
+ if (transformed.data) {
362
+ updateInput = true;
363
+ for (const k in transformed.data) {
364
+ let field = schemaFields.get(k);
365
+ if (!field) {
366
+ throw new Error(`tried to transform field with unknown field ${k}`);
367
+ }
368
+ let val = transformed.data[k];
369
+ if (field.format) {
370
+ val = field.format(transformed.data[k]);
371
+ }
372
+ let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
373
+ data[dbKey] = val;
374
+ this.defaultFieldsByTSName[(0, camel_case_1.camelCase)(k)] = val;
375
+ // hmm do we need this?
376
+ // TODO how to do this for local tests?
377
+ // this.defaultFieldsByFieldName[k] = val;
378
+ }
379
+ }
380
+ this.actualOperation = this.getWriteOpForSQLStamentOp(transformed.op);
381
+ if (transformed.existingEnt) {
382
+ this.existingEnt = transformed.existingEnt;
383
+ }
384
+ }
385
+ // transforming before doing default fields so that we don't create a new id
386
+ // and anything that depends on the type of operations knows what it is
309
387
  for (const [fieldName, field] of schemaFields) {
310
388
  let value = editedFields.get(fieldName);
311
389
  let defaultValue = undefined;
312
390
  let dbKey = field.storageKey || (0, snake_case_1.snakeCase)(field.name);
313
391
  if (value === undefined) {
314
- if (this.options.operation === action_1.WriteOperation.Insert) {
392
+ if (this.actualOperation === action_1.WriteOperation.Insert) {
315
393
  if (field.defaultToViewerOnCreate && field.defaultValueOnCreate) {
316
394
  throw new Error(`cannot set both defaultToViewerOnCreate and defaultValueOnCreate`);
317
395
  }
@@ -326,7 +404,7 @@ class Orchestrator {
326
404
  }
327
405
  }
328
406
  if (field.defaultValueOnEdit &&
329
- this.options.operation === action_1.WriteOperation.Edit) {
407
+ this.actualOperation === action_1.WriteOperation.Edit) {
330
408
  defaultValue = field.defaultValueOnEdit(builder, input);
331
409
  }
332
410
  }
@@ -374,7 +452,7 @@ class Orchestrator {
374
452
  // not setting server default as we're depending on the database handling that.
375
453
  // server default allowed
376
454
  field.serverDefault === undefined &&
377
- this.options.operation === action_1.WriteOperation.Insert) {
455
+ this.actualOperation === action_1.WriteOperation.Insert) {
378
456
  throw new Error(`required field ${field.name} not set`);
379
457
  }
380
458
  }
@@ -406,7 +484,7 @@ class Orchestrator {
406
484
  return value;
407
485
  }
408
486
  async formatAndValidateFields(schemaFields) {
409
- const op = this.options.operation;
487
+ const op = this.actualOperation;
410
488
  if (op === action_1.WriteOperation.Delete) {
411
489
  return;
412
490
  }
@@ -494,7 +572,7 @@ class Orchestrator {
494
572
  const viewer = await this.viewerForEntLoad(row);
495
573
  const ent = await (0, ent_1.applyPrivacyPolicyForRow)(viewer, this.options.loaderOptions, row);
496
574
  if (!ent) {
497
- if (this.options.operation == action_1.WriteOperation.Insert) {
575
+ if (this.actualOperation == action_1.WriteOperation.Insert) {
498
576
  throw new Error(`was able to create ent but not load it`);
499
577
  }
500
578
  else {
package/core/base.d.ts CHANGED
@@ -62,6 +62,7 @@ export interface SelectBaseDataOptions extends DataOptions {
62
62
  }
63
63
  export interface SelectDataOptions extends SelectBaseDataOptions {
64
64
  key: string;
65
+ clause?: clause.Clause;
65
66
  }
66
67
  export interface QueryableDataOptions extends SelectBaseDataOptions, QueryDataOptions {
67
68
  }
package/core/clause.d.ts CHANGED
@@ -12,8 +12,10 @@ declare class simpleClause implements Clause {
12
12
  protected col: string;
13
13
  private value;
14
14
  private op;
15
- constructor(col: string, value: any, op: string);
15
+ private handleSqliteNull?;
16
+ constructor(col: string, value: any, op: string, handleSqliteNull?: Clause | undefined);
16
17
  clause(idx: number): string;
18
+ private sqliteNull;
17
19
  values(): any[];
18
20
  logValues(): any[];
19
21
  instanceKey(): string;
@@ -27,8 +29,8 @@ declare class compositeClause implements Clause {
27
29
  logValues(): any[];
28
30
  instanceKey(): string;
29
31
  }
30
- export declare function Eq(col: string, value: any): simpleClause;
31
- export declare function NotEq(col: string, value: any): simpleClause;
32
+ export declare function Eq(col: string, value: any): Clause;
33
+ export declare function NotEq(col: string, value: any): Clause;
32
34
  export declare function Greater(col: string, value: any): simpleClause;
33
35
  export declare function Less(col: string, value: any): simpleClause;
34
36
  export declare function GreaterEq(col: string, value: any): simpleClause;
package/core/clause.js CHANGED
@@ -22,7 +22,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
22
22
  exports.sensitiveValue = exports.In = exports.Or = exports.And = exports.LessEq = exports.GreaterEq = exports.Less = exports.Greater = exports.NotEq = exports.Eq = void 0;
23
23
  const db_1 = __importStar(require("./db"));
24
24
  function isSensitive(val) {
25
- return (typeof val === "object" && val.logValue !== undefined);
25
+ return (val !== null &&
26
+ typeof val === "object" &&
27
+ val.logValue !== undefined);
26
28
  }
27
29
  function rawValue(val) {
28
30
  if (isSensitive(val)) {
@@ -31,33 +33,94 @@ function rawValue(val) {
31
33
  return val;
32
34
  }
33
35
  class simpleClause {
34
- constructor(col, value, op) {
36
+ constructor(col, value, op, handleSqliteNull) {
35
37
  this.col = col;
36
38
  this.value = value;
37
39
  this.op = op;
40
+ this.handleSqliteNull = handleSqliteNull;
38
41
  }
39
42
  clause(idx) {
43
+ const sqliteClause = this.sqliteNull();
44
+ if (sqliteClause) {
45
+ return sqliteClause.clause(idx);
46
+ }
40
47
  if (db_1.default.getDialect() === db_1.Dialect.Postgres) {
41
48
  return `${this.col} ${this.op} $${idx}`;
42
49
  }
43
50
  return `${this.col} ${this.op} ?`;
44
51
  }
52
+ sqliteNull() {
53
+ if (!this.handleSqliteNull) {
54
+ return;
55
+ }
56
+ const dialect = db_1.default.getDialect();
57
+ if (this.value !== null || dialect !== db_1.Dialect.SQLite) {
58
+ return;
59
+ }
60
+ return this.handleSqliteNull;
61
+ }
45
62
  values() {
63
+ const sqliteClause = this.sqliteNull();
64
+ if (sqliteClause) {
65
+ return sqliteClause.values();
66
+ }
46
67
  if (isSensitive(this.value)) {
47
68
  return [this.value.value()];
48
69
  }
49
70
  return [this.value];
50
71
  }
51
72
  logValues() {
73
+ const sqliteClause = this.sqliteNull();
74
+ if (sqliteClause) {
75
+ return sqliteClause.logValues();
76
+ }
52
77
  if (isSensitive(this.value)) {
53
78
  return [this.value.logValue()];
54
79
  }
55
80
  return [this.value];
56
81
  }
57
82
  instanceKey() {
83
+ const sqliteClause = this.sqliteNull();
84
+ if (sqliteClause) {
85
+ return sqliteClause.instanceKey();
86
+ }
58
87
  return `${this.col}${this.op}${rawValue(this.value)}`;
59
88
  }
60
89
  }
90
+ class isNullClause {
91
+ constructor(col) {
92
+ this.col = col;
93
+ }
94
+ clause(idx) {
95
+ return `${this.col} IS NULL`;
96
+ }
97
+ values() {
98
+ return [];
99
+ }
100
+ logValues() {
101
+ return [];
102
+ }
103
+ instanceKey() {
104
+ return `${this.col} IS NULL`;
105
+ }
106
+ }
107
+ class isNotNullClause {
108
+ constructor(col) {
109
+ this.col = col;
110
+ }
111
+ clause(idx) {
112
+ return `${this.col} IS NOT NULL`;
113
+ }
114
+ values() {
115
+ return [];
116
+ }
117
+ logValues() {
118
+ return [];
119
+ }
120
+ instanceKey() {
121
+ return `${this.col} IS NOT NULL`;
122
+ }
123
+ }
61
124
  class inClause {
62
125
  constructor(col, value) {
63
126
  this.col = col;
@@ -146,11 +209,11 @@ class compositeClause {
146
209
  }
147
210
  }
148
211
  function Eq(col, value) {
149
- return new simpleClause(col, value, "=");
212
+ return new simpleClause(col, value, "=", new isNullClause(col));
150
213
  }
151
214
  exports.Eq = Eq;
152
215
  function NotEq(col, value) {
153
- return new simpleClause(col, value, "!=");
216
+ return new simpleClause(col, value, "!=", new isNotNullClause(col));
154
217
  }
155
218
  exports.NotEq = NotEq;
156
219
  function Greater(col, value) {
package/core/config.d.ts CHANGED
@@ -15,6 +15,7 @@ export interface Config {
15
15
  db?: Database | DBDict;
16
16
  log?: logType | logType[];
17
17
  codegen?: CodegenConfig;
18
+ customGraphQLJSONPath?: string;
18
19
  }
19
20
  interface CodegenConfig {
20
21
  defaultEntPolicy?: PrivacyConfig;
package/core/ent.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Queryer, SyncQueryer } from "./db";
2
- import { Viewer, Ent, ID, LoadRowsOptions, LoadRowOptions, Data, DataOptions, QueryableDataOptions, EditRowOptions, LoadEntOptions, LoadCustomEntOptions, EdgeQueryableDataOptions, Context, SelectBaseDataOptions, CreateRowOptions, QueryDataOptions, EntConstructor } from "./base";
2
+ import { Viewer, Ent, ID, LoadRowsOptions, LoadRowOptions, Data, DataOptions, QueryableDataOptions, EditRowOptions, LoadEntOptions, LoadCustomEntOptions, EdgeQueryableDataOptions, Context, SelectBaseDataOptions, CreateRowOptions, QueryDataOptions } from "./base";
3
3
  import { Executor } from "../action/action";
4
4
  import * as clause from "./clause";
5
5
  import { Builder } from "../action";
@@ -51,7 +51,7 @@ export interface DataOperation<T extends Ent = Ent> {
51
51
  }
52
52
  export interface EditNodeOptions<T extends Ent> extends EditRowOptions {
53
53
  fieldsToResolve: string[];
54
- ent: EntConstructor<T>;
54
+ loadEntOptions: LoadEntOptions<T>;
55
55
  placeholderID?: ID;
56
56
  }
57
57
  export declare class EditNodeOperation<T extends Ent> implements DataOperation {
package/core/ent.js CHANGED
@@ -84,8 +84,54 @@ function createDataLoader(options) {
84
84
  return result;
85
85
  }, loaderOptions);
86
86
  }
87
+ // TODO probably delete since we're going to generate it now
88
+ // instead of passing this here.
89
+ // async function doPerformQuery<T extends Ent>(
90
+ // viewer: Viewer,
91
+ // id: ID,
92
+ // options: LoadEntOptions<T>,
93
+ // ): Promise<Data | null> {
94
+ // let newClause: clause.Clause | undefined = undefined;
95
+ // if (options.schema) {
96
+ // const schema = getSchema(options.schema);
97
+ // if (schema.patterns) {
98
+ // for (const p of schema.patterns) {
99
+ // if (p.transformRead) {
100
+ // newClause = p.transformRead({
101
+ // op: QueryOperation.Select,
102
+ // clause: clause.Eq("id", id),
103
+ // });
104
+ // }
105
+ // }
106
+ // }
107
+ // }
108
+ // // we want a loader if possible . we don't want this to slow
109
+ // // things down...
110
+ // // id = x and deleted_at == null
111
+ // if (newClause) {
112
+ // // loader
113
+ // // return loadRow({});
114
+ // // TODO
115
+ // }
116
+ // // we want a deleted_at loader...
117
+ // return options.loaderFactory.createLoader(viewer.context).load(id);
118
+ // }
87
119
  // Ent accessors
88
120
  async function loadEnt(viewer, id, options) {
121
+ let newClause;
122
+ // if (options.schema) {
123
+ // const schema = getSchema(options.schema);
124
+ // if (schema.patterns) {
125
+ // for (const p of schema.patterns) {
126
+ // if (p.transformRead) {
127
+ // newClause = p.transformRead({
128
+ // op: QueryOperation.Select,
129
+ // clause: clause.Eq("id", id),
130
+ // });
131
+ // }
132
+ // }
133
+ // }
134
+ // }
89
135
  const row = await options.loaderFactory.createLoader(viewer.context).load(id);
90
136
  return await applyPrivacyPolicyForRow(viewer, options, row);
91
137
  }
@@ -434,6 +480,8 @@ class EditNodeOperation {
434
480
  };
435
481
  if (this.existingEnt) {
436
482
  if (this.hasData(options.fields)) {
483
+ // even this with returning * doesn't work if transformed...
484
+ // we can have a transformed flag to see if it should be returned?
437
485
  this.row = await editRow(queryer, options, this.existingEnt.id, "RETURNING *");
438
486
  }
439
487
  else {
@@ -445,20 +493,27 @@ class EditNodeOperation {
445
493
  }
446
494
  }
447
495
  reloadRow(queryer, id, options) {
496
+ // TODO this isn'talways an ObjectLoader. should throw or figure out a way to get query
497
+ // and run this on its own...
498
+ const loader = this.options.loadEntOptions.loaderFactory.createLoader(options.context);
499
+ const opts = loader.getOptions();
500
+ let cls = clause.Eq(options.key, id);
501
+ if (opts.clause) {
502
+ cls = clause.And(opts.clause, cls);
503
+ }
448
504
  const query = buildQuery({
449
- fields: ["*"],
505
+ fields: opts.fields.length ? opts.fields : ["*"],
450
506
  tableName: options.tableName,
451
- clause: clause.Eq(options.key, id),
507
+ clause: cls,
452
508
  });
453
509
  // special case log here because we're not going through any of the normal
454
510
  // methods here because those are async and this is sync
455
511
  // this is the only place we're doing this so only handling here
456
512
  logQuery(query, [id]);
457
513
  const r = queryer.querySync(query, [id]);
458
- if (r.rows.length !== 1) {
459
- throw new Error(`couldn't reload row for ${id}`);
514
+ if (r.rows.length === 1) {
515
+ this.row = r.rows[0];
460
516
  }
461
- this.row = r.rows[0];
462
517
  }
463
518
  performWriteSync(queryer, context) {
464
519
  let options = {
@@ -487,7 +542,7 @@ class EditNodeOperation {
487
542
  if (!this.row) {
488
543
  return null;
489
544
  }
490
- return new this.options.ent(viewer, this.row);
545
+ return new this.options.loadEntOptions.ent(viewer, this.row);
491
546
  }
492
547
  }
493
548
  exports.EditNodeOperation = EditNodeOperation;
@@ -7,6 +7,7 @@ export declare class ObjectLoader<T> implements Loader<T, Data | null> {
7
7
  private primedLoaders;
8
8
  private memoizedInitPrime;
9
9
  constructor(options: SelectDataOptions, context?: Context | undefined, toPrime?: ObjectLoaderFactory<T>[] | undefined);
10
+ getOptions(): SelectDataOptions;
10
11
  private initPrime;
11
12
  load(key: T): Promise<Data | null>;
12
13
  clearAll(): void;
@@ -29,6 +29,9 @@ const clause = __importStar(require("../clause"));
29
29
  const logger_1 = require("../logger");
30
30
  const loader_1 = require("./loader");
31
31
  const memoizee_1 = __importDefault(require("memoizee"));
32
+ // optional clause...
33
+ // so ObjectLoaderFactory and createDataLoader need to take a new optional field which is a clause that's always added here
34
+ // and we need a disableTransform which skips loader completely and uses loadRow...
32
35
  function createDataLoader(options) {
33
36
  const loaderOptions = {};
34
37
  // if query logging is enabled, we should log what's happening with loader
@@ -40,9 +43,13 @@ function createDataLoader(options) {
40
43
  return [];
41
44
  }
42
45
  let col = options.key;
46
+ let cls = clause.In(col, ...ids);
47
+ if (options.clause) {
48
+ cls = clause.And(options.clause, cls);
49
+ }
43
50
  const rowOptions = {
44
51
  ...options,
45
- clause: clause.In(col, ...ids),
52
+ clause: cls,
46
53
  };
47
54
  let m = new Map();
48
55
  let result = [];
@@ -77,6 +84,9 @@ class ObjectLoader {
77
84
  }
78
85
  this.memoizedInitPrime = (0, memoizee_1.default)(this.initPrime.bind(this));
79
86
  }
87
+ getOptions() {
88
+ return this.options;
89
+ }
80
90
  initPrime() {
81
91
  if (!this.context || !this.toPrime) {
82
92
  return;
@@ -107,9 +117,13 @@ class ObjectLoader {
107
117
  }
108
118
  return result;
109
119
  }
120
+ let cls = clause.Eq(this.options.key, key);
121
+ if (this.options.clause) {
122
+ cls = clause.And(this.options.clause, cls);
123
+ }
110
124
  const rowOptions = {
111
125
  ...this.options,
112
- clause: clause.Eq(this.options.key, key),
126
+ clause: cls,
113
127
  context: this.context,
114
128
  };
115
129
  return await (0, ent_1.loadRow)(rowOptions);
@@ -121,9 +135,13 @@ class ObjectLoader {
121
135
  if (this.loader) {
122
136
  return await this.loader.loadMany(keys);
123
137
  }
138
+ let cls = clause.In(this.options.key, ...keys);
139
+ if (this.options.clause) {
140
+ cls = clause.And(this.options.clause, cls);
141
+ }
124
142
  const rowOptions = {
125
143
  ...this.options,
126
- clause: clause.In(this.options.key, ...keys),
144
+ clause: cls,
127
145
  context: this.context,
128
146
  };
129
147
  return await (0, ent_1.loadRows)(rowOptions);
@@ -142,7 +160,7 @@ class ObjectLoaderFactory {
142
160
  constructor(options) {
143
161
  this.options = options;
144
162
  this.toPrime = [];
145
- this.name = `${options.tableName}:${options.key}`;
163
+ this.name = `${options.tableName}:${options.key}:${options.clause?.instanceKey() || ""}`;
146
164
  }
147
165
  createLoader(context) {
148
166
  return (0, loader_1.getLoader)(this, () => {
@@ -82,6 +82,9 @@ declare enum NullableResult {
82
82
  CONTENTS_AND_LIST = "contentsAndList",
83
83
  ITEM = "true"
84
84
  }
85
+ export declare const knownAllowedNames: Map<string, string>;
86
+ export declare const knownDisAllowedNames: Map<string, boolean>;
87
+ export declare const isCustomType: (type: Type) => type is CustomType;
85
88
  export declare const addCustomType: (type: CustomType) => void;
86
89
  export declare class GQLCapture {
87
90
  private static enabled;
@@ -107,8 +110,6 @@ export declare class GQLCapture {
107
110
  static getProcessedCustomMutations(): ProcessedCustomField[];
108
111
  static getProcessedCustomQueries(): ProcessedCustomField[];
109
112
  private static getProcessedCustomFieldsImpl;
110
- private static knownAllowedNames;
111
- private static knownDisAllowedNames;
112
113
  private static getResultFromMetadata;
113
114
  static gqlField(options?: gqlFieldOptions): any;
114
115
  private static getCustomField;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.gqlFileUpload = exports.gqlConnection = exports.gqlContextType = exports.gqlMutation = exports.gqlQuery = exports.gqlObjectType = exports.gqlInputObjectType = exports.gqlArgType = exports.gqlArg = exports.gqlField = exports.GQLCapture = exports.addCustomType = exports.CustomFieldType = void 0;
3
+ exports.gqlFileUpload = exports.gqlConnection = exports.gqlContextType = exports.gqlMutation = exports.gqlQuery = exports.gqlObjectType = exports.gqlInputObjectType = exports.gqlArgType = exports.gqlArg = exports.gqlField = exports.GQLCapture = exports.addCustomType = exports.isCustomType = exports.knownDisAllowedNames = exports.knownAllowedNames = exports.CustomFieldType = void 0;
4
4
  require("reflect-metadata");
5
5
  // export interface gqlTopLevelOptions
6
6
  // name?: string;
@@ -20,6 +20,22 @@ var NullableResult;
20
20
  NullableResult["CONTENTS_AND_LIST"] = "contentsAndList";
21
21
  NullableResult["ITEM"] = "true";
22
22
  })(NullableResult || (NullableResult = {}));
23
+ exports.knownAllowedNames = new Map([
24
+ ["Date", "Date"],
25
+ ["Boolean", "boolean"],
26
+ ["Number", "number"],
27
+ ["String", "string"],
28
+ // TODO not right to have this and Number
29
+ ["Int", "number"],
30
+ ["Float", "number"],
31
+ ["ID", "ID"],
32
+ ]);
33
+ exports.knownDisAllowedNames = new Map([
34
+ ["Function", true],
35
+ ["Object", true],
36
+ ["Array", true],
37
+ ["Promise", true],
38
+ ]);
23
39
  const isArray = (type) => {
24
40
  if (typeof type === "function") {
25
41
  return false;
@@ -41,6 +57,7 @@ const isString = (type) => {
41
57
  const isCustomType = (type) => {
42
58
  return type.importPath !== undefined;
43
59
  };
60
+ exports.isCustomType = isCustomType;
44
61
  const isGraphQLScalarType = (type) => {
45
62
  return type.serialize !== undefined;
46
63
  };
@@ -92,7 +109,7 @@ const getType = (typ, result) => {
92
109
  }
93
110
  return;
94
111
  }
95
- if (isCustomType(typ)) {
112
+ if ((0, exports.isCustomType)(typ)) {
96
113
  result.type = typ.type;
97
114
  (0, exports.addCustomType)(typ);
98
115
  return;
@@ -197,20 +214,20 @@ class GQLCapture {
197
214
  connection = r.connection;
198
215
  type = r.type;
199
216
  }
200
- if (GQLCapture.knownDisAllowedNames.has(type)) {
217
+ if (exports.knownDisAllowedNames.has(type)) {
201
218
  throw new Error(`${type} isn't a valid type for accessor/function/property`);
202
219
  }
203
220
  let result = {
204
221
  name: metadata.paramName || "",
205
222
  type,
206
- tsType: this.knownAllowedNames.get(type) || this.customTypes.get(type)?.tsType,
223
+ tsType: exports.knownAllowedNames.get(type) || this.customTypes.get(type)?.tsType,
207
224
  nullable: options?.nullable,
208
225
  list: list,
209
226
  connection: connection,
210
227
  isContextArg: metadata.isContextArg,
211
228
  };
212
229
  // unknown type. we need to flag that this field needs to eventually be resolved
213
- if (!GQLCapture.knownAllowedNames.has(type)) {
230
+ if (!exports.knownAllowedNames.has(type)) {
214
231
  if (scalarType) {
215
232
  throw new Error(`custom scalar type ${type} is not supported this way. use CustomType syntax. see \`gqlFileUpload\` as an example`);
216
233
  }
@@ -461,22 +478,6 @@ GQLCapture.customArgs = new Map();
461
478
  GQLCapture.customInputObjects = new Map();
462
479
  GQLCapture.customObjects = new Map();
463
480
  GQLCapture.customTypes = new Map();
464
- GQLCapture.knownAllowedNames = new Map([
465
- ["Date", "Date"],
466
- ["Boolean", "boolean"],
467
- ["Number", "number"],
468
- ["String", "string"],
469
- // TODO not right to have this and Number
470
- ["Int", "number"],
471
- ["Float", "number"],
472
- ["ID", "ID"],
473
- ]);
474
- GQLCapture.knownDisAllowedNames = new Map([
475
- ["Function", true],
476
- ["Object", true],
477
- ["Array", true],
478
- ["Promise", true],
479
- ]);
480
481
  // User -> add -> [{name, options}, {}, {}]
481
482
  GQLCapture.argMap = new Map();
482
483
  // why is this a static class lol?
@@ -5,7 +5,6 @@ interface Node {
5
5
  id: ID;
6
6
  }
7
7
  export interface NodeResolver {
8
- encode(node: Node): string;
9
8
  decodeObj(viewer: Viewer, id: string): Promise<Node | null>;
10
9
  }
11
10
  interface loadEnt {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.0.38",
3
+ "version": "0.0.39-alpha4",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -12,7 +12,13 @@ declare type ProcessedAssocEdge = Omit<AssocEdge, "actionOnlyFields" | "edgeActi
12
12
  patternName?: string;
13
13
  edgeActions?: OutputAction[];
14
14
  };
15
- declare type ProcessedSchema = Omit<Schema, "edges" | "actions" | "edgeGroups" | "fields"> & {
15
+ interface TransformFlags {
16
+ transformsSelect?: boolean;
17
+ transformsDelete?: boolean;
18
+ transformsInsert?: boolean;
19
+ transformsUpdate?: boolean;
20
+ }
21
+ declare type ProcessedSchema = Omit<Schema, "edges" | "actions" | "edgeGroups" | "fields"> & TransformFlags & {
16
22
  actions: OutputAction[];
17
23
  assocEdges: ProcessedAssocEdge[];
18
24
  assocEdgeGroups: ProcessedAssocEdgeGroup[];
@@ -78,6 +78,9 @@ function processEdgeGroups(processedSchema, edgeGroups) {
78
78
  }
79
79
  }
80
80
  function processPattern(patterns, pattern, processedSchema) {
81
+ let ret = {
82
+ ...pattern,
83
+ };
81
84
  const name = pattern.name;
82
85
  const fields = processFields(pattern.fields, pattern.name);
83
86
  processedSchema.fields.push(...fields);
@@ -85,6 +88,10 @@ function processPattern(patterns, pattern, processedSchema) {
85
88
  const edges = processEdges(pattern.edges, pattern.name);
86
89
  processedSchema.assocEdges.push(...edges);
87
90
  }
91
+ // flag transformsSelect
92
+ if (pattern.transformRead) {
93
+ ret.transformsSelect = true;
94
+ }
88
95
  if (patterns[name] === undefined) {
89
96
  // intentionally processing separately and not passing pattern.name
90
97
  const edges = processEdges(pattern.edges || []);
@@ -98,6 +105,7 @@ function processPattern(patterns, pattern, processedSchema) {
98
105
  // TODO ideally we want to make sure that different patterns don't have the same name
99
106
  // can't do a deepEqual check because function calls and therefore different instances in fields
100
107
  }
108
+ return ret;
101
109
  }
102
110
  var NullableResult;
103
111
  (function (NullableResult) {
@@ -160,7 +168,19 @@ function parseSchema(potentialSchemas) {
160
168
  // ¯\_(ツ)_/¯
161
169
  if (schema.patterns) {
162
170
  for (const pattern of schema.patterns) {
163
- processPattern(patterns, pattern, processedSchema);
171
+ const ret = processPattern(patterns, pattern, processedSchema);
172
+ if (ret.transformsSelect) {
173
+ if (processedSchema.transformsSelect) {
174
+ throw new Error(`can only have one pattern which transforms default querying behavior`);
175
+ }
176
+ processedSchema.transformsSelect = true;
177
+ }
178
+ if (ret.transformsDelete) {
179
+ if (processedSchema.transformsDelete) {
180
+ throw new Error(`can only have one pattern which transforms default deletion behavior`);
181
+ }
182
+ processedSchema.transformsDelete = true;
183
+ }
164
184
  }
165
185
  }
166
186
  const fields = processFields(schema.fields);
package/schema/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import Schema from "./schema";
2
2
  export { Schema };
3
- export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, ActionOperation, Action, EdgeAction, NoFields, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, } from "./schema";
3
+ export { Field, AssocEdge, AssocEdgeGroup, InverseAssocEdge, Edge, Pattern, DBType, Type, FieldOptions, SchemaConstructor, SchemaInputType, getFields, ActionOperation, Action, EdgeAction, NoFields, Constraint, Index, ConstraintType, ForeignKeyInfo, requiredField, optionalField, UpdateOperation, TransformedUpdateOperation, SQLStatementOperation, getTransformedReadClause, } from "./schema";
4
4
  export { Timestamps, Node, BaseEntSchema, BaseEntSchemaWithTZ, } from "./base_schema";
5
5
  export * from "./field";
6
6
  export * from "./json_field";
package/schema/index.js CHANGED
@@ -10,7 +10,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
10
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.BaseEntSchemaWithTZ = exports.BaseEntSchema = exports.Node = exports.Timestamps = exports.optionalField = exports.requiredField = exports.ConstraintType = exports.NoFields = exports.ActionOperation = exports.getFields = exports.DBType = void 0;
13
+ exports.BaseEntSchemaWithTZ = exports.BaseEntSchema = exports.Node = exports.Timestamps = exports.getTransformedReadClause = exports.SQLStatementOperation = exports.optionalField = exports.requiredField = exports.ConstraintType = exports.NoFields = exports.ActionOperation = exports.getFields = exports.DBType = void 0;
14
14
  var schema_1 = require("./schema");
15
15
  Object.defineProperty(exports, "DBType", { enumerable: true, get: function () { return schema_1.DBType; } });
16
16
  Object.defineProperty(exports, "getFields", { enumerable: true, get: function () { return schema_1.getFields; } });
@@ -19,6 +19,8 @@ Object.defineProperty(exports, "NoFields", { enumerable: true, get: function ()
19
19
  Object.defineProperty(exports, "ConstraintType", { enumerable: true, get: function () { return schema_1.ConstraintType; } });
20
20
  Object.defineProperty(exports, "requiredField", { enumerable: true, get: function () { return schema_1.requiredField; } });
21
21
  Object.defineProperty(exports, "optionalField", { enumerable: true, get: function () { return schema_1.optionalField; } });
22
+ Object.defineProperty(exports, "SQLStatementOperation", { enumerable: true, get: function () { return schema_1.SQLStatementOperation; } });
23
+ Object.defineProperty(exports, "getTransformedReadClause", { enumerable: true, get: function () { return schema_1.getTransformedReadClause; } });
22
24
  var base_schema_1 = require("./base_schema");
23
25
  Object.defineProperty(exports, "Timestamps", { enumerable: true, get: function () { return base_schema_1.Timestamps; } });
24
26
  Object.defineProperty(exports, "Node", { enumerable: true, get: function () { return base_schema_1.Node; } });
@@ -1,5 +1,6 @@
1
- import { Data, Ent, LoaderInfo } from "../core/base";
1
+ import { Data, Ent, LoaderInfo, Viewer } from "../core/base";
2
2
  import { Builder } from "../action/action";
3
+ import { Clause } from "../core/clause";
3
4
  export default interface Schema {
4
5
  fields: Field[];
5
6
  tableName?: string;
@@ -59,6 +60,27 @@ export interface Pattern {
59
60
  name: string;
60
61
  fields: Field[];
61
62
  edges?: Edge[];
63
+ transformRead?: () => Clause;
64
+ transformWrite?: <T extends Ent>(stmt: UpdateOperation<T>) => TransformedUpdateOperation<T> | undefined;
65
+ transformsDelete?: boolean;
66
+ transformsInsert?: boolean;
67
+ transformsUpdate?: boolean;
68
+ }
69
+ export declare enum SQLStatementOperation {
70
+ Insert = "insert",
71
+ Update = "update",
72
+ Delete = "delete"
73
+ }
74
+ export interface UpdateOperation<T extends Ent> {
75
+ op: SQLStatementOperation;
76
+ existingEnt?: T;
77
+ viewer: Viewer;
78
+ data?: Map<string, any>;
79
+ }
80
+ export interface TransformedUpdateOperation<T extends Ent> {
81
+ op: SQLStatementOperation;
82
+ data?: Data;
83
+ existingEnt?: T;
62
84
  }
63
85
  export declare enum DBType {
64
86
  UUID = "UUID",
@@ -155,7 +177,10 @@ export interface SchemaConstructor {
155
177
  new (): Schema;
156
178
  }
157
179
  export declare type SchemaInputType = Schema | SchemaConstructor;
180
+ export declare function getSchema(value: SchemaInputType): Schema;
158
181
  export declare function getFields(value: SchemaInputType): Map<string, Field>;
182
+ export declare function getTransformedReadClause(value: SchemaInputType): Clause | undefined;
183
+ export declare function getTransformedUpdateOp<T extends Ent>(value: SchemaInputType, stmt: UpdateOperation<T>): TransformedUpdateOperation<T> | undefined;
159
184
  export declare enum ActionOperation {
160
185
  Create = 1,
161
186
  Edit = 2,
package/schema/schema.js CHANGED
@@ -1,6 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ConstraintType = exports.optionalField = exports.requiredField = exports.NoFields = exports.ActionOperation = exports.getFields = exports.DBType = void 0;
3
+ exports.ConstraintType = exports.optionalField = exports.requiredField = exports.NoFields = exports.ActionOperation = exports.getTransformedUpdateOp = exports.getTransformedReadClause = exports.getFields = exports.getSchema = exports.DBType = exports.SQLStatementOperation = void 0;
4
+ // we also want this transformation to exist on a per-action basis
5
+ // if it exists on an action, we don't do the global schema transformation
6
+ var SQLStatementOperation;
7
+ (function (SQLStatementOperation) {
8
+ // transform insert e.g. to an update based on whatever logic
9
+ SQLStatementOperation["Insert"] = "insert";
10
+ // // transform select e.g. deleted_at. can't change from select to different query type
11
+ // // but can change the query
12
+ // Select = "select",
13
+ // e.g. change updated value
14
+ SQLStatementOperation["Update"] = "update";
15
+ // delete -> update theoretically e.g. deleted_at
16
+ SQLStatementOperation["Delete"] = "delete";
17
+ })(SQLStatementOperation = exports.SQLStatementOperation || (exports.SQLStatementOperation = {}));
4
18
  // we want --strictNullChecks flag so nullable is used to type graphql, ts, db
5
19
  // should eventually generate (boolean | null) etc
6
20
  // supported db types
@@ -28,14 +42,17 @@ var DBType;
28
42
  function isSchema(value) {
29
43
  return value.fields !== undefined;
30
44
  }
31
- function getFields(value) {
32
- let schema;
45
+ function getSchema(value) {
33
46
  if (isSchema(value)) {
34
- schema = value;
47
+ return value;
35
48
  }
36
49
  else {
37
- schema = new value();
50
+ return new value();
38
51
  }
52
+ }
53
+ exports.getSchema = getSchema;
54
+ function getFields(value) {
55
+ const schema = getSchema(value);
39
56
  function addFields(fields) {
40
57
  for (const field of fields) {
41
58
  const derivedFields = field.derivedFields;
@@ -55,6 +72,33 @@ function getFields(value) {
55
72
  return m;
56
73
  }
57
74
  exports.getFields = getFields;
75
+ function getTransformedReadClause(value) {
76
+ const schema = getSchema(value);
77
+ if (!schema.patterns) {
78
+ return;
79
+ }
80
+ for (const p of schema.patterns) {
81
+ // e.g. discarded_at, deleted_at, etc
82
+ if (p.transformRead) {
83
+ // return clause.Eq('deleted_at', null);
84
+ return p.transformRead();
85
+ }
86
+ }
87
+ return;
88
+ }
89
+ exports.getTransformedReadClause = getTransformedReadClause;
90
+ function getTransformedUpdateOp(value, stmt) {
91
+ const schema = getSchema(value);
92
+ if (!schema.patterns) {
93
+ return;
94
+ }
95
+ for (const p of schema.patterns) {
96
+ if (p.transformWrite) {
97
+ return p.transformWrite(stmt);
98
+ }
99
+ }
100
+ }
101
+ exports.getTransformedUpdateOp = getTransformedUpdateOp;
58
102
  // this maps to ActionOperation in ent/action.go
59
103
  var ActionOperation;
60
104
  (function (ActionOperation) {
@@ -24,6 +24,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const glob_1 = __importDefault(require("glob"));
27
+ const json5_1 = __importDefault(require("json5"));
27
28
  const minimist_1 = __importDefault(require("minimist"));
28
29
  const graphql_1 = require("../graphql/graphql");
29
30
  const readline = __importStar(require("readline"));
@@ -53,7 +54,103 @@ async function readInputs() {
53
54
  });
54
55
  });
55
56
  }
56
- async function captureCustom(filePath, filesCsv) {
57
+ function processCustomObjects(l, gqlCapture, input) {
58
+ let m;
59
+ if (input) {
60
+ m = gqlCapture.getCustomInputObjects();
61
+ }
62
+ else {
63
+ m = gqlCapture.getCustomObjects();
64
+ }
65
+ for (const input of l) {
66
+ m.set(input.name, {
67
+ nodeName: input.graphQLName || input.name,
68
+ className: input.name,
69
+ });
70
+ if (input.fields) {
71
+ processCustomFields(input.fields, gqlCapture, input.name);
72
+ }
73
+ }
74
+ }
75
+ function transformArgs(f) {
76
+ return (f.args || []).map((v) => {
77
+ const ret = {
78
+ ...v,
79
+ };
80
+ // duplicated from getType in graphql.ts
81
+ if ((0, graphql_1.isCustomType)(ret.type)) {
82
+ ret.type = v.type.type;
83
+ (0, graphql_1.addCustomType)(v.type);
84
+ }
85
+ // scalar types not supported for now
86
+ ret.tsType = graphql_1.knownAllowedNames.get(v.type);
87
+ return ret;
88
+ });
89
+ }
90
+ function transformResultType(f) {
91
+ return f.resultType
92
+ ? [
93
+ {
94
+ name: "",
95
+ type: f.resultType,
96
+ tsType: graphql_1.knownAllowedNames.get(f.resultType),
97
+ list: f.list,
98
+ nullable: f.nullable,
99
+ },
100
+ ]
101
+ : [];
102
+ }
103
+ function processTopLevel(l, l2) {
104
+ for (const custom of l) {
105
+ l2.push({
106
+ nodeName: custom.class,
107
+ functionName: custom.functionName || custom.name,
108
+ gqlName: custom.graphQLName || custom.name,
109
+ fieldType: custom.fieldType,
110
+ args: transformArgs(custom),
111
+ results: transformResultType(custom),
112
+ });
113
+ }
114
+ }
115
+ function processCustomFields(fields, gqlCapture, nodeName) {
116
+ const m = gqlCapture.getCustomFields();
117
+ let results = [];
118
+ for (const f of fields) {
119
+ results.push({
120
+ nodeName: nodeName,
121
+ gqlName: f.graphQLName || f.name,
122
+ functionName: f.functionName || f.name,
123
+ fieldType: f.fieldType,
124
+ args: transformArgs(f),
125
+ results: transformResultType(f),
126
+ });
127
+ }
128
+ m.set(nodeName, results);
129
+ }
130
+ async function captureCustom(filePath, filesCsv, jsonPath, gqlCapture) {
131
+ if (jsonPath !== undefined) {
132
+ let json = json5_1.default.parse(fs.readFileSync(jsonPath, {
133
+ encoding: "utf8",
134
+ }));
135
+ if (json.fields) {
136
+ for (const k in json.fields) {
137
+ processCustomFields(json.fields[k], gqlCapture, k);
138
+ }
139
+ }
140
+ if (json.inputs) {
141
+ processCustomObjects(json.inputs, gqlCapture, true);
142
+ }
143
+ if (json.objects) {
144
+ processCustomObjects(json.objects, gqlCapture);
145
+ }
146
+ if (json.queries) {
147
+ processTopLevel(json.queries, gqlCapture.getCustomQueries());
148
+ }
149
+ if (json.mutations) {
150
+ processTopLevel(json.mutations, gqlCapture.getCustomMutations());
151
+ }
152
+ return;
153
+ }
57
154
  if (filesCsv !== undefined) {
58
155
  let files = filesCsv.split(",");
59
156
  for (let i = 0; i < files.length; i++) {
@@ -153,15 +250,25 @@ async function main() {
153
250
  if (!gqlPath) {
154
251
  throw new Error("could not find graphql path");
155
252
  }
156
- const r = require(gqlPath);
157
- if (!r.GQLCapture) {
158
- throw new Error("could not find GQLCapture in module");
253
+ // use different variable so that we use the correct GQLCapture as needed
254
+ // for local dev, get the one from the file system. otherwise, get the one
255
+ // from node_modules
256
+ let gqlCapture;
257
+ if (process.env.LOCAL_SCRIPT_PATH) {
258
+ const r = require("../graphql/graphql");
259
+ gqlCapture = r.GQLCapture;
260
+ }
261
+ else {
262
+ const r = require(gqlPath);
263
+ if (!r.GQLCapture) {
264
+ throw new Error("could not find GQLCapture in module");
265
+ }
266
+ gqlCapture = r.GQLCapture;
267
+ gqlCapture.enable(true);
159
268
  }
160
- const GQLCapture = r.GQLCapture;
161
- GQLCapture.enable(true);
162
269
  const [inputsRead, _, imports] = await Promise.all([
163
270
  readInputs(),
164
- captureCustom(options.path, options.files),
271
+ captureCustom(options.path, options.files, options.json_path, gqlCapture),
165
272
  parseImports(options.path),
166
273
  ]);
167
274
  const { nodes, nodesMap } = inputsRead;
@@ -172,14 +279,14 @@ async function main() {
172
279
  }
173
280
  return result;
174
281
  }
175
- GQLCapture.resolve(nodes);
176
- let args = fromMap(GQLCapture.getCustomArgs());
177
- let inputs = fromMap(GQLCapture.getCustomInputObjects());
178
- let fields = GQLCapture.getProcessedCustomFields();
179
- let queries = GQLCapture.getProcessedCustomQueries();
180
- let mutations = GQLCapture.getProcessedCustomMutations();
181
- let objects = fromMap(GQLCapture.getCustomObjects());
182
- let customTypes = fromMap(GQLCapture.getCustomTypes());
282
+ gqlCapture.resolve(nodes);
283
+ let args = fromMap(gqlCapture.getCustomArgs());
284
+ let inputs = fromMap(gqlCapture.getCustomInputObjects());
285
+ let fields = gqlCapture.getProcessedCustomFields();
286
+ let queries = gqlCapture.getProcessedCustomQueries();
287
+ let mutations = gqlCapture.getProcessedCustomMutations();
288
+ let objects = fromMap(gqlCapture.getCustomObjects());
289
+ let customTypes = fromMap(gqlCapture.getCustomTypes());
183
290
  let classes = {};
184
291
  let allFiles = {};
185
292
  const buildClasses2 = (args) => {
@@ -149,6 +149,11 @@ class SimpleBuilder {
149
149
  editedFields: () => {
150
150
  return this.fields;
151
151
  },
152
+ updateInput: (input) => {
153
+ for (const k in input) {
154
+ this.fields.set(k, input[k]);
155
+ }
156
+ },
152
157
  });
153
158
  }
154
159
  build() {