@bedrockio/model 0.2.5 → 0.2.8

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/README.md CHANGED
@@ -436,12 +436,11 @@ validation which will:
436
436
  - Append the same validation to `Model.getCreateSchema` and
437
437
  `Model.getUpdateSchema` to allow this constraint to trickle down to the API.
438
438
 
439
- > [!WARNING]
440
- > Note that calling `Model.updateOne` will throw an error when a unique field
441
- > exists on any document **including the document being updated**. This is an
442
- > intentional constraint that allows `updateOne` better peformance by not having
443
- > to fetch the ids of the documents being updated in order to exclude them. To
444
- > avoid this call `Document.save` instead.
439
+ > [!WARNING] Note that calling `Model.updateOne` will throw an error when a
440
+ > unique field exists on any document **including the document being updated**.
441
+ > This is an intentional constraint that allows `updateOne` better peformance by
442
+ > not having to fetch the ids of the documents being updated in order to exclude
443
+ > them. To avoid this call `Document.save` instead.
445
444
  >
446
445
  > Note also that calling `Model.updateMany` with a unique field passed will
447
446
  > always throw an error as the result would inherently be non-unique.
@@ -1023,8 +1022,8 @@ deletion. They are defined in the `onDelete` field of the model definition file:
1023
1022
  "clean": {
1024
1023
  "local": "profile",
1025
1024
  "foreign": {
1026
- Shop: "owner"
1027
- },
1025
+ "Shop": "owner"
1026
+ }
1028
1027
  },
1029
1028
  "errorOnReferenced": {
1030
1029
  "except": ["AuditEntry"]
@@ -1081,7 +1080,7 @@ user.delete();
1081
1080
  ```
1082
1081
 
1083
1082
  In this case, "referenced by" means any other model that explicitly uses "User"
1084
- as a `ref` for type `ObjectId`. `errorOnReference` may also be simply `true`,
1083
+ as a `ref` for type `ObjectId`. `errorOnReferenced` may also be simply `true`,
1085
1084
  which will error on any foreign references of any kind.
1086
1085
 
1087
1086
  `only` may be passed instead of `except`, which will only error when the
@@ -1093,9 +1092,8 @@ Models that have delete hooks defined on them will keep a reference of the
1093
1092
  documents that were deleted. Calling `.restore()` on the document will also
1094
1093
  restore these references.
1095
1094
 
1096
- > [!WARNING]
1097
- > Delete hooks are **only** run on a single document (`.delete` or `.restore`).
1098
- > They will not be run when using model methods like `deleteOne` or
1095
+ > [!WARNING] Delete hooks are **only** run on a single document (`.delete` or
1096
+ > `.restore`). They will not be run when using model methods like `deleteOne` or
1099
1097
  > `deleteMany`.
1100
1098
 
1101
1099
  ### Assign
@@ -121,7 +121,6 @@ function validateError(deleteHooks) {
121
121
  async function errorOnForeignReferences(doc, options) {
122
122
  const {
123
123
  errorHook,
124
- cleanForeign,
125
124
  references
126
125
  } = options;
127
126
  if (!errorHook) {
@@ -138,57 +137,54 @@ async function errorOnForeignReferences(doc, options) {
138
137
  model,
139
138
  paths
140
139
  } of references) {
141
- if (referenceIsAllowed(errorHook, model)) {
140
+ if (referenceIsAllowed(model, options)) {
142
141
  continue;
143
142
  }
144
- const $or = paths.filter(path => {
145
- if (cleanForeign) {
146
- return cleanForeign[model.modelName] !== path;
147
- }
148
- return true;
149
- }).map(path => {
150
- return {
143
+ const {
144
+ modelName
145
+ } = model;
146
+ for (let path of paths) {
147
+ const docs = await model.find({
151
148
  [path]: doc.id
152
- };
153
- });
154
- if (!$or.length) {
155
- continue;
156
- }
157
- const docs = await model.find({
158
- $or
159
- }, {
160
- _id: 1
161
- }).lean();
162
- if (docs.length > 0) {
163
- const ids = docs.map(doc => {
164
- return String(doc._id);
165
- });
166
- results.push({
167
- ids,
168
- model,
169
- count: ids.length
170
- });
149
+ }, {
150
+ _id: 1
151
+ }).lean();
152
+ if (docs.length > 0) {
153
+ const ids = docs.map(doc => {
154
+ return String(doc._id);
155
+ });
156
+ const strId = ids.join(', ');
157
+ const message = `Referenced as "${path}" by ${modelName}: ${strId}.`;
158
+ results.push({
159
+ ids,
160
+ path,
161
+ message,
162
+ model: modelName
163
+ });
164
+ }
171
165
  }
172
166
  }
173
167
  if (results.length) {
174
168
  const {
175
169
  modelName
176
170
  } = doc.constructor;
177
- const refNames = results.map(reference => {
178
- return reference.model.modelName;
179
- });
180
- throw new _errors.ReferenceError(`Refusing to delete ${modelName} referenced by ${refNames}.`, results);
171
+ throw new _errors.ReferenceError(`Refusing to delete ${modelName}.`, results);
181
172
  }
182
173
  }
183
- function referenceIsAllowed(errorHook, model) {
174
+ function referenceIsAllowed(model, options) {
175
+ const {
176
+ cleanForeign
177
+ } = options;
184
178
  const {
185
179
  only,
186
180
  except
187
- } = errorHook;
181
+ } = options?.errorHook || {};
188
182
  if (only) {
189
183
  return !only.includes(model.modelName);
190
184
  } else if (except) {
191
185
  return except.includes(model.modelName);
186
+ } else if (cleanForeign) {
187
+ return model.modelName in cleanForeign;
192
188
  } else {
193
189
  return false;
194
190
  }
@@ -269,6 +265,10 @@ async function deleteForeignReferences(doc, refs) {
269
265
  await runDeletes(Model, doc, {
270
266
  [arg]: id
271
267
  });
268
+ } else if (Array.isArray(arg)) {
269
+ await runDeletes(Model, doc, {
270
+ $or: mapArrayQuery(arg, id)
271
+ });
272
272
  } else {
273
273
  const {
274
274
  $and,
@@ -14,9 +14,9 @@ class ImplementationError extends Error {
14
14
  }
15
15
  exports.ImplementationError = ImplementationError;
16
16
  class ReferenceError extends Error {
17
- constructor(message, references) {
17
+ constructor(message, details) {
18
18
  super(message);
19
- this.references = references;
19
+ this.details = details;
20
20
  }
21
21
  }
22
22
  exports.ReferenceError = ReferenceError;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bedrockio/model",
3
- "version": "0.2.5",
3
+ "version": "0.2.8",
4
4
  "description": "Bedrock utilities for model creation.",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -117,7 +117,7 @@ function validateError(deleteHooks) {
117
117
  // Error on references
118
118
 
119
119
  async function errorOnForeignReferences(doc, options) {
120
- const { errorHook, cleanForeign, references } = options;
120
+ const { errorHook, references } = options;
121
121
 
122
122
  if (!errorHook) {
123
123
  return;
@@ -131,59 +131,53 @@ async function errorOnForeignReferences(doc, options) {
131
131
  const results = [];
132
132
 
133
133
  for (let { model, paths } of references) {
134
- if (referenceIsAllowed(errorHook, model)) {
134
+ if (referenceIsAllowed(model, options)) {
135
135
  continue;
136
136
  }
137
137
 
138
- const $or = paths
139
- .filter((path) => {
140
- if (cleanForeign) {
141
- return cleanForeign[model.modelName] !== path;
142
- }
143
- return true;
144
- })
145
- .map((path) => {
146
- return {
147
- [path]: doc.id,
148
- };
149
- });
150
-
151
- if (!$or.length) {
152
- continue;
153
- }
154
-
155
- const docs = await model.find({ $or }, { _id: 1 }).lean();
156
-
157
- if (docs.length > 0) {
158
- const ids = docs.map((doc) => {
159
- return String(doc._id);
160
- });
161
- results.push({
162
- ids,
163
- model,
164
- count: ids.length,
165
- });
138
+ const { modelName } = model;
139
+
140
+ for (let path of paths) {
141
+ const docs = await model
142
+ .find(
143
+ {
144
+ [path]: doc.id,
145
+ },
146
+ { _id: 1 }
147
+ )
148
+ .lean();
149
+
150
+ if (docs.length > 0) {
151
+ const ids = docs.map((doc) => {
152
+ return String(doc._id);
153
+ });
154
+ const strId = ids.join(', ');
155
+ const message = `Referenced as "${path}" by ${modelName}: ${strId}.`;
156
+ results.push({
157
+ ids,
158
+ path,
159
+ message,
160
+ model: modelName,
161
+ });
162
+ }
166
163
  }
167
164
  }
168
165
 
169
166
  if (results.length) {
170
167
  const { modelName } = doc.constructor;
171
- const refNames = results.map((reference) => {
172
- return reference.model.modelName;
173
- });
174
- throw new ReferenceError(
175
- `Refusing to delete ${modelName} referenced by ${refNames}.`,
176
- results
177
- );
168
+ throw new ReferenceError(`Refusing to delete ${modelName}.`, results);
178
169
  }
179
170
  }
180
171
 
181
- function referenceIsAllowed(errorHook, model) {
182
- const { only, except } = errorHook;
172
+ function referenceIsAllowed(model, options) {
173
+ const { cleanForeign } = options;
174
+ const { only, except } = options?.errorHook || {};
183
175
  if (only) {
184
176
  return !only.includes(model.modelName);
185
177
  } else if (except) {
186
178
  return except.includes(model.modelName);
179
+ } else if (cleanForeign) {
180
+ return model.modelName in cleanForeign;
187
181
  } else {
188
182
  return false;
189
183
  }
@@ -263,6 +257,10 @@ async function deleteForeignReferences(doc, refs) {
263
257
  await runDeletes(Model, doc, {
264
258
  [arg]: id,
265
259
  });
260
+ } else if (Array.isArray(arg)) {
261
+ await runDeletes(Model, doc, {
262
+ $or: mapArrayQuery(arg, id),
263
+ });
266
264
  } else {
267
265
  const { $and, $or } = arg;
268
266
  if ($and) {
package/src/errors.js CHANGED
@@ -8,8 +8,8 @@ export class ImplementationError extends Error {
8
8
  }
9
9
 
10
10
  export class ReferenceError extends Error {
11
- constructor(message, references) {
11
+ constructor(message, details) {
12
12
  super(message);
13
- this.references = references;
13
+ this.details = details;
14
14
  }
15
15
  }
package/types/errors.d.ts CHANGED
@@ -5,7 +5,7 @@ export class ImplementationError extends Error {
5
5
  name: any;
6
6
  }
7
7
  export class ReferenceError extends Error {
8
- constructor(message: any, references: any);
9
- references: any;
8
+ constructor(message: any, details: any);
9
+ details: any;
10
10
  }
11
11
  //# sourceMappingURL=errors.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.js"],"names":[],"mappings":"AAAA;CAA8C;AAE9C;IACE,uBAGC;IADC,UAAgB;CAEnB;AAED;IACE,2CAGC;IADC,gBAA4B;CAE/B"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.js"],"names":[],"mappings":"AAAA;CAA8C;AAE9C;IACE,uBAGC;IADC,UAAgB;CAEnB;AAED;IACE,wCAGC;IADC,aAAsB;CAEzB"}