Skip to content

Commit

Permalink
feat(p3): add basic assertions for Sinap params decorators
Browse files Browse the repository at this point in the history
  • Loading branch information
pismenskiy authored Apr 28, 2020
1 parent 8c01ea6 commit 9d53721
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 13 deletions.
83 changes: 80 additions & 3 deletions packages/p3/src/main/ts/sinap/decortors/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {IProto} from '@qiwi/decorator-utils/target/es5/interface'
import {constructDecorator, METHOD, PARAM} from '@qiwi/decorator-utils'
import {JsonRpcMethod} from 'nestjs-json-rpc'
import {JSON_RPC_METADATA, JsonRpcMethod} from 'nestjs-json-rpc'
import {JsonRpcData, ParamMetadataKeys} from 'expressjs-json-rpc'

export type TSinapSuggest = {
Expand All @@ -8,14 +9,89 @@ export type TSinapSuggest = {
locale: string
}

export class SinapSuggestRequest implements TSinapSuggest {

query: string
fields?: Record<string, any>
locale: string

constructor(request: TSinapSuggest) {
this.fields = request.fields
this.locale = request.locale
this.query = request.query
}

}

export type TSinapContext = {
fields?: Record<string, any>
locale: string
}

export class SinapContextRequest implements TSinapContext {

fields?: Record<string, any>
locale: string

constructor(request: TSinapContext) {
this.fields = request.fields
this.locale = request.locale
}

}

export class SinapSuggestResponse<T = object> extends Array<T> {}

export class SinapContextResponse {

[key: string]: any

}

const returnTypeMap = {
SinapSuggestResponse: 'SinapSuggest',
SinapContextResponse: 'SinapContext',
}

const paramTypeMap = {
SinapSuggestRequest: 'SinapSuggest',
SinapContextRequest: 'SinapContext',
}

const decoratorCompatibilityCheck = (
proto: IProto,
propName: string | undefined,
method: string,
ctor: Function,
) => {
const returnType = Reflect.getMetadata('design:returntype', proto, propName + '')?.name
// @ts-ignore
if (returnType && returnTypeMap[returnType] !== method) {
throw new Error(`Cannot return ${returnType} in ${method}`)
}

const sinapParam = Reflect.getMetadata('design:paramtypes', proto, propName + '')
const meta = Reflect.getMetadata(JSON_RPC_METADATA, ctor)
// @ts-ignore
meta?.[propName]?.params.forEach(({index, type}) => {
if (type === 'params') {
// @ts-ignore
if (paramTypeMap[sinapParam[index].name] === undefined) {
throw new Error(`Cannot use ${sinapParam[index].name} class with this parameter decorator`)
}

// @ts-ignore
if (paramTypeMap[sinapParam[index].name] !== method) {
throw new Error(`Class ${sinapParam[index].name} not compatible with ${method} method`)
}
}
})
}

export const SinapSuggest = (arg?: any) => {
return constructDecorator(({targetType, proto, propName, paramIndex}) => {
return constructDecorator(({targetType, proto, propName, paramIndex, ctor}) => {
if (targetType === METHOD) {
decoratorCompatibilityCheck(proto, propName, 'SinapSuggest', ctor)
JsonRpcMethod(`suggest.${arg}`)(proto, propName!)
}

Expand All @@ -27,8 +103,9 @@ export const SinapSuggest = (arg?: any) => {
}

export const SinapContext = (arg?: any) => {
return constructDecorator(({targetType, proto, propName, paramIndex}) => {
return constructDecorator(({targetType, proto, propName, paramIndex, ctor}) => {
if (targetType === METHOD) {
decoratorCompatibilityCheck(proto, propName, 'SinapContext', ctor)
JsonRpcMethod(`context.${arg}`)(proto, propName!)
}

Expand Down
23 changes: 13 additions & 10 deletions packages/p3/src/test/ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import {HttpStatus} from '@nestjs/common'
import {NestApplication} from '@nestjs/core'
import request from 'supertest'
import {RpcId} from 'nestjs-json-rpc'
// import {METHOD} from '@qiwi/decorator-utils'

import {
P3Provider,
Auth,
ClientAuth,
TSinapSuggest,
SinapSuggestRequest,
SinapSuggest,
SinapContext,
Client,
Expand All @@ -17,6 +17,8 @@ import {
TSecurity,
ClientType,
SecurityLevel,
SinapContextResponse,
SinapSuggestResponse,
} from '../../main/ts'

describe('P3', () => {
Expand All @@ -27,21 +29,22 @@ describe('P3', () => {
@SinapSuggest('test2')
bar(
@RpcId() id: string,
@SinapSuggest() params: TSinapSuggest,
@SinapSuggest() params: SinapSuggestRequest,
@Auth() auth: string,
@ClientAuth() clientAuth: string,
@Client() client: TClient,
@Security() security: TSecurity,
) {
return {
): SinapSuggestResponse {
// @ts-ignore
return [{
foo: 'bar',
id,
params,
auth,
clientAuth,
client,
security,
}
}]
}

}
Expand Down Expand Up @@ -87,15 +90,15 @@ describe('P3', () => {
.expect({
jsonrpc: '2.0',
id: '123',
result: {
result: [{
foo: 'bar',
id: '123',
params: {fields: {a: '123', foo: 'bar'}, locale: 'baz', query: 'qwe'},
auth: 'Authorization test2',
clientAuth: 'Client-Authorization test3344',
client: {clientId: 'SINAP-CLIENT', clientType: 'SINAP'},
security: {level: 0},
},
}],
})
})
})
Expand All @@ -106,12 +109,12 @@ describe('P3', () => {

@Security(SecurityLevel.SECURE)
@SinapContext('test2')
bar() {
bar(): SinapContextResponse {
return {foo: 'bar'}
}

@SinapContext('test1')
baz() {
baz(): SinapContextResponse {
return {foo: 'bar'}
}

Expand Down

0 comments on commit 9d53721

Please sign in to comment.