arkos 1.1.67-beta → 1.1.69-test
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/dist/cjs/app.js +1 -1
- package/dist/cjs/app.js.map +1 -1
- package/dist/cjs/exports/controllers/index.js +11 -0
- package/dist/cjs/exports/controllers/index.js.map +1 -0
- package/dist/cjs/exports/services/index.js +4 -4
- package/dist/cjs/exports/services/index.js.map +1 -1
- package/dist/cjs/modules/auth/auth.controller.js +6 -6
- package/dist/cjs/modules/auth/auth.controller.js.map +1 -1
- package/dist/cjs/modules/auth/auth.service.js +11 -1
- package/dist/cjs/modules/auth/auth.service.js.map +1 -1
- package/dist/cjs/modules/base/base.controller.js +3 -3
- package/dist/cjs/modules/base/base.controller.js.map +1 -1
- package/dist/cjs/modules/base/base.service.js +19 -10
- package/dist/cjs/modules/base/base.service.js.map +1 -1
- package/dist/cjs/modules/base/utils/helpers/base.service.helpers.js.map +1 -1
- package/dist/cjs/modules/file-upload/file-upload.controller.js +254 -0
- package/dist/cjs/modules/file-upload/file-upload.controller.js.map +1 -0
- package/dist/cjs/modules/{file-uploader/file-uploader.router.js → file-upload/file-upload.router.js} +7 -6
- package/dist/cjs/modules/file-upload/file-upload.router.js.map +1 -0
- package/dist/cjs/modules/{file-uploader/file-uploader.service.js → file-upload/file-upload.service.js} +74 -39
- package/dist/cjs/modules/file-upload/file-upload.service.js.map +1 -0
- package/dist/cjs/modules/{file-uploader/utils/helpers/file-uploader.helpers.js → file-upload/utils/helpers/file-upload.helpers.js} +1 -1
- package/dist/cjs/modules/file-upload/utils/helpers/file-upload.helpers.js.map +1 -0
- package/dist/cjs/types/arkos-config.js.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/utils/cli/build.js +8 -5
- package/dist/cjs/utils/cli/build.js.map +1 -1
- package/dist/cjs/utils/cli/generate.js +170 -0
- package/dist/cjs/utils/cli/generate.js.map +1 -0
- package/dist/cjs/utils/cli/index.js +39 -1
- package/dist/cjs/utils/cli/index.js.map +1 -1
- package/dist/cjs/utils/cli/start.js +4 -2
- package/dist/cjs/utils/cli/start.js.map +1 -1
- package/dist/cjs/utils/cli/utils/generators.js +200 -0
- package/dist/cjs/utils/cli/utils/generators.js.map +1 -0
- package/dist/cjs/utils/cli/utils/helpers.js +17 -0
- package/dist/cjs/utils/cli/utils/helpers.js.map +1 -0
- package/dist/cjs/utils/helpers/global.helpers.js +2 -0
- package/dist/cjs/utils/helpers/global.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/models.helpers.js +44 -6
- package/dist/cjs/utils/helpers/models.helpers.js.map +1 -1
- package/dist/es2020/app.js +1 -1
- package/dist/es2020/app.js.map +1 -1
- package/dist/es2020/exports/controllers/index.js +4 -0
- package/dist/es2020/exports/controllers/index.js.map +1 -0
- package/dist/es2020/exports/services/index.js +2 -2
- package/dist/es2020/exports/services/index.js.map +1 -1
- package/dist/es2020/modules/auth/auth.controller.js +6 -6
- package/dist/es2020/modules/auth/auth.controller.js.map +1 -1
- package/dist/es2020/modules/auth/auth.service.js +11 -1
- package/dist/es2020/modules/auth/auth.service.js.map +1 -1
- package/dist/es2020/modules/base/base.controller.js +3 -3
- package/dist/es2020/modules/base/base.controller.js.map +1 -1
- package/dist/es2020/modules/base/base.service.js +19 -10
- package/dist/es2020/modules/base/base.service.js.map +1 -1
- package/dist/es2020/modules/base/utils/helpers/base.service.helpers.js.map +1 -1
- package/dist/es2020/modules/file-upload/file-upload.controller.js +249 -0
- package/dist/es2020/modules/file-upload/file-upload.controller.js.map +1 -0
- package/dist/es2020/modules/{file-uploader/file-uploader.router.js → file-upload/file-upload.router.js} +6 -5
- package/dist/es2020/modules/file-upload/file-upload.router.js.map +1 -0
- package/dist/es2020/modules/{file-uploader/file-uploader.service.js → file-upload/file-upload.service.js} +67 -32
- package/dist/es2020/modules/file-upload/file-upload.service.js.map +1 -0
- package/dist/es2020/modules/{file-uploader/utils/helpers/file-uploader.helpers.js → file-upload/utils/helpers/file-upload.helpers.js} +1 -1
- package/dist/es2020/modules/file-upload/utils/helpers/file-upload.helpers.js.map +1 -0
- package/dist/es2020/types/arkos-config.js.map +1 -1
- package/dist/es2020/types/index.js.map +1 -1
- package/dist/es2020/utils/cli/build.js +8 -5
- package/dist/es2020/utils/cli/build.js.map +1 -1
- package/dist/es2020/utils/cli/generate.js +164 -0
- package/dist/es2020/utils/cli/generate.js.map +1 -0
- package/dist/es2020/utils/cli/index.js +38 -1
- package/dist/es2020/utils/cli/index.js.map +1 -1
- package/dist/es2020/utils/cli/start.js +4 -2
- package/dist/es2020/utils/cli/start.js.map +1 -1
- package/dist/es2020/utils/cli/utils/generators.js +197 -0
- package/dist/es2020/utils/cli/utils/generators.js.map +1 -0
- package/dist/es2020/utils/cli/utils/helpers.js +10 -0
- package/dist/es2020/utils/cli/utils/helpers.js.map +1 -0
- package/dist/es2020/utils/helpers/global.helpers.js +1 -0
- package/dist/es2020/utils/helpers/global.helpers.js.map +1 -1
- package/dist/es2020/utils/helpers/models.helpers.js +42 -6
- package/dist/es2020/utils/helpers/models.helpers.js.map +1 -1
- package/dist/types/exports/controllers/index.d.ts +3 -0
- package/dist/types/exports/services/index.d.ts +2 -2
- package/dist/types/modules/auth/auth.service.d.ts +1 -0
- package/dist/types/modules/base/base.service.d.ts +31 -12
- package/dist/types/modules/file-upload/file-upload.controller.d.ts +9 -0
- package/dist/types/modules/file-upload/file-upload.router.d.ts +3 -0
- package/dist/types/modules/{file-uploader/file-uploader.service.d.ts → file-upload/file-upload.service.d.ts} +8 -7
- package/dist/types/types/arkos-config.d.ts +2 -2
- package/dist/types/types/index.d.ts +1 -3
- package/dist/types/utils/cli/generate.d.ts +12 -0
- package/dist/types/utils/cli/index.d.ts +2 -1
- package/dist/types/utils/cli/utils/generators.d.ts +17 -0
- package/dist/types/utils/cli/utils/helpers.d.ts +2 -0
- package/dist/types/utils/helpers/global.helpers.d.ts +1 -0
- package/dist/types/utils/helpers/models.helpers.d.ts +6 -0
- package/package.json +6 -1
- package/dist/cjs/modules/file-uploader/file-uploader.controller.js +0 -149
- package/dist/cjs/modules/file-uploader/file-uploader.controller.js.map +0 -1
- package/dist/cjs/modules/file-uploader/file-uploader.router.js.map +0 -1
- package/dist/cjs/modules/file-uploader/file-uploader.service.js.map +0 -1
- package/dist/cjs/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +0 -1
- package/dist/es2020/modules/file-uploader/file-uploader.controller.js +0 -143
- package/dist/es2020/modules/file-uploader/file-uploader.controller.js.map +0 -1
- package/dist/es2020/modules/file-uploader/file-uploader.router.js.map +0 -1
- package/dist/es2020/modules/file-uploader/file-uploader.service.js.map +0 -1
- package/dist/es2020/modules/file-uploader/utils/helpers/file-uploader.helpers.js.map +0 -1
- package/dist/types/modules/file-uploader/file-uploader.controller.d.ts +0 -3
- package/dist/types/modules/file-uploader/file-uploader.router.d.ts +0 -3
- /package/dist/types/modules/{file-uploader/utils/helpers/file-uploader.helpers.d.ts → file-upload/utils/helpers/file-upload.helpers.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.service.js","sourceRoot":"","sources":["../../../../src/modules/base/base.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n camelCase,\n kebabCase,\n pascalCase,\n} from \"../../utils/helpers/change-case.helpers\";\nimport {\n getModels,\n getPrismaModelRelations,\n RelationFields,\n} from \"../../utils/helpers/models.helpers\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { handleRelationFieldsInBody } from \"./utils/helpers/base.service.helpers\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport authService from \"../auth/auth.service\";\n\n/**\n * Base service class for handling CRUD operations on a specific model.\n * This class provides standard implementation of data operations that can be extended\n * by model-specific service classes.\n *\n * @class BaseService\n *\n * @usage\n *\n * **Example:** creating a simple service\n *\n * ```ts\n * import prisma from 'your-prisma-path'\n *\n * const userService = new BaseService<typeof prisma.user>(\"user\")\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/api-reference/the-base-service-class}\n *\n */\nexport class BaseService<TModel extends Record<string, any> = any> {\n /**\n * The camelCase name of the model\n * @public\n */\n modelName: string;\n\n /**\n * Object containing singular and list relation fields for the model\n * @public\n */\n relationFields: RelationFields;\n\n /**\n * Instance of the Prisma client\n * @public\n */\n prisma: any;\n\n /**\n * Creates an instance of BaseService.\n * @param {string} modelName - The name of the model to perform operations on.\n */\n constructor(modelName: string) {\n this.modelName = camelCase(modelName);\n this.relationFields = getPrismaModelRelations(pascalCase(modelName))!;\n }\n\n /**\n * Creates a single record in the database.\n *\n * @param {Parameters<TModel[\"create\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to create the record with.\n * @param {Omit<Parameters<TModel[\"create\"]>[0], \"data\">} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"create\"]>>} The created record.\n */\n async createOne(\n data: Parameters<TModel[\"create\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: Omit<Parameters<TModel[\"create\"]>[0], \"data\">\n ): Promise<ReturnType<TModel[\"create\"]>> {\n if (kebabCase(this.modelName) === \"user\" && (data as any).password) {\n (data as any).password = await authService.hashPassword(\n (data as any).password\n );\n }\n\n const prisma = getPrismaInstance();\n\n const dataWithRelationFieldsHandled = handleRelationFieldsInBody(\n data as Record<string, any>,\n {\n ...this.relationFields,\n },\n [\"delete\", \"disconnect\", \"update\"]\n );\n\n return await prisma[this.modelName].create(\n deepmerge(\n {\n data: dataWithRelationFieldsHandled,\n },\n (queryOptions as {}) || {}\n )\n );\n }\n\n /**\n * Creates multiple records in the database.\n *\n * @param {Parameters<TModel[\"createMany\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - An array of data to create records with.\n * @param {Omit<Parameters<TModel[\"createMany\"]>[0], \"data\">} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"createMany\"]>>} The result of the createMany operation.\n */\n async createMany(\n data: Parameters<TModel[\"createMany\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: Omit<Parameters<TModel[\"createMany\"]>[0], \"data\">\n ): Promise<ReturnType<TModel[\"createMany\"]>> {\n const prisma = getPrismaInstance();\n\n if (Array.isArray(data))\n (data as any[]).forEach(async (_, i) => {\n if (\"password\" in data[i] && this.modelName === \"user\")\n (data[i] as any).password = await authService.hashPassword(\n (data as any)?.password\n );\n\n data[i] = handleRelationFieldsInBody(\n data as Record<string, any>,\n {\n ...this.relationFields,\n },\n [\"delete\", \"disconnect\", \"update\"]\n );\n });\n\n return await prisma[this.modelName].createMany(\n deepmerge({ data }, (queryOptions as {}) || {})\n );\n }\n\n /**\n * Counts records based on provided filters.\n *\n * @param {Parameters<TModel[\"count\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to apply to the query.\n * @returns {Promise<number>} The count of records matching the filters.\n */\n async count(\n filters: Parameters<TModel[\"count\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any\n ): Promise<number> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].count({\n where: filters,\n });\n }\n\n /**\n * Finds multiple records based on provided filters.\n *\n * @param {Parameters<TModel[\"findMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to apply to the query.\n * @param {Omit<Parameters<TModel[\"findMany\"]>[0], \"where\">} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"findMany\"]>>} The found data.\n */\n async findMany(\n filters: Parameters<TModel[\"findMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n queryOptions?: Omit<Parameters<TModel[\"findMany\"]>[0], \"where\">\n ): Promise<ReturnType<TModel[\"findMany\"]>> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].findMany(\n deepmerge({ where: filters }, (queryOptions as {}) || {})\n );\n }\n\n /**\n * Finds a single record by its parameters.\n *\n * @param {Parameters<TModel[\"findFirst\"]>[0] extends { where: infer W; [x: string]: any } ? W : any | Parameters<TModel[\"findUnique\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @param {Omit<Parameters<TModel[\"findFirst\"]>[0], \"where\"> | Omit<Parameters<TModel[\"findUnique\"]>[0], \"where\">} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"findFirst\"]> | ReturnType<TModel[\"findUnique\"]>>} The found record or null if not found.\n */\n async findOne(\n filters: Parameters<TModel[\"findFirst\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any | Parameters<TModel[\"findUnique\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n queryOptions?:\n | Omit<Parameters<TModel[\"findFirst\"]>[0], \"where\">\n | Omit<Parameters<TModel[\"findUnique\"]>[0], \"where\">\n ): Promise<\n ReturnType<TModel[\"findFirst\"]> | ReturnType<TModel[\"findUnique\"]>\n > {\n const prisma = getPrismaInstance();\n\n if (\n Object.keys(filters as Record<string, any>).length === 1 &&\n \"id\" in (filters as Record<string, any>) &&\n (filters as any).id !== \"me\"\n )\n return prisma[this.modelName].findUnique(\n deepmerge(\n {\n where: filters,\n },\n (queryOptions as {}) || {}\n )\n );\n\n return await prisma[this.modelName].findFirst(\n deepmerge(\n {\n where: filters,\n },\n (queryOptions as {}) || {}\n )\n );\n }\n\n /**\n * Updates a single record by its ID.\n *\n * @param {Parameters<TModel[\"update\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @param {Parameters<TModel[\"update\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to update the record with.\n * @param {Omit<Parameters<TModel[\"update\"]>[0], \"where\" | \"data\">} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"update\"]>>} The updated record or null if not found.\n */\n async updateOne(\n filters: Parameters<TModel[\"update\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n data: Parameters<TModel[\"update\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: Omit<Parameters<TModel[\"update\"]>[0], \"where\" | \"data\">\n ): Promise<ReturnType<TModel[\"update\"]>> {\n const prisma = getPrismaInstance();\n\n if (kebabCase(this.modelName) === \"user\" && (data as any)?.password) {\n (data as any).password = await authService.hashPassword(\n (data as any)?.password\n );\n }\n\n const dataWithRelationFieldsHandled = handleRelationFieldsInBody(\n data as Record<string, any>,\n {\n ...this.relationFields,\n }\n );\n\n return await prisma[this.modelName].update(\n deepmerge(\n {\n where: filters,\n data: dataWithRelationFieldsHandled,\n },\n (queryOptions as {}) || {}\n )\n );\n }\n\n /**\n * Updates multiple records based on the provided filter and data.\n *\n * @param {Parameters<TModel[\"updateMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to identify records to update.\n * @param {Parameters<TModel[\"updateMany\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to update the records with.\n * @param {Omit<Parameters<TModel[\"updateMany\"]>[0], \"where\" | \"data\">} [queryOptions] - Additional query options.\n * @returns {Promise<ReturnType<TModel[\"updateMany\"]>>} The result of the updateMany operation.\n */\n async updateMany(\n filters: Parameters<TModel[\"updateMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n data: Parameters<TModel[\"updateMany\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: Omit<Parameters<TModel[\"updateMany\"]>[0], \"where\" | \"data\">\n ): Promise<ReturnType<TModel[\"updateMany\"]>> {\n const prisma = getPrismaInstance();\n\n if (Array.isArray(data) && this.modelName === \"user\")\n (data as any[]).forEach(async (_, i) => {\n if (\"password\" in data[i])\n (data[i] as any).password = await authService.hashPassword(\n (data as any)?.password\n );\n });\n\n const firstMerge = deepmerge({ data }, (queryOptions as {}) || {});\n\n return await prisma[this.modelName].updateMany(\n deepmerge({ where: filters }, firstMerge)\n );\n }\n\n /**\n * Deletes a single record by its ID.\n *\n * @param {Parameters<TModel[\"delete\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @returns {Promise<ReturnType<TModel[\"delete\"]>>} The deleted record or null if an error occurs.\n */\n async deleteOne(\n filters: Parameters<TModel[\"delete\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any\n ): Promise<ReturnType<TModel[\"delete\"]>> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].delete({\n where: filters,\n });\n }\n\n /**\n * Deletes multiple records based on the provided filter.\n *\n * @param {Parameters<TModel[\"deleteMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : Record<string, any>} filters - The filter to identify records to delete.\n * @returns {Promise<ReturnType<TModel[\"deleteMany\"]>>} The result of the deleteMany operation.\n */\n async deleteMany(\n filters: Parameters<TModel[\"deleteMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : Record<string, any>\n ): Promise<ReturnType<TModel[\"deleteMany\"]>> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].deleteMany({ where: filters });\n }\n}\n\n/**\n * Generates a set of base service instances for all available models.\n *\n * @returns {Record<string, BaseService>} A dictionary of base service instances, keyed by model name.\n */\nexport function getBaseServices(): Record<string, BaseService<any>> {\n const models = getModels();\n const baseServices: Record<string, BaseService<any>> = {};\n models.forEach((model) => {\n baseServices[`${camelCase(model)}`] = new BaseService(model);\n });\n return baseServices;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"base.service.js","sourceRoot":"","sources":["../../../../src/modules/base/base.service.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n camelCase,\n kebabCase,\n pascalCase,\n} from \"../../utils/helpers/change-case.helpers\";\nimport {\n getModels,\n getPrismaModelRelations,\n RelationFields,\n} from \"../../utils/helpers/models.helpers\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { handleRelationFieldsInBody } from \"./utils/helpers/base.service.helpers\";\nimport { getPrismaInstance } from \"../../utils/helpers/prisma.helpers\";\nimport authService from \"../auth/auth.service\";\n\n/**\n * Base service class for handling CRUD operations on a specific model.\n * This class provides standard implementation of data operations that can be extended\n * by model-specific service classes.\n *\n * @class BaseService\n *\n * @usage\n *\n * **Example:** creating a simple service\n *\n * ```ts\n * import prisma from '../../utils/prisma'\n *\n * const userService = new BaseService<typeof prisma.user>(\"user\")\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/api-reference/the-base-service-class}\n *\n */\nexport class BaseService<TModel extends Record<string, any> = any> {\n /**\n * The camelCase name of the model\n * @public\n */\n modelName: string;\n\n /**\n * Object containing singular and list relation fields for the model\n * @public\n */\n relationFields: RelationFields;\n\n /**\n * Instance of the Prisma client\n * @public\n */\n prisma: any;\n\n /**\n * Creates an instance of BaseService.\n * @param {string} modelName - The name of the model to perform operations on.\n */\n constructor(modelName: string) {\n this.modelName = camelCase(modelName);\n this.relationFields = getPrismaModelRelations(pascalCase(modelName))!;\n }\n\n /**\n * Creates a single record in the database.\n *\n * @param {Parameters<TModel[\"create\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to create the record with.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"create\"]>>} The created record.\n */\n async createOne<\n TOptions extends Omit<Parameters<TModel[\"create\"]>[0], \"data\">\n >(\n data: Parameters<TModel[\"create\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"create\"] extends (args: { data: any } & TOptions) => infer R\n ? R\n : never\n > {\n if (kebabCase(this.modelName) === \"user\" && (data as any).password)\n if (!authService.isPasswordHashed((data as any).password))\n (data as any).password = await authService.hashPassword(\n (data as any).password\n );\n\n const prisma = getPrismaInstance();\n\n const dataWithRelationFieldsHandled = handleRelationFieldsInBody(\n data as Record<string, any>,\n {\n ...this.relationFields,\n },\n [\"delete\", \"disconnect\", \"update\"]\n );\n\n return await prisma[this.modelName].create(\n deepmerge(\n {\n data: dataWithRelationFieldsHandled,\n },\n (queryOptions as {}) || {}\n ) as { data: any } & TOptions\n );\n }\n\n /**\n * Creates multiple records in the database.\n *\n * @param {Parameters<TModel[\"createMany\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - An array of data to create records with.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"createMany\"]>>} The result of the createMany operation.\n */\n async createMany<\n TOptions extends Omit<Parameters<TModel[\"createMany\"]>[0], \"data\">\n >(\n data: Parameters<TModel[\"createMany\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"createMany\"] extends (args: { data: any } & TOptions) => infer R\n ? R\n : never\n > {\n const prisma = getPrismaInstance();\n\n if (Array.isArray(data))\n (data as { [x: string]: any; password?: string }[]).forEach(\n async (curr, i) => {\n if (\"password\" in curr && this.modelName === \"user\")\n if (!authService.isPasswordHashed(curr.password!))\n curr.password = await authService.hashPassword(curr?.password!);\n\n data[i] = handleRelationFieldsInBody(\n data[i] as Record<string, any>,\n {\n ...this.relationFields,\n },\n [\"delete\", \"disconnect\", \"update\"]\n );\n }\n );\n\n return await prisma[this.modelName].createMany(\n deepmerge({ data }, (queryOptions as {}) || {}) as {\n data: any;\n } & TOptions\n );\n }\n\n /**\n * Counts records based on provided filters.\n *\n * @param {Parameters<TModel[\"count\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to apply to the query.\n * @returns {Promise<number>} The count of records matching the filters.\n */\n async count(\n filters: Parameters<TModel[\"count\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any\n ): Promise<number> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].count({\n where: filters,\n });\n }\n\n /**\n * Finds multiple records based on provided filters.\n *\n * @param {Parameters<TModel[\"findMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to apply to the query.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"findMany\"]>>} The found data.\n */\n async findMany<\n TOptions extends Omit<Parameters<TModel[\"findMany\"]>[0], \"where\">\n >(\n filters: Parameters<TModel[\"findMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"findMany\"] extends (args: { where: any } & TOptions) => infer R\n ? R\n : never\n > {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].findMany(\n deepmerge({ where: filters }, (queryOptions as {}) || {}) as {\n where: any;\n } & TOptions\n );\n }\n\n /**\n * Finds a single record by its ID.\n *\n * @param {string | number} id - The ID of the record to find.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"findUnique\"]>>} The found record or null if not found.\n */\n async findById<\n TOptions extends Omit<Parameters<TModel[\"findUnique\"]>[0], \"where\">\n >(\n id: string | number,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"findUnique\"] extends (args: { where: any } & TOptions) => infer R\n ? R\n : never\n > {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].findUnique(\n deepmerge(\n {\n where: { id },\n },\n queryOptions || {}\n ) as { where: { id: string | number } } & TOptions\n );\n }\n\n /**\n * Finds a single record by its parameters.\n *\n * @param {Parameters<TModel[\"findFirst\"]>[0] extends { where: infer W; [x: string]: any } ? W : any | Parameters<TModel[\"findUnique\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"findFirst\"]> | ReturnType<TModel[\"findUnique\"]>>} The found record or null if not found.\n */\n async findOne<\n TOptions extends\n | Omit<Parameters<TModel[\"findFirst\"]>[0], \"where\">\n | Omit<Parameters<TModel[\"findUnique\"]>[0], \"where\">\n >(\n filters: Parameters<TModel[\"findFirst\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any | Parameters<TModel[\"findUnique\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"findFirst\"] extends (args: { where: any } & TOptions) => infer R\n ? R\n : TModel[\"findUnique\"] extends (\n args: { where: any } & TOptions\n ) => infer R2\n ? R2\n : never\n > {\n const prisma = getPrismaInstance();\n\n if (\n Object.keys(filters as Record<string, any>).length === 1 &&\n \"id\" in (filters as Record<string, any>) &&\n (filters as any).id !== \"me\"\n )\n return prisma[this.modelName].findUnique(\n deepmerge(\n {\n where: filters,\n },\n (queryOptions as {}) || {}\n ) as { where: any } & TOptions\n );\n\n return await prisma[this.modelName].findFirst(\n deepmerge(\n {\n where: filters,\n },\n (queryOptions as {}) || {}\n ) as { where: any } & TOptions\n );\n }\n\n /**\n * Updates a single record by its ID.\n *\n * @param {Parameters<TModel[\"update\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @param {Parameters<TModel[\"update\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to update the record with.\n * @param {TOptions} [queryOptions] - Additional query options to modify the Prisma query.\n * @returns {Promise<ReturnType<TModel[\"update\"]>>} The updated record or null if not found.\n */\n async updateOne<\n TOptions extends Omit<Parameters<TModel[\"update\"]>[0], \"where\" | \"data\">\n >(\n filters: Parameters<TModel[\"update\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n data: Parameters<TModel[\"update\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"update\"] extends (\n args: { where: any; data: any } & TOptions\n ) => infer R\n ? R\n : never\n > {\n const prisma = getPrismaInstance();\n\n if (kebabCase(this.modelName) === \"user\" && (data as any)?.password) {\n if (!authService.isPasswordHashed((data as any).password!))\n (data as any).password = await authService.hashPassword(\n (data as any)?.password\n );\n }\n\n const dataWithRelationFieldsHandled = handleRelationFieldsInBody(\n data as Record<string, any>,\n {\n ...this.relationFields,\n }\n );\n\n return await prisma[this.modelName].update(\n deepmerge(\n {\n where: filters,\n data: dataWithRelationFieldsHandled,\n },\n (queryOptions as {}) || {}\n ) as { where: any; data: any } & TOptions\n );\n }\n\n /**\n * Updates multiple records based on the provided filter and data.\n *\n * @param {Parameters<TModel[\"updateMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The filters to identify records to update.\n * @param {Parameters<TModel[\"updateMany\"]>[0] extends { data: infer D; [x: string]: any } ? D : any} data - The data to update the records with.\n * @param {TOptions} [queryOptions] - Additional query options.\n * @returns {Promise<ReturnType<TModel[\"updateMany\"]>>} The result of the updateMany operation.\n */\n async updateMany<\n TOptions extends Omit<Parameters<TModel[\"updateMany\"]>[0], \"where\" | \"data\">\n >(\n filters: Parameters<TModel[\"updateMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any,\n data: Parameters<TModel[\"updateMany\"]>[0] extends {\n data: infer D;\n [x: string]: any;\n }\n ? D\n : any,\n queryOptions?: TOptions\n ): Promise<\n TModel[\"updateMany\"] extends (\n args: { where: any; data: any } & TOptions\n ) => infer R\n ? R\n : never\n > {\n const prisma = getPrismaInstance();\n\n if (Array.isArray(data) && this.modelName === \"user\")\n (data as { [x: string]: any; password?: string }[]).forEach(\n async (curr, i) => {\n if (\"password\" in data[i])\n if (!authService.isPasswordHashed(curr.password!))\n (data[i] as any).password = await authService.hashPassword(\n curr.password!\n );\n }\n );\n\n const firstMerge = deepmerge({ data }, (queryOptions as {}) || {});\n\n return await prisma[this.modelName].updateMany(\n deepmerge({ where: filters }, firstMerge) as {\n where: any;\n data: any;\n } & TOptions\n );\n }\n\n /**\n * Deletes a single record by its ID.\n *\n * @param {Parameters<TModel[\"delete\"]>[0] extends { where: infer W; [x: string]: any } ? W : any} filters - The parameters to find the record by.\n * @returns {Promise<ReturnType<TModel[\"delete\"]>>} The deleted record or null if an error occurs.\n */\n async deleteOne(\n filters: Parameters<TModel[\"delete\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : any\n ): Promise<ReturnType<TModel[\"delete\"]>> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].delete({\n where: filters,\n });\n }\n\n /**\n * Deletes multiple records based on the provided filter.\n *\n * @param {Parameters<TModel[\"deleteMany\"]>[0] extends { where: infer W; [x: string]: any } ? W : Record<string, any>} filters - The filter to identify records to delete.\n * @returns {Promise<ReturnType<TModel[\"deleteMany\"]>>} The result of the deleteMany operation.\n */\n async deleteMany(\n filters: Parameters<TModel[\"deleteMany\"]>[0] extends {\n where: infer W;\n [x: string]: any;\n }\n ? W\n : Record<string, any>\n ): Promise<ReturnType<TModel[\"deleteMany\"]>> {\n const prisma = getPrismaInstance();\n\n return await prisma[this.modelName].deleteMany({ where: filters });\n }\n}\n\n/**\n * Generates a set of base service instances for all available models.\n *\n * @returns {Record<string, BaseService>} A dictionary of base service instances, keyed by model name.\n */\nexport function getBaseServices(): Record<string, BaseService<any>> {\n const models = getModels();\n const baseServices: Record<string, BaseService<any>> = {};\n models.forEach((model) => {\n baseServices[`${camelCase(model)}`] = new BaseService(model);\n });\n return baseServices;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.service.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/base/utils/helpers/base.service.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getPrismaModelRelations,\n RelationFields,\n getModelUniqueFields,\n} from \"../../../../utils/helpers/models.helpers\";\n\n/**\n * Removes apiAction field from an object and all nested objects\n *\n * @param {Record<string, any>} obj - The object to clean\n * @returns {Record<string, any>} - The cleaned object\n */\nexport function removeApiAction(obj: Record<string, any>): Record<string, any> {\n if (!obj || typeof obj !== \"object\") return obj;\n\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (key === \"apiAction\") continue;\n\n if (Array.isArray(value)) {\n result[key] = value.map((item) =>\n typeof item === \"object\" && item !== null ? removeApiAction(item) : item\n );\n } else if (typeof value === \"object\" && value !== null) {\n result[key] = removeApiAction(value);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Checks if an object is already formatted as a Prisma relation operation\n *\n * @param {Record<string, any>} obj - The object to check\n * @returns {boolean} - True if the object contains Prisma relation operations\n */\nexport function isPrismaRelationFormat(obj: Record<string, any>): boolean {\n if (!obj || typeof obj !== \"object\") return false;\n\n // Common Prisma relation operations\n const prismaOperations = [\n \"create\",\n \"connect\",\n \"update\",\n \"delete\",\n \"disconnect\",\n \"deleteMany\",\n \"connectOrCreate\",\n \"upsert\",\n \"set\",\n ];\n\n // Check if any key is a Prisma operation\n return prismaOperations.some((op) => op in obj);\n}\n\n/**\n * Determines the appropriate Prisma operation (`create`, `connect`, `update`, `delete`, or `disconnect`)\n * for each relation field in the provided body based on its nested data and recursively does the same for each relation field.\n *\n * This function handles the following types of relations:\n * - **One-to-one**\n * - **One-to-many**\n *\n *\n * ### Operation Rules:\n *\n *\n * - **Create**: Used when the nested relation data is provided **without an `id` or unique field**.\n * - **Connect**: Used when the nested relation data contains **only an `id` or a unique field** (e.g., email).\n * - **Update**: Used when the nested relation data contains **both an `id` and additional fields**.\n * - **Delete**: Used when the nested relation data includes **`apiAction: \"delete\"`**.\n * - **Disconnect**: Used when the nested relation data includes **`apiAction: \"disconnect\"`**.\n *\n * The function will preserve existing Prisma operation formats if detected,\n * allowing developers to manually structure relation operations when needed.\n *\n * @param {Record<string, any>} body - The object containing relation fields to be processed.\n * @param {Object} relationFields - Defines relation field types.\n * @param {RelationFields[]} relationFields.singular - List of one-side relation field names (one-to-one).\n * @param {RelationFields[]} relationFields.list - List of many-side relation field names (one-to-many).\n * @param {string[]} ignoreActions - Optional list of apiAction values to ignore.\n * @returns {Record<string, any>} The transformed data with appropriate Prisma operations applied.\n */\nexport function handleRelationFieldsInBody(\n body: Record<string, any>,\n relationFields: RelationFields,\n ignoreActions: string[] = []\n) {\n let mutableBody = { ...body };\n\n relationFields?.list?.forEach((field) => {\n if (!body[field.name]) return;\n\n // Skip if the field is already in Prisma relation format\n if (isPrismaRelationFormat(body[field.name])) {\n return;\n }\n\n // Skip if the field is not an array (likely already handled manually)\n if (!Array.isArray(body[field.name])) {\n return;\n }\n\n const createData: any[] = [];\n const connectData: any[] = [];\n const updateData: any[] = [];\n const disconnectData: any[] = [];\n const deleteManyIds: any[] = [];\n\n body[field.name]?.forEach((bodyField: any) => {\n if (ignoreActions?.includes?.(bodyField?.apiAction)) return;\n\n const apiAction = bodyField?.apiAction;\n\n if (apiAction === \"delete\") {\n deleteManyIds.push(bodyField.id);\n } else if (apiAction === \"disconnect\") {\n disconnectData.push({ id: bodyField.id });\n } else if (canBeUsedToConnect(field.type, bodyField)) {\n // Handle connection with unique fields or ID\n const { apiAction: _, ...cleanedData } = bodyField;\n connectData.push(cleanedData);\n } else if (!bodyField?.id) {\n // If no ID, assume create operation\n let nestedRelations = getPrismaModelRelations(field.type);\n\n let dataToPush = { ...bodyField };\n\n if (nestedRelations) {\n dataToPush = handleRelationFieldsInBody(\n dataToPush,\n nestedRelations,\n ignoreActions\n );\n }\n\n // Ensure apiAction is removed\n if (\"apiAction\" in dataToPush) {\n const { apiAction: _, ...rest } = dataToPush;\n dataToPush = rest;\n }\n\n createData.push(dataToPush);\n } else {\n // If ID and other fields, assume update operation\n const { id, apiAction: _, ...data } = bodyField;\n\n let nestedRelations = getPrismaModelRelations(field.type);\n\n let dataToPush = data;\n if (nestedRelations) {\n dataToPush = handleRelationFieldsInBody(\n data,\n nestedRelations,\n ignoreActions\n );\n }\n\n updateData.push({\n where: { id },\n data: dataToPush,\n });\n }\n });\n\n mutableBody[field.name] = {\n ...(createData.length ? { create: createData } : {}),\n ...(connectData.length ? { connect: connectData } : {}),\n ...(updateData.length ? { update: updateData } : {}),\n ...(disconnectData.length ? { disconnect: disconnectData } : {}),\n ...(deleteManyIds.length\n ? { deleteMany: { id: { in: deleteManyIds } } }\n : {}),\n };\n });\n\n relationFields?.singular?.forEach((field) => {\n if (!body[field.name]) return;\n if (ignoreActions?.includes?.(body[field.name]?.apiAction)) return;\n\n // Skip if the field is already in Prisma relation format\n if (isPrismaRelationFormat(body[field.name])) {\n return;\n }\n\n const relationData = body[field.name];\n let nestedRelations = getPrismaModelRelations(field.type);\n\n if (canBeUsedToConnect(field.type, relationData)) {\n // Handle connection with unique fields or ID\n const { apiAction: _, ...cleanedData } = relationData;\n mutableBody[field.name] = { connect: cleanedData };\n } else if (!relationData?.id) {\n // If no ID, assume create operation\n let dataToCreate = { ...relationData };\n\n if (\"apiAction\" in dataToCreate) {\n const { apiAction: _, ...rest } = dataToCreate;\n dataToCreate = rest;\n }\n\n if (nestedRelations) {\n dataToCreate = handleRelationFieldsInBody(\n dataToCreate,\n nestedRelations,\n ignoreActions\n );\n }\n\n mutableBody[field.name] = { create: dataToCreate };\n } else {\n // If ID and other fields, assume update operation\n const { id, apiAction: _, ...data } = relationData;\n\n let dataToUpdate = data;\n if (nestedRelations) {\n dataToUpdate = handleRelationFieldsInBody(\n data,\n nestedRelations,\n ignoreActions\n );\n }\n\n mutableBody[field.name] = {\n update: {\n data: dataToUpdate,\n },\n };\n }\n });\n\n // Remove any remaining apiAction fields from the top level\n if (\"apiAction\" in mutableBody) {\n const { apiAction, ...rest } = mutableBody;\n mutableBody = rest;\n }\n\n // As a final step, recursively remove any remaining apiAction fields\n return removeApiAction(mutableBody);\n}\n\n/**\n * Checks if a field value can be used to connect to a model\n * This happens when the field contains only an ID or a single unique field\n *\n * @param {string} modelName - The model name to get unique fields for\n * @param {Record<string, any>} bodyField - The field value from the body\n * @returns {boolean} True if the field can be used for a connect operation\n */\nexport function canBeUsedToConnect(\n modelName: string,\n bodyField: Record<string, any> | undefined | null\n): boolean {\n // If the field is null or undefined, it can't be used to connect\n if (!bodyField) return false;\n\n // If the field has an apiAction that's not for connecting, return false\n if (bodyField.apiAction && ![\"connect\"]?.includes?.(bodyField.apiAction)) {\n return false;\n }\n\n // If explicitly marked for connect, allow it\n if (bodyField.apiAction === \"connect\") {\n return true;\n }\n\n // If only ID is present, it can be used to connect\n if (Object.keys(bodyField)?.length === 1 && bodyField?.id) {\n return true;\n }\n\n // Get unique fields for the model\n const uniqueFields = getModelUniqueFields(modelName);\n\n // If the field has exactly one property and it's a unique field, it can be used to connect\n if (Object.keys(bodyField).length === 1) {\n const fieldName = Object.keys(bodyField)[0];\n return uniqueFields?.some((field) => field.name === fieldName);\n }\n\n return false;\n}\n\n// /**\n// * Checks if a list field is actually an array\n// *\n// * @param {any} field - The field to check\n// * @returns {boolean} - True if the field is an array\n// */\n// export function isListFieldAnArray(field: any): boolean {\n// return Array.isArray(field);\n// }\n"]}
|
|
1
|
+
{"version":3,"file":"base.service.helpers.js","sourceRoot":"","sources":["../../../../../../src/modules/base/utils/helpers/base.service.helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n getPrismaModelRelations,\n RelationFields,\n getModelUniqueFields,\n} from \"../../../../utils/helpers/models.helpers\";\n\n/**\n * Removes apiAction field from an object and all nested objects\n *\n * @param {Record<string, any>} obj - The object to clean\n * @returns {Record<string, any>} - The cleaned object\n */\nexport function removeApiAction(obj: Record<string, any>): Record<string, any> {\n if (!obj || typeof obj !== \"object\") return obj;\n\n const result: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n if (key === \"apiAction\") continue;\n\n if (Array.isArray(value)) {\n result[key] = value.map((item) =>\n typeof item === \"object\" && item !== null ? removeApiAction(item) : item\n );\n } else if (typeof value === \"object\" && value !== null) {\n result[key] = removeApiAction(value);\n } else {\n result[key] = value;\n }\n }\n\n return result;\n}\n\n/**\n * Checks if an object is already formatted as a Prisma relation operation\n *\n * @param {Record<string, any>} obj - The object to check\n * @returns {boolean} - True if the object contains Prisma relation operations\n */\nexport function isPrismaRelationFormat(obj: Record<string, any>): boolean {\n if (!obj || typeof obj !== \"object\") return false;\n\n // Common Prisma relation operations\n const prismaOperations = [\n \"create\",\n \"connect\",\n \"update\",\n \"delete\",\n \"disconnect\",\n \"deleteMany\",\n \"connectOrCreate\",\n \"upsert\",\n \"set\",\n ];\n\n // Check if any key is a Prisma operation\n return prismaOperations.some((op) => op in obj);\n}\n\n/**\n * Determines the appropriate Prisma operation (`create`, `connect`, `update`, `delete`, or `disconnect`)\n * for each relation field in the provided body based on its nested data and recursively does the same for each relation field.\n *\n * This function handles the following types of relations:\n * - **One-to-one**\n * - **One-to-many**\n *\n *\n * ### Operation Rules:\n *\n *\n * - **Create**: Used when the nested relation data is provided **without an `id` or unique field**.\n * - **Connect**: Used when the nested relation data contains **only an `id` or a unique field** (e.g., email).\n * - **Update**: Used when the nested relation data contains **both an `id` and additional fields**.\n * - **Delete**: Used when the nested relation data includes **`apiAction: \"delete\"`**.\n * - **Disconnect**: Used when the nested relation data includes **`apiAction: \"disconnect\"`**.\n *\n * The function will preserve existing Prisma operation formats if detected,\n * allowing developers to manually structure relation operations when needed.\n *\n * @param {Record<string, any>} body - The object containing relation fields to be processed.\n * @param {Object} relationFields - Defines relation field types.\n * @param {RelationFields[]} relationFields.singular - List of one-side relation field names (one-to-one).\n * @param {RelationFields[]} relationFields.list - List of many-side relation field names (one-to-many).\n * @param {string[]} ignoreActions - Optional list of apiAction values to ignore.\n * @returns {Record<string, any>} The transformed data with appropriate Prisma operations applied.\n */\nexport function handleRelationFieldsInBody(\n body: Record<string, any>,\n relationFields: RelationFields,\n ignoreActions: string[] = []\n) {\n let mutableBody = { ...body };\n\n relationFields?.list?.forEach((field) => {\n if (!body[field.name]) return;\n\n // Skip if the field is already in Prisma relation format\n if (isPrismaRelationFormat(body[field.name])) {\n return;\n }\n\n // Skip if the field is not an array (likely already handled manually)\n if (!Array.isArray(body[field.name])) {\n return;\n }\n\n const createData: any[] = [];\n const connectData: any[] = [];\n const updateData: any[] = [];\n const disconnectData: any[] = [];\n const deleteManyIds: any[] = [];\n\n body[field.name]?.forEach((bodyField: any) => {\n if (ignoreActions?.includes?.(bodyField?.apiAction)) return;\n\n const apiAction = bodyField?.apiAction;\n\n if (apiAction === \"delete\") {\n deleteManyIds.push(bodyField.id);\n } else if (apiAction === \"disconnect\") {\n disconnectData.push({ id: bodyField.id });\n } else if (canBeUsedToConnect(field.type, bodyField)) {\n // Handle connection with unique fields or ID\n const { apiAction: _, ...cleanedData } = bodyField;\n connectData.push(cleanedData);\n } else if (!bodyField?.id) {\n // If no ID, assume create operation\n let nestedRelations = getPrismaModelRelations(field.type);\n\n let dataToPush = { ...bodyField };\n\n if (nestedRelations) {\n dataToPush = handleRelationFieldsInBody(\n dataToPush,\n nestedRelations,\n ignoreActions\n );\n }\n\n // Ensure apiAction is removed\n if (\"apiAction\" in dataToPush) {\n const { apiAction: _, ...rest } = dataToPush;\n dataToPush = rest;\n }\n\n createData.push(dataToPush);\n } else {\n // If ID and other fields, assume update operation\n const { id, apiAction: _, ...data } = bodyField;\n\n let nestedRelations = getPrismaModelRelations(field.type);\n\n let dataToPush = data;\n if (nestedRelations) {\n dataToPush = handleRelationFieldsInBody(\n data,\n nestedRelations,\n ignoreActions\n );\n }\n\n updateData.push({\n where: { id },\n data: dataToPush,\n });\n }\n });\n\n mutableBody[field.name] = {\n ...(createData.length ? { create: createData } : {}),\n ...(connectData.length ? { connect: connectData } : {}),\n ...(updateData.length ? { update: updateData } : {}),\n ...(disconnectData.length ? { disconnect: disconnectData } : {}),\n ...(deleteManyIds.length\n ? { deleteMany: { id: { in: deleteManyIds } } }\n : {}),\n };\n });\n\n relationFields?.singular?.forEach((field) => {\n if (!body[field.name]) return;\n if (ignoreActions?.includes?.(body[field.name]?.apiAction)) return;\n\n // Skip if the field is already in Prisma relation format\n if (isPrismaRelationFormat(body[field.name])) {\n return;\n }\n\n const relationData = body[field.name];\n let nestedRelations = getPrismaModelRelations(field.type);\n\n if (canBeUsedToConnect(field.type, relationData)) {\n // Handle connection with unique fields or ID\n const { apiAction: _, ...cleanedData } = relationData;\n mutableBody[field.name] = { connect: cleanedData };\n } else if (!relationData?.id) {\n // If no ID, assume create operation\n let dataToCreate = { ...relationData };\n\n if (\"apiAction\" in dataToCreate) {\n const { apiAction: _, ...rest } = dataToCreate;\n dataToCreate = rest;\n }\n\n if (nestedRelations) {\n dataToCreate = handleRelationFieldsInBody(\n dataToCreate,\n nestedRelations,\n ignoreActions\n );\n }\n\n mutableBody[field.name] = { create: dataToCreate };\n } else {\n // If ID and other fields, assume update operation\n const { id, apiAction: _, ...data } = relationData;\n\n let dataToUpdate = data;\n if (nestedRelations) {\n dataToUpdate = handleRelationFieldsInBody(\n data,\n nestedRelations,\n ignoreActions\n );\n }\n\n mutableBody[field.name] = {\n update: {\n data: dataToUpdate,\n },\n };\n }\n });\n\n // Remove any remaining apiAction fields from the top level\n if (\"apiAction\" in mutableBody) {\n const { apiAction, ...rest } = mutableBody;\n mutableBody = rest;\n }\n\n // As a final step, recursively remove any remaining apiAction fields\n return removeApiAction(mutableBody);\n}\n\n/**\n * Checks if a field value can be used to connect to a model\n * This happens when the field contains only an ID or a single unique field\n *\n * @param {string} modelName - The model name to get unique fields for\n * @param {Record<string, any>} bodyField - The field value from the body\n * @returns {boolean} True if the field can be used for a connect operation\n */\nexport function canBeUsedToConnect(\n modelName: string,\n bodyField: Record<string, any> | undefined | null\n): boolean {\n // If the field is null or undefined, it can't be used to connect\n if (!bodyField) return false;\n\n // If the field has an apiAction that's not for connecting, return false\n if (bodyField.apiAction && ![\"connect\"]?.includes?.(bodyField.apiAction)) {\n return false;\n }\n\n // If explicitly marked for connect, allow it\n if (bodyField.apiAction === \"connect\") {\n return true;\n }\n\n // If only ID is present, it can be used to connect\n if (Object.keys(bodyField)?.length === 1 && bodyField?.id) {\n return true;\n }\n\n // Get unique fields for the model\n const uniqueFields = getModelUniqueFields(modelName);\n\n // If the field has exactly one property and it's a unique field, it can be used to connect\n if (Object.keys(bodyField).length === 1) {\n const fieldName = Object.keys(bodyField)[0];\n return uniqueFields?.some((field) => field.name === fieldName);\n }\n\n return false;\n}\n"]}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const app_error_1 = __importDefault(require("../error-handler/utils/app-error"));
|
|
7
|
+
const file_upload_service_1 = require("./file-upload.service");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const catch_async_1 = __importDefault(require("../error-handler/utils/catch-async"));
|
|
11
|
+
const server_1 = require("../../server");
|
|
12
|
+
const file_upload_helpers_1 = require("./utils/helpers/file-upload.helpers");
|
|
13
|
+
const fs_helpers_1 = require("../../utils/helpers/fs.helpers");
|
|
14
|
+
class FileUploadController {
|
|
15
|
+
constructor() {
|
|
16
|
+
this.uploadFile = (0, catch_async_1.default)(async (req, res, next) => {
|
|
17
|
+
const { fileType } = req.params;
|
|
18
|
+
const { format, width, height, resizeTo } = req.query;
|
|
19
|
+
const options = { format, width, height, resizeTo };
|
|
20
|
+
const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = (0, file_upload_service_1.getFileUploadServices)();
|
|
21
|
+
const { fileUpload } = (0, server_1.getArkosConfig)();
|
|
22
|
+
const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
|
|
23
|
+
const uploadPath = path_1.default.resolve(process.cwd(), baseUploadDir, fileType);
|
|
24
|
+
try {
|
|
25
|
+
await (0, fs_helpers_1.accessAsync)(uploadPath);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
await (0, fs_helpers_1.mkdirAsync)(uploadPath, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
let uploader;
|
|
31
|
+
switch (fileType) {
|
|
32
|
+
case "images":
|
|
33
|
+
uploader = imageUploadService;
|
|
34
|
+
break;
|
|
35
|
+
case "videos":
|
|
36
|
+
uploader = videoUploadService;
|
|
37
|
+
break;
|
|
38
|
+
case "documents":
|
|
39
|
+
uploader = documentUploadService;
|
|
40
|
+
break;
|
|
41
|
+
case "files":
|
|
42
|
+
uploader = fileUploadService;
|
|
43
|
+
break;
|
|
44
|
+
default:
|
|
45
|
+
return next(new app_error_1.default("Invalid file type", 400));
|
|
46
|
+
}
|
|
47
|
+
uploader.handleMultipleUpload()(req, res, async (err) => {
|
|
48
|
+
if (err)
|
|
49
|
+
return next(err);
|
|
50
|
+
let data;
|
|
51
|
+
if (req.files && Array.isArray(req.files)) {
|
|
52
|
+
if (fileType === "images") {
|
|
53
|
+
data = await Promise.all(req.files.map((file) => (0, file_upload_helpers_1.processImage)(req, file.path, options)));
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
data = await Promise.all(req.files.map((file) => (0, file_upload_helpers_1.processFile)(req, file.path)));
|
|
57
|
+
}
|
|
58
|
+
data = data.filter((url) => url !== null);
|
|
59
|
+
}
|
|
60
|
+
else if (req.file) {
|
|
61
|
+
if (fileType === "images") {
|
|
62
|
+
data = await (0, file_upload_helpers_1.processImage)(req, req.file.path, options);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
data = await (0, file_upload_helpers_1.processFile)(req, req.file.path);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
return next(new app_error_1.default("No file uploaded", 400));
|
|
70
|
+
}
|
|
71
|
+
res.status(200).json({
|
|
72
|
+
success: true,
|
|
73
|
+
data,
|
|
74
|
+
message: Array.isArray(data)
|
|
75
|
+
? `${data.length} files uploaded successfully`
|
|
76
|
+
: "File uploaded successfully",
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
this.deleteFile = (0, catch_async_1.default)(async (req, res, next) => {
|
|
81
|
+
const { fileType, fileName } = req.params;
|
|
82
|
+
const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = (0, file_upload_service_1.getFileUploadServices)();
|
|
83
|
+
let uploader;
|
|
84
|
+
switch (fileType) {
|
|
85
|
+
case "images":
|
|
86
|
+
uploader = imageUploadService;
|
|
87
|
+
break;
|
|
88
|
+
case "videos":
|
|
89
|
+
uploader = videoUploadService;
|
|
90
|
+
break;
|
|
91
|
+
case "documents":
|
|
92
|
+
uploader = documentUploadService;
|
|
93
|
+
break;
|
|
94
|
+
case "files":
|
|
95
|
+
uploader = fileUploadService;
|
|
96
|
+
break;
|
|
97
|
+
default:
|
|
98
|
+
return next(new app_error_1.default("Invalid file type", 400));
|
|
99
|
+
}
|
|
100
|
+
try {
|
|
101
|
+
const { fileUpload } = (0, server_1.getArkosConfig)();
|
|
102
|
+
const baseUploadRoute = fileUpload?.baseRoute || "/api/uploads";
|
|
103
|
+
const urlPattern = new RegExp(`${baseUploadRoute}/${fileType}/${fileName}`);
|
|
104
|
+
const isExpectedUrlPattern = urlPattern.test(req.originalUrl);
|
|
105
|
+
if (isExpectedUrlPattern) {
|
|
106
|
+
const fullUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
|
|
107
|
+
await uploader.deleteFileByUrl(fullUrl);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
await uploader.deleteFileByName(fileName, fileType);
|
|
111
|
+
}
|
|
112
|
+
res.status(200).json({
|
|
113
|
+
success: true,
|
|
114
|
+
message: "File deleted successfully",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
if (error instanceof app_error_1.default) {
|
|
119
|
+
return next(error);
|
|
120
|
+
}
|
|
121
|
+
return next(new app_error_1.default("File not found", 404));
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
this.updateFile = (0, catch_async_1.default)(async (req, res, next) => {
|
|
125
|
+
const { fileType, fileName } = req.params;
|
|
126
|
+
const { format, width, height, resizeTo } = req.query;
|
|
127
|
+
const options = { format, width, height, resizeTo };
|
|
128
|
+
const { documentUploadService, fileUploadService, imageUploadService, videoUploadService, } = (0, file_upload_service_1.getFileUploadServices)();
|
|
129
|
+
const { fileUpload } = (0, server_1.getArkosConfig)();
|
|
130
|
+
const baseUploadDir = fileUpload?.baseUploadDir || "/uploads";
|
|
131
|
+
const uploadPath = path_1.default.resolve(process.cwd(), baseUploadDir, fileType);
|
|
132
|
+
try {
|
|
133
|
+
await (0, fs_helpers_1.accessAsync)(uploadPath);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
await (0, fs_helpers_1.mkdirAsync)(uploadPath, { recursive: true });
|
|
137
|
+
}
|
|
138
|
+
let uploader;
|
|
139
|
+
switch (fileType) {
|
|
140
|
+
case "images":
|
|
141
|
+
uploader = imageUploadService;
|
|
142
|
+
break;
|
|
143
|
+
case "videos":
|
|
144
|
+
uploader = videoUploadService;
|
|
145
|
+
break;
|
|
146
|
+
case "documents":
|
|
147
|
+
uploader = documentUploadService;
|
|
148
|
+
break;
|
|
149
|
+
case "files":
|
|
150
|
+
uploader = fileUploadService;
|
|
151
|
+
break;
|
|
152
|
+
default:
|
|
153
|
+
return next(new app_error_1.default("Invalid file type", 400));
|
|
154
|
+
}
|
|
155
|
+
uploader.handleMultipleUpload()(req, res, async (err) => {
|
|
156
|
+
if (err)
|
|
157
|
+
return next(err);
|
|
158
|
+
if (!req.file &&
|
|
159
|
+
(!req.files || !Array.isArray(req.files) || req.files.length === 0)) {
|
|
160
|
+
return next(new app_error_1.default("No new file uploaded", 400));
|
|
161
|
+
}
|
|
162
|
+
if (fileName && fileName.trim() !== "") {
|
|
163
|
+
try {
|
|
164
|
+
const baseUploadRoute = fileUpload?.baseRoute || "/api/uploads";
|
|
165
|
+
const urlPattern = new RegExp(`${baseUploadRoute}/${fileType}/${fileName}`);
|
|
166
|
+
const isExpectedUrlPattern = urlPattern.test(req.originalUrl);
|
|
167
|
+
if (isExpectedUrlPattern) {
|
|
168
|
+
const oldFileUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`;
|
|
169
|
+
await uploader.deleteFileByUrl(oldFileUrl);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
await uploader.deleteFileByName(fileName, fileType);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
console.warn(`Could not delete old file: ${fileName}`, error);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
let data;
|
|
180
|
+
if (req.files && Array.isArray(req.files)) {
|
|
181
|
+
if (fileType === "images") {
|
|
182
|
+
data = await Promise.all(req.files.map((file) => (0, file_upload_helpers_1.processImage)(req, file.path, options)));
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
data = await Promise.all(req.files.map((file) => (0, file_upload_helpers_1.processFile)(req, file.path)));
|
|
186
|
+
}
|
|
187
|
+
data = data.filter((url) => url !== null);
|
|
188
|
+
}
|
|
189
|
+
else if (req.file) {
|
|
190
|
+
if (fileType === "images") {
|
|
191
|
+
data = await (0, file_upload_helpers_1.processImage)(req, req.file.path, options);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
data = await (0, file_upload_helpers_1.processFile)(req, req.file.path);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
res.status(200).json({
|
|
198
|
+
success: true,
|
|
199
|
+
data,
|
|
200
|
+
message: Array.isArray(data)
|
|
201
|
+
? fileName && fileName.trim() !== ""
|
|
202
|
+
? `File updated successfully. ${data.length} new files uploaded`
|
|
203
|
+
: `${data.length} files uploaded successfully`
|
|
204
|
+
: fileName && fileName.trim() !== ""
|
|
205
|
+
? "File updated successfully"
|
|
206
|
+
: "File uploaded successfully",
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
this.streamFile = (0, catch_async_1.default)(async (req, res, next) => {
|
|
211
|
+
const { fileName, fileType } = req.params;
|
|
212
|
+
const filePath = path_1.default.join(".", "uploads", fileType, fileName);
|
|
213
|
+
try {
|
|
214
|
+
await (0, fs_helpers_1.accessAsync)(filePath);
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
throw new app_error_1.default("File not found", 404);
|
|
218
|
+
}
|
|
219
|
+
const fileStat = await (0, fs_helpers_1.statAsync)(filePath);
|
|
220
|
+
const fileSize = fileStat.size;
|
|
221
|
+
const range = req.headers.range;
|
|
222
|
+
if (range) {
|
|
223
|
+
const [partialStart, partialEnd] = range
|
|
224
|
+
.replace(/bytes=/, "")
|
|
225
|
+
.split("-");
|
|
226
|
+
const start = parseInt(partialStart, 10) || 0;
|
|
227
|
+
const end = partialEnd ? parseInt(partialEnd, 10) : fileSize - 1;
|
|
228
|
+
if (start >= fileSize || end >= fileSize) {
|
|
229
|
+
res.status(416).json({ error: "Range Not Satisfiable" });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
res.writeHead(206, {
|
|
233
|
+
"Content-Range": `bytes ${start}-${end}/${fileSize}`,
|
|
234
|
+
"Accept-Ranges": "bytes",
|
|
235
|
+
"Content-Length": end - start + 1,
|
|
236
|
+
"Content-Type": "application/octet-stream",
|
|
237
|
+
"Content-Disposition": `inline; filename="${fileName}"`,
|
|
238
|
+
});
|
|
239
|
+
fs_1.default.createReadStream(filePath, { start, end }).pipe(res);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
res.writeHead(200, {
|
|
243
|
+
"Content-Length": fileSize,
|
|
244
|
+
"Content-Type": "application/octet-stream",
|
|
245
|
+
"Content-Disposition": `inline; filename="${fileName}"`,
|
|
246
|
+
});
|
|
247
|
+
fs_1.default.createReadStream(filePath).pipe(res);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
const fileUploadController = new FileUploadController();
|
|
253
|
+
exports.default = fileUploadController;
|
|
254
|
+
//# sourceMappingURL=file-upload.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-upload.controller.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import AppError from \"../error-handler/utils/app-error\";\nimport {\n FileUploadService,\n getFileUploadServices,\n} from \"./file-upload.service\";\nimport path from \"path\";\nimport fs from \"fs\";\nimport catchAsync from \"../error-handler/utils/catch-async\";\nimport { getArkosConfig } from \"../../server\";\nimport { processFile, processImage } from \"./utils/helpers/file-upload.helpers\";\nimport {\n accessAsync,\n mkdirAsync,\n statAsync,\n} from \"../../utils/helpers/fs.helpers\";\nimport { ArkosNextFunction, ArkosRequest, ArkosResponse } from \"../../types\";\n\n/**\n * Handles files uploads and allow to be extended\n */\nclass FileUploadController {\n /**\n * Handles file upload requests, processes images if needed, and returns URLs\n *\n * Supports paths outside of the project directory with '../' prefix\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n uploadFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType } = req.params;\n const { format, width, height, resizeTo } = req.query;\n const options = { format, width, height, resizeTo };\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n // Ensure upload directory exists\n const uploadPath = path.resolve(process.cwd(), baseUploadDir, fileType);\n try {\n await accessAsync(uploadPath);\n } catch (err) {\n // Create directory if it doesn't exist\n await mkdirAsync(uploadPath, { recursive: true });\n }\n\n // Select the appropriate uploader service based on file type\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(new AppError(\"Invalid file type\", 400));\n }\n\n // Handle the file upload\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) return next(err);\n\n // Process all uploaded files\n let data;\n if (req.files && Array.isArray(req.files)) {\n if (fileType === \"images\") {\n // Process multiple image files with image transformations\n data = await Promise.all(\n req.files.map((file) => processImage(req, file.path, options))\n );\n } else {\n // Just store other file types without processing\n data = await Promise.all(\n req.files.map((file) => processFile(req, file.path))\n );\n }\n // Filter out any null values from failed processing\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n // Process a single file\n if (fileType === \"images\") {\n data = await processImage(req, req.file.path, options);\n } else {\n data = await processFile(req, req.file.path);\n }\n } else {\n return next(new AppError(\"No file uploaded\", 400));\n }\n\n res.status(200).json({\n success: true,\n data,\n message: Array.isArray(data)\n ? `${data.length} files uploaded successfully`\n : \"File uploaded successfully\",\n });\n });\n }\n );\n\n /**\n * Handles file deletion requests\n *\n * Supports paths outside of the project directory with '../' prefix\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n deleteFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType, fileName } = req.params;\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(new AppError(\"Invalid file type\", 400));\n }\n\n try {\n const { fileUpload } = getArkosConfig();\n const baseUploadRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n // This checks if the URL follows the expected format: /api/files/{fileType}/{fileName}\n const urlPattern = new RegExp(\n `${baseUploadRoute}/${fileType}/${fileName}`\n );\n\n const isExpectedUrlPattern = urlPattern.test(req.originalUrl);\n\n if (isExpectedUrlPattern) {\n // Build the expected URL for this request\n const fullUrl = `${req.protocol}://${req.get(\"host\")}${\n req.originalUrl\n }`;\n\n // URL matches expected pattern, use deleteFileByUrl\n await uploader.deleteFileByUrl(fullUrl);\n } else {\n // URL doesn't match expected pattern, use deleteFileByName\n await uploader.deleteFileByName(fileName, fileType);\n }\n\n res.status(200).json({\n success: true,\n message: \"File deleted successfully\",\n });\n } catch (error) {\n // Handle different types of errors\n if (error instanceof AppError) {\n return next(error);\n }\n // File doesn't exist or other error\n return next(new AppError(\"File not found\", 404));\n }\n }\n );\n\n /**\n * Handles file update requests by deleting the old file and uploading a new one\n * @param {ArkosRequest} req - Arkos request object\n * @param {ArkosResponse} res - Arkos response object\n * @param {ArkosNextFunction} next - Arkos next middleware function\n */\n updateFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileType, fileName } = req.params;\n const { format, width, height, resizeTo } = req.query;\n const options = { format, width, height, resizeTo };\n\n const {\n documentUploadService,\n fileUploadService,\n imageUploadService,\n videoUploadService,\n } = getFileUploadServices();\n\n const { fileUpload } = getArkosConfig();\n const baseUploadDir = fileUpload?.baseUploadDir || \"/uploads\";\n\n // Ensure upload directory exists\n const uploadPath = path.resolve(process.cwd(), baseUploadDir, fileType);\n try {\n await accessAsync(uploadPath);\n } catch (err) {\n // Create directory if it doesn't exist\n await mkdirAsync(uploadPath, { recursive: true });\n }\n\n // Select the appropriate uploader service based on file type\n let uploader: FileUploadService;\n switch (fileType) {\n case \"images\":\n uploader = imageUploadService;\n break;\n case \"videos\":\n uploader = videoUploadService;\n break;\n case \"documents\":\n uploader = documentUploadService;\n break;\n case \"files\":\n uploader = fileUploadService;\n break;\n default:\n return next(new AppError(\"Invalid file type\", 400));\n }\n\n // Handle the file upload\n uploader.handleMultipleUpload()(req, res, async (err) => {\n if (err) return next(err);\n\n // Check if new file was uploaded\n if (\n !req.file &&\n (!req.files || !Array.isArray(req.files) || req.files.length === 0)\n ) {\n return next(new AppError(\"No new file uploaded\", 400));\n }\n\n // Only attempt to delete old file if fileName is specified\n if (fileName && fileName.trim() !== \"\") {\n try {\n const baseUploadRoute = fileUpload?.baseRoute || \"/api/uploads\";\n\n // Check if the URL follows the expected format\n const urlPattern = new RegExp(\n `${baseUploadRoute}/${fileType}/${fileName}`\n );\n\n const isExpectedUrlPattern = urlPattern.test(req.originalUrl);\n\n if (isExpectedUrlPattern) {\n // URL matches expected pattern, use deleteFileByUrl\n const oldFileUrl = `${req.protocol}://${req.get(\"host\")}${\n req.originalUrl\n }`;\n await uploader.deleteFileByUrl(oldFileUrl);\n } else {\n // URL doesn't match expected pattern, use deleteFileByName\n await uploader.deleteFileByName(fileName, fileType);\n }\n } catch (error) {\n // Log the error but continue with upload - old file might not exist\n console.warn(`Could not delete old file: ${fileName}`, error);\n }\n }\n\n // Process the new uploaded file(s)\n let data;\n if (req.files && Array.isArray(req.files)) {\n if (fileType === \"images\") {\n // Process multiple image files with image transformations\n data = await Promise.all(\n req.files.map((file) => processImage(req, file.path, options))\n );\n } else {\n // Just store other file types without processing\n data = await Promise.all(\n req.files.map((file) => processFile(req, file.path))\n );\n }\n // Filter out any null values from failed processing\n data = data.filter((url) => url !== null);\n } else if (req.file) {\n // Process a single file\n if (fileType === \"images\") {\n data = await processImage(req, req.file.path, options);\n } else {\n data = await processFile(req, req.file.path);\n }\n }\n\n res.status(200).json({\n success: true,\n data,\n message: Array.isArray(data)\n ? fileName && fileName.trim() !== \"\"\n ? `File updated successfully. ${data.length} new files uploaded`\n : `${data.length} files uploaded successfully`\n : fileName && fileName.trim() !== \"\"\n ? \"File updated successfully\"\n : \"File uploaded successfully\",\n });\n });\n }\n );\n\n /**\n * Not implemented yet\n *\n * @deprecated\n */\n streamFile = catchAsync(\n async (req: ArkosRequest, res: ArkosResponse, next: ArkosNextFunction) => {\n const { fileName, fileType } = req.params;\n\n const filePath = path.join(\".\", \"uploads\", fileType, fileName);\n try {\n await accessAsync(filePath);\n } catch (err) {\n throw new AppError(\"File not found\", 404);\n }\n\n const fileStat = await statAsync(filePath);\n const fileSize = fileStat.size;\n const range = req.headers.range;\n\n if (range) {\n const [partialStart, partialEnd] = range\n .replace(/bytes=/, \"\")\n .split(\"-\");\n const start = parseInt(partialStart, 10) || 0;\n const end = partialEnd ? parseInt(partialEnd, 10) : fileSize - 1;\n\n if (start >= fileSize || end >= fileSize) {\n res.status(416).json({ error: \"Range Not Satisfiable\" });\n return;\n }\n\n res.writeHead(206, {\n \"Content-Range\": `bytes ${start}-${end}/${fileSize}`,\n \"Accept-Ranges\": \"bytes\",\n \"Content-Length\": end - start + 1,\n \"Content-Type\": \"application/octet-stream\",\n \"Content-Disposition\": `inline; filename=\"${fileName}\"`,\n });\n\n fs.createReadStream(filePath, { start, end }).pipe(res);\n } else {\n res.writeHead(200, {\n \"Content-Length\": fileSize,\n \"Content-Type\": \"application/octet-stream\",\n \"Content-Disposition\": `inline; filename=\"${fileName}\"`,\n });\n fs.createReadStream(filePath).pipe(res);\n }\n }\n );\n}\n\n/**\n * Controller instance responsible for handling file upload operations.\n * Manages the processing and routing of file upload requests.\n *\n * @remarks\n * This controller handles various file upload operations including validation,\n * storage, and response management.\n *\n * @instance\n * @constant\n * @see {@link https://www.arkosjs.com/docs/api-reference/file-upload-controller-object}\n */\nconst fileUploadController = new FileUploadController();\n\nexport default fileUploadController;\n"]}
|
package/dist/cjs/modules/{file-uploader/file-uploader.router.js → file-upload/file-upload.router.js}
RENAMED
|
@@ -3,16 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.getFileUploadRouter = getFileUploadRouter;
|
|
7
7
|
const express_1 = require("express");
|
|
8
8
|
const models_helpers_1 = require("../../utils/helpers/models.helpers");
|
|
9
9
|
const auth_service_1 = __importDefault(require("../auth/auth.service"));
|
|
10
|
-
const
|
|
10
|
+
const file_upload_controller_1 = __importDefault(require("./file-upload.controller"));
|
|
11
11
|
const path_1 = __importDefault(require("path"));
|
|
12
12
|
const express_2 = __importDefault(require("express"));
|
|
13
13
|
const deepmerge_helper_1 = __importDefault(require("../../utils/helpers/deepmerge.helper"));
|
|
14
14
|
const router = (0, express_1.Router)();
|
|
15
|
-
async function
|
|
15
|
+
async function getFileUploadRouter({ fileUpload }) {
|
|
16
16
|
const modelModules = await (0, models_helpers_1.importPrismaModelModules)("file-upload");
|
|
17
17
|
let { middlewares = {}, authConfigs = {} } = {};
|
|
18
18
|
if (modelModules) {
|
|
@@ -32,8 +32,9 @@ async function getFileUploaderRouter({ fileUpload }) {
|
|
|
32
32
|
index: false,
|
|
33
33
|
cacheControl: true,
|
|
34
34
|
}, fileUpload?.expressStaticOptions || {})));
|
|
35
|
-
router.post(`${basePathname}:fileType`, auth_service_1.default.handleAuthenticationControl("Create", authConfigs.authenticationControl), auth_service_1.default.handleAccessControl("Create", "file-upload", authConfigs.accessControl),
|
|
36
|
-
router.delete(`${basePathname}:fileType/:fileName`, auth_service_1.default.handleAuthenticationControl("Delete", authConfigs.authenticationControl), auth_service_1.default.handleAccessControl("
|
|
35
|
+
router.post(`${basePathname}:fileType`, auth_service_1.default.handleAuthenticationControl("Create", authConfigs.authenticationControl), auth_service_1.default.handleAccessControl("Create", "file-upload", authConfigs.accessControl), file_upload_controller_1.default.uploadFile);
|
|
36
|
+
router.delete(`${basePathname}:fileType/:fileName`, auth_service_1.default.handleAuthenticationControl("Delete", authConfigs.authenticationControl), auth_service_1.default.handleAccessControl("Delete", "file-upload", authConfigs.accessControl), file_upload_controller_1.default.deleteFile);
|
|
37
|
+
router.delete(`${basePathname}:fileType/:fileName`, auth_service_1.default.handleAuthenticationControl("Update", authConfigs.authenticationControl), auth_service_1.default.handleAccessControl("Update", "file-upload", authConfigs.accessControl), file_upload_controller_1.default.updateFile);
|
|
37
38
|
return router;
|
|
38
39
|
}
|
|
39
|
-
//# sourceMappingURL=file-
|
|
40
|
+
//# sourceMappingURL=file-upload.router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-upload.router.js","sourceRoot":"","sources":["../../../../src/modules/file-upload/file-upload.router.ts"],"names":[],"mappings":";;;;;AAYA,kDAoFC;AAhGD,qCAAiC;AACjC,uEAA8E;AAC9E,wEAA+C;AAC/C,sFAA4D;AAE5D,gDAAwB;AACxB,sDAA8B;AAC9B,4FAA6D;AAG7D,MAAM,MAAM,GAAW,IAAA,gBAAM,GAAE,CAAC;AAEzB,KAAK,UAAU,mBAAmB,CAAC,EAAE,UAAU,EAAe;IACnE,MAAM,YAAY,GAAG,MAAM,IAAA,yCAAwB,EAAC,aAAa,CAAC,CAAC;IACnE,IAAI,EAAE,WAAW,GAAG,EAAE,EAAE,WAAW,GAAG,EAAiB,EAAE,GAAG,EAAE,CAAC;IAE/D,IAAI,YAAY,EAAE,CAAC;QACjB,CAAC,EAAE,WAAW,GAAG,EAAE,EAAE,WAAW,GAAG,EAAE,EAAE,GAAG,YAAY,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,YAAY,GAAG,UAAU,EAAE,SAAS,IAAI,eAAe,CAAC;IAE5D,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,YAAY,GAAG,GAAG,GAAG,YAAY,CAAC;IACrE,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,YAAY,GAAG,YAAY,GAAG,GAAG,CAAC;IAEnE,MAAM,CAAC,GAAG,CACR,YAAY,EACZ,sBAAW,CAAC,2BAA2B,CACrC,MAAM,EACN,WAAW,CAAC,qBAAqB,CAClC,EACD,sBAAW,CAAC,mBAAmB,CAC7B,MAAM,EACN,aAAa,EACb,WAAW,CAAC,aAAa,CAC1B,EACD,iBAAO,CAAC,MAAM,CACZ,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,aAAa,IAAI,SAAS,CAAC,EACnE,IAAA,0BAAS,EACP;QACE,MAAM,EAAE,IAAI;QACZ,IAAI,EAAE,IAAI;QACV,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,QAAQ;QAClB,WAAW,EAAE,IAAI;QACjB,KAAK,EAAE,KAAK;QACZ,YAAY,EAAE,IAAI;KACnB,EACD,UAAU,EAAE,oBAAoB,IAAI,EAAE,CACvC,CACF,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,GAAG,YAAY,WAAW,EAC1B,sBAAW,CAAC,2BAA2B,CACrC,QAAQ,EACR,WAAW,CAAC,qBAAqB,CAClC,EACD,sBAAW,CAAC,mBAAmB,CAC7B,QAAQ,EACR,aAAa,EACb,WAAW,CAAC,aAAa,CAC1B,EACD,gCAAoB,CAAC,UAAU,CAChC,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,GAAG,YAAY,qBAAqB,EACpC,sBAAW,CAAC,2BAA2B,CACrC,QAAQ,EACR,WAAW,CAAC,qBAAqB,CAClC,EACD,sBAAW,CAAC,mBAAmB,CAC7B,QAAQ,EACR,aAAa,EACb,WAAW,CAAC,aAAa,CAC1B,EACD,gCAAoB,CAAC,UAAU,CAChC,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,GAAG,YAAY,qBAAqB,EACpC,sBAAW,CAAC,2BAA2B,CACrC,QAAQ,EACR,WAAW,CAAC,qBAAqB,CAClC,EACD,sBAAW,CAAC,mBAAmB,CAC7B,QAAQ,EACR,aAAa,EACb,WAAW,CAAC,aAAa,CAC1B,EACD,gCAAoB,CAAC,UAAU,CAChC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import { Router } from \"express\";\nimport { importPrismaModelModules } from \"../../utils/helpers/models.helpers\";\nimport authService from \"../auth/auth.service\";\nimport fileUploadController from \"./file-upload.controller\";\nimport { ArkosConfig } from \"../../types/arkos-config\";\nimport path from \"path\";\nimport express from \"express\";\nimport deepmerge from \"../../utils/helpers/deepmerge.helper\";\nimport { AuthConfigs } from \"../../types/auth\";\n\nconst router: Router = Router();\n\nexport async function getFileUploadRouter({ fileUpload }: ArkosConfig) {\n const modelModules = await importPrismaModelModules(\"file-upload\");\n let { middlewares = {}, authConfigs = {} as AuthConfigs } = {};\n\n if (modelModules) {\n ({ middlewares = {}, authConfigs = {} } = modelModules);\n }\n\n let basePathname = fileUpload?.baseRoute || \"/api/uploads/\";\n\n if (!basePathname.startsWith(\"/\")) basePathname = \"/\" + basePathname;\n if (!basePathname.endsWith(\"/\")) basePathname = basePathname + \"/\";\n\n router.use(\n basePathname,\n authService.handleAuthenticationControl(\n \"View\",\n authConfigs.authenticationControl\n ),\n authService.handleAccessControl(\n \"View\",\n \"file-upload\",\n authConfigs.accessControl\n ),\n express.static(\n path.resolve(process.cwd(), fileUpload?.baseUploadDir || \"uploads\"),\n deepmerge(\n {\n maxAge: \"1y\",\n etag: true,\n lastModified: true,\n dotfiles: \"ignore\",\n fallthrough: true,\n index: false,\n cacheControl: true,\n },\n fileUpload?.expressStaticOptions || {}\n )\n )\n );\n\n router.post(\n `${basePathname}:fileType`,\n authService.handleAuthenticationControl(\n \"Create\",\n authConfigs.authenticationControl\n ),\n authService.handleAccessControl(\n \"Create\",\n \"file-upload\",\n authConfigs.accessControl\n ),\n fileUploadController.uploadFile\n );\n\n router.delete(\n `${basePathname}:fileType/:fileName`,\n authService.handleAuthenticationControl(\n \"Delete\",\n authConfigs.authenticationControl\n ),\n authService.handleAccessControl(\n \"Delete\",\n \"file-upload\",\n authConfigs.accessControl\n ),\n fileUploadController.deleteFile\n );\n\n router.delete(\n `${basePathname}:fileType/:fileName`,\n authService.handleAuthenticationControl(\n \"Update\",\n authConfigs.authenticationControl\n ),\n authService.handleAccessControl(\n \"Update\",\n \"file-upload\",\n authConfigs.accessControl\n ),\n fileUploadController.updateFile\n );\n\n return router;\n}\n"]}
|