@aeriajs/validation 0.0.162 → 0.0.163

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.
@@ -1,4 +1,5 @@
1
- import type { JsonSchema, Property, InferSchema, Description, PropertyValidationError, ValidationError } from '@aeriajs/types';
1
+ import type { JsonSchema, Property, InferSchema, Description, PropertyValidationError, ValidationError, CollectionModel } from '@aeriajs/types';
2
+ import type { ObjectId } from 'mongodb';
2
3
  import { Result } from '@aeriajs/types';
3
4
  export type ValidateOptions = {
4
5
  tolerateExtraneous?: boolean;
@@ -7,10 +8,16 @@ export type ValidateOptions = {
7
8
  coerce?: boolean;
8
9
  parentProperty?: Property | Description;
9
10
  descriptions?: Record<string, Description>;
11
+ objectIdConstructor?: new (arg: unknown) => ObjectId;
12
+ context?: {
13
+ collections: Record<string, {
14
+ model: CollectionModel<Description>;
15
+ }>;
16
+ };
10
17
  };
11
18
  export declare const makeValidationError: <TValidationError extends ValidationError>(error: TValidationError) => TValidationError;
12
19
  export declare const validateProperty: <TWhat>(what: TWhat, property: Property | undefined, options?: ValidateOptions) => Result.Either<PropertyValidationError | ValidationError, unknown>;
13
- export declare const validateRefs: <TWhat>(what: TWhat, property: Property | Description | undefined, options?: ValidateOptions) => Promise<Result.Either<PropertyValidationError | ValidationError, unknown>>;
20
+ export declare const validateRefs: <TWhat>(what: TWhat, property: Property | Description, options?: ValidateOptions) => Promise<Result.Either<PropertyValidationError | ValidationError, unknown>>;
14
21
  export declare const validateWholeness: (what: Record<string, unknown>, schema: Omit<JsonSchema, "$id">) => {
15
22
  code: "MISSING_PROPERTIES";
16
23
  details: {
@@ -37,6 +44,7 @@ export declare const validateWithRefs: <TWhat, const TJsonSchema extends Propert
37
44
  readonly error: undefined;
38
45
  readonly result: InferSchema<TJsonSchema, {}>;
39
46
  }>;
47
+ export declare const validatePropertyWithRefs: <TWhat>(what: TWhat | undefined, property: Property, options?: ValidateOptions) => Promise<Result.Either<PropertyValidationError | ValidationError, unknown>>;
40
48
  export declare const validator: <const TJsonSchema extends Property | Description>(schema: TJsonSchema, options?: ValidateOptions) => readonly [InferSchema<TJsonSchema>, <TWhat>(what: TWhat) => {
41
49
  readonly _tag: "Error";
42
50
  readonly error: PropertyValidationError | ValidationError;
package/dist/validate.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.validator = exports.validateWithRefs = exports.validate = exports.validateWholeness = exports.validateRefs = exports.validateProperty = exports.makeValidationError = void 0;
3
+ exports.validator = exports.validatePropertyWithRefs = exports.validateWithRefs = exports.validate = exports.validateWholeness = exports.validateRefs = exports.validateProperty = exports.makeValidationError = void 0;
4
4
  const common_1 = require("@aeriajs/common");
5
5
  const types_1 = require("@aeriajs/types");
6
6
  const entrypoint_1 = require("@aeriajs/entrypoint");
@@ -212,53 +212,93 @@ const validateProperty = (what, property, options = {}) => {
212
212
  };
213
213
  exports.validateProperty = validateProperty;
214
214
  const validateRefs = async (what, property, options = {}) => {
215
- if (property) {
216
- if ('$ref' in property) {
217
- let description;
218
- if (options.descriptions) {
219
- description = options.descriptions[property.$ref];
215
+ if ('$ref' in property) {
216
+ if (options.checkObjectIds) {
217
+ if (!options.context || !options.objectIdConstructor) {
218
+ throw new Error;
220
219
  }
221
- else {
222
- const collection = await (0, entrypoint_1.getCollection)(property.$ref);
223
- if (!collection) {
224
- throw new Error;
225
- }
226
- description = collection.description;
220
+ if (what === null) {
221
+ return types_1.Result.result({});
227
222
  }
228
- if (typeof what !== 'object') {
223
+ if (!isValidObjectId(String(what))) {
229
224
  return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
230
- expected: 'object',
225
+ expected: 'objectid',
231
226
  got: typeof what,
232
227
  }));
233
228
  }
234
- return (0, exports.validate)(what, description, options);
229
+ let query;
230
+ if (property.constraints) {
231
+ query = {
232
+ $and: [
233
+ {
234
+ _id: new options.objectIdConstructor(what),
235
+ },
236
+ (0, common_1.convertConditionToQuery)(property.constraints),
237
+ ],
238
+ };
239
+ }
240
+ else {
241
+ query = {
242
+ _id: new options.objectIdConstructor(what),
243
+ };
244
+ }
245
+ const exists = await options.context.collections[property.$ref].model.findOne(query, {
246
+ projection: {
247
+ _id: 1,
248
+ },
249
+ });
250
+ if (!exists) {
251
+ return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.ReferenceConstraint, {
252
+ expected: 'objectid',
253
+ got: 'invalid_objectid',
254
+ }));
255
+ }
256
+ return types_1.Result.result({});
257
+ }
258
+ let description;
259
+ if (options.descriptions) {
260
+ description = options.descriptions[property.$ref];
235
261
  }
236
- else if ('items' in property) {
237
- if (!Array.isArray(what)) {
262
+ else {
263
+ const collection = await (0, entrypoint_1.getCollection)(property.$ref);
264
+ if (!collection) {
238
265
  throw new Error;
239
266
  }
240
- for (const elem of what) {
241
- const { error } = await (0, exports.validateRefs)(elem, property.items, options);
242
- if (error) {
243
- return types_1.Result.error(error);
244
- }
245
- }
267
+ description = collection.description;
246
268
  }
247
- else if ('properties' in property) {
248
- const details = {};
249
- for (const propName in what) {
250
- const { error } = await (0, exports.validateRefs)(what[propName], property.properties[propName], options);
251
- if (error) {
252
- details[propName] = error;
253
- }
269
+ if (typeof what !== 'object') {
270
+ return types_1.Result.error(makePropertyError(types_1.PropertyValidationErrorCode.Unmatching, {
271
+ expected: 'object',
272
+ got: typeof what,
273
+ }));
274
+ }
275
+ return (0, exports.validate)(what, description, options);
276
+ }
277
+ else if ('items' in property) {
278
+ if (!Array.isArray(what)) {
279
+ throw new Error;
280
+ }
281
+ for (const elem of what) {
282
+ const { error } = await (0, exports.validateRefs)(elem, property.items, options);
283
+ if (error) {
284
+ return types_1.Result.error(error);
254
285
  }
255
- if (Object.keys(details).length > 0) {
256
- return types_1.Result.error((0, exports.makeValidationError)({
257
- code: types_1.ValidationErrorCode.InvalidProperties,
258
- details,
259
- }));
286
+ }
287
+ }
288
+ else if ('properties' in property) {
289
+ const details = {};
290
+ for (const propName in what) {
291
+ const { error } = await (0, exports.validateRefs)(what[propName], property.properties[propName], options);
292
+ if (error) {
293
+ details[propName] = error;
260
294
  }
261
295
  }
296
+ if (Object.keys(details).length > 0) {
297
+ return types_1.Result.error((0, exports.makeValidationError)({
298
+ code: types_1.ValidationErrorCode.InvalidProperties,
299
+ details,
300
+ }));
301
+ }
262
302
  }
263
303
  return types_1.Result.result({});
264
304
  };
@@ -337,6 +377,14 @@ const validateWithRefs = async (what, schema, options = {}) => {
337
377
  return (0, exports.validate)(what, schema, options);
338
378
  };
339
379
  exports.validateWithRefs = validateWithRefs;
380
+ const validatePropertyWithRefs = async (what, property, options = {}) => {
381
+ const { error: refsError } = await (0, exports.validateRefs)(what, property, options);
382
+ if (refsError) {
383
+ return types_1.Result.error(refsError);
384
+ }
385
+ return (0, exports.validateProperty)(what, property, options);
386
+ };
387
+ exports.validatePropertyWithRefs = validatePropertyWithRefs;
340
388
  const validator = (schema, options = {}) => {
341
389
  return [
342
390
  {},
package/dist/validate.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- import { getMissingProperties } from "@aeriajs/common";
2
+ import { convertConditionToQuery, getMissingProperties } from "@aeriajs/common";
3
3
  import { Result, ValidationErrorCode, PropertyValidationErrorCode } from "@aeriajs/types";
4
4
  import { getCollection } from "@aeriajs/entrypoint";
5
5
  const isValidObjectId = (what) => {
@@ -198,50 +198,89 @@ export const validateProperty = (what, property, options = {}) => {
198
198
  return Result.result(what);
199
199
  };
200
200
  export const validateRefs = async (what, property, options = {}) => {
201
- if (property) {
202
- if ("$ref" in property) {
203
- let description;
204
- if (options.descriptions) {
205
- description = options.descriptions[property.$ref];
206
- } else {
207
- const collection = await getCollection(property.$ref);
208
- if (!collection) {
209
- throw new Error();
210
- }
211
- description = collection.description;
201
+ if ("$ref" in property) {
202
+ if (options.checkObjectIds) {
203
+ if (!options.context || !options.objectIdConstructor) {
204
+ throw new Error();
212
205
  }
213
- if (typeof what !== "object") {
206
+ if (what === null) {
207
+ return Result.result({});
208
+ }
209
+ if (!isValidObjectId(String(what))) {
214
210
  return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
215
- expected: "object",
211
+ expected: "objectid",
216
212
  got: typeof what
217
213
  }));
218
214
  }
219
- return validate(what, description, options);
220
- } else if ("items" in property) {
221
- if (!Array.isArray(what)) {
222
- throw new Error();
215
+ let query;
216
+ if (property.constraints) {
217
+ query = {
218
+ $and: [
219
+ {
220
+ _id: new options.objectIdConstructor(what)
221
+ },
222
+ convertConditionToQuery(property.constraints)
223
+ ]
224
+ };
225
+ } else {
226
+ query = {
227
+ _id: new options.objectIdConstructor(what)
228
+ };
223
229
  }
224
- for (const elem of what) {
225
- const { error } = await validateRefs(elem, property.items, options);
226
- if (error) {
227
- return Result.error(error);
230
+ const exists = await options.context.collections[property.$ref].model.findOne(query, {
231
+ projection: {
232
+ _id: 1
228
233
  }
234
+ });
235
+ if (!exists) {
236
+ return Result.error(makePropertyError(PropertyValidationErrorCode.ReferenceConstraint, {
237
+ expected: "objectid",
238
+ got: "invalid_objectid"
239
+ }));
229
240
  }
230
- } else if ("properties" in property) {
231
- const details = {};
232
- for (const propName in what) {
233
- const { error } = await validateRefs(what[propName], property.properties[propName], options);
234
- if (error) {
235
- details[propName] = error;
236
- }
241
+ return Result.result({});
242
+ }
243
+ let description;
244
+ if (options.descriptions) {
245
+ description = options.descriptions[property.$ref];
246
+ } else {
247
+ const collection = await getCollection(property.$ref);
248
+ if (!collection) {
249
+ throw new Error();
237
250
  }
238
- if (Object.keys(details).length > 0) {
239
- return Result.error(makeValidationError({
240
- code: ValidationErrorCode.InvalidProperties,
241
- details
242
- }));
251
+ description = collection.description;
252
+ }
253
+ if (typeof what !== "object") {
254
+ return Result.error(makePropertyError(PropertyValidationErrorCode.Unmatching, {
255
+ expected: "object",
256
+ got: typeof what
257
+ }));
258
+ }
259
+ return validate(what, description, options);
260
+ } else if ("items" in property) {
261
+ if (!Array.isArray(what)) {
262
+ throw new Error();
263
+ }
264
+ for (const elem of what) {
265
+ const { error } = await validateRefs(elem, property.items, options);
266
+ if (error) {
267
+ return Result.error(error);
268
+ }
269
+ }
270
+ } else if ("properties" in property) {
271
+ const details = {};
272
+ for (const propName in what) {
273
+ const { error } = await validateRefs(what[propName], property.properties[propName], options);
274
+ if (error) {
275
+ details[propName] = error;
243
276
  }
244
277
  }
278
+ if (Object.keys(details).length > 0) {
279
+ return Result.error(makeValidationError({
280
+ code: ValidationErrorCode.InvalidProperties,
281
+ details
282
+ }));
283
+ }
245
284
  }
246
285
  return Result.result({});
247
286
  };
@@ -314,6 +353,13 @@ export const validateWithRefs = async (what, schema, options = {}) => {
314
353
  }
315
354
  return validate(what, schema, options);
316
355
  };
356
+ export const validatePropertyWithRefs = async (what, property, options = {}) => {
357
+ const { error: refsError } = await validateRefs(what, property, options);
358
+ if (refsError) {
359
+ return Result.error(refsError);
360
+ }
361
+ return validateProperty(what, property, options);
362
+ };
317
363
  export const validator = (schema, options = {}) => {
318
364
  return [
319
365
  {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeriajs/validation",
3
- "version": "0.0.162",
3
+ "version": "0.0.163",
4
4
  "description": "## Installation",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -24,13 +24,14 @@
24
24
  "devDependencies": {
25
25
  "@aeriajs/common": "link:../common",
26
26
  "@aeriajs/entrypoint": "link:../entrypoint",
27
- "@aeriajs/types": "link:../types"
27
+ "@aeriajs/types": "link:../types",
28
+ "mongodb": "^6.16.0"
28
29
  },
29
30
  "peerDependencies": {
30
- "@aeriajs/common": "^0.0.144",
31
- "@aeriajs/entrypoint": "^0.0.149",
32
- "@aeriajs/types": "^0.0.126",
33
- "mongodb": "^6.5.0"
31
+ "@aeriajs/common": "^0.0.145",
32
+ "@aeriajs/entrypoint": "^0.0.150",
33
+ "@aeriajs/types": "^0.0.127",
34
+ "mongodb": "^6.16.0"
34
35
  },
35
36
  "scripts": {
36
37
  "test": "vitest run",