Comparing version 1.0.0-alpha.9 to 1.0.0-alpha.10
import { IPopulateMap } from './populate'; | ||
import { ISchemaSanitizeOptions, ISchemaToObjectOptions, SchemaMap, SchemaValue } from './schema'; | ||
export declare abstract class Model<T> { | ||
export declare abstract class Model<T extends object> { | ||
static _schema: SchemaMap; | ||
@@ -12,2 +12,3 @@ /** | ||
constructor(data?: Partial<T>); | ||
inspect(): T; | ||
populate(populateMap: IPopulateMap): Promise<object>; | ||
@@ -18,3 +19,3 @@ set(data: object, options?: ISchemaSanitizeOptions): void; | ||
toJSON(): T; | ||
inspect(): T; | ||
validate(): Promise<void>; | ||
} |
@@ -14,2 +14,3 @@ "use strict"; | ||
const schema_1 = require("./schema"); | ||
const validate_1 = require("./validate"); | ||
function defineModelProperty(target, key, enumerable) { | ||
@@ -52,2 +53,5 @@ Object.defineProperty(target, key, { | ||
} | ||
inspect() { | ||
return this.toObject(); | ||
} | ||
populate(populateMap) { | ||
@@ -95,4 +99,7 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
inspect() { | ||
return this.toObject(); | ||
validate() { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
const constructor = this.constructor; | ||
yield validate_1.validateObject(constructor._schema, this, [], this); | ||
}); | ||
} | ||
@@ -99,0 +106,0 @@ } |
@@ -0,1 +1,2 @@ | ||
import { Model } from './model'; | ||
export interface ISchemaValueBase { | ||
@@ -8,2 +9,3 @@ type: string; | ||
default?: () => any; | ||
validate?(value: any, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -15,2 +17,3 @@ export interface ISchemaValueArray extends ISchemaValueBase { | ||
maxLength?: number; | ||
validate?(value: any[], path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -20,2 +23,3 @@ export interface ISchemaValueBoolean extends ISchemaValueBase { | ||
default?: boolean | (() => boolean); | ||
validate?(value: boolean, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -27,2 +31,3 @@ export interface ISchemaValueDate extends ISchemaValueBase { | ||
max?: Date; | ||
validate?(value: Date, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -36,2 +41,3 @@ export interface IModelConstructor { | ||
model: IModelConstructor; | ||
validate?(value: Model<object>, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -44,2 +50,3 @@ export interface ISchemaValueNumber extends ISchemaValueBase { | ||
integer?: boolean; | ||
validate?(value: number, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -49,2 +56,3 @@ export interface ISchemaValueObject extends ISchemaValueBase { | ||
definition: ISchemaMap; | ||
validate?(value: object, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -54,2 +62,3 @@ export interface ISchemaValueReference extends ISchemaValueBase { | ||
collection: () => any; | ||
validate?(value: any, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -59,3 +68,2 @@ export interface ISchemaValueString extends ISchemaValueBase { | ||
default?: string | (() => string); | ||
allowEmpty?: boolean; | ||
enum?: string[]; | ||
@@ -65,2 +73,3 @@ min?: number; | ||
regex?: RegExp; | ||
validate?(value: string, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -67,0 +76,0 @@ export declare type SchemaValue = ISchemaValueAny | ISchemaValueArray | ISchemaValueBoolean | ISchemaValueDate | ISchemaValueModel | ISchemaValueNumber | ISchemaValueObject | ISchemaValueReference | ISchemaValueString; |
@@ -1,3 +0,1 @@ | ||
import { spy } from 'sinon'; | ||
import { collections } from '../test/data/collections'; | ||
@@ -11,2 +9,4 @@ import { CatModel } from '../test/data/models/cat'; | ||
import { ValidationError } from './errors'; | ||
import { Model } from './model'; | ||
import { ModelArray } from './model-array'; | ||
@@ -195,6 +195,4 @@ | ||
const person = new PersonModel({id: '42', name: 'Bob'}); | ||
const toObject = spy(person, 'toObject'); | ||
const group = new GroupWithArrayModel({id: '1337', members: [person]}); | ||
expect(group.toObject({unpopulate: true})).to.eql({id: '1337', members: [{id: '42', name: 'Bob'}]}); | ||
expect(toObject.calledWith({unpopulate: true})); | ||
}); | ||
@@ -372,2 +370,70 @@ }); | ||
}); | ||
describe('validate()', () => { | ||
class TestModel extends Model<TestModel> { | ||
@Model.PropertySchema({type: 'string', required: true}) | ||
public required: string; | ||
@Model.PropertySchema({type: 'array', definition: {type: 'string', enum: ['foo', 'bar']}}) | ||
public array: string[]; | ||
@Model.PropertySchema({type: 'model', model: TestModel}) | ||
public model: TestModel; | ||
@Model.PropertySchema({type: 'object', definition: {foo: {type: 'string', enum: ['bar']}}}) | ||
public object: {foo: string}; | ||
} | ||
it('should throw if a key is required', async () => { | ||
const instance = new TestModel(); | ||
await expect(instance.validate()) | ||
.to.be.rejectedWith(ValidationError, 'Required value is undefined.'); | ||
}); | ||
it('should throw if nested array validation throws', async () => { | ||
const instance = new TestModel({required: 'foo', array: ['foo', 'baz']}); | ||
let error; | ||
await instance.validate().catch(e => error = e); | ||
expect(error).to.be.instanceOf(ValidationError); | ||
expect(error.message).to.equal('String not in enum: foo, bar.'); | ||
expect(error.value).to.equal('baz'); | ||
expect(error.path).to.eql(['array', 1]); | ||
expect(error.instance).to.equal(instance); | ||
}); | ||
it('should throw if nested model validation throws', async () => { | ||
const instance = new TestModel({ | ||
required: 'foo', | ||
model: new TestModel({}), | ||
}); | ||
let error; | ||
await instance.validate().catch(e => error = e); | ||
expect(error).to.be.instanceOf(ValidationError); | ||
expect(error.message).to.equal('Required value is undefined.'); | ||
expect(error.value).to.equal(undefined); | ||
expect(error.path).to.eql(['model', 'required']); | ||
expect(error.instance).to.equal(instance); | ||
}); | ||
it('should throw if nested object validation throws', async () => { | ||
const instance = new TestModel({required: 'foo', object: {foo: 'baz'}}); | ||
let error; | ||
await instance.validate().catch(e => error = e); | ||
expect(error).to.be.instanceOf(ValidationError); | ||
expect(error.message).to.equal('String not in enum: bar.'); | ||
expect(error.value).to.equal('baz'); | ||
expect(error.path).to.eql(['object', 'foo']); | ||
expect(error.instance).to.equal(instance); | ||
}); | ||
it('should pass with a valid instance', async () => { | ||
const instance = new TestModel({ | ||
required: 'foo', | ||
array: ['foo', 'bar'], | ||
model: new TestModel({required: 'bar'}), | ||
object: {foo: 'bar'}, | ||
}); | ||
await instance.validate(); | ||
}); | ||
}); | ||
}); |
@@ -6,2 +6,3 @@ import { cloneDeep, difference, forEach } from 'lodash'; | ||
SchemaMap, SchemaValue, toObject } from './schema'; | ||
import { validateObject } from './validate'; | ||
@@ -30,3 +31,3 @@ interface IModel { | ||
export abstract class Model<T> { | ||
export abstract class Model<T extends object> { | ||
public static _schema: SchemaMap = {}; | ||
@@ -59,2 +60,6 @@ | ||
public inspect() { | ||
return this.toObject(); | ||
} | ||
public async populate(populateMap: IPopulateMap) { | ||
@@ -111,5 +116,6 @@ const constructor = this.constructor as typeof Model; | ||
public inspect() { | ||
return this.toObject(); | ||
public async validate() { | ||
const constructor = this.constructor as typeof Model; | ||
await validateObject(constructor._schema, this, [], this); | ||
} | ||
} |
import { difference, forEach, isArray, isBoolean, isDate, isFunction, isNumber, isString } from 'lodash'; | ||
import { Model } from './model'; | ||
import { ModelArray } from './model-array'; | ||
@@ -13,2 +14,3 @@ | ||
default?: () => any; | ||
validate?(value: any, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -21,2 +23,3 @@ | ||
maxLength?: number; | ||
validate?(value: any[], path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -27,2 +30,3 @@ | ||
default?: boolean | (() => boolean); | ||
validate?(value: boolean, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -35,2 +39,3 @@ | ||
max?: Date; | ||
validate?(value: Date, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -46,2 +51,3 @@ | ||
model: IModelConstructor; | ||
validate?(value: Model<object>, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -55,2 +61,3 @@ | ||
integer?: boolean; | ||
validate?(value: number, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -61,2 +68,3 @@ | ||
definition: ISchemaMap; | ||
validate?(value: object, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -67,2 +75,3 @@ | ||
collection: () => any; // TODO | ||
validate?(value: any, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -73,3 +82,2 @@ | ||
default?: string | (() => string); | ||
allowEmpty?: boolean; | ||
enum?: string[]; | ||
@@ -79,2 +87,3 @@ min?: number; | ||
regex?: RegExp; | ||
validate?(value: string, path: Array<string | number>, instance: Model<any>): Promise<void>; | ||
} | ||
@@ -81,0 +90,0 @@ |
{ | ||
"name": "octonom", | ||
"version": "1.0.0-alpha.9", | ||
"version": "1.0.0-alpha.10", | ||
"description": "Object Document Mapper for any database", | ||
@@ -5,0 +5,0 @@ "main": "build/lib/main.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
177773
77
3480