@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 +10 -12
- package/dist/cjs/delete-hooks.js +34 -34
- package/dist/cjs/errors.js +2 -2
- package/package.json +1 -1
- package/src/delete-hooks.js +37 -39
- package/src/errors.js +2 -2
- package/types/errors.d.ts +2 -2
- package/types/errors.d.ts.map +1 -1
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
|
-
>
|
|
441
|
-
>
|
|
442
|
-
>
|
|
443
|
-
>
|
|
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`. `
|
|
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
|
-
>
|
|
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
|
package/dist/cjs/delete-hooks.js
CHANGED
|
@@ -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(
|
|
140
|
+
if (referenceIsAllowed(model, options)) {
|
|
142
141
|
continue;
|
|
143
142
|
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
|
|
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(
|
|
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,
|
package/dist/cjs/errors.js
CHANGED
|
@@ -14,9 +14,9 @@ class ImplementationError extends Error {
|
|
|
14
14
|
}
|
|
15
15
|
exports.ImplementationError = ImplementationError;
|
|
16
16
|
class ReferenceError extends Error {
|
|
17
|
-
constructor(message,
|
|
17
|
+
constructor(message, details) {
|
|
18
18
|
super(message);
|
|
19
|
-
this.
|
|
19
|
+
this.details = details;
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
exports.ReferenceError = ReferenceError;
|
package/package.json
CHANGED
package/src/delete-hooks.js
CHANGED
|
@@ -117,7 +117,7 @@ function validateError(deleteHooks) {
|
|
|
117
117
|
// Error on references
|
|
118
118
|
|
|
119
119
|
async function errorOnForeignReferences(doc, options) {
|
|
120
|
-
const { errorHook,
|
|
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(
|
|
134
|
+
if (referenceIsAllowed(model, options)) {
|
|
135
135
|
continue;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
const
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
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
|
-
|
|
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(
|
|
182
|
-
const {
|
|
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,
|
|
11
|
+
constructor(message, details) {
|
|
12
12
|
super(message);
|
|
13
|
-
this.
|
|
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,
|
|
9
|
-
|
|
8
|
+
constructor(message: any, details: any);
|
|
9
|
+
details: any;
|
|
10
10
|
}
|
|
11
11
|
//# sourceMappingURL=errors.d.ts.map
|
package/types/errors.d.ts.map
CHANGED
|
@@ -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,
|
|
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"}
|