@coderich/autograph 0.13.22 → 0.13.24

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@coderich/autograph",
3
3
  "main": "index.js",
4
- "version": "0.13.22",
4
+ "version": "0.13.24",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -74,12 +74,14 @@ module.exports = class Pipeline {
74
74
 
75
75
  //
76
76
  Pipeline.define('$pk', (params) => {
77
- const value = get(params.query.doc, params.path) || params.value?.id || params.value;
77
+ const { pkField } = params.model;
78
+ const value = get(params.query.doc, params.path) || params.value?.[pkField] || params.value; // I "think" the get() is for embedded documents
78
79
  return Pipeline[params.field.id]({ ...params, value });
79
80
  }, { ignoreNull: false });
80
81
 
81
82
  Pipeline.define('$fk', (params) => {
82
- const value = params.value?.id || params.value;
83
+ const { fkField } = params.field;
84
+ const value = params.value?.[fkField] || params.value;
83
85
  return Pipeline[params.field.id]({ ...params, value });
84
86
  });
85
87
 
@@ -116,10 +118,10 @@ module.exports = class Pipeline {
116
118
  });
117
119
 
118
120
  //
119
- Pipeline.define('ensureId', ({ query, resolver, model, field, value }) => {
120
- const { type } = field;
121
+ Pipeline.define('ensureFK', ({ query, resolver, field, value }) => {
122
+ const { type, fkField } = field;
121
123
  const ids = Util.filterBy(Util.ensureArray(value), (a, b) => `${a}` === `${b}`);
122
- return resolver.match(type).flags(query.flags).where({ id: ids }).count().then((count) => {
124
+ return resolver.match(type).flags(query.flags).where({ [fkField]: ids }).count().then((count) => {
123
125
  if (count !== ids.length) throw Boom.notFound(`${type} Not Found`);
124
126
  });
125
127
  }, { itemize: false });
@@ -229,11 +229,11 @@ module.exports = class Resolver {
229
229
  return (...args) => {
230
230
  switch (cmd) {
231
231
  case 'save': {
232
- return queryResolver.save({ ...$doc, ...args[0] });
232
+ return queryResolver.save({ ...$doc, ...args[0] }); // $doc incase it's mutated
233
233
  }
234
234
  case 'lookup': {
235
235
  const field = self.toModel(model).fields[args[0]];
236
- const where = { [field.linkBy]: $doc[field.linkField.name] };
236
+ const where = field.isVirtual ? { [field.linkBy]: $doc[field.linkField] } : { [field.fkField]: $doc[field] };
237
237
  return self.match(field.model).where(where);
238
238
  }
239
239
  default: {
@@ -1,6 +1,6 @@
1
1
  const Util = require('@coderich/util');
2
2
  const Pipeline = require('../data/Pipeline');
3
- const { isGlob, globToRegex, mergeDeep, finalizeWhereClause } = require('../service/AppService');
3
+ const { isGlob, globToRegex, mergeDeep, finalizeWhereClause, JSONParse } = require('../service/AppService');
4
4
 
5
5
  module.exports = class Query {
6
6
  #config;
@@ -82,8 +82,8 @@ module.exports = class Query {
82
82
  input: this.#model.walk(input, node => node.value !== undefined && Object.assign(node, { key: node.field.key })),
83
83
  where: isNative ? where : this.#model.walk(where, node => Object.assign(node, { key: node.field.key })),
84
84
  sort: this.#model.walk(sort, node => Object.assign(node, { key: node.field.key })),
85
- before: (!isCursorPaging || !before) ? undefined : JSON.parse(Buffer.from(before, 'base64').toString('ascii')),
86
- after: (!isCursorPaging || !after) ? undefined : JSON.parse(Buffer.from(after, 'base64').toString('ascii')),
85
+ before: (!isCursorPaging || !before) ? undefined : JSONParse(Buffer.from(before, 'base64').toString('ascii')),
86
+ after: (!isCursorPaging || !after) ? undefined : JSONParse(Buffer.from(after, 'base64').toString('ascii')),
87
87
  $schema: this.#schema.resolvePath,
88
88
  });
89
89
 
@@ -68,7 +68,7 @@ module.exports = class QueryBuilder {
68
68
  }
69
69
 
70
70
  info(info) {
71
- this.select(getGQLSelectFields(this.#query.model, info));
71
+ // this.select(getGQLSelectFields(this.#query.model, info));
72
72
  return this;
73
73
  }
74
74
 
@@ -82,7 +82,7 @@ module.exports = class QueryBuilder {
82
82
  }
83
83
 
84
84
  where(clause) {
85
- this.#propCheck('where', 'native', false);
85
+ this.#propCheck('where', 'native', false); // Allow redefine of "where" because we merge it
86
86
  const $clause = mergeDeep(this.#query.where || {}, clause);
87
87
  this.#query.where = $clause;
88
88
  this.#query.args.where = $clause;
@@ -59,7 +59,7 @@ module.exports = class Schema {
59
59
 
60
60
  if (directive) {
61
61
  const arg = directive.arguments.find(({ name }) => name.value === 'decorate');
62
- const value = arg?.value.value || 'default';
62
+ const value = Util.uvl(Schema.#resolveNodeValue(arg?.value), 'default');
63
63
  const decorator = this.#config.decorators?.[value];
64
64
 
65
65
  if (decorator) {
@@ -214,6 +214,10 @@ module.exports = class Schema {
214
214
  break;
215
215
  }
216
216
  // Field specific directives
217
+ case `${directives.field}-fk`: {
218
+ target.fkField = value;
219
+ break;
220
+ }
217
221
  case `${directives.field}-default`: {
218
222
  target.defaultValue = value;
219
223
  break;
@@ -230,9 +234,14 @@ module.exports = class Schema {
230
234
  target.pipelines.normalize = target.pipelines.normalize.concat(value).filter(Boolean);
231
235
  break;
232
236
  }
237
+ case `${directives.link}-to`: {
238
+ target.linkTo = value;
239
+ target.isVirtual ??= true;
240
+ break;
241
+ }
233
242
  case `${directives.link}-by`: {
234
243
  target.linkBy = value;
235
- target.isVirtual = true;
244
+ target.isVirtual ??= true;
236
245
  break;
237
246
  }
238
247
  // Generic by target directives
@@ -339,8 +348,10 @@ module.exports = class Schema {
339
348
  thunks.unshift(($schema) => {
340
349
  $field.id ??= $model.id;
341
350
  $field.model = $schema.models[$field.type];
342
- $field.linkBy ??= $field.model?.pkField;
343
351
  $field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
352
+ $field.linkTo ??= $field.model;
353
+ $field.linkBy ??= $field.linkTo?.pkField; // This defines join logic (below) for both straight+virtual references
354
+ $field.fkField ??= $field.model?.pkField; // This is the fkReference field for straight references
344
355
  $field.linkField = $field.isVirtual ? $model.fields[$model.pkField] : $field;
345
356
  $field.isFKReference = !$field.isPrimaryKey && $field.model?.isMarkedModel && !$field.model?.isEmbedded;
346
357
  $field.isEmbedded = Boolean($field.model && !$field.isFKReference && !$field.isPrimaryKey);
@@ -354,16 +365,16 @@ module.exports = class Schema {
354
365
 
355
366
  if ($field.isArray) $field.pipelines.normalize.unshift('toArray');
356
367
  if ($field.isPrimaryKey) $field.pipelines.serialize.unshift('$pk'); // Will create/convert to FK type always
357
- if ($field.isFKReference) $field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
358
-
359
368
  if ($field.isRequired && $field.isPersistable && !$field.isVirtual) $field.pipelines.finalize.push('required');
369
+
360
370
  if ($field.isFKReference) {
361
371
  const to = $field.model.key;
362
372
  const on = $field.model.fields[$field.linkBy].key;
363
373
  const from = $field.linkField.key;
364
374
  const as = `join_${to}`;
365
375
  $field.join = { to, on, from, as };
366
- $field.pipelines.finalize.push('ensureId'); // Absolute Last
376
+ $field.pipelines.serialize.unshift('$fk'); // Will convert to FK type IFF defined in payload
377
+ $field.pipelines.finalize.push('ensureFK'); // Absolute Last
367
378
  }
368
379
  });
369
380
 
@@ -446,6 +457,8 @@ module.exports = class Schema {
446
457
  }
447
458
 
448
459
  static #resolveNodeValue(node) {
460
+ if (node == null) return node;
461
+
449
462
  switch (node.kind) {
450
463
  case 'NullValue': return null;
451
464
  case 'ListValue': return node.values.map(Schema.#resolveNodeValue);
@@ -493,6 +506,7 @@ module.exports = class Schema {
493
506
 
494
507
  directive @${field}(
495
508
  id: String # Specify the ID strategy (eg. "toObjectId")
509
+ fk: String # Specify the FK field (default model.pk)
496
510
  key: String # Specify db key
497
511
  persist: Boolean # Persist this field (default true)
498
512
  connection: Boolean # Treat this field as a connection type (default false - rolling this out slowly)
@@ -589,7 +603,7 @@ module.exports = class Schema {
589
603
  }
590
604
  ${connectionFields.length ? `
591
605
  extend type ${model} {
592
- ${connectionFields.map(field => `${field}: ${field.model}Connection`)}
606
+ ${connectionFields.map(field => `${field}(${Schema.#getConnectionArguments(field.model)}): ${field.model}Connection`)}
593
607
  }
594
608
  ` : ''}
595
609
  `;
@@ -619,16 +633,7 @@ module.exports = class Schema {
619
633
  node(id: ID!): Node
620
634
  ${queryModels.map(model => `
621
635
  get${model}(id: ID!): ${model}
622
- find${model}(
623
- where: ${model}InputWhere
624
- sortBy: ${model}InputSort
625
- limit: Int
626
- skip: Int
627
- first: Int
628
- after: String
629
- last: Int
630
- before: String
631
- ): ${model}Connection!
636
+ find${model}(${Schema.#getConnectionArguments(model)}): ${model}Connection!
632
637
  `)}
633
638
  }
634
639
 
@@ -713,13 +718,7 @@ module.exports = class Schema {
713
718
  Query: queryModels.reduce((prev, model) => {
714
719
  return Object.assign(prev, {
715
720
  [`get${model}`]: (doc, args, context, info) => context[schema.namespace].resolver.match(model).args(args).info(info).one({ required: true }),
716
- [`find${model}`]: (doc, args, context, info) => {
717
- return {
718
- edges: () => context[schema.namespace].resolver.match(model).args(args).info(info).many(),
719
- count: () => context[schema.namespace].resolver.match(model).args(args).info(info).count(),
720
- pageInfo: () => context[schema.namespace].resolver.match(model).args(args).info(info).many(),
721
- };
722
- },
721
+ [`find${model}`]: (doc, args, context, info) => context[schema.namespace].resolver.match(model).args(args).info(info).resolve(info),
723
722
  });
724
723
  }, {
725
724
  node: (doc, args, context, info) => {
@@ -746,7 +745,7 @@ module.exports = class Schema {
746
745
  [model]: Object.values(model.fields).filter(field => field.model?.isEntity).reduce((prev2, field) => {
747
746
  return Object.assign(prev2, {
748
747
  [field]: (doc, args, context, info) => {
749
- return context[schema.namespace].resolver.match(field.model).where({ [field.linkBy]: doc[field.linkField.name] }).args(args).info(info).resolve(info);
748
+ return doc.$.lookup(field).args(args).info(info).resolve(info);
750
749
  },
751
750
  });
752
751
  }, {}),
@@ -767,6 +766,19 @@ module.exports = class Schema {
767
766
  return type;
768
767
  }
769
768
 
769
+ static #getConnectionArguments(model) {
770
+ return `
771
+ where: ${model}InputWhere
772
+ sortBy: ${model}InputSort
773
+ limit: Int
774
+ skip: Int
775
+ first: Int
776
+ after: String
777
+ last: Int
778
+ before: String
779
+ `;
780
+ }
781
+
770
782
  static #identifyOnDeletes(models, parentName) {
771
783
  return models.reduce((prev, model) => {
772
784
  Object.values(model.fields).filter(f => f.onDelete).forEach((field) => {
@@ -43,3 +43,12 @@ exports.getGQLSelectFields = (model, info) => {
43
43
  // return value === undefined ? prev : Object.assign(prev, { [key]: value });
44
44
  // }, {}));
45
45
  // };
46
+
47
+ exports.JSONParse = (mixed) => {
48
+ try {
49
+ const json = JSON.parse(mixed);
50
+ return json;
51
+ } catch (e) {
52
+ return undefined;
53
+ }
54
+ };