import { getItems } from './faker-types' import { Repository } from './repository' import { type Model, type CreateApiOptions, type CreateApiResourceOptions, type RequestConfig, type ResponseConfig, } from './interfaces' export default function createApi(resources: CreateApiResourceOptions, options: CreateApiOptions) { const repository: { [code: string]: Repository } = {} const isRelation = (key: string) => key in repository Object.entries(resources).forEach(([nameKey, resource]) => { repository[nameKey] = new Repository(nameKey, resources[nameKey]) if (repository[nameKey].count()) return for (let i = 0; i < resource.count; i++) { const item: Model = { id: i } Object.entries(resource.fields).forEach(([fieldKey, field]) => { const dataFromFaker = getItems(field.type) if (dataFromFaker !== undefined) { item[fieldKey] = dataFromFaker return } if (isRelation(field.type)) { item[fieldKey] = repository[field.type].getRandomItem() return } throw new Error(`Неизвестный тип поля ${field.type}`) }) repository[nameKey].models.push(item) } repository[nameKey].saveToStorage() }) const paginate = (items: Model[], params: NonNullable, pagination: CreateApiOptions) => { if (pagination.type === 'limit-offset') { const offset = Number(params[pagination.requestOffsetKey]) const limit = Number(params[pagination.requestLimitKey]) return { count: items.length, results: items.slice(offset, offset + limit), } } const page = Number(params[pagination.requestPageKey]) const perPage = Number(params[pagination.requestPerPageKey]) const offset = (page - 1) * perPage return { count: items.length, results: items.slice(offset, offset + perPage), } } const explodePath = (path: string) => { let explodedPath = path.split('?') explodedPath = explodedPath[0].split('/') if (explodedPath[0] === '') { explodedPath.shift() } return explodedPath } const getRepository = (path: string) => { const explodedPath = explodePath(path) const resourceType: keyof CreateApiResourceOptions = explodedPath[0] if (!(resourceType in repository)) { throw new Error(`В репозитории нет объектов типа ${resourceType}`) } return repository[resourceType] } const isFilterQuery = (path: string) => { const explodedPath = explodePath(path) return explodedPath[1] === 'filter' && explodedPath[2] !== '' } const isResourceQuery = (path: string) => { const explodedPath = explodePath(path) return !explodedPath[1] || explodedPath[1] === '' } const get = (path: string, params: NonNullable) => { const repository = getRepository(path) const explodedPath = explodePath(path) if (isResourceQuery(path)) { return repository.isEnum ? repository.select(params, options) : paginate(repository.select(params, options), params, options) } if (isFilterQuery(path)) { return paginate(repository.distinct(explodedPath[2], params, options), params, options) } throw new Error(`Неизвестный тип запроса ${path}`) } const post = (path: string, data: any, config?: RequestConfig) => { const repository = getRepository(path) data.id = repository.count() repository.add(data) return new Promise((resolve) => { setTimeout(() => { resolve({ data, status: 200, statusText: 'OK', headers: {}, config: {}, }) }, Math.random() * 1000) }) } const update = (path: string, data: any, config?: RequestConfig) => { const repository = getRepository(path) const oldData = repository.find(data.id) repository.update({ ...oldData, ...data }) return new Promise((resolve) => { setTimeout(() => { resolve({ data, status: 200, statusText: 'OK', headers: {}, config: {}, }) }, Math.random() * 1000) }) } const remove = (path: string, data: any, config?: RequestConfig) => { const explodedPath = explodePath(path) const repository = getRepository(path) repository.delete(Number(explodedPath.reverse()[0])) return new Promise((resolve) => { setTimeout(() => { resolve({ status: 200, statusText: 'OK', headers: {}, config: {}, }) }, Math.random() * 1000) }) } return { request(url: string, data: any, config?: RequestConfig): Promise { const params: RequestConfig['params'] = config?.params || { page: '1', perPage: '10', limit: '10', offset: '10', } // console.log('PARAMS', params) return new Promise((resolve) => { const data = get(url, params) // console.log(url, params, data) setTimeout(() => { resolve({ data, status: 200, statusText: 'OK', headers: {}, config: {}, }) }, Math.random() * 1000) }) }, get(url: string, config?: RequestConfig): Promise { return this.request(url, {}, config) }, post(url: string, data: any, config?: RequestConfig): Promise { return post(url, data, config) }, put(url: string, data: any, config?: RequestConfig): Promise { return update(url, data, config) }, patch(url: string, data: any, config?: RequestConfig): Promise { return update(url, data, config) }, delete(url: string, config?: RequestConfig): Promise { return remove(url, {}, config) }, } }