Make query optional

This commit is contained in:
Jerko Steiner 2019-04-02 14:38:11 +08:00
parent 0a9648c392
commit b8ff27128b
4 changed files with 65 additions and 30 deletions

View File

@ -58,8 +58,8 @@ describe('CRUD', () => {
const http = new HTTPClientMock<ITestAPI>() const http = new HTTPClientMock<ITestAPI>()
const actions = createCRUDActions( const actions = createCRUDActions(
http, http,
'/one/:oneId/two',
'/one/:oneId/two/:twoId', '/one/:oneId/two/:twoId',
'/one/:oneId/two',
'TEST', 'TEST',
) )
const crudReducer = new CRUDReducer<ITwo, 'TEST'>('TEST') const crudReducer = new CRUDReducer<ITwo, 'TEST'>('TEST')
@ -249,7 +249,6 @@ describe('CRUD', () => {
it('updates state', async () => { it('updates state', async () => {
const action = dispatch(testCase.method, actions[method]({ const action = dispatch(testCase.method, actions[method]({
query: undefined,
params: testCase.params, params: testCase.params,
body: testCase.body, body: testCase.body,
})) }))
@ -300,7 +299,6 @@ describe('CRUD', () => {
expect(store.getState().Crud.ids).toEqual([entity.id]) expect(store.getState().Crud.ids).toEqual([entity.id])
const action2 = store.dispatch(actions.remove({ const action2 = store.dispatch(actions.remove({
params: removeTestCase.params, params: removeTestCase.params,
body: removeTestCase.body,
})) }))
await action2.payload await action2.payload
expect(store.getState().Crud.ids).toEqual([]) expect(store.getState().Crud.ids).toEqual([])

View File

@ -1,12 +1,10 @@
import {ICRUDAction} from './ICRUDAction' import {ICRUDAction} from './ICRUDAction'
import {ICRUDMethod} from './ICRUDMethod' import {ICRUDMethod} from './ICRUDMethod'
import {IHTTPClient, ITypedRequestParams} from '../http' import {IHTTPClient, ITypedRequestParams} from '../http'
import {IRoutes} from '@rondo/common' import {IRoutes, Filter, OnlyDefined} from '@rondo/common'
export type Optional<T> = T extends {} ? T : undefined export type Optional<T> = T extends {} ? T : undefined
type Filter<T, U> = T extends U ? T : never
type Action<T, ActionType extends string, Method extends ICRUDMethod> = type Action<T, ActionType extends string, Method extends ICRUDMethod> =
Filter<ICRUDAction<T, ActionType>, {method: Method, status: 'pending'}> Filter<ICRUDAction<T, ActionType>, {method: Method, status: 'pending'}>
@ -22,12 +20,13 @@ export class SaveActionCreator<
readonly type: ActionType, readonly type: ActionType,
) {} ) {}
save = (params: { save = (params: OnlyDefined<{
body: T[Route]['post']['body'], body: T[Route]['post']['body'],
params: T[Route]['post']['params'], params: T[Route]['post']['params'],
}): Action<T[Route]['post']['response'], ActionType, 'save'> => { }>): Action<T[Route]['post']['response'], ActionType, 'save'> => {
const p = params as any
return { return {
payload: this.http.post(this.route, params.body, params.params), payload: this.http.post(this.route, p.body, p.params),
type: this.type, type: this.type,
method: 'save', method: 'save',
status: 'pending', status: 'pending',
@ -47,12 +46,13 @@ export class FindOneActionCreator<
readonly type: ActionType, readonly type: ActionType,
) {} ) {}
findOne = (params: { findOne = (params: OnlyDefined<{
query: Optional<T[Route]['get']['query']>, query: Optional<T[Route]['get']['query']>,
params: T[Route]['get']['params'], params: T[Route]['get']['params'],
}): Action<T[Route]['get']['response'], ActionType, 'findOne'> => { }>): Action<T[Route]['get']['response'], ActionType, 'findOne'> => {
const p = params as any
return { return {
payload: this.http.get(this.route, params.query, params.params), payload: this.http.get(this.route, p.query, p.params),
type: this.type, type: this.type,
method: 'findOne', method: 'findOne',
status: 'pending', status: 'pending',
@ -73,12 +73,13 @@ export class UpdateActionCreator<
readonly type: ActionType, readonly type: ActionType,
) {} ) {}
update = (params: { update = (params: OnlyDefined<{
body: T[Route]['put']['body'], body: T[Route]['put']['body'],
params: T[Route]['put']['params'], params: T[Route]['put']['params'],
}): Action<T[Route]['put']['response'], ActionType, 'update'> => { }>): Action<T[Route]['put']['response'], ActionType, 'update'> => {
const p = params as any
return { return {
payload: this.http.put(this.route, params.body, params.params), payload: this.http.put(this.route, p.body, p.params),
type: this.type, type: this.type,
method: 'update', method: 'update',
status: 'pending', status: 'pending',
@ -99,12 +100,13 @@ export class RemoveActionCreator<
readonly type: ActionType, readonly type: ActionType,
) {} ) {}
remove = (params: { remove = (params: OnlyDefined<{
body: T[Route]['delete']['body'], body: Optional<T[Route]['delete']['body']>,
params: T[Route]['delete']['params'], params: T[Route]['delete']['params'],
}): Action<T[Route]['delete']['response'], ActionType, 'remove'> => { }>): Action<T[Route]['delete']['response'], ActionType, 'remove'> => {
const p = params as any
return { return {
payload: this.http.delete(this.route, params.body, params.params), payload: this.http.delete(this.route, p.body, p.params),
type: this.type, type: this.type,
method: 'remove', method: 'remove',
status: 'pending', status: 'pending',
@ -124,12 +126,18 @@ export class FindManyActionCreator<
readonly type: ActionType, readonly type: ActionType,
) {} ) {}
findMany = (params: { findMany = (params: OnlyDefined<{
query: Optional<T[Route]['get']['query']>, query: Optional<T[Route]['get']['query']>,
params: T[Route]['get']['params'], params: T[Route]['get']['params'],
}): Action<T[Route]['get']['response'], ActionType, 'findMany'> => { }>): {
payload: Promise<T[Route]['get']['response']>
type: ActionType
status: 'pending',
method: 'findMany',
} => {
const p = params as any
return { return {
payload: this.http.get(this.route, params.query, params.params), payload: this.http.get(this.route, p.query, p.params),
type: this.type, type: this.type,
method: 'findMany', method: 'findMany',
status: 'pending', status: 'pending',
@ -149,11 +157,11 @@ export function createCRUDActions<
listRoute: ListRoute, listRoute: ListRoute,
actionType: ActionType, actionType: ActionType,
) { ) {
const {save} = new SaveActionCreator(http, entityRoute, actionType) const {save} = new SaveActionCreator(http, listRoute, actionType)
const {update} = new UpdateActionCreator(http, listRoute, actionType) const {update} = new UpdateActionCreator(http, entityRoute, actionType)
const {remove} = new RemoveActionCreator(http, listRoute, actionType) const {remove} = new RemoveActionCreator(http, entityRoute, actionType)
const {findOne} = new FindOneActionCreator(http, listRoute, actionType) const {findOne} = new FindOneActionCreator(http, entityRoute, actionType)
const {findMany} = new FindManyActionCreator(http, entityRoute, actionType) const {findMany} = new FindManyActionCreator(http, listRoute, actionType)
return {save, update, remove, findOne, findMany} return {save, update, remove, findOne, findMany}
} }

View File

@ -1,9 +1,7 @@
import {IAction, IResolvedAction} from '../actions' import {IAction, IResolvedAction} from '../actions'
import {ICRUDAction} from './ICRUDAction' import {ICRUDAction} from './ICRUDAction'
import {ICRUDMethod} from './ICRUDMethod' import {ICRUDMethod} from './ICRUDMethod'
import {indexBy, without} from '@rondo/common' import {indexBy, without, Filter} from '@rondo/common'
type Filter<T, U> = T extends U ? T : never
export interface ICRUDEntity { export interface ICRUDEntity {
readonly id: number readonly id: number

View File

@ -0,0 +1,31 @@
export type NonUndefinedPropertyNames<T> = {
[K in keyof T]: T[K] extends undefined ? never: K
}[keyof T]
export type OnlyRequired<T> = Pick<T, NonUndefinedPropertyNames<T>>
type Args1 = OnlyRequired<{
query: {a: number, b: string}
params: {c: number}
}>
type Args2 = OnlyRequired<{
query: {a: number, b: string}
params: undefined
}>
type Args3 = OnlyRequired<{
query: undefined
params: undefined
}>
const a: Args1 = {
query: {a: 1, b: 'two'},
params: {c: 3},
}
const b: Args2 = {
query: {a: 1, b: 'two'},
}
const c: Args3 = {}