Skip to content

Commit

Permalink
feat(endpoints)
Browse files Browse the repository at this point in the history
- add expand
- exclude test cases
- add EndpointInterfaceInfo
  • Loading branch information
wmakeev committed Jul 19, 2021
1 parent 8d148d6 commit 6690cf8
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 111 deletions.
144 changes: 33 additions & 111 deletions src/model/api/endpoints.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
import type {
EntityByMetaType,
IsExtends,
DocumentWithPositionsMetaType
} from '..'
import type { EntityByMetaType, DocumentWithPositionsMetaType } from '..'
import type { Collection } from '../Collection'
import type { CustomerOrder } from '../CustomerOrder'
import type { DocumentMetaType } from '../Document'
import type { EntityRef } from '../EntityRef'
import type { Patch } from '../utils'
import type { Expand, Patch } from '../utils'
import type { DomineEntityMetaType } from './types'

export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
Expand Down Expand Up @@ -39,129 +33,57 @@ export type HttpMethodPath = {
DELETE: `entity/${DomineEntityMetaType}/${string}`
}

export type EndpointInterfaceInfo<
Payload,
Response,
ExpandStr extends string | undefined
> = {
payload: Payload
response: ExpandStr extends string ? Expand<Response, ExpandStr> : Response
}

// prettier-ignore
export type EndpointInterface<
Method extends HttpMethod,
Ref extends HttpMethodPath[Method]
Endpoint extends HttpMethodPath[Method],
ExpandStr extends string | undefined = undefined
> =
// string
string extends Ref
? { payload: unknown; response: unknown }
string extends Endpoint
? EndpointInterfaceInfo<unknown, unknown, undefined>

// entity/{type}/{id}
: Ref extends `entity/${infer EntityType}/${string}`
: Endpoint extends `entity/${infer EntityType}/${string}`
? EntityType extends DomineEntityMetaType
// GET entity/{type}/{id}
? Method extends 'GET'
? { payload: never; response: EntityByMetaType[EntityType] }
? EndpointInterfaceInfo<
never,
EntityByMetaType[EntityType],
ExpandStr
>

// PUT entity/{type}/{id}
: Method extends 'PUT'
? {
payload: Patch<EntityType>
response: EntityByMetaType[EntityType]
}
? EndpointInterfaceInfo<
Patch<EntityType>,
EntityByMetaType[EntityType],
ExpandStr
>

// Unknown method
: { payload: never; response: unknown }
: EndpointInterfaceInfo<never, unknown, undefined>

// Unknown {type}
: { payload: unknown; response: unknown }
: EndpointInterfaceInfo<unknown, unknown, undefined>

// entity/{type}
: Ref extends `entity/${infer EntityType}`
: Endpoint extends `entity/${infer EntityType}`
? EntityType extends DomineEntityMetaType
// GET entity/{type}
? Method extends 'GET'
? { payload: never; response: Collection<EntityType> }
: { payload: never; response: unknown }
: { payload: unknown; response: unknown }

: { payload: unknown; response: unknown }

// Неизвестный пусть
// @ts-expect-error
const t1 = {} as EndpointInterface<'GET', 'foo/bar'>['response']

// @ts-expect-error
const t2: 'foo' = {} as EndpointInterface<
'GET',
'entity/customerorder'
>['response']

const t3: EndpointInterface<'POST', 'entity/customerorder'>['response'] =
'unknown'

const t4: IsExtends<
EndpointInterface<'GET', 'entity/customerorder'>['response'],
Collection<'customerorder'>
> = true

const t5: IsExtends<
EndpointInterface<'GET', `entity/customerorder/123-456`>['response'],
CustomerOrder
> = true

function request<M extends HttpMethod, P extends HttpMethodPath[M]>(
method: M,
path: P,
body?: EndpointInterface<M, P>['payload']
): EndpointInterface<M, P>['response'] {
return { method, path, body } as any
}

const t6: Collection<'customerorder'> = request('GET', `entity/customerorder`)

const id = '123-456'

const t7: CustomerOrder = request('GET', `entity/customerorder/${id}`)

// @ts-expect-error
const t7e: EntityRef = request('GET', `entity/customerorder3/${id}`)

// @ts-expect-error
const t6e: Collection<'customerorder'> = request(
'GET',
`entity/customerorder/123`
)

const t8 = request('POST', 'entity/customerorder')

// Метод не поддерживает указанный путь
// @ts-expect-error
const t8e = request('POST', 'entity/customerorder/123-456')

const t9_1 = request('PUT', 'entity/customerorder/123-456', {
name: 'new-name'
})

const t9_2: CustomerOrder = request('PUT', 'entity/customerorder/123-456', {
name: 'new-name'
})

const e9_1 = request('PUT', 'entity/customerorder/123-456', {
// @ts-expect-error
id: '123-456'
})

const e9_2 = request('PUT', 'entity/customerorder/123-456', {
// @ts-expect-error
id: '123-456',
name: 'Foo'
})

const t10_1: Patch<'customerorder'> = {
name: 'Foo'
}

const t10_2 = request('PUT', 'entity/customerorder/123-456', t10_1)

const t11_1: Partial<CustomerOrder> = {
meta: {
type: 'customerorder',
href: ''
}
}
? EndpointInterfaceInfo<never, Collection<EntityType>, ExpandStr>
: EndpointInterfaceInfo<never, unknown, undefined>
: EndpointInterfaceInfo<unknown, unknown, undefined>

// @ts-expect-error
const t11_2 = request('PUT', 'entity/customerorder/123-456', t11_1)
: EndpointInterfaceInfo<unknown, unknown, undefined>
114 changes: 114 additions & 0 deletions test/model/api/endpoints.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import type {
Collection,
CustomerOrder,
EndpointInterface,
HttpMethod,
HttpMethodPath,
IsExtends,
Patch
} from '../../../src'

// Неизвестный пусть
// @ts-expect-error
const t1 = {} as EndpointInterface<'GET', 'foo/bar'>['response']

// @ts-expect-error
const t2: 'foo' = {} as EndpointInterface<
'GET',
'entity/customerorder'
>['response']

const t3: EndpointInterface<'POST', 'entity/customerorder'>['response'] =
'unknown'

const t4: IsExtends<
EndpointInterface<'GET', 'entity/customerorder'>['response'],
Collection<'customerorder'>
> = true

const t5: IsExtends<
EndpointInterface<'GET', `entity/customerorder/123-456`>['response'],
CustomerOrder
> = true

function request<
M extends HttpMethod,
P extends HttpMethodPath[M],
E extends string | undefined = undefined
>(
method: M,
path: P,
body?: EndpointInterface<M, P>['payload'],
expand?: E
): EndpointInterface<M, P, E>['response'] {
return { method, path, body, expand } as any
}

const t6: Collection<'customerorder'> = request('GET', `entity/customerorder`)

const id = '123-456'

const t7: CustomerOrder = request('GET', `entity/customerorder/${id}`)

// @ts-expect-error
const t7e: EntityRef = request('GET', `entity/customerorder3/${id}`)

// @ts-expect-error
const t6e: Collection<'customerorder'> = request(
'GET',
`entity/customerorder/123`
)

const t8 = request('POST', 'entity/customerorder')

// Метод не поддерживает указанный путь
// @ts-expect-error
const t8e = request('POST', 'entity/customerorder/123-456')

const t9_1 = request('PUT', 'entity/customerorder/123-456', {
name: 'new-name'
})

const t9_2: CustomerOrder = request('PUT', 'entity/customerorder/123-456', {
name: 'new-name'
})

const e9_1 = request('PUT', 'entity/customerorder/123-456', {
// @ts-expect-error
id: '123-456'
})

const e9_2 = request('PUT', 'entity/customerorder/123-456', {
// @ts-expect-error
id: '123-456',
name: 'Foo'
})

const t10_1: Patch<'customerorder'> = {
name: 'Foo'
}

const t10_2 = request('PUT', 'entity/customerorder/123-456', t10_1)

const t11_1: Partial<CustomerOrder> = {
meta: {
type: 'customerorder',
href: ''
}
}

// @ts-expect-error
const t11_2 = request('PUT', 'entity/customerorder/123-456', t11_1)

// Expand

const t12_1 = request(
'GET',
'entity/customerorder',
undefined,
'agent,positions.assortment'
)

t12_1.rows[0].agent.name

t12_1.rows[0].positions.rows[0].assortment.id

0 comments on commit 6690cf8

Please sign in to comment.