@snowtop/ent 0.0.27 → 0.0.29

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.
@@ -27,9 +27,8 @@ export interface Changeset<T extends Ent> {
27
27
  executor(): Executor;
28
28
  viewer: Viewer;
29
29
  placeholderID: ID;
30
- ent: EntConstructor<T>;
31
30
  changesets?: Changeset<Ent>[];
32
- dependencies?: Map<ID, Builder<T>>;
31
+ dependencies?: Map<ID, Builder<Ent>>;
33
32
  }
34
33
  export declare type TriggerReturn = void | Promise<Changeset<Ent> | void | (Changeset<Ent> | void)[]> | Promise<Changeset<Ent>>[];
35
34
  export interface Trigger<T extends Ent> {
@@ -1,22 +1,21 @@
1
- import { ID, Data, Ent, Viewer, EntConstructor, Context } from "../core/base";
1
+ import { ID, Data, Ent, Viewer, Context } from "../core/base";
2
2
  import { DataOperation } from "../core/ent";
3
- import { Changeset, Executor } from "../action";
3
+ import { Changeset, Executor } from "../action/action";
4
4
  import { Builder } from "../action";
5
5
  import { OrchestratorOptions } from "./orchestrator";
6
6
  import { Queryer } from "../core/db";
7
7
  export declare class ListBasedExecutor<T extends Ent> implements Executor {
8
8
  private viewer;
9
9
  placeholderID: ID;
10
- private ent;
11
10
  private operations;
12
11
  private options?;
13
12
  private idx;
14
- constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], options?: OrchestratorOptions<T, Data> | undefined);
13
+ constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation<T>[], options?: OrchestratorOptions<T, Data> | undefined);
15
14
  private lastOp;
16
15
  private createdEnt;
17
16
  resolveValue(val: ID): Ent | null;
18
17
  [Symbol.iterator](): this;
19
- next(): IteratorResult<DataOperation>;
18
+ next(): IteratorResult<DataOperation<T>>;
20
19
  executeObservers(): Promise<void>;
21
20
  execute(): Promise<void>;
22
21
  preFetch?(queryer: Queryer, context: Context): Promise<void>;
@@ -25,23 +24,19 @@ export declare class ListBasedExecutor<T extends Ent> implements Executor {
25
24
  export declare class ComplexExecutor<T extends Ent> implements Executor {
26
25
  private viewer;
27
26
  placeholderID: ID;
28
- private ent;
29
- private options?;
30
27
  private idx;
31
28
  private mapper;
32
29
  private lastOp;
33
30
  private allOperations;
34
- private changesetMap;
35
- private nodeOpMap;
36
31
  private executors;
37
- constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset<T>[], options?: OrchestratorOptions<T, Data> | undefined);
32
+ constructor(viewer: Viewer, placeholderID: ID, operations: DataOperation[], dependencies: Map<ID, Builder<T>>, changesets: Changeset<T>[], options?: OrchestratorOptions<T, Data>);
38
33
  [Symbol.iterator](): this;
39
34
  private handleCreatedEnt;
40
- next(): IteratorResult<DataOperation>;
35
+ next(): IteratorResult<DataOperation<Ent>>;
41
36
  resolveValue(val: ID): Ent | null;
42
37
  executeObservers(): Promise<void>;
43
38
  execute(): Promise<void>;
44
39
  preFetch?(queryer: Queryer, context: Context): Promise<void>;
45
40
  postFetch?(queryer: Queryer, context: Context): Promise<void>;
46
41
  }
47
- export declare function executeOperations(executor: Executor, context?: Context, trackOps?: true): Promise<DataOperation[]>;
42
+ export declare function executeOperations(executor: Executor, context?: Context, trackOps?: true): Promise<DataOperation<Ent>[]>;
@@ -9,10 +9,9 @@ const db_1 = __importDefault(require("../core/db"));
9
9
  const logger_1 = require("../core/logger");
10
10
  // private to ent
11
11
  class ListBasedExecutor {
12
- constructor(viewer, placeholderID, ent, operations, options) {
12
+ constructor(viewer, placeholderID, operations, options) {
13
13
  this.viewer = viewer;
14
14
  this.placeholderID = placeholderID;
15
- this.ent = ent;
16
15
  this.operations = operations;
17
16
  this.options = options;
18
17
  this.idx = 0;
@@ -27,8 +26,9 @@ class ListBasedExecutor {
27
26
  [Symbol.iterator]() {
28
27
  return this;
29
28
  }
29
+ // returns true and null|undefined when done
30
30
  next() {
31
- let createdEnt = getCreatedEnt(this.viewer, this.lastOp, this.ent);
31
+ let createdEnt = getCreatedEnt(this.viewer, this.lastOp);
32
32
  if (createdEnt) {
33
33
  this.createdEnt = createdEnt;
34
34
  }
@@ -36,6 +36,10 @@ class ListBasedExecutor {
36
36
  const op = this.operations[this.idx];
37
37
  this.idx++;
38
38
  this.lastOp = op;
39
+ // reset since this could be called multiple times. not needed if we have getSortedOps or something like that
40
+ if (done) {
41
+ this.idx = 0;
42
+ }
39
43
  return {
40
44
  value: op,
41
45
  done: done,
@@ -74,30 +78,24 @@ class ListBasedExecutor {
74
78
  }
75
79
  }
76
80
  exports.ListBasedExecutor = ListBasedExecutor;
77
- function getCreatedEnt(viewer, op, ent) {
78
- if (op && op.returnedEntRow) {
79
- let row = op.returnedEntRow();
80
- if (row) {
81
- return new ent(viewer, row);
82
- }
81
+ function getCreatedEnt(viewer, op) {
82
+ if (op && op.createdEnt) {
83
+ return op.createdEnt(viewer);
83
84
  }
84
85
  return null;
85
86
  }
86
87
  class ComplexExecutor {
87
- constructor(viewer, placeholderID, ent, operations, dependencies, changesets, options) {
88
+ constructor(viewer, placeholderID, operations, dependencies, changesets, options) {
88
89
  this.viewer = viewer;
89
90
  this.placeholderID = placeholderID;
90
- this.ent = ent;
91
- this.options = options;
92
91
  this.idx = 0;
93
92
  this.mapper = new Map();
94
93
  this.allOperations = [];
95
- this.changesetMap = new Map();
96
- this.nodeOpMap = new Map();
97
94
  this.executors = [];
98
95
  let graph = (0, graph_data_structure_1.default)();
96
+ const changesetMap = new Map();
99
97
  const impl = (c) => {
100
- this.changesetMap.set(c.placeholderID.toString(), c);
98
+ changesetMap.set(c.placeholderID.toString(), c);
101
99
  graph.addNode(c.placeholderID.toString());
102
100
  if (c.dependencies) {
103
101
  for (let [key, builder] of c.dependencies) {
@@ -117,20 +115,19 @@ class ComplexExecutor {
117
115
  impl({
118
116
  viewer: this.viewer,
119
117
  placeholderID: this.placeholderID,
120
- ent: this.ent,
121
118
  changesets: changesets,
122
119
  dependencies: dependencies,
123
120
  executor: () => {
124
- return new ListBasedExecutor(this.viewer, this.placeholderID, this.ent, operations, this.options);
121
+ return new ListBasedExecutor(this.viewer, this.placeholderID, operations, options);
125
122
  },
126
123
  });
127
124
  // use a set to handle repeated ops because of how the executor logic currently works
128
- // TODO: this logic can be rewritten to be smarter and probably not need a set
125
+ // TODO: can this logic be rewritten to not have a set yet avoid duplicates?
129
126
  let nodeOps = new Set();
130
127
  let remainOps = new Set();
131
128
  let sorted = graph.topologicalSort(graph.nodes());
132
129
  sorted.forEach((node) => {
133
- let c = this.changesetMap.get(node);
130
+ let c = changesetMap.get(node);
134
131
  if (!c) {
135
132
  // phew. expect it to be handled somewhere else
136
133
  // we can just skip it and expect the resolver to handle this correctly
@@ -143,9 +140,8 @@ class ComplexExecutor {
143
140
  // get ordered list of ops
144
141
  let executor = c.executor();
145
142
  for (let op of executor) {
146
- if (op.returnedEntRow) {
143
+ if (op.createdEnt) {
147
144
  nodeOps.add(op);
148
- this.nodeOpMap.set(op, c);
149
145
  }
150
146
  else {
151
147
  remainOps.add(op);
@@ -165,26 +161,30 @@ class ComplexExecutor {
165
161
  return this;
166
162
  }
167
163
  handleCreatedEnt() {
168
- let c = this.nodeOpMap.get(this.lastOp);
169
- if (!c) {
170
- // nothing to do here
164
+ if (!this.lastOp) {
171
165
  return;
172
166
  }
173
- let createdEnt = getCreatedEnt(this.viewer, this.lastOp, c.ent);
167
+ let createdEnt = getCreatedEnt(this.viewer, this.lastOp);
174
168
  if (!createdEnt) {
175
169
  return;
176
170
  }
177
- let placeholderID = c.placeholderID;
171
+ const placeholderID = this.lastOp.placeholderID;
172
+ if (!placeholderID) {
173
+ console.error(`op ${this.lastOp} which implements getCreatedEnt doesn't have a placeholderID`);
174
+ return;
175
+ }
178
176
  this.mapper.set(placeholderID, createdEnt);
179
177
  }
180
178
  next() {
181
- if (this.lastOp) {
182
- this.handleCreatedEnt();
183
- }
179
+ this.handleCreatedEnt();
184
180
  const done = this.idx === this.allOperations.length;
185
181
  const op = this.allOperations[this.idx];
186
182
  this.idx++;
187
183
  this.lastOp = op;
184
+ // reset since this could be called multiple times. not needed if we have getSortedOps or something like that
185
+ if (done) {
186
+ this.idx = 0;
187
+ }
188
188
  return {
189
189
  value: op,
190
190
  done: done,
@@ -195,6 +195,12 @@ class ComplexExecutor {
195
195
  if (ent) {
196
196
  return ent;
197
197
  }
198
+ for (const c of this.executors) {
199
+ const ent = c.resolveValue(val);
200
+ if (ent) {
201
+ return ent;
202
+ }
203
+ }
198
204
  return null;
199
205
  }
200
206
  async executeObservers() {
package/action/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { WriteOperation, Builder, Executor, Changeset, Trigger, Observer, Validator, Action, saveBuilder, saveBuilderX, setEdgeTypeInGroup, TriggerReturn, } from "./action";
1
+ export { WriteOperation, Builder, Changeset, Trigger, Observer, Validator, Action, saveBuilder, saveBuilderX, setEdgeTypeInGroup, TriggerReturn, } from "./action";
2
2
  export { OrchestratorOptions, Orchestrator, EntChangeset, EdgeInputData, } from "./orchestrator";
3
3
  export { DenyIfBuilder, AllowIfBuilder } from "./privacy";
@@ -1,7 +1,7 @@
1
1
  import { ID, Data, Ent, Viewer, EntConstructor, LoadEntOptions } from "../core/base";
2
2
  import { AssocEdgeInputOptions, DataOperation } from "../core/ent";
3
3
  import { SchemaInputType } from "../schema/schema";
4
- import { Changeset, Executor } from "../action";
4
+ import { Changeset, Executor } from "../action/action";
5
5
  import { WriteOperation, Builder, Action } from "../action";
6
6
  export interface OrchestratorOptions<T extends Ent, TData extends Data> {
7
7
  viewer: Viewer;
@@ -64,7 +64,7 @@ export declare class Orchestrator<T extends Ent> {
64
64
  validX(): Promise<void>;
65
65
  build(): Promise<EntChangeset<T>>;
66
66
  private viewerForEntLoad;
67
- returnedRow(): Promise<Data | null>;
67
+ private returnedRow;
68
68
  editedEnt(): Promise<T | null>;
69
69
  editedEntX(): Promise<T>;
70
70
  }
@@ -73,10 +73,11 @@ export declare class EntChangeset<T extends Ent> implements Changeset<T> {
73
73
  readonly placeholderID: ID;
74
74
  readonly ent: EntConstructor<T>;
75
75
  operations: DataOperation[];
76
- dependencies?: Map<ID, Builder<T>> | undefined;
76
+ dependencies?: Map<ID, Builder<Ent>> | undefined;
77
77
  changesets?: Changeset<Ent>[] | undefined;
78
78
  private options?;
79
- constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<T>> | undefined, changesets?: Changeset<Ent>[] | undefined, options?: OrchestratorOptions<T, Data> | undefined);
79
+ private _executor;
80
+ constructor(viewer: Viewer, placeholderID: ID, ent: EntConstructor<T>, operations: DataOperation[], dependencies?: Map<ID, Builder<Ent>> | undefined, changesets?: Changeset<Ent>[] | undefined, options?: OrchestratorOptions<T, Data> | undefined);
80
81
  executor(): Executor;
81
82
  }
82
83
  export {};
@@ -146,6 +146,8 @@ class Orchestrator {
146
146
  tableName: this.options.tableName,
147
147
  fieldsToResolve: this.fieldsToResolve,
148
148
  key: this.options.key,
149
+ ent: this.options.loaderOptions.ent,
150
+ placeholderID: this.options.builder.placeholderID,
149
151
  };
150
152
  if (this.logValues) {
151
153
  opts.fieldsToLog = this.logValues;
@@ -432,8 +434,8 @@ class Orchestrator {
432
434
  return action.viewerForEntLoad(data);
433
435
  }
434
436
  async returnedRow() {
435
- if (this.mainOp && this.mainOp.returnedEntRow) {
436
- return this.mainOp.returnedEntRow();
437
+ if (this.mainOp && this.mainOp.returnedRow) {
438
+ return this.mainOp.returnedRow();
437
439
  }
438
440
  return null;
439
441
  }
@@ -475,13 +477,17 @@ class EntChangeset {
475
477
  this.options = options;
476
478
  }
477
479
  executor() {
478
- // TODO: write comment here similar to go
479
- // if we have dependencies but no changesets, we just need a simple
480
- // executor and depend on something else in the stack to handle this correctly
481
- if (this.changesets?.length) {
482
- return new executor_1.ComplexExecutor(this.viewer, this.placeholderID, this.ent, this.operations, this.dependencies, this.changesets, this.options);
480
+ if (this._executor) {
481
+ return this._executor;
483
482
  }
484
- return new executor_1.ListBasedExecutor(this.viewer, this.placeholderID, this.ent, this.operations, this.options);
483
+ if (!this.changesets?.length) {
484
+ // if we have dependencies but no changesets, we just need a simple
485
+ // executor and depend on something else in the stack to handle this correctly
486
+ // ComplexExecutor which could be a parent of this should make sure the dependency
487
+ // is resolved beforehand
488
+ return (this._executor = new executor_1.ListBasedExecutor(this.viewer, this.placeholderID, this.operations, this.options));
489
+ }
490
+ return (this._executor = new executor_1.ComplexExecutor(this.viewer, this.placeholderID, this.operations, this.dependencies || new Map(), this.changesets || [], this.options));
485
491
  }
486
492
  }
487
493
  exports.EntChangeset = EntChangeset;
package/core/clause.js CHANGED
@@ -177,7 +177,7 @@ function Or(...args) {
177
177
  return new compositeClause(args, " OR ");
178
178
  }
179
179
  exports.Or = Or;
180
- // todo?
180
+ // TODO this breaks if values.length ===1 and array. todo fix
181
181
  function In(col, ...values) {
182
182
  return new inClause(col, values);
183
183
  }
package/core/ent.d.ts CHANGED
@@ -1,6 +1,6 @@
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 } from "./base";
3
- import { Executor } from "../action";
2
+ import { Viewer, Ent, ID, LoadRowsOptions, LoadRowOptions, Data, DataOptions, QueryableDataOptions, EditRowOptions, LoadEntOptions, LoadCustomEntOptions, EdgeQueryableDataOptions, Context, SelectBaseDataOptions, CreateRowOptions, QueryDataOptions, EntConstructor } from "./base";
3
+ import { Executor } from "../action/action";
4
4
  import * as clause from "./clause";
5
5
  import { Builder } from "../action";
6
6
  import DataLoader from "dataloader";
@@ -39,27 +39,33 @@ interface GroupQueryOptions {
39
39
  limit: number;
40
40
  }
41
41
  export declare function buildGroupQuery(options: GroupQueryOptions): [string, clause.Clause];
42
- export interface DataOperation {
42
+ export interface DataOperation<T extends Ent = Ent> {
43
43
  preFetch?(queryer: Queryer, context?: Context): Promise<void>;
44
44
  performWriteSync(queryer: SyncQueryer, context?: Context): void;
45
45
  performWrite(queryer: Queryer, context?: Context): Promise<void>;
46
- returnedEntRow?(): Data | null;
46
+ placeholderID?: ID;
47
+ returnedRow?(): Data | null;
48
+ createdEnt?(viewer: Viewer): T | null;
47
49
  resolve?(executor: Executor): void;
48
50
  postFetch?(queryer: Queryer, context?: Context): Promise<void>;
49
51
  }
50
- export interface EditNodeOptions extends EditRowOptions {
52
+ export interface EditNodeOptions<T extends Ent> extends EditRowOptions {
51
53
  fieldsToResolve: string[];
54
+ ent: EntConstructor<T>;
55
+ placeholderID?: ID;
52
56
  }
53
- export declare class EditNodeOperation implements DataOperation {
54
- options: EditNodeOptions;
57
+ export declare class EditNodeOperation<T extends Ent> implements DataOperation {
58
+ options: EditNodeOptions<T>;
55
59
  private existingEnt;
56
60
  row: Data | null;
57
- constructor(options: EditNodeOptions, existingEnt?: Ent | null);
61
+ placeholderID?: ID | undefined;
62
+ constructor(options: EditNodeOptions<T>, existingEnt?: Ent | null);
58
63
  resolve<T extends Ent>(executor: Executor): void;
59
64
  performWrite(queryer: Queryer, context?: Context): Promise<void>;
60
- reloadRow(queryer: SyncQueryer, id: ID, options: EditNodeOptions): void;
65
+ private reloadRow;
61
66
  performWriteSync(queryer: SyncQueryer, context?: Context): void;
62
- returnedEntRow(): Data | null;
67
+ returnedRow(): Data | null;
68
+ createdEnt(viewer: Viewer): T | null;
63
69
  }
64
70
  export declare class EdgeOperation implements DataOperation {
65
71
  edgeInput: AssocEdgeInput;
package/core/ent.js CHANGED
@@ -401,6 +401,7 @@ class EditNodeOperation {
401
401
  constructor(options, existingEnt = null) {
402
402
  this.options = options;
403
403
  this.existingEnt = existingEnt;
404
+ this.placeholderID = options.placeholderID;
404
405
  }
405
406
  resolve(executor) {
406
407
  if (!this.options.fieldsToResolve.length) {
@@ -463,9 +464,15 @@ class EditNodeOperation {
463
464
  this.reloadRow(queryer, id, options);
464
465
  }
465
466
  }
466
- returnedEntRow() {
467
+ returnedRow() {
467
468
  return this.row;
468
469
  }
470
+ createdEnt(viewer) {
471
+ if (!this.row) {
472
+ return null;
473
+ }
474
+ return new this.options.ent(viewer, this.row);
475
+ }
469
476
  }
470
477
  exports.EditNodeOperation = EditNodeOperation;
471
478
  class EdgeOperation {
@@ -5,6 +5,7 @@ const graphql_1 = require("graphql");
5
5
  const node_1 = require("./node");
6
6
  const edge_1 = require("./edge");
7
7
  const page_info_1 = require("../query/page_info");
8
+ // NB: if this changes, need to update renderer.go also
8
9
  exports.GraphQLConnectionInterface = new graphql_1.GraphQLInterfaceType({
9
10
  name: "Connection",
10
11
  description: "connection interface",
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GraphQLEdgeInterface = void 0;
4
4
  const graphql_1 = require("graphql");
5
5
  const node_1 = require("./node");
6
+ // NB: if this changes, need to update renderer.go also
6
7
  exports.GraphQLEdgeInterface = new graphql_1.GraphQLInterfaceType({
7
8
  name: "Edge",
8
9
  description: "edge interface",
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GraphQLNodeInterface = void 0;
4
4
  const graphql_1 = require("graphql");
5
+ // NB: if this changes, need to update renderer.go also
5
6
  exports.GraphQLNodeInterface = new graphql_1.GraphQLInterfaceType({
6
7
  name: "Node",
7
8
  description: "node interface",
@@ -8,6 +8,7 @@ export interface CustomType {
8
8
  importPath: string;
9
9
  tsType?: string;
10
10
  tsImportPath?: string;
11
+ [x: string]: any;
11
12
  }
12
13
  declare type Type = GraphQLScalarType | ClassType | string | CustomType;
13
14
  export declare type GraphQLConnection<T> = {
@@ -81,6 +82,7 @@ declare enum NullableResult {
81
82
  CONTENTS_AND_LIST = "contentsAndList",
82
83
  ITEM = "true"
83
84
  }
85
+ export declare const addCustomType: (type: CustomType) => void;
84
86
  export declare class GQLCapture {
85
87
  private static enabled;
86
88
  static enable(enabled: boolean): void;
@@ -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.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.CustomFieldType = void 0;
4
4
  require("reflect-metadata");
5
5
  // export interface gqlTopLevelOptions
6
6
  // name?: string;
@@ -20,6 +20,88 @@ var NullableResult;
20
20
  NullableResult["CONTENTS_AND_LIST"] = "contentsAndList";
21
21
  NullableResult["ITEM"] = "true";
22
22
  })(NullableResult || (NullableResult = {}));
23
+ const isArray = (type) => {
24
+ if (typeof type === "function") {
25
+ return false;
26
+ }
27
+ return type.push !== undefined;
28
+ };
29
+ const isConnection = (type) => {
30
+ if (typeof type !== "object") {
31
+ return false;
32
+ }
33
+ return type.node !== undefined;
34
+ };
35
+ const isString = (type) => {
36
+ if (type.lastIndexOf !== undefined) {
37
+ return true;
38
+ }
39
+ return false;
40
+ };
41
+ const isCustomType = (type) => {
42
+ return type.importPath !== undefined;
43
+ };
44
+ const isGraphQLScalarType = (type) => {
45
+ return type.serialize !== undefined;
46
+ };
47
+ const addCustomType = (type) => {
48
+ // TODO these should return ReadOnly objects...
49
+ const customType = GQLCapture.getCustomTypes().get(type.type);
50
+ if (customType && customType !== type) {
51
+ throw new Error(`cannot add multiple custom types of name ${type.type}`);
52
+ }
53
+ if (customType) {
54
+ return;
55
+ }
56
+ try {
57
+ const r = require(type.importPath);
58
+ const ct = r[type.type];
59
+ // this gets us the information needed for scalars
60
+ if (ct && isGraphQLScalarType(ct)) {
61
+ type.scalarInfo = {
62
+ description: ct.description,
63
+ name: ct.name,
64
+ };
65
+ if (ct.specifiedByUrl) {
66
+ type.scalarInfo.specifiedByUrl = ct.specifiedByUrl;
67
+ }
68
+ }
69
+ }
70
+ catch (e) {
71
+ return;
72
+ }
73
+ GQLCapture.getCustomTypes().set(type.type, type);
74
+ };
75
+ exports.addCustomType = addCustomType;
76
+ const getType = (typ, result) => {
77
+ if (isConnection(typ)) {
78
+ result.connection = true;
79
+ return getType(typ.node, result);
80
+ }
81
+ if (isArray(typ)) {
82
+ result.list = true;
83
+ return getType(typ[0], result);
84
+ }
85
+ if (isString(typ)) {
86
+ if (typ.lastIndexOf("]") !== -1) {
87
+ result.list = true;
88
+ result.type = typ.substr(1, typ.length - 2);
89
+ }
90
+ else {
91
+ result.type = typ;
92
+ }
93
+ return;
94
+ }
95
+ if (isCustomType(typ)) {
96
+ result.type = typ.type;
97
+ (0, exports.addCustomType)(typ);
98
+ return;
99
+ }
100
+ // GraphQLScalarType or ClassType
101
+ result.scalarType = isGraphQLScalarType(typ);
102
+ result.type = typ.name;
103
+ return;
104
+ };
23
105
  class GQLCapture {
24
106
  static enable(enabled) {
25
107
  this.enabled = enabled;
@@ -104,66 +186,6 @@ class GQLCapture {
104
186
  if ((type === "Number" || type === "Object") && !options?.type) {
105
187
  throw new Error(`type is required when accessor/function/property returns a ${type}`);
106
188
  }
107
- const isArray = (type) => {
108
- if (typeof type === "function") {
109
- return false;
110
- }
111
- return type.push !== undefined;
112
- };
113
- const isConnection = (type) => {
114
- if (typeof type !== "object") {
115
- return false;
116
- }
117
- return type.node !== undefined;
118
- };
119
- const isString = (type) => {
120
- if (type.lastIndexOf !== undefined) {
121
- return true;
122
- }
123
- return false;
124
- };
125
- const isCustomType = (type) => {
126
- return type.importPath !== undefined;
127
- };
128
- const isGraphQLScalarType = (type) => {
129
- return type.serialize !== undefined;
130
- };
131
- const addCustomType = (type) => {
132
- const customType = this.customTypes.get(type.type);
133
- if (customType && customType !== type) {
134
- throw new Error(`cannot add multiple custom types of name ${type.type}`);
135
- }
136
- this.customTypes.set(type.type, type);
137
- };
138
- const getType = (typ, result) => {
139
- if (isConnection(typ)) {
140
- result.connection = true;
141
- return getType(typ.node, result);
142
- }
143
- if (isArray(typ)) {
144
- result.list = true;
145
- return getType(typ[0], result);
146
- }
147
- if (isString(typ)) {
148
- if (typ.lastIndexOf("]") !== -1) {
149
- result.list = true;
150
- result.type = typ.substr(1, typ.length - 2);
151
- }
152
- else {
153
- result.type = typ;
154
- }
155
- return;
156
- }
157
- if (isCustomType(typ)) {
158
- result.type = typ.type;
159
- addCustomType(typ);
160
- return;
161
- }
162
- // GraphQLScalarType or ClassType
163
- result.scalarType = isGraphQLScalarType(typ);
164
- result.type = typ.name;
165
- return;
166
- };
167
189
  let list;
168
190
  let scalarType = false;
169
191
  let connection;
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GraphQLPageInfo = void 0;
4
4
  const graphql_1 = require("graphql");
5
+ // NB: if this changes, need to update renderer.go also
5
6
  exports.GraphQLPageInfo = new graphql_1.GraphQLObjectType({
6
7
  name: "PageInfo",
7
8
  fields: () => ({
@@ -10,7 +10,7 @@ interface classResult {
10
10
  class: classInfo;
11
11
  file: file;
12
12
  }
13
- export declare function parseCustomInput(filePath: string, opts?: Options): PathResult;
13
+ export declare function parseCustomImports(filePath: string, opts?: Options): PathResult;
14
14
  export declare function findTSConfigFile(filePath: string): string | null;
15
15
  export interface importInfo {
16
16
  name: string;
package/imports/index.js CHANGED
@@ -22,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
22
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
23
23
  };
24
24
  Object.defineProperty(exports, "__esModule", { value: true });
25
- exports.findTSConfigFile = exports.parseCustomInput = void 0;
25
+ exports.findTSConfigFile = exports.parseCustomImports = void 0;
26
26
  const glob_1 = __importDefault(require("glob"));
27
27
  const typescript_1 = __importDefault(require("typescript"));
28
28
  const json5_1 = __importDefault(require("json5"));
@@ -42,10 +42,9 @@ function getFiles(filePath, opts) {
42
42
  }
43
43
  return files;
44
44
  }
45
- function parseCustomInput(filePath, opts) {
45
+ function parseCustomImports(filePath, opts) {
46
46
  const files = getFiles(filePath, opts);
47
47
  const options = readCompilerOptions(filePath);
48
- // classMap
49
48
  let classMap = new Map();
50
49
  files.forEach((file) => {
51
50
  const sourceFile = typescript_1.default.createSourceFile(file, fs.readFileSync(file).toString(), options.target || typescript_1.default.ScriptTarget.ES2015);
@@ -77,7 +76,7 @@ function parseCustomInput(filePath, opts) {
77
76
  },
78
77
  };
79
78
  }
80
- exports.parseCustomInput = parseCustomInput;
79
+ exports.parseCustomImports = parseCustomImports;
81
80
  function findTSConfigFile(filePath) {
82
81
  while (filePath != "/") {
83
82
  let configPath = `${filePath}/tsconfig.json`;
@@ -95,7 +94,6 @@ function readCompilerOptions(filePath) {
95
94
  if (!configPath) {
96
95
  return {};
97
96
  }
98
- const root = path.join(filePath, "..");
99
97
  let json = {};
100
98
  try {
101
99
  json = json5_1.default.parse(fs.readFileSync(configPath, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowtop/ent",
3
- "version": "0.0.27",
3
+ "version": "0.0.29",
4
4
  "description": "snowtop ent framework",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -39,7 +39,7 @@
39
39
  }
40
40
  },
41
41
  "engines": {
42
- "node": "^16.1.0"
42
+ "node": ">=14.0"
43
43
  },
44
44
  "devDependencies": {},
45
45
  "scripts": {},
File without changes
@@ -25,6 +25,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  const glob_1 = __importDefault(require("glob"));
27
27
  const minimist_1 = __importDefault(require("minimist"));
28
+ const graphql_1 = require("../graphql/graphql");
28
29
  const readline = __importStar(require("readline"));
29
30
  const path = __importStar(require("path"));
30
31
  const fs = __importStar(require("fs"));
@@ -52,7 +53,17 @@ async function readInputs() {
52
53
  });
53
54
  });
54
55
  }
55
- async function captureCustom(filePath) {
56
+ async function captureCustom(filePath, filesCsv) {
57
+ if (filesCsv !== undefined) {
58
+ let files = filesCsv.split(",");
59
+ for (let i = 0; i < files.length; i++) {
60
+ // TODO fix. we have "src" in the path we get here
61
+ files[i] = path.join(filePath, "..", files[i]);
62
+ }
63
+ await requireFiles(files);
64
+ return;
65
+ }
66
+ // TODO delete all of this eventually
56
67
  // TODO configurable paths eventually
57
68
  // for now only files that are in the include path of the roots are allowed
58
69
  const rootFiles = [
@@ -81,18 +92,28 @@ async function captureCustom(filePath) {
81
92
  ignore: ignore,
82
93
  });
83
94
  const files = rootFiles.concat(customGQLResolvers, customGQLMutations);
84
- //console.log(files);
85
- let promises = [];
86
- files.forEach((file) => {
95
+ await requireFiles(files);
96
+ }
97
+ async function requireFiles(files) {
98
+ await Promise.all(files.map(async (file) => {
87
99
  if (fs.existsSync(file)) {
88
- promises.push(require(file));
100
+ try {
101
+ await require(file);
102
+ }
103
+ catch (e) {
104
+ throw new Error(`${e.message} loading ${file}`);
105
+ }
106
+ }
107
+ else {
108
+ throw new Error(`file ${file} doesn't exist`);
89
109
  }
110
+ })).catch((err) => {
111
+ throw new Error(err);
90
112
  });
91
- await Promise.all(promises);
92
113
  }
93
114
  async function parseImports(filePath) {
94
115
  // only do graphql files...
95
- return (0, imports_1.parseCustomInput)(path.join(filePath, "graphql"), {
116
+ return (0, imports_1.parseCustomImports)(path.join(filePath, "graphql"), {
96
117
  ignore: ["**/generated/**", "**/tests/**"],
97
118
  });
98
119
  }
@@ -110,6 +131,20 @@ function findGraphQLPath(filePath) {
110
131
  return undefined;
111
132
  }
112
133
  async function main() {
134
+ // known custom types that are not required
135
+ // if not in the schema, will be ignored
136
+ // something like GraphQLUpload gotten via gqlArg({type: gqlFileUpload})
137
+ // these 2 need this because they're added by the schema
138
+ // if this list grows too long, need to build this into golang types and passed here
139
+ // TODO foreign non-scalars eventually
140
+ (0, graphql_1.addCustomType)({
141
+ importPath: "../graphql/scalars/time",
142
+ type: "GraphQLTime",
143
+ });
144
+ (0, graphql_1.addCustomType)({
145
+ importPath: "graphql-type-json",
146
+ type: "GraphQLJSON",
147
+ });
113
148
  const options = (0, minimist_1.default)(process.argv.slice(2));
114
149
  if (!options.path) {
115
150
  throw new Error("path required");
@@ -126,7 +161,7 @@ async function main() {
126
161
  GQLCapture.enable(true);
127
162
  const [inputsRead, _, imports] = await Promise.all([
128
163
  readInputs(),
129
- captureCustom(options.path),
164
+ captureCustom(options.path, options.files),
130
165
  parseImports(options.path),
131
166
  ]);
132
167
  const { nodes, nodesMap } = inputsRead;
@@ -93,7 +93,7 @@ export declare class SimpleAction<T extends Ent> implements Action<T> {
93
93
  viewerForEntLoad: viewerEntLoadFunc | undefined;
94
94
  constructor(viewer: Viewer, schema: BuilderSchema<T>, fields: Map<string, any>, operation?: WriteOperation, existingEnt?: T | undefined);
95
95
  getPrivacyPolicy(): import("../core/base").PrivacyPolicy;
96
- getInput(): Map<string, any>;
96
+ getInput(): Data;
97
97
  changeset(): Promise<Changeset<T>>;
98
98
  valid(): Promise<boolean>;
99
99
  validX(): Promise<void>;
@@ -185,7 +185,11 @@ class SimpleAction {
185
185
  return privacy_1.AlwaysAllowPrivacyPolicy;
186
186
  }
187
187
  getInput() {
188
- return this.fields;
188
+ const ret = {};
189
+ for (const [k, v] of this.fields) {
190
+ ret[k] = v;
191
+ }
192
+ return ret;
189
193
  }
190
194
  changeset() {
191
195
  return this.builder.build();
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.QueryRecorder = exports.queryType = void 0;
4
4
  const uuid_1 = require("uuid");
5
- const utils_1 = require("ts-jest/utils");
5
+ const jest_mock_1 = require("jest-mock");
6
6
  const parse_sql_1 = require("./parse_sql");
7
7
  const eventEmitter = {
8
8
  on: jest.fn(),
@@ -185,7 +185,7 @@ class QueryRecorder {
185
185
  }
186
186
  }
187
187
  static mockPool(pool) {
188
- const mockedPool = (0, utils_1.mocked)(pool, true);
188
+ const mockedPool = (0, jest_mock_1.mocked)(pool, true);
189
189
  mockedPool.mockImplementation(() => {
190
190
  return {
191
191
  totalCount: 1,
@@ -286,11 +286,11 @@ async function expectFromRoot(config, ...options) {
286
286
  let fields = query?.getFields();
287
287
  if (!fields) {
288
288
  // TODO custom error?
289
- fail("schema doesn't have query or fields");
289
+ throw new Error("schema doesn't have query or fields");
290
290
  }
291
291
  let field = fields[config.root];
292
292
  if (!field) {
293
- fail(`could not find field ${config.root} in GraphQL query schema`);
293
+ throw new Error(`could not find field ${config.root} in GraphQL query schema`);
294
294
  }
295
295
  let fieldArgs = field.args;
296
296
  let queryParams = [];
@@ -361,7 +361,7 @@ async function expectFromRoot(config, ...options) {
361
361
  expect(errors[0].message).toMatch(config.expectedError);
362
362
  }
363
363
  else {
364
- fail(`unhandled error ${JSON.stringify(errors)}`);
364
+ throw new Error(`unhandled error ${JSON.stringify(errors)}`);
365
365
  }
366
366
  return st;
367
367
  }
@@ -416,7 +416,7 @@ async function expectFromRoot(config, ...options) {
416
416
  if (idx !== -1) {
417
417
  let endIdx = part.indexOf("]");
418
418
  if (endIdx === -1) {
419
- fail("can't have a beginning index without an end index");
419
+ throw new Error("can't have a beginning index without an end index");
420
420
  }
421
421
  // get the idx we care about
422
422
  listIdx = parseInt(part.substr(idx + 1, endIdx - idx), 10);
@@ -428,7 +428,7 @@ async function expectFromRoot(config, ...options) {
428
428
  if (idx !== -1) {
429
429
  let endIdx = part.indexOf(")");
430
430
  if (endIdx === -1) {
431
- fail("can't have a beginning index without an end index");
431
+ throw new Error("can't have a beginning index without an end index");
432
432
  }
433
433
  // update part
434
434
  part = part.substr(0, idx);
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAllEvents = exports.tempDBTables = exports.setupTempDB = exports.createTestEvent = exports.edgeTableNames = exports.createEdges = exports.verifyUserToContacts = exports.verifyUserToContactRawData = exports.verifyUserToContactEdges = exports.addEdge = exports.createUserPlusFriendRequests = exports.createAllContacts = exports.inputs = exports.createTestUser = exports.getEventInput = exports.getUserInput = exports.getContactInput = void 0;
4
- const assert_1 = require("assert");
5
4
  const jest_date_mock_1 = require("jest-date-mock");
6
5
  const viewer_1 = require("../../core/viewer");
7
6
  const ent_1 = require("../../core/ent");
@@ -56,7 +55,7 @@ async function createTestUser(input) {
56
55
  ...input,
57
56
  });
58
57
  if (!user) {
59
- (0, assert_1.fail)("error creating user");
58
+ throw new Error("error creating user");
60
59
  }
61
60
  return user;
62
61
  }
@@ -74,7 +74,7 @@ function getColumns(cols) {
74
74
  count = true;
75
75
  }
76
76
  else {
77
- fail("unsupported expr type");
77
+ throw new Error("unsupported expr type");
78
78
  }
79
79
  }
80
80
  }