diff --git a/src/api/validator2.ts b/src/api/validator2.ts index ed58f445d3cd317c72cb3d82eef38bafc008c1c6..04dff59aacf7648ac06c1819f34756204d5ecdcc 100644 --- a/src/api/validator2.ts +++ b/src/api/validator2.ts @@ -1,17 +1,20 @@ import * as mongo from 'mongodb'; import hasDuplicates from '../common/has-duplicates'; -type CustomValidator<T> = (value: T) => boolean | string; +type Validator<T> = (value: T) => boolean | string; +type Modifier<T> = (value: T) => T; -interface Validator { +interface Fuctory { get: () => [any, string]; - required: () => Validator; + required: () => Fuctory; - validate: (validator: CustomValidator<any>) => Validator; + validate: (validator: Validator<any>) => Fuctory; + + modify: (modifier: Modifier<any>) => Fuctory; } -class ValidatorCore implements Validator { +class FuctoryCore implements Fuctory { value: any; error: string; @@ -20,6 +23,9 @@ class ValidatorCore implements Validator { this.error = null; } + /** + * ã“ã®å€¤ãŒ undefined ã¾ãŸã¯ã€€null ã®å ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + */ required() { if (this.error === null && this.value === null) { this.error = 'required'; @@ -27,11 +33,19 @@ class ValidatorCore implements Validator { return this; } + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ get(): [any, string] { return [this.value, this.error]; } - validate(validator: CustomValidator<any>) { + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<any>) { if (this.error || this.value === null) return this; const result = validator(this.value); if (result === false) { @@ -41,9 +55,59 @@ class ValidatorCore implements Validator { } return this; } + + modify(modifier: Modifier<any>) { + if (this.error || this.value === null) return this; + try { + this.value = modifier(this.value); + } catch (e) { + this.error = e; + } + return this; + } +} + +class BooleanFuctory extends FuctoryCore { + value: boolean; + error: string; + + constructor(value) { + super(); + if (value === undefined || value === null) { + this.value = null; + } else if (typeof value != 'boolean') { + this.error = 'must-be-a-boolean'; + } else { + this.value = value; + } + } + + required() { + return super.required(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ + get(): [boolean, string] { + return super.get(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<boolean>) { + return super.validate(validator); + } + + modify(modifier: Modifier<boolean>) { + return super.modify(modifier); + } } -class NumberValidator extends ValidatorCore { +class NumberFuctory extends FuctoryCore { value: number; error: string; @@ -58,6 +122,11 @@ class NumberValidator extends ValidatorCore { } } + /** + * 値ãŒæŒ‡å®šã•ã‚ŒãŸç¯„囲内ã«ãªã„å ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param min ä¸‹é™ + * @param max ä¸Šé™ + */ range(min: number, max: number) { if (this.error || this.value === null) return this; if (this.value < min || this.value > max) { @@ -70,28 +139,242 @@ class NumberValidator extends ValidatorCore { return super.required(); } + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ get(): [number, string] { return super.get(); } - validate(validator: CustomValidator<number>) { + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<number>) { + return super.validate(validator); + } + + modify(modifier: Modifier<number>) { + return super.modify(modifier); + } +} + +class StringFuctory extends FuctoryCore { + value: string; + error: string; + + constructor(value) { + super(); + if (value === undefined || value === null) { + this.value = null; + } else if (typeof value != 'string') { + this.error = 'must-be-a-string'; + } else { + this.value = value; + } + } + + /** + * æ–‡å—æ•°ãŒæŒ‡å®šã•ã‚ŒãŸç¯„囲内ã«ãªã„å ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param min ä¸‹é™ + * @param max ä¸Šé™ + */ + range(min: number, max: number) { + if (this.error || this.value === null) return this; + if (this.value.length < min || this.value.length > max) { + this.error = 'invalid-range'; + } + return this; + } + + trim() { + if (this.error || this.value === null) return this; + this.value = this.value.trim(); + return this; + } + + required() { + return super.required(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ + get(): [string, string] { + return super.get(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<string>) { + return super.validate(validator); + } + + modify(modifier: Modifier<string>) { + return super.modify(modifier); + } +} + +class ArrayFuctory extends FuctoryCore { + value: any[]; + error: string; + + constructor(value) { + super(); + if (value === undefined || value === null) { + this.value = null; + } else if (!Array.isArray(value)) { + this.error = 'must-be-an-array'; + } else { + this.value = value; + } + } + + /** + * é…列ã®å€¤ãŒãƒ¦ãƒ‹ãƒ¼ã‚¯ã§ãªã„å ´åˆ(=é‡è¤‡ã—ãŸé …ç›®ãŒã‚ã‚‹å ´åˆ)エラーã«ã—ã¾ã™ + */ + unique() { + if (this.error || this.value === null) return this; + if (hasDuplicates(this.value)) { + this.error = 'must-be-unique'; + } + return this; + } + + /** + * é…列ã®é•·ã•ãŒæŒ‡å®šã•ã‚ŒãŸç¯„囲内ã«ãªã„å ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param min ä¸‹é™ + * @param max ä¸Šé™ + */ + range(min: number, max: number) { + if (this.error || this.value === null) return this; + if (this.value.length < min || this.value.length > max) { + this.error = 'invalid-range'; + } + return this; + } + + required() { + return super.required(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ + get(): [any[], string] { + return super.get(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<any[]>) { + return super.validate(validator); + } + + modify(modifier: Modifier<any[]>) { + return super.modify(modifier); + } +} + +class IdFuctory extends FuctoryCore { + value: mongo.ObjectID; + error: string; + + constructor(value) { + super(); + if (value === undefined || value === null) { + this.value = null; + } else if (typeof value != 'string' || !mongo.ObjectID.isValid(value)) { + this.error = 'must-be-an-id'; + } else { + this.value = new mongo.ObjectID(value); + } + } + + required() { + return super.required(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ + get(): [any[], string] { + return super.get(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<any[]>) { + return super.validate(validator); + } + + modify(modifier: Modifier<any[]>) { + return super.modify(modifier); + } +} + +class ObjectFuctory extends FuctoryCore { + value: any; + error: string; + + constructor(value) { + super(); + if (value === undefined || value === null) { + this.value = null; + } else if (typeof value != 'object') { + this.error = 'must-be-an-object'; + } else { + this.value = value; + } + } + + required() { + return super.required(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ãŠã‚ˆã³ã‚¨ãƒ©ãƒ¼ã‚’å–å¾—ã—ã¾ã™ + */ + get(): [any, string] { + return super.get(); + } + + /** + * ã“ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã®å€¤ã«å¯¾ã—ã¦å¦¥å½“性を検証ã—ã¾ã™ + * ãƒãƒªãƒ‡ãƒ¼ã‚¿ãŒ false ã¾ãŸã¯(エラーを表ã™)æ–‡å—列を返ã—ãŸå ´åˆã‚¨ãƒ©ãƒ¼ã«ã—ã¾ã™ + * @param validator ãƒãƒªãƒ‡ãƒ¼ã‚¿ + */ + validate(validator: Validator<any>) { return super.validate(validator); } + + modify(modifier: Modifier<any>) { + return super.modify(modifier); + } } const it = (value: any) => ({ must: { be: { a: { - string: 0, - number: () => new NumberValidator(value), - boolean: 0, - set: 0 + string: () => new StringFuctory(value), + number: () => new NumberFuctory(value), + boolean: () => new BooleanFuctory(value) }, an: { - id: 0, - array: 0, - object: 0 + id: () => new IdFuctory(value), + array: () => new ArrayFuctory(value), + object: () => new ObjectFuctory(value) } } }