@coderich/autograph 0.13.45 → 0.13.46

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.45",
4
+ "version": "0.13.46",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -1,7 +1,13 @@
1
1
  const Util = require('@coderich/util');
2
2
 
3
3
  module.exports = class Transformer {
4
- #config = { shape: {}, defaults: {}, args: {}, strictSchema: false, keepUndefined: false };
4
+ #config = {
5
+ args: {}, // Arguments passed to each thunk
6
+ shape: {}, // The final shape
7
+ defaults: {}, // Default values applied at beginning of transformation
8
+ strictSchema: false, // If true, will strip away unknown attributes
9
+ keepUndefined: false, // If true, will preserve undefined values
10
+ };
5
11
 
6
12
  #operation = {
7
13
  set: (target, prop, startValue, proxy) => {
@@ -60,7 +60,7 @@ module.exports = class QueryResolver extends QueryBuilder {
60
60
  case 'pullOne': {
61
61
  return this.#get(query).then((doc) => {
62
62
  const [key] = Object.keys(input);
63
- const values = get(this.#model.transformers.input.transform(input), key);
63
+ const values = get(this.#model.transformers.input.transform(input), key, []);
64
64
  const $input = { [key]: (get(doc, key) || []).filter(el => values.every(v => `${v}` !== `${el}`)) };
65
65
  return this.#resolver.match(this.#model.name).id(doc.id).save($input);
66
66
  });
@@ -109,17 +109,17 @@ module.exports = class QueryResolver extends QueryBuilder {
109
109
  const { id } = query.toObject();
110
110
  const txn = this.#resolver.transaction(false);
111
111
 
112
- // if (this.#model.name === 'Person') console.log(this.#model.referentialIntegrity);
113
- return txn.run(Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, fieldRef, isArray, op }) => () => {
114
- const fieldStr = fieldRef ? `${field}.${fieldRef}` : `${field.name}`;
115
- const $where = { [fieldStr]: id };
112
+ return txn.run(Util.promiseChain(this.#model.referentialIntegrity.map(({ model, field, path }) => () => {
113
+ const { onDelete, isArray } = field;
114
+ const $path = path.join('.');
115
+ const $where = { [$path]: id };
116
116
 
117
- switch (op) {
118
- case 'cascade': return isArray ? txn.match(model).where($where).pull(fieldStr, id) : txn.match(model).where($where).remove();
119
- case 'nullify': return txn.match(model).where($where).save({ [fieldStr]: null });
117
+ switch (onDelete) {
118
+ case 'cascade': return isArray ? txn.match(model).where($where).pull($path, id) : txn.match(model).where($where).remove();
119
+ case 'nullify': return txn.match(model).where($where).save({ [$path]: null });
120
120
  case 'restrict': return txn.match(model).where($where).count().then(count => (count ? Promise.reject(new Error('Restricted')) : count));
121
121
  case 'defer': return Promise.resolve(); // Used for embedded models (could be improved)
122
- default: throw new Error(`Unknown onDelete operator: '${op}'`);
122
+ default: throw new Error(`Unknown onDelete operator: '${onDelete}'`);
123
123
  }
124
124
  })));
125
125
  }
@@ -129,6 +129,7 @@ module.exports = class Schema {
129
129
  visit(this.#typeDefs, {
130
130
  enter: (node) => {
131
131
  const name = node.name?.value;
132
+
132
133
  if (!allowedKinds.includes(node.kind) || operations.includes(name)) return false;
133
134
 
134
135
  if (modelKinds.includes(node.kind)) {
@@ -424,8 +425,9 @@ module.exports = class Schema {
424
425
  curr.name, // Rename key
425
426
  a => Pipeline.$deserialize({ ...a, ...args, path: a.path.concat(curr.name) }),
426
427
  ];
428
+
427
429
  if (curr.isArray) rules.unshift(({ value }) => (value == null ? value : Util.ensureArray(value)));
428
- // if (curr.isEmbedded) rules.unshift(({ value }) => Util.map(value, v => curr.model.transformers.doc.transform(v)));
430
+
429
431
  if (curr.isEmbedded) {
430
432
  rules.unshift(a => Util.map(a.value, (value, i) => {
431
433
  const path = a.path.concat(curr.name);
@@ -433,6 +435,7 @@ module.exports = class Schema {
433
435
  return curr.model.transformers.doc.transform(value, { ...args, query: a.query, context: a.context, path });
434
436
  }));
435
437
  }
438
+
436
439
  return Object.assign(prev, { [curr.key]: rules });
437
440
  }, {}),
438
441
  defaults: Object.values($model.fields).reduce((prev, curr) => {
@@ -450,6 +453,7 @@ module.exports = class Schema {
450
453
 
451
454
  // Field resolution comes first (unshift)
452
455
  thunks.unshift(($schema) => {
456
+ $field.parent = $model;
453
457
  $field.model = $schema.models[$field.type];
454
458
  $field.crud = Util.uvl($field.crud, $field.model?.scope, 'crud');
455
459
  $field.linkTo ??= $field.model;
@@ -514,8 +518,12 @@ module.exports = class Schema {
514
518
  });
515
519
 
516
520
  // Resolve referential integrity
521
+ const onDeleteFields = Array.from(new Set(Object.values(this.#schema.models).reduce((prev, curr) => {
522
+ return prev.concat(Object.values(curr.fields).filter(el => el.onDelete)).flat();
523
+ }, [])));
524
+
517
525
  Object.values(this.#schema.models).forEach(($model) => {
518
- $model.referentialIntegrity = Schema.#identifyOnDeletes(Object.values(this.#schema.models), $model.name);
526
+ $model.referentialIntegrity = Schema.#identifyOnDeletes(Object.values(this.#schema.models).filter(m => m.isEntity), onDeleteFields.filter(f => `${f.model}` === `${$model}`));
519
527
  });
520
528
 
521
529
  // Helper methods
@@ -894,21 +902,25 @@ module.exports = class Schema {
894
902
  `;
895
903
  }
896
904
 
897
- static #identifyOnDeletes(models, parentName) {
898
- return models.reduce((prev, model) => {
899
- Object.values(model.fields).filter(f => f.onDelete).forEach((field) => {
900
- if (`${field.model.name}` === `${parentName}`) {
901
- if (model.isEntity) {
902
- prev.push({ model, field, isArray: field.isArray, op: field.onDelete });
903
- }
904
- // else {
905
- // prev.push(...Schema.#identifyOnDeletes(models, model.name).map(od => Object.assign(od, { fieldRef: field.name, isArray: field.isArray, op: field.onDelete })));
906
- // }
907
- }
908
- });
905
+ static #findPathToField(model, field, path = []) {
906
+ const { target, embeds } = Object.values(model.fields).reduce((prev, curr) => {
907
+ if (curr === field) prev.target = curr;
908
+ else if (curr.isEmbedded) prev.embeds.push(curr);
909
+ return prev;
910
+ }, { embeds: [] });
909
911
 
910
- // Assign model referential integrity
911
- return Util.filterBy(prev, (a, b) => `${a.model.name}:${a.field.name}:${a.fieldRef}:${a.op}` === `${b.model.name}:${b.field.name}:${b.fieldRef}:${b.op}`);
912
- }, []);
912
+ if (target) return path.concat(target.name);
913
+ if (embeds.length) return embeds.map(f => Schema.#findPathToField(f.model, field, path.concat(f.name))).filter(Boolean)[0];
914
+ return undefined;
915
+ }
916
+
917
+ static #identifyOnDeletes(models, fields) {
918
+ return models.map((model) => {
919
+ return fields.map((field) => {
920
+ const path = Schema.#findPathToField(model, field);
921
+ if (!path) return null;
922
+ return { model, field, path };
923
+ });
924
+ }).flat().filter(Boolean);
913
925
  }
914
926
  };