@constructive-io/graphql-query 2.4.7 → 2.5.0

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.
package/index.js CHANGED
@@ -15,6 +15,9 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
19
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
20
+ };
18
21
  var __importStar = (this && this.__importStar) || (function () {
19
22
  var ownKeys = function(o) {
20
23
  ownKeys = Object.getOwnPropertyNames || function (o) {
@@ -32,351 +35,9 @@ var __importStar = (this && this.__importStar) || (function () {
32
35
  return result;
33
36
  };
34
37
  })();
35
- var __importDefault = (this && this.__importDefault) || function (mod) {
36
- return (mod && mod.__esModule) ? mod : { "default": mod };
37
- };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.QueryBuilder = exports.MetaObject = void 0;
40
- // @ts-nocheck
41
- const graphql_1 = require("graphql");
42
- const inflection_1 = __importDefault(require("inflection"));
43
- const ast_1 = require("./ast");
44
- const meta_object_1 = require("./meta-object");
39
+ exports.MetaObject = exports.QueryBuilder = void 0;
40
+ var query_builder_1 = require("./query-builder");
41
+ Object.defineProperty(exports, "QueryBuilder", { enumerable: true, get: function () { return query_builder_1.QueryBuilder; } });
42
+ __exportStar(require("./types"), exports);
45
43
  exports.MetaObject = __importStar(require("./meta-object"));
46
- const isObject = val => val !== null && typeof val === 'object';
47
- class QueryBuilder {
48
- constructor({ meta = {}, introspection }) {
49
- this._introspection = introspection;
50
- this._meta = meta;
51
- this.clear();
52
- this.initModelMap();
53
- this.pickScalarFields = pickScalarFields.bind(this);
54
- this.pickAllFields = pickAllFields.bind(this);
55
- const result = (0, meta_object_1.validateMetaObject)(this._meta);
56
- if (typeof result === 'object' && result.errors) {
57
- throw new Error(`QueryBuilder: meta object is invalid:\n${result.message}`);
58
- }
59
- }
60
- /*
61
- * Save all gql queries and mutations by model name for quicker lookup
62
- */
63
- initModelMap() {
64
- this._models = Object.keys(this._introspection).reduce((map, key) => {
65
- const defn = this._introspection[key];
66
- map = {
67
- ...map,
68
- [defn.model]: {
69
- ...map[defn.model],
70
- ...{ [key]: defn }
71
- }
72
- };
73
- return map;
74
- }, {});
75
- }
76
- clear() {
77
- this._model = '';
78
- this._fields = [];
79
- this._key = null;
80
- this._queryName = '';
81
- this._ast = null;
82
- this._edges = false;
83
- }
84
- query(model) {
85
- this.clear();
86
- this._model = model;
87
- return this;
88
- }
89
- _findQuery() {
90
- // based on the op, finds the relevant GQL query
91
- const queries = this._models[this._model];
92
- if (!queries) {
93
- throw new Error('No queries found for ' + this._model);
94
- }
95
- const matchQuery = Object.entries(queries).find(([_, defn]) => defn.qtype === this._op);
96
- if (!matchQuery) {
97
- throw new Error('No query found for ' + this._model + ':' + this._op);
98
- }
99
- const queryKey = matchQuery[0];
100
- return queryKey;
101
- }
102
- _findMutation() {
103
- // For mutation, there can be many defns that match the operation being requested
104
- // .ie: deleteAction, deleteActionBySlug, deleteActionByName
105
- const matchingDefns = Object.keys(this._introspection).reduce((arr, mutationKey) => {
106
- const defn = this._introspection[mutationKey];
107
- if (defn.model === this._model &&
108
- defn.qtype === this._op &&
109
- defn.qtype === 'mutation' &&
110
- defn.mutationType === this._mutation) {
111
- arr = [...arr, { defn, mutationKey }];
112
- }
113
- return arr;
114
- }, []);
115
- if (!matchingDefns.length === 0) {
116
- throw new Error('no mutation found for ' + this._model + ':' + this._mutation);
117
- }
118
- // We only need deleteAction from all of [deleteAction, deleteActionBySlug, deleteActionByName]
119
- const getInputName = (mutationType) => {
120
- switch (mutationType) {
121
- case 'delete': {
122
- return `Delete${inflection_1.default.camelize(this._model)}Input`;
123
- }
124
- case 'create': {
125
- return `Create${inflection_1.default.camelize(this._model)}Input`;
126
- }
127
- case 'patch': {
128
- return `Update${inflection_1.default.camelize(this._model)}Input`;
129
- }
130
- default:
131
- throw new Error('Unhandled mutation type' + mutationType);
132
- }
133
- };
134
- const matchDefn = matchingDefns.find(({ defn }) => defn.properties.input.type === getInputName(this._mutation));
135
- if (!matchDefn) {
136
- throw new Error('no mutation found for ' + this._model + ':' + this._mutation);
137
- }
138
- return matchDefn.mutationKey;
139
- }
140
- select(selection) {
141
- const defn = this._introspection[this._key];
142
- // If selection not given, pick only scalar fields
143
- if (selection == null) {
144
- this._select = this.pickScalarFields(null, defn);
145
- return this;
146
- }
147
- this._select = this.pickAllFields(selection, defn);
148
- return this;
149
- }
150
- edges(useEdges) {
151
- this._edges = useEdges;
152
- return this;
153
- }
154
- getMany({ select } = {}) {
155
- this._op = 'getMany';
156
- this._key = this._findQuery();
157
- this.queryName(inflection_1.default.camelize(['get', inflection_1.default.underscore(this._key), 'query'].join('_'), true));
158
- const defn = this._introspection[this._key];
159
- this.select(select);
160
- this._ast = (0, ast_1.getMany)({
161
- builder: this,
162
- queryName: this._queryName,
163
- operationName: this._key,
164
- query: defn,
165
- selection: this._select
166
- });
167
- return this;
168
- }
169
- all({ select } = {}) {
170
- this._op = 'getMany';
171
- this._key = this._findQuery();
172
- this.queryName(inflection_1.default.camelize(['get', inflection_1.default.underscore(this._key), 'query', 'all'].join('_'), true));
173
- const defn = this._introspection[this._key];
174
- this.select(select);
175
- this._ast = (0, ast_1.getAll)({
176
- builder: this,
177
- queryName: this._queryName,
178
- operationName: this._key,
179
- query: defn,
180
- selection: this._select
181
- });
182
- return this;
183
- }
184
- getOne({ select } = {}) {
185
- this._op = 'getOne';
186
- this._key = this._findQuery();
187
- this.queryName(inflection_1.default.camelize(['get', inflection_1.default.underscore(this._key), 'query'].join('_'), true));
188
- const defn = this._introspection[this._key];
189
- this.select(select);
190
- this._ast = (0, ast_1.getOne)({
191
- builder: this,
192
- queryName: this._queryName,
193
- operationName: this._key,
194
- query: defn,
195
- selection: this._select
196
- });
197
- return this;
198
- }
199
- create({ select } = {}) {
200
- this._op = 'mutation';
201
- this._mutation = 'create';
202
- this._key = this._findMutation();
203
- this.queryName(inflection_1.default.camelize([inflection_1.default.underscore(this._key), 'mutation'].join('_'), true));
204
- const defn = this._introspection[this._key];
205
- this.select(select);
206
- this._ast = (0, ast_1.createOne)({
207
- builder: this,
208
- operationName: this._key,
209
- mutationName: this._queryName,
210
- mutation: defn,
211
- selection: this._select
212
- });
213
- return this;
214
- }
215
- delete({ select } = {}) {
216
- this._op = 'mutation';
217
- this._mutation = 'delete';
218
- this._key = this._findMutation();
219
- this.queryName(inflection_1.default.camelize([inflection_1.default.underscore(this._key), 'mutation'].join('_'), true));
220
- const defn = this._introspection[this._key];
221
- this.select(select);
222
- this._ast = (0, ast_1.deleteOne)({
223
- builder: this,
224
- operationName: this._key,
225
- mutationName: this._queryName,
226
- mutation: defn,
227
- selection: this._select
228
- });
229
- return this;
230
- }
231
- update({ select } = {}) {
232
- this._op = 'mutation';
233
- this._mutation = 'patch';
234
- this._key = this._findMutation();
235
- this.queryName(inflection_1.default.camelize([inflection_1.default.underscore(this._key), 'mutation'].join('_'), true));
236
- const defn = this._introspection[this._key];
237
- this.select(select);
238
- this._ast = (0, ast_1.patchOne)({
239
- builder: this,
240
- operationName: this._key,
241
- mutationName: this._queryName,
242
- mutation: defn,
243
- selection: this._select
244
- });
245
- return this;
246
- }
247
- queryName(name) {
248
- this._queryName = name;
249
- return this;
250
- }
251
- print() {
252
- this._hash = (0, graphql_1.print)(this._ast);
253
- return this;
254
- }
255
- }
256
- exports.QueryBuilder = QueryBuilder;
257
- /**
258
- * Pick scalar fields of a query definition
259
- * @param {Object} defn Query definition
260
- * @param {Object} meta Meta object containing info about table relations
261
- * @returns {Array}
262
- */
263
- function pickScalarFields(selection, defn) {
264
- const model = defn.model;
265
- const modelMeta = this._meta.tables.find((t) => t.name === model);
266
- const isInTableSchema = (fieldName) => !!modelMeta.fields.find((field) => field.name === fieldName);
267
- const pickFrom = (modelSelection) => modelSelection
268
- .filter((fieldName) => {
269
- // If not specified or not a valid selection list, allow all
270
- if (selection == null || !Array.isArray(selection))
271
- return true;
272
- return selection.includes(fieldName);
273
- })
274
- .filter((fieldName) => !isRelationalField(fieldName, modelMeta) && isInTableSchema(fieldName))
275
- .map((fieldName) => ({
276
- name: fieldName,
277
- isObject: false,
278
- fieldDefn: modelMeta.fields.find((f) => f.name === fieldName)
279
- }));
280
- // This is for inferring the sub-selection of a mutation query
281
- // from a definition model .eg UserSetting, find its related queries in the introspection object, and pick its selection fields
282
- if (defn.qtype === 'mutation') {
283
- const relatedQuery = this._introspection[`${modelNameToGetMany(defn.model)}`];
284
- return pickFrom(relatedQuery.selection);
285
- }
286
- return pickFrom(defn.selection);
287
- }
288
- /**
289
- * Pick scalar fields and sub-selection fields of a query definition
290
- * @param {Object} selection Selection clause object
291
- * @param {Object} defn Query definition
292
- * @param {Object} meta Meta object containing info about table relations
293
- * @returns {Array}
294
- */
295
- function pickAllFields(selection, defn) {
296
- const model = defn.model;
297
- const modelMeta = this._meta.tables.find((t) => t.name === model);
298
- const selectionEntries = Object.entries(selection);
299
- let fields = [];
300
- const isWhiteListed = (selectValue) => {
301
- return typeof selectValue === 'boolean' && selectValue;
302
- };
303
- for (const entry of selectionEntries) {
304
- const [fieldName, fieldOptions] = entry;
305
- // Case
306
- // {
307
- // goalResults: // fieldName
308
- // { select: { id: true }, variables: { first: 100 } } // fieldOptions
309
- // }
310
- if (isObject(fieldOptions)) {
311
- if (!isFieldInDefinition(fieldName, defn, modelMeta, this)) {
312
- continue;
313
- }
314
- const referencedForeignConstraint = modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName ||
315
- constraint.fromKey.alias === fieldName);
316
- const subFields = Object.keys(fieldOptions.select).filter((subField) => {
317
- return (!isRelationalField(subField, modelMeta) &&
318
- isWhiteListed(fieldOptions.select[subField]));
319
- });
320
- const isBelongTo = !!referencedForeignConstraint;
321
- const fieldSelection = {
322
- name: fieldName,
323
- isObject: true,
324
- isBelongTo,
325
- selection: subFields,
326
- variables: fieldOptions.variables
327
- };
328
- // Need to further expand selection of object fields,
329
- // but only non-graphql-builtin, non-relation fields
330
- // .ie action { id location }
331
- // location is non-scalar and non-relational, thus need to further expand into { x y ... }
332
- if (isBelongTo) {
333
- const getManyName = modelNameToGetMany(referencedForeignConstraint.refTable);
334
- const refDefn = this._introspection[getManyName];
335
- fieldSelection.selection = pickScalarFields.call(this, subFields, refDefn);
336
- }
337
- fields = [...fields, fieldSelection];
338
- }
339
- else {
340
- // Case
341
- // {
342
- // userId: true // [fieldName, fieldOptions]
343
- // }
344
- if (isWhiteListed(fieldOptions)) {
345
- fields = [
346
- ...fields,
347
- {
348
- name: fieldName,
349
- isObject: false,
350
- fieldDefn: modelMeta.fields.find((f) => f.name === fieldName)
351
- }
352
- ];
353
- }
354
- }
355
- }
356
- return fields;
357
- }
358
- function isFieldInDefinition(fieldName, defn, modelMeta) {
359
- const isReferenced = !!modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName ||
360
- constraint.fromKey.alias === fieldName);
361
- return (isReferenced ||
362
- defn.selection.some((selectionItem) => {
363
- if (typeof selectionItem === 'string') {
364
- return fieldName === selectionItem;
365
- }
366
- if (isObject(selectionItem)) {
367
- return selectionItem.name === fieldName;
368
- }
369
- return false;
370
- }));
371
- }
372
- // TODO: see if there is a possibility of supertyping table (a key is both a foreign and primary key)
373
- // A relational field is a foreign key but not a primary key
374
- function isRelationalField(fieldName, modelMeta) {
375
- return (!modelMeta.primaryConstraints.find((field) => field.name === fieldName) &&
376
- !!modelMeta.foreignConstraints.find((constraint) => constraint.fromKey.name === fieldName));
377
- }
378
- // Get getMany op name from model
379
- // ie. UserSetting => userSettings
380
- function modelNameToGetMany(model) {
381
- return inflection_1.default.camelize(inflection_1.default.pluralize(inflection_1.default.underscore(model)), true);
382
- }
@@ -1,3 +1,62 @@
1
- export declare function convertFromMetaSchema(metaSchema: any): {
2
- tables: any[];
3
- };
1
+ import type { MetaFieldType } from '../types';
2
+ interface MetaSchemaField {
3
+ name: string;
4
+ type: MetaFieldType;
5
+ }
6
+ interface MetaSchemaConstraint {
7
+ fields: MetaSchemaField[];
8
+ }
9
+ interface MetaSchemaForeignConstraint {
10
+ fields: MetaSchemaField[];
11
+ refFields: MetaSchemaField[];
12
+ refTable: {
13
+ name: string;
14
+ };
15
+ }
16
+ interface MetaSchemaBelongsTo {
17
+ keys: MetaSchemaField[];
18
+ fieldName: string;
19
+ }
20
+ interface MetaSchemaRelations {
21
+ belongsTo: MetaSchemaBelongsTo[];
22
+ }
23
+ interface MetaSchemaTable {
24
+ name: string;
25
+ fields: MetaSchemaField[];
26
+ primaryKeyConstraints: MetaSchemaConstraint[];
27
+ uniqueConstraints: MetaSchemaConstraint[];
28
+ foreignKeyConstraints: MetaSchemaForeignConstraint[];
29
+ relations: MetaSchemaRelations;
30
+ }
31
+ interface MetaSchemaInput {
32
+ _meta: {
33
+ tables: MetaSchemaTable[];
34
+ };
35
+ }
36
+ interface ConvertedField {
37
+ name: string;
38
+ type: MetaFieldType;
39
+ alias?: string;
40
+ }
41
+ interface ConvertedConstraint {
42
+ name: string;
43
+ type: MetaFieldType;
44
+ alias?: string;
45
+ }
46
+ interface ConvertedForeignConstraint {
47
+ refTable: string;
48
+ fromKey: ConvertedField;
49
+ toKey: ConvertedField;
50
+ }
51
+ interface ConvertedTable {
52
+ name: string;
53
+ fields: ConvertedField[];
54
+ primaryConstraints: ConvertedConstraint[];
55
+ uniqueConstraints: ConvertedConstraint[];
56
+ foreignConstraints: ConvertedForeignConstraint[];
57
+ }
58
+ interface ConvertedMetaObject {
59
+ tables: ConvertedTable[];
60
+ }
61
+ export declare function convertFromMetaSchema(metaSchema: MetaSchemaInput): ConvertedMetaObject;
62
+ export {};
@@ -1,11 +1,10 @@
1
1
  "use strict";
2
- // @ts-nocheck
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
4
3
  exports.convertFromMetaSchema = convertFromMetaSchema;
5
4
  function convertFromMetaSchema(metaSchema) {
6
- const { _meta: { tables } } = metaSchema;
5
+ const { _meta: { tables }, } = metaSchema;
7
6
  const result = {
8
- tables: []
7
+ tables: [],
9
8
  };
10
9
  for (const table of tables) {
11
10
  result.tables.push({
@@ -13,7 +12,7 @@ function convertFromMetaSchema(metaSchema) {
13
12
  fields: table.fields.map((f) => pickField(f)),
14
13
  primaryConstraints: pickArrayConstraint(table.primaryKeyConstraints),
15
14
  uniqueConstraints: pickArrayConstraint(table.uniqueConstraints),
16
- foreignConstraints: pickForeignConstraint(table.foreignKeyConstraints, table.relations)
15
+ foreignConstraints: pickForeignConstraint(table.foreignKeyConstraints, table.relations),
17
16
  });
18
17
  }
19
18
  return result;
@@ -22,7 +21,7 @@ function pickArrayConstraint(constraints) {
22
21
  if (constraints.length === 0)
23
22
  return [];
24
23
  const c = constraints[0];
25
- return c.fields.map((field) => pickField(field));
24
+ return c.fields.map((field) => pickConstraintField(field));
26
25
  }
27
26
  function pickForeignConstraint(constraints, relations) {
28
27
  if (constraints.length === 0)
@@ -32,8 +31,8 @@ function pickForeignConstraint(constraints, relations) {
32
31
  const { fields, refFields, refTable } = c;
33
32
  const fromKey = pickField(fields[0]);
34
33
  const toKey = pickField(refFields[0]);
35
- const matchingBelongsTo = belongsTo.find((c) => {
36
- const field = pickField(c.keys[0]);
34
+ const matchingBelongsTo = belongsTo.find((belongsToItem) => {
35
+ const field = pickField(belongsToItem.keys[0]);
37
36
  return field.name === fromKey.name;
38
37
  });
39
38
  // Ex: 'ownerId' will have an alias of 'owner', which has further selection of 'User' type
@@ -43,13 +42,19 @@ function pickForeignConstraint(constraints, relations) {
43
42
  return {
44
43
  refTable: refTable.name,
45
44
  fromKey,
46
- toKey
45
+ toKey,
47
46
  };
48
47
  });
49
48
  }
50
49
  function pickField(field) {
51
50
  return {
52
51
  name: field.name,
53
- type: field.type
52
+ type: field.type,
53
+ };
54
+ }
55
+ function pickConstraintField(field) {
56
+ return {
57
+ name: field.name,
58
+ type: field.type,
54
59
  };
55
60
  }
@@ -5,27 +5,44 @@
5
5
  "definitions": {
6
6
  "field": {
7
7
  "type": "object",
8
- "required": ["name", "type"],
8
+ "required": [
9
+ "name",
10
+ "type"
11
+ ],
9
12
  "additionalProperties": true,
10
13
  "properties": {
11
14
  "name": {
12
15
  "type": "string",
13
16
  "default": "id",
14
- "examples": ["id"]
17
+ "examples": [
18
+ "id"
19
+ ]
15
20
  },
16
21
  "type": {
17
22
  "type": "object",
18
- "required": ["pgType", "gqlType"],
23
+ "required": [
24
+ "pgType",
25
+ "gqlType"
26
+ ],
19
27
  "additionalProperties": true,
20
28
  "properties": {
21
29
  "gqlType": {
22
- "type": ["string", "null"]
30
+ "type": [
31
+ "string",
32
+ "null"
33
+ ]
23
34
  },
24
35
  "pgType": {
25
- "type": ["string", "null"]
36
+ "type": [
37
+ "string",
38
+ "null"
39
+ ]
26
40
  },
27
41
  "subtype": {
28
- "type": ["string", "null"]
42
+ "type": [
43
+ "string",
44
+ "null"
45
+ ]
29
46
  }
30
47
  }
31
48
  }
@@ -41,19 +58,27 @@
41
58
  "name": {
42
59
  "type": "string",
43
60
  "default": "User",
44
- "examples": ["User"]
61
+ "examples": [
62
+ "User"
63
+ ]
45
64
  },
46
65
  "fields": {
47
66
  "type": "array",
48
- "items": { "$ref": "#/definitions/field" }
67
+ "items": {
68
+ "$ref": "#/definitions/field"
69
+ }
49
70
  },
50
71
  "primaryConstraints": {
51
72
  "type": "array",
52
- "items": { "$ref": "#/definitions/field" }
73
+ "items": {
74
+ "$ref": "#/definitions/field"
75
+ }
53
76
  },
54
77
  "uniqueConstraints": {
55
78
  "type": "array",
56
- "items": { "$ref": "#/definitions/field" }
79
+ "items": {
80
+ "$ref": "#/definitions/field"
81
+ }
57
82
  },
58
83
  "foreignConstraints": {
59
84
  "type": "array",
@@ -63,21 +88,36 @@
63
88
  "refTable": {
64
89
  "type": "string",
65
90
  "default": "User",
66
- "examples": ["User"]
91
+ "examples": [
92
+ "User"
93
+ ]
94
+ },
95
+ "fromKey": {
96
+ "$ref": "#/definitions/field"
67
97
  },
68
- "fromKey": { "$ref": "#/definitions/field" },
69
- "toKey": { "$ref": "#/definitions/field" }
98
+ "toKey": {
99
+ "$ref": "#/definitions/field"
100
+ }
70
101
  },
71
- "required": ["refTable", "fromKey", "toKey"],
102
+ "required": [
103
+ "refTable",
104
+ "fromKey",
105
+ "toKey"
106
+ ],
72
107
  "additionalProperties": false
73
108
  }
74
109
  }
75
110
  },
76
- "required": ["name", "fields"],
111
+ "required": [
112
+ "name",
113
+ "fields"
114
+ ],
77
115
  "additionalProperties": false
78
116
  }
79
117
  }
80
118
  },
81
- "required": ["tables"],
119
+ "required": [
120
+ "tables"
121
+ ],
82
122
  "additionalProperties": false
83
123
  }
@@ -13,6 +13,6 @@ function validateMetaObject(obj) {
13
13
  return true;
14
14
  return {
15
15
  errors: ajv.errors,
16
- message: ajv.errorsText(ajv.errors, { separator: '\n' })
16
+ message: ajv.errorsText(ajv.errors, { separator: '\n' }),
17
17
  };
18
18
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constructive-io/graphql-query",
3
- "version": "2.4.7",
3
+ "version": "2.5.0",
4
4
  "description": "Constructive GraphQL Query",
5
5
  "author": "Constructive <developers@constructive.io>",
6
6
  "main": "index.js",
@@ -44,5 +44,5 @@
44
44
  "devDependencies": {
45
45
  "makage": "^0.1.10"
46
46
  },
47
- "gitHead": "f2f9c9851beff3214790dfca371e4ca7f6c1373f"
47
+ "gitHead": "baa2f7598cde3baf3f05f161a11bafa12c66f6aa"
48
48
  }