From 2fee8fbba36376651161249964e1a3eca0f3d573 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 3 Mar 2017 02:10:27 +0900 Subject: [PATCH] wip --- src/api/endpoints/posts/create.ts | 8 +- src/api/it.ts | 203 +++++++++--------------------- 2 files changed, 64 insertions(+), 147 deletions(-) diff --git a/src/api/endpoints/posts/create.ts b/src/api/endpoints/posts/create.ts index f707c81b1..5ce852280 100644 --- a/src/api/endpoints/posts/create.ts +++ b/src/api/endpoints/posts/create.ts @@ -27,11 +27,11 @@ module.exports = (params, user, app) => new Promise(async (res, rej) => { // Get 'text' parameter - const [text, textErr] = it(params.text).must.be.a.string().validate(isValidText).get(); + const [text, textErr] = it(params.text).must.be.a.string().validate(isValidText).qed(); if (textErr) return rej('invalid text'); // Get 'media_ids' parameter - const [mediaIds, mediaIdsErr] = it(params.media_ids).must.be.an.array().unique().range(1, 4).get(); + const [mediaIds, mediaIdsErr] = it(params.media_ids).must.be.an.array().unique().range(1, 4).qed(); if (mediaIdsErr) return rej('invalid media_ids'); let files = []; @@ -40,7 +40,7 @@ module.exports = (params, user, app) => // forEach だと途中でエラーなどがあっても return できないので // 敢えて for を使っています。 for (let i = 0; i < mediaIds.length; i++) { - const [mediaId, mediaIdErr] = it(mediaIds[i]).must.be.an.id().required().get(); + const [mediaId, mediaIdErr] = it(mediaIds[i]).must.be.an.id().required().qed(); if (mediaIdErr) return rej('invalid media id'); // Fetch file @@ -63,7 +63,7 @@ module.exports = (params, user, app) => } // Get 'repost_id' parameter - const [repostId, repostIdErr] = it(params.repost_id).must.be.an.id().get(); + const [repostId, repostIdErr] = it(params.repost_id).must.be.an.id().qed(); if (repostIdErr) return rej('invalid repost_id'); let repost = null; diff --git a/src/api/it.ts b/src/api/it.ts index 1aff99c9e..6e8aefdf2 100644 --- a/src/api/it.ts +++ b/src/api/it.ts @@ -2,16 +2,16 @@ import * as mongo from 'mongodb'; import hasDuplicates from '../common/has-duplicates'; type Validator = (value: T) => boolean | Error; -type Modifier = (value: T) => T; interface Factory { - get: () => [any, Error]; + /** + * qedはQ.E.D.でもあり'QueryENd'の略でもある + */ + qed: () => [any, Error]; required: () => Factory; validate: (validator: Validator) => Factory; - - modify: (modifier: Modifier) => Factory; } class FactoryCore implements Factory { @@ -36,7 +36,7 @@ class FactoryCore implements Factory { /** * このインスタンスの値およびエラーを取得します */ - get(): [any, Error] { + qed(): [any, Error] { return [this.value, this.error]; } @@ -55,16 +55,6 @@ class FactoryCore implements Factory { } return this; } - - modify(modifier: Modifier) { - if (this.error || this.value === null) return this; - try { - this.value = modifier(this.value); - } catch (e) { - this.error = e; - } - return this; - } } class BooleanFactory extends FactoryCore { @@ -92,8 +82,8 @@ class BooleanFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [boolean, Error] { - return super.get(); + qed(): [boolean, Error] { + return super.qed(); } /** @@ -104,10 +94,6 @@ class BooleanFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } class NumberFactory extends FactoryCore { @@ -148,8 +134,8 @@ class NumberFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [number, Error] { - return super.get(); + qed(): [number, Error] { + return super.qed(); } /** @@ -160,10 +146,6 @@ class NumberFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } class StringFactory extends FactoryCore { @@ -210,8 +192,8 @@ class StringFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [string, Error] { - return super.get(); + qed(): [string, Error] { + return super.qed(); } /** @@ -222,10 +204,6 @@ class StringFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } class ArrayFactory extends FactoryCore { @@ -277,8 +255,8 @@ class ArrayFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [any[], Error] { - return super.get(); + qed(): [any[], Error] { + return super.qed(); } /** @@ -289,10 +267,6 @@ class ArrayFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } class IdFactory extends FactoryCore { @@ -320,8 +294,8 @@ class IdFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [any[], Error] { - return super.get(); + qed(): [any[], Error] { + return super.qed(); } /** @@ -332,10 +306,6 @@ class IdFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } class ObjectFactory extends FactoryCore { @@ -363,8 +333,8 @@ class ObjectFactory extends FactoryCore { /** * このインスタンスの値およびエラーを取得します */ - get(): [any, Error] { - return super.get(); + qed(): [any, Error] { + return super.qed(); } /** @@ -375,13 +345,9 @@ class ObjectFactory extends FactoryCore { validate(validator: Validator) { return super.validate(validator); } - - modify(modifier: Modifier) { - return super.modify(modifier); - } } -type MustBe = { +type It = { must: { be: { a: { @@ -396,9 +362,17 @@ type MustBe = { }; }; }; + expect: { + string: () => StringFactory; + number: () => NumberFactory; + boolean: () => BooleanFactory; + id: () => IdFactory; + array: () => ArrayFactory; + object: () => ObjectFactory; + }; }; -const mustBe = (value: any) => ({ +const it = (value: any) => ({ must: { be: { a: { @@ -412,107 +386,50 @@ const mustBe = (value: any) => ({ object: () => new ObjectFactory(value) } } + }, + expect: { + string: () => new StringFactory(value), + number: () => new NumberFactory(value), + boolean: () => new BooleanFactory(value), + id: () => new IdFactory(value), + array: () => new ArrayFactory(value), + object: () => new ObjectFactory(value) } }); type Type = 'id' | 'string' | 'number' | 'boolean' | 'array' | 'set' | 'object'; -type Pipe = (x: T) => T | boolean | Error; -function validate(value: any, type: 'id', isRequired?: boolean, pipe?: Pipe | Pipe[]): [mongo.ObjectID, Error]; -function validate(value: any, type: 'string', isRequired?: boolean, pipe?: Pipe | Pipe[]): [string, Error]; -function validate(value: any, type: 'number', isRequired?: boolean, pipe?: Pipe | Pipe[]): [number, Error]; -function validate(value: any, type: 'boolean', isRequired?: boolean): [boolean, Error]; -function validate(value: any, type: 'array', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any[], Error]; -function validate(value: any, type: 'set', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any[], Error]; -function validate(value: any, type: 'object', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any, Error]; -function validate(value: any, type: Type, isRequired?: boolean, pipe?: Pipe | Pipe[]): [any, Error] { - if (value === undefined || value === null) { - if (isRequired) { - return [null, new Error('is-required')] - } else { - return [null, null] - } - } +function x(value: any): It; +function x(value: any, type: 'id', isRequired?: boolean, validator?: Validator | Validator[]): [mongo.ObjectID, Error]; +function x(value: any, type: 'string', isRequired?: boolean, validator?: Validator | Validator[]): [string, Error]; +function x(value: any, type: 'number', isRequired?: boolean, validator?: Validator | Validator[]): [number, Error]; +function x(value: any, type: 'boolean', isRequired?: boolean): [boolean, Error]; +function x(value: any, type: 'array', isRequired?: boolean, validator?: Validator | Validator[]): [any[], Error]; +function x(value: any, type: 'set', isRequired?: boolean, validator?: Validator | Validator[]): [any[], Error]; +function x(value: any, type: 'object', isRequired?: boolean, validator?: Validator | Validator[]): [any, Error]; +function x(value: any, type?: Type, isRequired?: boolean, validator?: Validator | Validator[]): any { + if (typeof type === 'undefined') return it(value); + + let factory: Factory = null; switch (type) { - case 'id': - if (typeof value != 'string' || !mongo.ObjectID.isValid(value)) { - return [null, new Error('incorrect-id')]; - } - break; - - case 'string': - if (typeof value != 'string') { - return [null, new Error('must-be-a-string')]; - } - break; - - case 'number': - if (!Number.isFinite(value)) { - return [null, new Error('must-be-a-number')]; - } - break; - - case 'boolean': - if (typeof value != 'boolean') { - return [null, new Error('must-be-a-boolean')]; - } - break; - - case 'array': - if (!Array.isArray(value)) { - return [null, new Error('must-be-an-array')]; - } - break; - - case 'set': - if (!Array.isArray(value)) { - return [null, new Error('must-be-an-array')]; - } else if (hasDuplicates(value)) { - return [null, new Error('duplicated-contents')]; - } - break; - - case 'object': - if (typeof value != 'object') { - return [null, new Error('must-be-an-object')]; - } - break; + case 'id': factory = it(value).expect.id(); break; + case 'string': factory = it(value).expect.string(); break; + case 'number': factory = it(value).expect.number(); break; + case 'boolean': factory = it(value).expect.boolean(); break; + case 'array': factory = it(value).expect.array(); break; + case 'set': factory = it(value).expect.array().unique(); break; + case 'object': factory = it(value).expect.object(); break; } - if (type == 'id') value = new mongo.ObjectID(value); + if (isRequired) factory = factory.required(); - if (pipe) { - const pipes = Array.isArray(pipe) ? pipe : [pipe]; - for (let i = 0; i < pipes.length; i++) { - const result = pipes[i](value); - if (result === false) { - return [null, new Error('invalid-format')]; - } else if (result instanceof Error) { - return [null, result]; - } else if (result !== true) { - value = result; - } - } + if (validator) { + (Array.isArray(validator) ? validator : [validator]) + .forEach(v => factory = factory.validate(v)); } - return [value, null]; + return factory; } -function it(value: any): MustBe; -function it(value: any, type: 'id', isRequired?: boolean, pipe?: Pipe | Pipe[]): [mongo.ObjectID, Error]; -function it(value: any, type: 'string', isRequired?: boolean, pipe?: Pipe | Pipe[]): [string, Error]; -function it(value: any, type: 'number', isRequired?: boolean, pipe?: Pipe | Pipe[]): [number, Error]; -function it(value: any, type: 'boolean', isRequired?: boolean): [boolean, Error]; -function it(value: any, type: 'array', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any[], Error]; -function it(value: any, type: 'set', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any[], Error]; -function it(value: any, type: 'object', isRequired?: boolean, pipe?: Pipe | Pipe[]): [any, Error]; -function it(value: any, type?: any, isRequired?: boolean, pipe?: Pipe | Pipe[]): any { - if (typeof type === 'undefined') { - return mustBe(value); - } else { - return validate(value, type, isRequired, pipe); - } -} - -export default it; +export default x;