@visulima/crud 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/LICENSE.md +21 -0
- package/README.md +101 -0
- package/dist/chunk-FJWRITBO.js +52 -0
- package/dist/chunk-FJWRITBO.js.map +1 -0
- package/dist/chunk-UBXIGP5H.mjs +52 -0
- package/dist/chunk-UBXIGP5H.mjs.map +1 -0
- package/dist/index.d.ts +155 -0
- package/dist/index.js +1101 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1101 -0
- package/dist/index.mjs.map +1 -0
- package/dist/next/index.d.ts +8 -0
- package/dist/next/index.js +729 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/index.mjs +729 -0
- package/dist/next/index.mjs.map +1 -0
- package/dist/types.d-6817d247.d.ts +155 -0
- package/package.json +136 -0
- package/src/adapter/prisma/index.ts +241 -0
- package/src/adapter/prisma/types.d.ts +46 -0
- package/src/adapter/prisma/utils/models-to-route-names.ts +12 -0
- package/src/adapter/prisma/utils/parse-cursor.ts +26 -0
- package/src/adapter/prisma/utils/parse-order-by.ts +21 -0
- package/src/adapter/prisma/utils/parse-recursive.ts +26 -0
- package/src/adapter/prisma/utils/parse-where.ts +197 -0
- package/src/base-crud-handler.ts +181 -0
- package/src/handler/create.ts +21 -0
- package/src/handler/delete.ts +27 -0
- package/src/handler/list.ts +62 -0
- package/src/handler/read.ts +27 -0
- package/src/handler/update.ts +29 -0
- package/src/index.ts +27 -0
- package/src/next/api/edge/index.ts +23 -0
- package/src/next/api/node/index.ts +27 -0
- package/src/next/index.ts +2 -0
- package/src/query-parser.ts +94 -0
- package/src/swagger/adapter/prisma/index.ts +95 -0
- package/src/swagger/json-schema-parser.ts +456 -0
- package/src/swagger/parameters.ts +83 -0
- package/src/swagger/types.d.ts +53 -0
- package/src/swagger/utils/format-example-ref.ts +4 -0
- package/src/swagger/utils/format-schema-ref.ts +4 -0
- package/src/swagger/utils/get-models-accessible-routes.ts +23 -0
- package/src/swagger/utils/get-swagger-paths.ts +244 -0
- package/src/swagger/utils/get-swagger-tags.ts +13 -0
- package/src/types.d.ts +124 -0
- package/src/utils/format-resource-id.ts +3 -0
- package/src/utils/get-accessible-routes.ts +18 -0
- package/src/utils/get-resource-name-from-url.ts +23 -0
- package/src/utils/get-route-type.ts +99 -0
- package/src/utils/is-primitive.ts +5 -0
- package/src/utils/validate-adapter-methods.ts +15 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../node_modules/.pnpm/next@12.3.1/node_modules/next/dist/compiled/cookie/index.js","../../../../node_modules/.pnpm/next@12.3.1/node_modules/next/server/api-utils/index.ts","../../src/base-crud-handler.ts","../../src/handler/create.ts","../../src/handler/delete.ts","../../src/handler/list.ts","../../src/handler/read.ts","../../src/handler/update.ts","../../src/query-parser.ts","../../src/utils/format-resource-id.ts","../../src/utils/get-resource-name-from-url.ts","../../src/utils/get-route-type.ts","../../src/utils/validate-adapter-methods.ts","../../src/next/api/edge/index.ts","../../src/next/api/node/index.ts"],"sourcesContent":["(()=>{\"use strict\";if(typeof __nccwpck_require__!==\"undefined\")__nccwpck_require__.ab=__dirname+\"/\";var e={};(()=>{var r=e;\n/*!\n * cookie\n * Copyright(c) 2012-2014 Roman Shtylman\n * Copyright(c) 2015 Douglas Christopher Wilson\n * MIT Licensed\n */r.parse=parse;r.serialize=serialize;var i=decodeURIComponent;var t=encodeURIComponent;var a=/; */;var n=/^[\\u0009\\u0020-\\u007e\\u0080-\\u00ff]+$/;function parse(e,r){if(typeof e!==\"string\"){throw new TypeError(\"argument str must be a string\")}var t={};var n=r||{};var o=e.split(a);var s=n.decode||i;for(var p=0;p<o.length;p++){var f=o[p];var u=f.indexOf(\"=\");if(u<0){continue}var v=f.substr(0,u).trim();var c=f.substr(++u,f.length).trim();if('\"'==c[0]){c=c.slice(1,-1)}if(undefined==t[v]){t[v]=tryDecode(c,s)}}return t}function serialize(e,r,i){var a=i||{};var o=a.encode||t;if(typeof o!==\"function\"){throw new TypeError(\"option encode is invalid\")}if(!n.test(e)){throw new TypeError(\"argument name is invalid\")}var s=o(r);if(s&&!n.test(s)){throw new TypeError(\"argument val is invalid\")}var p=e+\"=\"+s;if(null!=a.maxAge){var f=a.maxAge-0;if(isNaN(f)||!isFinite(f)){throw new TypeError(\"option maxAge is invalid\")}p+=\"; Max-Age=\"+Math.floor(f)}if(a.domain){if(!n.test(a.domain)){throw new TypeError(\"option domain is invalid\")}p+=\"; Domain=\"+a.domain}if(a.path){if(!n.test(a.path)){throw new TypeError(\"option path is invalid\")}p+=\"; Path=\"+a.path}if(a.expires){if(typeof a.expires.toUTCString!==\"function\"){throw new TypeError(\"option expires is invalid\")}p+=\"; Expires=\"+a.expires.toUTCString()}if(a.httpOnly){p+=\"; HttpOnly\"}if(a.secure){p+=\"; Secure\"}if(a.sameSite){var u=typeof a.sameSite===\"string\"?a.sameSite.toLowerCase():a.sameSite;switch(u){case true:p+=\"; SameSite=Strict\";break;case\"lax\":p+=\"; SameSite=Lax\";break;case\"strict\":p+=\"; SameSite=Strict\";break;case\"none\":p+=\"; SameSite=None\";break;default:throw new TypeError(\"option sameSite is invalid\")}}return p}function tryDecode(e,r){try{return r(e)}catch(r){return e}}})();module.exports=e})();",null,"import type { HttpError } from \"http-errors\";\nimport createHttpError from \"http-errors\";\n// eslint-disable-next-line import/no-extraneous-dependencies\nimport { ApiError } from \"next/dist/server/api-utils\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\n\nimport createHandler from \"./handler/create\";\nimport deleteHandler from \"./handler/delete\";\nimport listHandler from \"./handler/list\";\nimport readHandler from \"./handler/read\";\nimport updateHandler from \"./handler/update\";\nimport parseQuery from \"./query-parser\";\nimport type {\n Adapter, ExecuteHandler, HandlerOptions, HandlerParameters, ParsedQueryParameters,\n} from \"./types.d\";\nimport { RouteType } from \"./types.d\";\nimport formatResourceId from \"./utils/format-resource-id\";\nimport getAccessibleRoutes from \"./utils/get-accessible-routes\";\nimport { getResourceNameFromUrl } from \"./utils/get-resource-name-from-url\";\nimport getRouteType from \"./utils/get-route-type\";\nimport validateAdapterMethods from \"./utils/validate-adapter-methods\";\n\ntype ResponseConfig = { status: number; data: any };\n\nasync function baseHandler<R extends Request, Context extends unknown, T, Q extends ParsedQueryParameters = any, M extends string = string>(\n responseExecutor: (responseOrContext: Context, responseConfig: ResponseConfig) => Promise<Response>,\n finalExecutor: (responseOrContext: Context) => Promise<void>,\n adapter: Adapter<T, Q>,\n options?: HandlerOptions<M>,\n): Promise<ExecuteHandler<R, Context>>;\n\nasync function baseHandler<R extends IncomingMessage, RResponse extends ServerResponse, T, Q extends ParsedQueryParameters = any, M extends string = string>(\n responseExecutor: (responseOrContext: RResponse, responseConfig: ResponseConfig) => Promise<void>,\n finalExecutor: (responseOrContext: RResponse) => Promise<void>,\n adapter: Adapter<T, Q>,\n options?: HandlerOptions<M>,\n): Promise<ExecuteHandler<R, RResponse>>;\n\n// eslint-disable-next-line radar/cognitive-complexity,max-len\nasync function baseHandler<R extends { url: string; method: string }, RResponse, T, Q extends ParsedQueryParameters = any, M extends string = string>(\n responseExecutor: (responseOrContext: RResponse, responseConfig: ResponseConfig) => Promise<RResponse>,\n finalExecutor: (responseOrContext: RResponse) => Promise<void>,\n adapter: Adapter<T, Q>,\n options?: HandlerOptions<M>,\n): Promise<ExecuteHandler<R, RResponse>> {\n try {\n validateAdapterMethods(adapter);\n } catch (error_: any) {\n const error = error_ as HttpError;\n\n throw new ApiError(error.statusCode, error.message);\n }\n\n await adapter.init?.();\n\n const config = {\n formatResourceId,\n pagination: {\n perPage: 20,\n },\n ...options,\n };\n\n const routeNames = await adapter.mapModelsToRouteNames?.();\n const modelRoutes: { [key in M]?: string } = {};\n\n adapter.getModels().forEach((modelName) => {\n modelRoutes[modelName as M] = config?.models?.[modelName as M]?.name || routeNames?.[modelName] || modelName;\n });\n\n return async (request, responseOrContext) => {\n const { resourceName, modelName } = getResourceNameFromUrl(request.url as string, modelRoutes);\n\n if (!resourceName) {\n if (process.env.NODE_ENV === \"development\") {\n const mappedModels = await adapter.mapModelsToRouteNames?.();\n\n if (typeof mappedModels === \"object\") {\n throw createHttpError(404, `Resource not found, possible models: ${Object.values(mappedModels).join(\", \")}`);\n }\n }\n\n throw createHttpError(404, `Resource not found: ${request.url}`);\n }\n\n const { routeType, resourceId } = getRouteType(request.method as string, request.url as string, resourceName);\n\n if (routeType === null) {\n throw createHttpError(404, `Route not found: ${request.url}`);\n }\n\n const modelConfig = options?.models?.[modelName as M];\n\n const accessibleRoutes = getAccessibleRoutes(modelConfig?.only, modelConfig?.exclude, options?.exposeStrategy || \"all\");\n\n if (!accessibleRoutes.includes(routeType)) {\n throw createHttpError(404, `Route not found: ${request.url}`);\n }\n\n try {\n const resourceIdFormatted = modelConfig?.formatResourceId?.(resourceId as string) ?? config.formatResourceId(resourceId as string);\n\n await adapter.connect?.();\n\n const parsedQuery = parseQuery((request.url as string).split(\"?\")[1]);\n const parameters: HandlerParameters<T, Q> = {\n adapter,\n query: adapter.parseQuery(modelName as M, parsedQuery),\n resourceName: modelName as string,\n };\n\n try {\n let responseConfig: ResponseConfig;\n\n switch (routeType) {\n case RouteType.READ_ONE: {\n responseConfig = await (config?.handlers?.get || readHandler)<T, Q>({\n ...parameters,\n resourceId: resourceIdFormatted,\n });\n break;\n }\n case RouteType.READ_ALL: {\n responseConfig = await (config?.handlers?.list || listHandler)<T, Q>({\n ...parameters,\n query: {\n ...parameters.query,\n page: parsedQuery.page ? Number(parsedQuery.page) : undefined,\n limit: parsedQuery.limit ? Number(parsedQuery.limit) : undefined,\n },\n pagination: config.pagination,\n });\n break;\n }\n case RouteType.CREATE: {\n responseConfig = await (config?.handlers?.create || createHandler)<T, Q, R>({\n ...parameters,\n request: request as R & { body: Record<string, any> },\n });\n break;\n }\n case RouteType.UPDATE: {\n responseConfig = await (config?.handlers?.update || updateHandler)<T, Q, R>({\n ...parameters,\n resourceId: resourceIdFormatted,\n request: request as R & { body: Partial<T> },\n });\n break;\n }\n case RouteType.DELETE: {\n responseConfig = await (config?.handlers?.delete || deleteHandler)<T, Q>({\n ...parameters,\n resourceId: resourceIdFormatted,\n });\n break;\n }\n default: {\n responseConfig = {\n status: 404,\n data: \"Method not found\",\n };\n }\n }\n\n await responseExecutor(responseOrContext, responseConfig);\n } catch (error: any) {\n if (adapter.handleError && !(error instanceof ApiError)) {\n adapter.handleError(error);\n } else {\n throw error;\n }\n }\n } finally {\n await adapter.disconnect?.();\n\n await finalExecutor(responseOrContext);\n }\n };\n}\n\nexport default baseHandler;\n","import type { HandlerParameters } from \"../types.d\";\n\nconst createHandler: Handler = async ({\n adapter, query, resourceName, request,\n}) => {\n const resources = await adapter.create(resourceName, request.body, query);\n\n return {\n data: resources,\n status: 201,\n };\n};\n\nexport type Handler = <T, Q, Request>(\n parameters: HandlerParameters<T, Q> & { request: Request & { body: Record<string, any> } },\n) => Promise<{\n data: any;\n status: number;\n}>;\n\nexport default createHandler;\n","import createHttpError from \"http-errors\";\n\nimport type { UniqueResourceHandlerParameters } from \"../types.d\";\n\nconst deleteHandler: Handler = async ({\n adapter, query, resourceName, resourceId,\n}) => {\n const resource = await adapter.getOne(resourceName, resourceId, query);\n\n if (resource) {\n const deletedResource = await adapter.delete(resourceName, resourceId, query);\n\n return {\n data: deletedResource,\n status: 200,\n };\n }\n throw createHttpError(404, `${resourceName} ${resourceId} not found`);\n};\n\nexport type Handler = <T, Q>(\n parameters: UniqueResourceHandlerParameters<T, Q>,\n) => Promise<{\n data: any;\n status: number;\n}>;\nexport default deleteHandler;\n","import { paginate } from \"@visulima/pagination\";\n\nimport type { HandlerParameters, PaginationConfig, ParsedQueryParameters } from \"../types.d\";\n\ntype PaginationOptions = {\n page: number;\n perPage: number;\n};\n\nconst listHandler: Handler = async ({\n adapter, query, resourceName, pagination,\n}) => {\n let isPaginated = false;\n let paginationOptions: PaginationOptions | undefined;\n\n if (typeof query?.page !== \"undefined\") {\n if (query?.page <= 0) {\n throw new Error(\"page query must be a strictly positive number\");\n }\n\n paginationOptions = {\n page: query?.page,\n perPage: query?.limit || pagination.perPage,\n };\n }\n\n if (paginationOptions) {\n isPaginated = true;\n\n // eslint-disable-next-line no-param-reassign\n query.skip = (paginationOptions.page - 1) * paginationOptions.perPage;\n // eslint-disable-next-line no-param-reassign\n query.limit = paginationOptions.perPage;\n }\n\n const resources = await adapter.getAll(resourceName, query);\n\n if (isPaginated) {\n const { page, total } = await adapter.getPaginationData(resourceName, query);\n\n const paginator = paginate(page, (paginationOptions as PaginationOptions).perPage as number, total, resources);\n\n return {\n data: paginator.toJSON(),\n status: 200,\n };\n }\n\n return {\n data: resources,\n status: 200,\n };\n};\n\nexport type Handler = <T, Q extends ParsedQueryParameters>(\n parameters: HandlerParameters<T, Q> & { pagination: PaginationConfig },\n) => Promise<{\n data: any;\n status: number;\n}>;\n\nexport default listHandler;\n","import createHttpError from \"http-errors\";\n\nimport type { UniqueResourceHandlerParameters } from \"../types.d\";\n\nconst readHandler: Handler = async ({\n adapter, query, resourceName, resourceId,\n}) => {\n const resource = await adapter.getOne(resourceName, resourceId, query);\n\n if (!resource) {\n throw createHttpError(404, `${resourceName} ${resourceId} not found`);\n }\n\n return {\n data: resource,\n status: 200,\n };\n};\n\nexport type Handler = <T, Q>(\n parameters: UniqueResourceHandlerParameters<T, Q>,\n) => Promise<{\n data: any;\n status: number;\n}>;\n\nexport default readHandler;\n","import createHttpError from \"http-errors\";\n\nimport type { UniqueResourceHandlerParameters } from \"../types.d\";\n\nconst updateHandler: Handler = async ({\n adapter, query, resourceName, resourceId, request,\n}) => {\n const resource = await adapter.getOne(resourceName, resourceId, query);\n\n if (resource) {\n const updatedResource = await adapter.update(resourceName, resourceId, request.body, query);\n\n return {\n status: 201,\n data: updatedResource,\n };\n }\n\n throw createHttpError(404, `${resourceName} ${resourceId} not found`);\n};\n\nexport type Handler = <T, Q, Request>(\n parameters: UniqueResourceHandlerParameters<T, Q> & { request: Request & { body: Partial<T> } },\n) => Promise<{\n data: any;\n status: number;\n}>;\n\nexport default updateHandler;\n","import set from \"lodash.set\";\nimport { parse } from \"qs\";\n\nimport type {\n OrderByField, ParsedQueryParameters, RecursiveField, WhereField,\n} from \"./types.d\";\n\nconst parseRecursive = (select: string): RecursiveField => {\n if (typeof select === \"string\") {\n const selectFields: RecursiveField = {};\n\n const fields = select.split(\",\");\n\n fields.forEach((field) => {\n set(selectFields, field, true);\n });\n\n return selectFields;\n }\n\n throw new Error(\"select query param must be a string\");\n};\n\nconst parseWhere = (where: string): WhereField => {\n const whereObject = JSON.parse(where);\n const parsed: WhereField = {};\n\n Object.keys(whereObject).forEach((key) => {\n set(parsed, key, whereObject[key]);\n });\n\n return parsed;\n};\n\nconst parseOrderBy = (orderBy: string): OrderByField => {\n const parsed: OrderByField = {};\n const orderByObject = JSON.parse(orderBy);\n\n if (Object.keys(orderByObject).length > 0) {\n const key = Object.keys(orderByObject)[0];\n\n if (orderByObject[key as keyof typeof orderByObject] === \"$asc\" || orderByObject[key as keyof typeof orderByObject] === \"$desc\") {\n parsed[key as string] = orderByObject[key as keyof typeof orderByObject];\n }\n }\n\n if (Object.keys(parsed).length !== 1) {\n throw new Error(\"orderBy needs to be an object with exactly 1 property with either $asc or $desc value\");\n }\n\n return parsed;\n};\n\n// eslint-disable-next-line radar/cognitive-complexity\nconst parseQuery = (queryString?: string): ParsedQueryParameters => {\n if (queryString) {\n const query = parse(queryString);\n const parsedQuery: ParsedQueryParameters = {};\n\n if (query.select) {\n parsedQuery.select = parseRecursive(query.select as string);\n }\n if (query.include) {\n parsedQuery.include = parseRecursive(query.include as string);\n }\n if (query.where) {\n parsedQuery.where = parseWhere(query.where as string);\n }\n if (query.orderBy) {\n parsedQuery.orderBy = parseOrderBy(query.orderBy as string);\n }\n if (typeof query.limit !== \"undefined\") {\n parsedQuery.limit = Number.isFinite(+query.limit) ? +query.limit : undefined;\n }\n if (typeof query.skip !== \"undefined\") {\n parsedQuery.skip = Number.isFinite(+query.skip) ? +query.skip : undefined;\n }\n if (query.distinct) {\n parsedQuery.distinct = query.distinct as string;\n }\n if (query.page) {\n parsedQuery.page = Number.isFinite(+query.page) ? +query.page : undefined;\n }\n\n return {\n originalQuery: query,\n ...parsedQuery,\n };\n }\n\n return {};\n};\n\nexport default parseQuery;\n","const formatResourceId = (resourceId: string): string | number => (Number.isSafeInteger(+resourceId) ? +resourceId : resourceId);\n\nexport default formatResourceId;\n","export const ensureCamelCase = (string_: string) => `${string_.charAt(0).toLowerCase()}${string_.slice(1)}`;\n\nexport const getResourceNameFromUrl = <M extends string = string>(url: string, models: { [key in M]?: string }) => {\n // Exclude the query params from the path\n const realPath = url.split(\"?\")[0];\n\n if (typeof realPath === \"undefined\") {\n throw new TypeError(\"Path is undefined\");\n }\n\n const modelName = (Object.keys(models) as M[]).find((name) => {\n const routeName = models[name] as string;\n const camelCaseModel = ensureCamelCase(routeName);\n\n // eslint-disable-next-line @rushstack/security/no-unsafe-regexp\n return new RegExp(`(${routeName}|${camelCaseModel}$)|(${routeName}|${camelCaseModel}/)`, \"g\").test(realPath);\n });\n\n return {\n modelName,\n resourceName: models[modelName] as string,\n };\n};\n","import { match } from \"path-to-regexp\";\n\nimport { RouteType } from \"../types.d\";\n\ntype PathMatch = { id: string };\n\nconst getRouteType: (\n method: string,\n url: string,\n resourceName: string,\n) => GetRouteType = (method, url, resourceName) => {\n // Exclude the query params from the path\n const realPath = url.split(\"?\")[0];\n\n if (typeof realPath === \"undefined\") {\n throw new TypeError(\"Path is undefined\");\n }\n\n if (!realPath.includes(`/${resourceName}`)) {\n throw new Error(`invalid resource name '${resourceName}' for route '${realPath}'`);\n }\n\n const entityMatcher = match<PathMatch>([`/(.*)/${resourceName}`, `/(.*)/${resourceName}/:id`], { decode: decodeURIComponent });\n const simpleMatcher = match(`/(.*)/${resourceName}`, {\n decode: decodeURIComponent,\n });\n\n switch (method) {\n case \"GET\": {\n const pathMatch = entityMatcher(realPath);\n\n // If we got a /something after the resource name, we are reading 1 entity\n if (pathMatch && pathMatch.params.id) {\n return {\n routeType: RouteType.READ_ONE,\n resourceId: pathMatch.params.id,\n };\n }\n\n return {\n routeType: RouteType.READ_ALL,\n };\n }\n case \"POST\": {\n const pathMatch = simpleMatcher(realPath);\n\n if (pathMatch) {\n return {\n routeType: RouteType.CREATE,\n };\n }\n\n return {\n routeType: null,\n };\n }\n case \"PUT\":\n case \"PATCH\": {\n const pathMatch = entityMatcher(realPath);\n\n if (pathMatch && pathMatch.params.id) {\n return {\n routeType: RouteType.UPDATE,\n resourceId: pathMatch.params.id,\n };\n }\n\n return {\n routeType: null,\n };\n }\n case \"DELETE\": {\n const pathMatch = entityMatcher(realPath);\n\n if (pathMatch && pathMatch.params.id) {\n return {\n routeType: RouteType.DELETE,\n resourceId: pathMatch.params.id,\n };\n }\n\n return {\n routeType: null,\n };\n }\n default: {\n return {\n routeType: null,\n };\n }\n }\n};\n\nexport type GetRouteType = {\n routeType: RouteType | null;\n resourceId?: string;\n};\n\nexport default getRouteType;\n","import createHttpError from \"http-errors\";\n\nimport type { Adapter } from \"../types.d\";\n\nconst adapterMethods = [\"create\" || \"delete\" || \"getAll\" || \"getOne\" || \"parseQuery\" || \"update\" || \"getPaginationData\" || \"getModels\"];\n\nconst validateAdapterMethods = <T, Q>(adapter: Adapter<T, Q>) => {\n adapterMethods.forEach((method) => {\n if (!adapter[method as keyof Adapter<T, Q>]) {\n throw createHttpError(500, `Adapter must implement the \"${method}\" method.`);\n }\n });\n};\n\nexport default validateAdapterMethods;\n","import baseHandler from \"../../../base-crud-handler\";\nimport type {\n Adapter, ExecuteHandler, HandlerOptions, ParsedQueryParameters,\n} from \"../../../types.d\";\n\nasync function handler<T, R extends Request, Context, Q extends ParsedQueryParameters = any, M extends string = string>(\n adapter: Adapter<T, Q>,\n options?: HandlerOptions<M>,\n): Promise<ExecuteHandler<R, Context>> {\n return baseHandler<R, Context, T, Q, M>(\n async (_, responseConfig) => new Response(JSON.stringify(responseConfig.data), {\n status: responseConfig.status,\n headers: {\n \"content-type\": \"application/json; charset=utf-8\",\n },\n }),\n async () => {},\n adapter,\n options,\n );\n}\n\nexport default handler;\n","import type { NextApiRequest, NextApiResponse } from \"next\";\n\nimport baseHandler from \"../../../base-crud-handler\";\nimport type {\n Adapter, ExecuteHandler, HandlerOptions, ParsedQueryParameters,\n} from \"../../../types.d\";\n\nasync function handler<\n T,\n Q extends ParsedQueryParameters = any,\n R extends NextApiRequest = NextApiRequest,\n Response extends NextApiResponse = NextApiResponse,\n M extends string = string,\n>(adapter: Adapter<T, Q>, options?: HandlerOptions<M>): Promise<ExecuteHandler<R, Response>> {\n return baseHandler<R, Response, T, Q, M>(\n async (response, responseConfig) => {\n response.status(responseConfig.status).send(responseConfig.data);\n },\n async (response) => {\n (response as Response).end();\n },\n adapter,\n options,\n );\n}\n\nexport default handler;\n"],"mappings":"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","names":["parse","e","r","t","n","i","a","getCookieParser","sendStatusCode","redirect","checkIsManualRevalidate","clearPreviewData","sendError","setLazyProp","headers","parseCookie","header","cookie","parse","parseCookieFn","require","Array","isArray","join","res","statusCode","statusOrUrl","url","Error","writeHead","Location","write","end","PRERENDER_REVALIDATE_HEADER","PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER","req","previewProps","isManualRevalidate","previewModeId","revalidateOnlyGenerated","COOKIE_NAME_PRERENDER_BYPASS","COOKIE_NAME_PRERENDER_DATA","RESPONSE_LIMIT_DEFAULT","SYMBOL_PREVIEW_DATA","Symbol","SYMBOL_CLEARED_COOKIES","options","serialize","previous","getHeader","setHeader","expires","Date","httpOnly","sameSite","process","secure","path","undefined","Object","defineProperty","value","enumerable","ApiError","constructor","message","statusMessage","prop","getter","opts","configurable","optsReset","writable","get","set","createHttpError","createHttpError","createHttpError","createHttpError","_a","_b","createHttpError","handler"]}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
declare type Handler$4 = <T, Q, Request>(parameters: HandlerParameters<T, Q> & {
|
|
2
|
+
request: Request & {
|
|
3
|
+
body: Record<string, any>;
|
|
4
|
+
};
|
|
5
|
+
}) => Promise<{
|
|
6
|
+
data: any;
|
|
7
|
+
status: number;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
declare type Handler$3 = <T, Q>(parameters: UniqueResourceHandlerParameters<T, Q>) => Promise<{
|
|
11
|
+
data: any;
|
|
12
|
+
status: number;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
declare type Handler$2 = <T, Q extends ParsedQueryParameters>(parameters: HandlerParameters<T, Q> & {
|
|
16
|
+
pagination: PaginationConfig;
|
|
17
|
+
}) => Promise<{
|
|
18
|
+
data: any;
|
|
19
|
+
status: number;
|
|
20
|
+
}>;
|
|
21
|
+
|
|
22
|
+
declare type Handler$1 = <T, Q>(parameters: UniqueResourceHandlerParameters<T, Q>) => Promise<{
|
|
23
|
+
data: any;
|
|
24
|
+
status: number;
|
|
25
|
+
}>;
|
|
26
|
+
|
|
27
|
+
declare type Handler = <T, Q, Request>(parameters: UniqueResourceHandlerParameters<T, Q> & {
|
|
28
|
+
request: Request & {
|
|
29
|
+
body: Partial<T>;
|
|
30
|
+
};
|
|
31
|
+
}) => Promise<{
|
|
32
|
+
data: any;
|
|
33
|
+
status: number;
|
|
34
|
+
}>;
|
|
35
|
+
|
|
36
|
+
enum RouteType {
|
|
37
|
+
CREATE = "CREATE",
|
|
38
|
+
READ_ALL = "READ_ALL",
|
|
39
|
+
READ_ONE = "READ_ONE",
|
|
40
|
+
UPDATE = "UPDATE",
|
|
41
|
+
DELETE = "DELETE",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
type ModelOption = {
|
|
45
|
+
name?: string
|
|
46
|
+
only?: RouteType[]
|
|
47
|
+
exclude?: RouteType[]
|
|
48
|
+
formatResourceId?: (resourceId: string) => string | number
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
type ModelsOptions<M extends string = string> = {
|
|
52
|
+
[key in M]?: ModelOption
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
type HandlerOptions<M extends string = string> = {
|
|
56
|
+
formatResourceId?: (resourceId: string) => string | number;
|
|
57
|
+
models?: ModelsOptions<M>;
|
|
58
|
+
exposeStrategy?: "all" | "none";
|
|
59
|
+
pagination?: PaginationConfig,
|
|
60
|
+
handlers?: {
|
|
61
|
+
create?: Handler$4;
|
|
62
|
+
delete?: Handler$3;
|
|
63
|
+
get?: Handler$1;
|
|
64
|
+
list?: Handler$2;
|
|
65
|
+
update?: Handler;
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
type PaginationConfig = {
|
|
70
|
+
perPage: number
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
interface HandlerParameters<T, Q> {
|
|
74
|
+
adapter: Adapter<T, Q>;
|
|
75
|
+
query: Q;
|
|
76
|
+
resourceName: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
interface UniqueResourceHandlerParameters<T, Q> {
|
|
80
|
+
adapter: Adapter<T, Q>;
|
|
81
|
+
query: Q;
|
|
82
|
+
resourceName: string;
|
|
83
|
+
resourceId: string | number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
interface Adapter<T, Q, M extends string = string> {
|
|
87
|
+
models?: M[];
|
|
88
|
+
init?: () => Promise<void>;
|
|
89
|
+
parseQuery(resourceName: M, query: ParsedQueryParameters): Q;
|
|
90
|
+
getAll(resourceName: M, query: Q): Promise<T[]>;
|
|
91
|
+
getOne(resourceName: M, resourceId: string | number, query: Q): Promise<T>;
|
|
92
|
+
create(resourceName: M, data: any, query: Q): Promise<T>;
|
|
93
|
+
update(resourceName: M, resourceId: string | number, data: any, query: Q): Promise<T>;
|
|
94
|
+
delete(resourceName: M, resourceId: string | number, query: Q): Promise<T>;
|
|
95
|
+
getPaginationData(resourceName: M, query: Q): Promise<PaginationData>;
|
|
96
|
+
getModels(): M[];
|
|
97
|
+
connect?: () => Promise<void>;
|
|
98
|
+
disconnect?: () => Promise<void>;
|
|
99
|
+
handleError?: (error: Error) => void;
|
|
100
|
+
mapModelsToRouteNames?: () => Promise<{ [key in M]?: string }>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
type PaginationData = {
|
|
104
|
+
total: number
|
|
105
|
+
pageCount: number
|
|
106
|
+
page: number
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
type RecursiveField = {
|
|
110
|
+
[key: string]: boolean | TRecursiveField;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type WhereOperator = "$eq" | "$neq" | "$in" | "$notin" | "$lt" | "$lte" | "$gt" | "$gte" | "$cont" | "$starts" | "$ends" | "$isnull";
|
|
114
|
+
|
|
115
|
+
type SearchCondition = string | boolean | number | Date | null;
|
|
116
|
+
|
|
117
|
+
type WhereCondition = {
|
|
118
|
+
[key in TWhereOperator]?: TSearchCondition;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
type Condition = {
|
|
122
|
+
[key: string]: TSearchCondition | TWhereCondition | TCondition;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
type WhereField = Condition & {
|
|
126
|
+
$and?: TCondition | TCondition[];
|
|
127
|
+
$or?: TCondition | TCondition[];
|
|
128
|
+
$not?: TCondition | TCondition[];
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
type OrderByOperator = "$asc" | "$desc";
|
|
132
|
+
|
|
133
|
+
type OrderByField = {
|
|
134
|
+
[key: string]: TOrderByOperator;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
interface ParsedQueryParameters {
|
|
138
|
+
select?: RecursiveField;
|
|
139
|
+
include?: RecursiveField;
|
|
140
|
+
where?: WhereField;
|
|
141
|
+
orderBy?: OrderByField;
|
|
142
|
+
limit?: number;
|
|
143
|
+
skip?: number;
|
|
144
|
+
distinct?: string;
|
|
145
|
+
page?: number;
|
|
146
|
+
originalQuery?: {
|
|
147
|
+
[key: string]: any;
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
interface ExecuteHandler<Request, Response> {
|
|
152
|
+
(request: Request, response: Response): Promise<void>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export { Adapter as A, Condition as C, ExecuteHandler as E, HandlerParameters as H, ModelsOptions as M, OrderByField as O, PaginationData as P, RouteType as R, SearchCondition as S, UniqueResourceHandlerParameters as U, WhereField as W, ParsedQueryParameters as a, PaginationConfig as b, HandlerOptions as c, ModelOption as d, OrderByOperator as e, RecursiveField as f, WhereOperator as g, WhereCondition as h };
|
package/package.json
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@visulima/crud",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "visulima crud",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"anolilab",
|
|
7
|
+
"visulima",
|
|
8
|
+
"api-platform",
|
|
9
|
+
"api",
|
|
10
|
+
"crud",
|
|
11
|
+
"prisma"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://visulima.com/packages/crud",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "https://github.com/visulima/visulima.git",
|
|
17
|
+
"directory": "packages/crud"
|
|
18
|
+
},
|
|
19
|
+
"funding": [
|
|
20
|
+
{
|
|
21
|
+
"type": "github",
|
|
22
|
+
"url": "https://github.com/sponsors/prisis"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"type": "consulting",
|
|
26
|
+
"url": "https://anolilab.com/support"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": {
|
|
31
|
+
"name": "Daniel Bannert",
|
|
32
|
+
"email": "d.bannert@anolilab.de"
|
|
33
|
+
},
|
|
34
|
+
"sideEffects": false,
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/index.d.ts",
|
|
38
|
+
"require": "./dist/index.js",
|
|
39
|
+
"import": "./dist/index.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./next": {
|
|
42
|
+
"types": "./dist/next/index.d.ts",
|
|
43
|
+
"require": "./dist/next/index.js",
|
|
44
|
+
"import": "./dist/next/index.mjs"
|
|
45
|
+
},
|
|
46
|
+
"./package.json": "./package.json"
|
|
47
|
+
},
|
|
48
|
+
"main": "dist/index.js",
|
|
49
|
+
"module": "dist/index.mjs",
|
|
50
|
+
"types": "dist/index.d.ts",
|
|
51
|
+
"files": [
|
|
52
|
+
"src",
|
|
53
|
+
"dist",
|
|
54
|
+
"README.md",
|
|
55
|
+
"CHANGELOG.md",
|
|
56
|
+
"LICENSE.md"
|
|
57
|
+
],
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "cross-env NODE_ENV=development tsup",
|
|
60
|
+
"build:prod": "cross-env NODE_ENV=production tsup",
|
|
61
|
+
"clean": "rimraf node_modules dist",
|
|
62
|
+
"coverage": "vitest run --coverage",
|
|
63
|
+
"dev": "pnpm predev && pnpm run build --watch",
|
|
64
|
+
"lint:eslint": "cross-env NO_LOGS=true eslint --ext js,jsx,ts,tsx --max-warnings=0 --config .eslintrc.cjs",
|
|
65
|
+
"lint:eslint:fix": "pnpm run lint:eslint --fix",
|
|
66
|
+
"test": "vitest"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"@visulima/pagination": "1.0.0",
|
|
70
|
+
"@visulima/prisma-dmmf-transformer": "1.0.0",
|
|
71
|
+
"http-errors": "^2.0.0",
|
|
72
|
+
"lodash.set": "^4.3.2",
|
|
73
|
+
"path-to-regexp": "^6.2.1",
|
|
74
|
+
"qs": "^6.11.0"
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"@anolilab/eslint-config": "^4.0.9",
|
|
78
|
+
"@anolilab/semantic-release-preset": "^2.0.7",
|
|
79
|
+
"@prisma/client": "^4.5.0",
|
|
80
|
+
"@rushstack/eslint-plugin-security": "^0.5.0",
|
|
81
|
+
"@testing-library/react": "^13.4.0",
|
|
82
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
83
|
+
"@types/http-errors": "^1.8.2",
|
|
84
|
+
"@types/json-schema": "7.0.11",
|
|
85
|
+
"@types/lodash.set": "^4.3.7",
|
|
86
|
+
"@types/node": "^18.8.4",
|
|
87
|
+
"@types/qs": "^6.9.7",
|
|
88
|
+
"@typescript-eslint/eslint-plugin": "^5.40.0",
|
|
89
|
+
"@typescript-eslint/parser": "^5.40.0",
|
|
90
|
+
"@visulima/connect": "1.2.0",
|
|
91
|
+
"cross-env": "^7.0.3",
|
|
92
|
+
"eslint": "^8.25.0",
|
|
93
|
+
"eslint-plugin-compat": "^4.0.2",
|
|
94
|
+
"eslint-plugin-eslint-comments": "^3.2.0",
|
|
95
|
+
"eslint-plugin-import": "^2.26.0",
|
|
96
|
+
"eslint-plugin-json": "^3.1.0",
|
|
97
|
+
"eslint-plugin-jsx-a11y": "^6.6.1",
|
|
98
|
+
"eslint-plugin-markdown": "^3.0.0",
|
|
99
|
+
"eslint-plugin-no-loops": "^0.3.0",
|
|
100
|
+
"eslint-plugin-no-secrets": "^0.8.9",
|
|
101
|
+
"eslint-plugin-node": "^11.1.0",
|
|
102
|
+
"eslint-plugin-optimize-regex": "^1.2.1",
|
|
103
|
+
"eslint-plugin-promise": "^6.0.1",
|
|
104
|
+
"eslint-plugin-radar": "^0.2.1",
|
|
105
|
+
"eslint-plugin-react": "7.31.10",
|
|
106
|
+
"eslint-plugin-react-hooks": "4.6.0",
|
|
107
|
+
"eslint-plugin-simple-import-sort": "^8.0.0",
|
|
108
|
+
"eslint-plugin-sort-keys-fix": "^1.1.2",
|
|
109
|
+
"eslint-plugin-testing-library": "^5.7.2",
|
|
110
|
+
"eslint-plugin-unicorn": "^44.0.2",
|
|
111
|
+
"eslint-plugin-you-dont-need-lodash-underscore": "^6.12.0",
|
|
112
|
+
"eslint-plugin-you-dont-need-momentjs": "^1.6.0",
|
|
113
|
+
"next": "^12.3.1",
|
|
114
|
+
"next-test-api-route-handler": "^4.0.0-canary.1",
|
|
115
|
+
"node-mocks-http": "^1.11.0",
|
|
116
|
+
"openapi-types": "^12.0.2",
|
|
117
|
+
"prettier": "^2.7.1",
|
|
118
|
+
"read-pkg": "^7.1.0",
|
|
119
|
+
"rimraf": "^3.0.2",
|
|
120
|
+
"semantic-release": "^19.0.5",
|
|
121
|
+
"tsup": "^6.2.3",
|
|
122
|
+
"typescript": "^4.8.4",
|
|
123
|
+
"vitest": "^0.24.1"
|
|
124
|
+
},
|
|
125
|
+
"peerDependencies": {},
|
|
126
|
+
"engines": {
|
|
127
|
+
"node": ">=16"
|
|
128
|
+
},
|
|
129
|
+
"publishConfig": {
|
|
130
|
+
"access": "public"
|
|
131
|
+
},
|
|
132
|
+
"sources": [
|
|
133
|
+
"src/index.ts",
|
|
134
|
+
"src/next/index.ts"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
+
import {
|
|
3
|
+
// @ts-ignore
|
|
4
|
+
PrismaAction,
|
|
5
|
+
// @ts-ignore
|
|
6
|
+
PrismaClient,
|
|
7
|
+
} from "@prisma/client";
|
|
8
|
+
import createHttpError from "http-errors";
|
|
9
|
+
|
|
10
|
+
import type { Adapter, PaginationData, ParsedQueryParameters } from "../../types.d";
|
|
11
|
+
import type { PrismaParsedQueryParameters } from "./types.d";
|
|
12
|
+
import modelsToRouteNames from "./utils/models-to-route-names";
|
|
13
|
+
import parsePrismaCursor from "./utils/parse-cursor";
|
|
14
|
+
import parsePrismaOrderBy from "./utils/parse-order-by";
|
|
15
|
+
import parsePrismaRecursiveField from "./utils/parse-recursive";
|
|
16
|
+
import parsePrismaWhere from "./utils/parse-where";
|
|
17
|
+
|
|
18
|
+
interface AdapterCtorArguments<M extends string = string> {
|
|
19
|
+
primaryKey?: string;
|
|
20
|
+
manyRelations?: {
|
|
21
|
+
[key in M]?: string[];
|
|
22
|
+
};
|
|
23
|
+
prismaClient: PrismaClient;
|
|
24
|
+
models?: M[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default class PrismaAdapter<T, M extends string> implements Adapter<T, PrismaParsedQueryParameters, M> {
|
|
28
|
+
private readonly primaryKey: string;
|
|
29
|
+
|
|
30
|
+
private readonly manyRelations: {
|
|
31
|
+
[key in M]?: string[];
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
private readonly prismaClient: PrismaClient;
|
|
35
|
+
|
|
36
|
+
models?: M[];
|
|
37
|
+
|
|
38
|
+
private readonly ctorModels?: M[];
|
|
39
|
+
|
|
40
|
+
private dmmf: any;
|
|
41
|
+
|
|
42
|
+
constructor({
|
|
43
|
+
primaryKey = "id", prismaClient, manyRelations = {}, models,
|
|
44
|
+
}: AdapterCtorArguments<M>) {
|
|
45
|
+
this.prismaClient = prismaClient;
|
|
46
|
+
this.primaryKey = primaryKey;
|
|
47
|
+
this.manyRelations = manyRelations;
|
|
48
|
+
this.ctorModels = models;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private getPrismaClientModels = async () => {
|
|
52
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
53
|
+
if (this.prismaClient._dmmf) {
|
|
54
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
55
|
+
this.dmmf = this.prismaClient._dmmf;
|
|
56
|
+
|
|
57
|
+
return this.dmmf?.mappingsMap;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
61
|
+
if (this.prismaClient._getDmmf) {
|
|
62
|
+
// eslint-disable-next-line no-underscore-dangle
|
|
63
|
+
this.dmmf = await this.prismaClient._getDmmf();
|
|
64
|
+
|
|
65
|
+
return this.dmmf.mappingsMap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
throw new Error("Couldn't get prisma client models");
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
async init() {
|
|
72
|
+
const models = this.ctorModels;
|
|
73
|
+
const prismaDmmfModels = await this.getPrismaClientModels();
|
|
74
|
+
|
|
75
|
+
if (typeof models !== "undefined") {
|
|
76
|
+
models.forEach((model) => {
|
|
77
|
+
if (!Object.keys(prismaDmmfModels).includes(model)) {
|
|
78
|
+
throw new Error(`Model name ${model} is invalid.`);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// @ts-ignore
|
|
84
|
+
this.models = models ?? (Object.keys(prismaDmmfModels) as M[]); // Retrieve model names from dmmf for prisma v2
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
async getPaginationData(resourceName: M, query: PrismaParsedQueryParameters): Promise<PaginationData> {
|
|
88
|
+
// @ts-ignore
|
|
89
|
+
const total: number = await this.getPrismaDelegate(resourceName).count({
|
|
90
|
+
where: query.where,
|
|
91
|
+
distinct: query.distinct,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
total,
|
|
96
|
+
pageCount: Math.ceil(total / (query.take as number)),
|
|
97
|
+
page: Math.ceil((query.skip as number) / (query.take as number)) + 1,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// eslint-disable-next-line class-methods-use-this
|
|
102
|
+
handleError(error: any) {
|
|
103
|
+
// eslint-disable-next-line no-console
|
|
104
|
+
console.error(error);
|
|
105
|
+
|
|
106
|
+
if (error instanceof Error && error.stack) {
|
|
107
|
+
// eslint-disable-next-line no-console
|
|
108
|
+
console.error(error.stack);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
throw error.constructor.name === "PrismaClientKnownRequestError" || error.constructor.name === "PrismaClientValidationError"
|
|
112
|
+
? createHttpError(400, "invalid request, check your server logs for more info")
|
|
113
|
+
: createHttpError(500, "an unknown error occured, check your server logs for more info");
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
parseQuery(resourceName: M, query: ParsedQueryParameters) {
|
|
117
|
+
const parsed: PrismaParsedQueryParameters = {};
|
|
118
|
+
|
|
119
|
+
if (query.select) {
|
|
120
|
+
parsed.select = parsePrismaRecursiveField(query.select, "select");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (query.include) {
|
|
124
|
+
parsed.include = parsePrismaRecursiveField(query.include, "include");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (query.originalQuery?.where) {
|
|
128
|
+
parsed.where = parsePrismaWhere(JSON.parse(query.originalQuery.where), this.manyRelations[resourceName] ?? []);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (query.orderBy) {
|
|
132
|
+
parsed.orderBy = parsePrismaOrderBy(query.orderBy);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (typeof query.limit !== "undefined") {
|
|
136
|
+
parsed.take = query.limit;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (typeof query.skip !== "undefined") {
|
|
140
|
+
parsed.skip = query.skip;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (query.originalQuery?.cursor) {
|
|
144
|
+
parsed.cursor = parsePrismaCursor(JSON.parse(query.originalQuery.cursor));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (query.distinct) {
|
|
148
|
+
parsed.distinct = query.distinct;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return parsed;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async getAll(resourceName: M, query: PrismaParsedQueryParameters): Promise<T[]> {
|
|
155
|
+
// @ts-ignore
|
|
156
|
+
return (await this.getPrismaDelegate(resourceName).findMany({
|
|
157
|
+
select: query.select,
|
|
158
|
+
include: query.include,
|
|
159
|
+
where: query.where,
|
|
160
|
+
orderBy: query.orderBy,
|
|
161
|
+
cursor: query.cursor,
|
|
162
|
+
take: query.take,
|
|
163
|
+
skip: query.skip,
|
|
164
|
+
distinct: query.distinct,
|
|
165
|
+
})) as T[];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async getOne(resourceName: M, resourceId: string | number, query: PrismaParsedQueryParameters): Promise<T> {
|
|
169
|
+
const delegate = this.getPrismaDelegate(resourceName);
|
|
170
|
+
/**
|
|
171
|
+
* On prisma v2.12, findOne has been deprecated in favor of findUnique
|
|
172
|
+
* We use findUnique in priority only if it's available
|
|
173
|
+
*/
|
|
174
|
+
const findFunction = delegate.findUnique || delegate.findOne;
|
|
175
|
+
|
|
176
|
+
// @ts-ignore
|
|
177
|
+
return findFunction({
|
|
178
|
+
where: {
|
|
179
|
+
[this.primaryKey]: resourceId,
|
|
180
|
+
},
|
|
181
|
+
select: query.select,
|
|
182
|
+
include: query.include,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async create(resourceName: M, data: any, query: PrismaParsedQueryParameters): Promise<T> {
|
|
187
|
+
// @ts-ignore
|
|
188
|
+
return this.getPrismaDelegate(resourceName).create({
|
|
189
|
+
data,
|
|
190
|
+
select: query.select,
|
|
191
|
+
include: query.include,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async update(resourceName: M, resourceId: string | number, data: any, query: PrismaParsedQueryParameters): Promise<T> {
|
|
196
|
+
// @ts-ignore
|
|
197
|
+
return this.getPrismaDelegate(resourceName).update({
|
|
198
|
+
where: {
|
|
199
|
+
[this.primaryKey]: resourceId,
|
|
200
|
+
},
|
|
201
|
+
data,
|
|
202
|
+
select: query.select,
|
|
203
|
+
include: query.include,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async delete(resourceName: M, resourceId: string | number, query: PrismaParsedQueryParameters): Promise<T> {
|
|
208
|
+
// @ts-ignore
|
|
209
|
+
return this.getPrismaDelegate(resourceName).delete({
|
|
210
|
+
where: {
|
|
211
|
+
[this.primaryKey]: resourceId,
|
|
212
|
+
},
|
|
213
|
+
select: query.select,
|
|
214
|
+
include: query.include,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
connect() {
|
|
219
|
+
return this.prismaClient.$connect();
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
disconnect() {
|
|
223
|
+
return this.prismaClient.$disconnect();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
get client() {
|
|
227
|
+
return this.prismaClient;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
getModels() {
|
|
231
|
+
return this.models || [];
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
private getPrismaDelegate(resourceName: M): Record<PrismaAction, (...arguments_: any[]) => Promise<T>> {
|
|
235
|
+
return this.prismaClient[`${resourceName.charAt(0).toLowerCase()}${resourceName.slice(1)}`];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
public async mapModelsToRouteNames() {
|
|
239
|
+
return modelsToRouteNames(await this.getPrismaClientModels(), this.getModels());
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Condition, SearchCondition } from "../../types.d";
|
|
2
|
+
|
|
3
|
+
export type PrismaRecursiveField = "select" | "include";
|
|
4
|
+
|
|
5
|
+
export type PrismaRecursive<T extends PrismaRecursiveField> = Record<string, boolean | { [key in T]: PrismaRecursive<T> }>;
|
|
6
|
+
|
|
7
|
+
export type PrismaWhereOperator = "equals" | "not" | "in" | "notIn" | "lt" | "lte" | "gt" | "gte" | "contains" | "startsWith" | "endsWith";
|
|
8
|
+
|
|
9
|
+
export type PrismaOrderByOperator = "asc" | "desc";
|
|
10
|
+
|
|
11
|
+
export type PrismaFieldFilterOperator = {
|
|
12
|
+
[key in PrismaWhereOperator]?: SearchCondition;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type PrismaFieldFilter = {
|
|
16
|
+
[key: string]: SearchCondition | PrismaFieldFilterOperator | PrismaRelationFilter | Condition | undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type PrismaWhereField = PrismaFieldFilter & {
|
|
20
|
+
AND?: PrismaFieldFilter;
|
|
21
|
+
OR?: PrismaFieldFilter;
|
|
22
|
+
NOT?: PrismaFieldFilter;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export type PrismaRelationFilter = {
|
|
26
|
+
some: SearchCondition | PrismaFieldFilter;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export type PrismaOrderBy = {
|
|
30
|
+
[key: string]: PrismaOrderByOperator;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type PrismaCursor = {
|
|
34
|
+
[key: string]: string | number | boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export interface PrismaParsedQueryParameters {
|
|
38
|
+
select?: PrismaRecursive<"select">;
|
|
39
|
+
include?: PrismaRecursive<"include">;
|
|
40
|
+
where?: PrismaWhereField;
|
|
41
|
+
orderBy?: PrismaOrderBy;
|
|
42
|
+
take?: number;
|
|
43
|
+
skip?: number;
|
|
44
|
+
cursor?: PrismaCursor;
|
|
45
|
+
distinct?: string;
|
|
46
|
+
}
|