@autofleet/sadot 1.5.2-beta-2cd7f45c.0 → 1.5.2
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/api/v1/validator/index.cjs +1 -1
- package/dist/api/v1/validator/index.cjs.map +1 -1
- package/dist/api/v1/validator/index.js +1 -1
- package/dist/api/v1/validator/index.js.map +1 -1
- package/dist/scopes/helpers/filter.helpers.cjs +5 -3
- package/dist/scopes/helpers/filter.helpers.cjs.map +1 -1
- package/dist/scopes/helpers/filter.helpers.js +5 -3
- package/dist/scopes/helpers/filter.helpers.js.map +1 -1
- package/package.json +4 -4
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const e=require(`../../../_virtual/rolldown_runtime.cjs`),t=require(`../../../utils/logger/index.cjs`),n=require(`../errors.cjs`),r=require(`../../../repository/validator.cjs`),
|
|
1
|
+
const e=require(`../../../_virtual/rolldown_runtime.cjs`),t=require(`../../../utils/logger/index.cjs`),n=require(`../errors.cjs`),r=require(`../../../mat-path-state.cjs`),i=require(`../../../repository/validator.cjs`),a=require(`./validations.cjs`),o=require(`../../../utils/validations/schema/validator-schema.cjs`);let s=require(`@autofleet/errors`),c=require(`@autofleet/node-common`),l=require(`http-status-codes`);const u=(0,c.Router)({logger:t.default}),d=`CustomValidator`;u.post(`/`,async(e,r)=>{let{modelName:s}=e.params;try{let t=await a.default.create.validateAsync(e.body);o.validateValidatorSchema(t.schema);let n=await i.create({...t,modelType:s});return r.status(l.StatusCodes.CREATED).json(n)}catch(e){return n.default(e,r,{logger:t.default,message:`Error in create ${d} request`})}}),u.get(`/`,async(e,a)=>{try{let{modelName:t}=e.params,{entityId:n,entityType:o}=e.query,s=!r.matPathState.isMatPathEnabled?.(),c={modelType:t,...s&&n&&{entityId:n},...s&&o&&{entityType:o}},u=await i.findAll(c);return a.status(l.StatusCodes.OK).json({validators:u})}catch(e){return n.default(e,a,{logger:t.default,message:`Error in get all ${d} request`})}}),u.get(`/:validatorId`,async(e,r)=>{try{let{validatorId:t,modelName:n}=e.params,a=await i.findAll({id:t,modelType:n},{withDisabled:!0});if(!a.length)throw new s.ResourceNotFoundError(`Validator not found`);return r.status(l.StatusCodes.OK).json(a[0])}catch(e){return n.default(e,r,{logger:t.default,message:`Error in get ${d} request`})}}),u.patch(`/:validatorId`,async(e,r)=>{try{let{validatorId:t}=e.params,n=await a.default.update.validateAsync(e.body);if(n.schema&&o.validateValidatorSchema(n.schema),!(await i.findAll({id:t},{withDisabled:!0})).length)throw new s.ResourceNotFoundError(`Validator not found`);let[c,u]=await i.update(t,n);if(!c)throw new s.ResourceNotFoundError(`Validator not found`);return r.status(l.StatusCodes.OK).json(u[0])}catch(e){return n.default(e,r,{logger:t.default,message:`Error in update ${d} request`})}}),u.delete(`/:validatorId`,async(e,r)=>{try{let{validatorId:t}=e.params;if(!(await i.findAll({id:t},{withDisabled:!0})).length)throw new s.ResourceNotFoundError(`Validator not found`);let[n]=await i.disable(t);if(!n)throw new s.ResourceNotFoundError(`Validator failed to be disabled`);return r.status(l.StatusCodes.NO_CONTENT).send()}catch(e){return n.default(e,r,{logger:t.default,message:`Error in delete ${d} request`})}});var f=u;exports.default=f;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["router: ReturnType<typeof Router>","validations","StatusCodes","handleError","ResourceNotFoundError"],"sources":["../../../../src/api/v1/validator/index.ts"],"sourcesContent":["import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport { StatusCodes } from 'http-status-codes';\nimport handleError from '../errors';\nimport * as ValidatorRepo from '../../../repository/validator';\nimport validations from './validations';\nimport logger from '../../../utils/logger';\nimport { validateValidatorSchema } from '../../../utils/validations/schema/validator-schema';\nimport type { CustomValidator } from '../../../models';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomValidator';\n\n/**\n * Create\n */\nrouter.post<{ modelName: string; }>('/', async (req, res) => {\n const { modelName } = req.params;\n try {\n // Validate the request body\n const validatedPayload = await validations.create.validateAsync(req.body);\n\n // Validate that the schema is a valid AJV schema\n validateValidatorSchema(validatedPayload.schema);\n\n const validator = await ValidatorRepo.create({\n ...validatedPayload,\n modelType: modelName,\n });\n\n return res.status(StatusCodes.CREATED).json(validator);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<\n { modelName: string; },\n { validators: CustomValidator[]; },\n never,\n { entityId?: string; entityType?: string; }\n>('/', async (req, res) => {\n try {\n const { modelName } = req.params;\n const { entityId, entityType } = req.query;\n\n const where = {\n modelType: modelName,\n ...(entityId && { entityId }),\n ...(entityType && { entityType }),\n };\n\n const validators = await ValidatorRepo.findAll(where);\n\n return res.status(StatusCodes.OK).json({ validators });\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId, modelName } = req.params;\n // Include disabled validators when fetching by ID\n const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });\n\n if (!validators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // Validate the request body\n const validatedPayload = await validations.update.validateAsync(req.body);\n\n // If schema is included in the update, validate that it's a valid AJV schema\n if (validatedPayload.schema) {\n validateValidatorSchema(validatedPayload.schema);\n }\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload as any);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\n/**\n * Delete (disable)\n */\nrouter.delete<{ modelName: string; validatorId: string; }>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count] = await ValidatorRepo.disable(validatorId);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator failed to be disabled');\n }\n\n return res.status(StatusCodes.NO_CONTENT).send();\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in delete ${ENTITY} request` });\n }\n});\n\nexport default router;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["router: ReturnType<typeof Router>","validations","StatusCodes","handleError","matPathState","ResourceNotFoundError"],"sources":["../../../../src/api/v1/validator/index.ts"],"sourcesContent":["import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport { StatusCodes } from 'http-status-codes';\nimport handleError from '../errors';\nimport * as ValidatorRepo from '../../../repository/validator';\nimport validations from './validations';\nimport logger from '../../../utils/logger';\nimport { validateValidatorSchema } from '../../../utils/validations/schema/validator-schema';\nimport type { CustomValidator } from '../../../models';\nimport { matPathState } from '../../../mat-path-state';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomValidator';\n\n/**\n * Create\n */\nrouter.post<{ modelName: string; }>('/', async (req, res) => {\n const { modelName } = req.params;\n try {\n // Validate the request body\n const validatedPayload = await validations.create.validateAsync(req.body);\n\n // Validate that the schema is a valid AJV schema\n validateValidatorSchema(validatedPayload.schema);\n\n const validator = await ValidatorRepo.create({\n ...validatedPayload,\n modelType: modelName,\n });\n\n return res.status(StatusCodes.CREATED).json(validator);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<\n { modelName: string; },\n { validators: CustomValidator[]; },\n never,\n { entityId?: string; entityType?: string; }\n>('/', async (req, res) => {\n try {\n const { modelName } = req.params;\n const { entityId, entityType } = req.query;\n\n // When mat-path is active, drop the explicit `entityId`/`entityType` WHERE filters — RLS\n // on `custom_validators` restricts the result to the caller's visible scope (fleet +\n // ancestor partners). Keeping the filters would exclude partner-level validators whose\n // entityId differs from the requested fleet's entityId.\n const applyEntityFilters = !matPathState.isMatPathEnabled?.();\n\n const where = {\n modelType: modelName,\n ...(applyEntityFilters && entityId && { entityId }),\n ...(applyEntityFilters && entityType && { entityType }),\n };\n\n const validators = await ValidatorRepo.findAll(where);\n\n return res.status(StatusCodes.OK).json({ validators });\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId, modelName } = req.params;\n // Include disabled validators when fetching by ID\n const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });\n\n if (!validators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // Validate the request body\n const validatedPayload = await validations.update.validateAsync(req.body);\n\n // If schema is included in the update, validate that it's a valid AJV schema\n if (validatedPayload.schema) {\n validateValidatorSchema(validatedPayload.schema);\n }\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload as any);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\n/**\n * Delete (disable)\n */\nrouter.delete<{ modelName: string; validatorId: string; }>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count] = await ValidatorRepo.disable(validatorId);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator failed to be disabled');\n }\n\n return res.status(StatusCodes.NO_CONTENT).send();\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in delete ${ENTITY} request` });\n }\n});\n\nexport default router;\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import e from"../../../utils/logger/index.js";import t from"../errors.js";import{create as
|
|
1
|
+
import e from"../../../utils/logger/index.js";import t from"../errors.js";import{matPathState as n}from"../../../mat-path-state.js";import{create as r,disable as i,findAll as a,update as o}from"../../../repository/validator.js";import s from"./validations.js";import{validateValidatorSchema as c}from"../../../utils/validations/schema/validator-schema.js";import{ResourceNotFoundError as l}from"@autofleet/errors";import{Router as u}from"@autofleet/node-common";import{StatusCodes as d}from"http-status-codes";const f=u({logger:e}),p=`CustomValidator`;f.post(`/`,async(n,i)=>{let{modelName:a}=n.params;try{let e=await s.create.validateAsync(n.body);c(e.schema);let t=await r({...e,modelType:a});return i.status(d.CREATED).json(t)}catch(n){return t(n,i,{logger:e,message:`Error in create ${p} request`})}}),f.get(`/`,async(r,i)=>{try{let{modelName:e}=r.params,{entityId:t,entityType:o}=r.query,s=!n.isMatPathEnabled?.(),c=await a({modelType:e,...s&&t&&{entityId:t},...s&&o&&{entityType:o}});return i.status(d.OK).json({validators:c})}catch(n){return t(n,i,{logger:e,message:`Error in get all ${p} request`})}}),f.get(`/:validatorId`,async(n,r)=>{try{let{validatorId:e,modelName:t}=n.params,i=await a({id:e,modelType:t},{withDisabled:!0});if(!i.length)throw new l(`Validator not found`);return r.status(d.OK).json(i[0])}catch(n){return t(n,r,{logger:e,message:`Error in get ${p} request`})}}),f.patch(`/:validatorId`,async(n,r)=>{try{let{validatorId:e}=n.params,t=await s.update.validateAsync(n.body);if(t.schema&&c(t.schema),!(await a({id:e},{withDisabled:!0})).length)throw new l(`Validator not found`);let[i,u]=await o(e,t);if(!i)throw new l(`Validator not found`);return r.status(d.OK).json(u[0])}catch(n){return t(n,r,{logger:e,message:`Error in update ${p} request`})}}),f.delete(`/:validatorId`,async(n,r)=>{try{let{validatorId:e}=n.params;if(!(await a({id:e},{withDisabled:!0})).length)throw new l(`Validator not found`);let[t]=await i(e);if(!t)throw new l(`Validator failed to be disabled`);return r.status(d.NO_CONTENT).send()}catch(n){return t(n,r,{logger:e,message:`Error in delete ${p} request`})}});var m=f;export{m as default};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["router: ReturnType<typeof Router>","validations","ValidatorRepo.create","handleError","ValidatorRepo.findAll","ValidatorRepo.update","ValidatorRepo.disable"],"sources":["../../../../src/api/v1/validator/index.ts"],"sourcesContent":["import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport { StatusCodes } from 'http-status-codes';\nimport handleError from '../errors';\nimport * as ValidatorRepo from '../../../repository/validator';\nimport validations from './validations';\nimport logger from '../../../utils/logger';\nimport { validateValidatorSchema } from '../../../utils/validations/schema/validator-schema';\nimport type { CustomValidator } from '../../../models';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomValidator';\n\n/**\n * Create\n */\nrouter.post<{ modelName: string; }>('/', async (req, res) => {\n const { modelName } = req.params;\n try {\n // Validate the request body\n const validatedPayload = await validations.create.validateAsync(req.body);\n\n // Validate that the schema is a valid AJV schema\n validateValidatorSchema(validatedPayload.schema);\n\n const validator = await ValidatorRepo.create({\n ...validatedPayload,\n modelType: modelName,\n });\n\n return res.status(StatusCodes.CREATED).json(validator);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<\n { modelName: string; },\n { validators: CustomValidator[]; },\n never,\n { entityId?: string; entityType?: string; }\n>('/', async (req, res) => {\n try {\n const { modelName } = req.params;\n const { entityId, entityType } = req.query;\n\n const where = {\n modelType: modelName,\n ...(entityId && { entityId }),\n ...(entityType && { entityType }),\n };\n\n const validators = await ValidatorRepo.findAll(where);\n\n return res.status(StatusCodes.OK).json({ validators });\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId, modelName } = req.params;\n // Include disabled validators when fetching by ID\n const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });\n\n if (!validators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // Validate the request body\n const validatedPayload = await validations.update.validateAsync(req.body);\n\n // If schema is included in the update, validate that it's a valid AJV schema\n if (validatedPayload.schema) {\n validateValidatorSchema(validatedPayload.schema);\n }\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload as any);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\n/**\n * Delete (disable)\n */\nrouter.delete<{ modelName: string; validatorId: string; }>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count] = await ValidatorRepo.disable(validatorId);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator failed to be disabled');\n }\n\n return res.status(StatusCodes.NO_CONTENT).send();\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in delete ${ENTITY} request` });\n }\n});\n\nexport default router;\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":["router: ReturnType<typeof Router>","validations","ValidatorRepo.create","handleError","ValidatorRepo.findAll","ValidatorRepo.update","ValidatorRepo.disable"],"sources":["../../../../src/api/v1/validator/index.ts"],"sourcesContent":["import { ResourceNotFoundError } from '@autofleet/errors';\nimport { Router } from '@autofleet/node-common';\nimport { StatusCodes } from 'http-status-codes';\nimport handleError from '../errors';\nimport * as ValidatorRepo from '../../../repository/validator';\nimport validations from './validations';\nimport logger from '../../../utils/logger';\nimport { validateValidatorSchema } from '../../../utils/validations/schema/validator-schema';\nimport type { CustomValidator } from '../../../models';\nimport { matPathState } from '../../../mat-path-state';\n\nconst router: ReturnType<typeof Router> = Router({ logger });\nconst ENTITY = 'CustomValidator';\n\n/**\n * Create\n */\nrouter.post<{ modelName: string; }>('/', async (req, res) => {\n const { modelName } = req.params;\n try {\n // Validate the request body\n const validatedPayload = await validations.create.validateAsync(req.body);\n\n // Validate that the schema is a valid AJV schema\n validateValidatorSchema(validatedPayload.schema);\n\n const validator = await ValidatorRepo.create({\n ...validatedPayload,\n modelType: modelName,\n });\n\n return res.status(StatusCodes.CREATED).json(validator);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in create ${ENTITY} request` });\n }\n});\n\n/**\n * Get all\n */\nrouter.get<\n { modelName: string; },\n { validators: CustomValidator[]; },\n never,\n { entityId?: string; entityType?: string; }\n>('/', async (req, res) => {\n try {\n const { modelName } = req.params;\n const { entityId, entityType } = req.query;\n\n // When mat-path is active, drop the explicit `entityId`/`entityType` WHERE filters — RLS\n // on `custom_validators` restricts the result to the caller's visible scope (fleet +\n // ancestor partners). Keeping the filters would exclude partner-level validators whose\n // entityId differs from the requested fleet's entityId.\n const applyEntityFilters = !matPathState.isMatPathEnabled?.();\n\n const where = {\n modelType: modelName,\n ...(applyEntityFilters && entityId && { entityId }),\n ...(applyEntityFilters && entityType && { entityType }),\n };\n\n const validators = await ValidatorRepo.findAll(where);\n\n return res.status(StatusCodes.OK).json({ validators });\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get all ${ENTITY} request` });\n }\n});\n\n/**\n * Get by id\n */\nrouter.get<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId, modelName } = req.params;\n // Include disabled validators when fetching by ID\n const validators = await ValidatorRepo.findAll({ id: validatorId, modelType: modelName }, { withDisabled: true });\n\n if (!validators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in get ${ENTITY} request` });\n }\n});\n\n/**\n * Update\n */\nrouter.patch<{ modelName: string; validatorId: string; }, CustomValidator>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // Validate the request body\n const validatedPayload = await validations.update.validateAsync(req.body);\n\n // If schema is included in the update, validate that it's a valid AJV schema\n if (validatedPayload.schema) {\n validateValidatorSchema(validatedPayload.schema);\n }\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count, validators] = await ValidatorRepo.update(validatorId, validatedPayload as any);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n return res.status(StatusCodes.OK).json(validators[0]);\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in update ${ENTITY} request` });\n }\n});\n\n/**\n * Delete (disable)\n */\nrouter.delete<{ modelName: string; validatorId: string; }>('/:validatorId', async (req, res) => {\n try {\n const { validatorId } = req.params;\n\n // First verify the validator exists, including disabled ones\n const existingValidators = await ValidatorRepo.findAll({ id: validatorId }, { withDisabled: true });\n if (!existingValidators.length) {\n throw new ResourceNotFoundError('Validator not found');\n }\n\n const [count] = await ValidatorRepo.disable(validatorId);\n\n if (!count) {\n throw new ResourceNotFoundError('Validator failed to be disabled');\n }\n\n return res.status(StatusCodes.NO_CONTENT).send();\n } catch (err) {\n return handleError(err as Error, res, { logger, message: `Error in delete ${ENTITY} request` });\n }\n});\n\nexport default router;\n"],"mappings":"8fAWA,MAAMA,EAAoC,EAAO,CAAE,OAAA,EAAQ,CAAC,CACtD,EAAS,kBAKf,EAAO,KAA6B,IAAK,MAAO,EAAK,IAAQ,CAC3D,GAAM,CAAE,aAAc,EAAI,OAC1B,GAAI,CAEF,IAAM,EAAmB,MAAMC,EAAY,OAAO,cAAc,EAAI,KAAK,CAGzE,EAAwB,EAAiB,OAAO,CAEhD,IAAM,EAAY,MAAMC,EAAqB,CAC3C,GAAG,EACH,UAAW,EACZ,CAAC,CAEF,OAAO,EAAI,OAAO,EAAY,QAAQ,CAAC,KAAK,EAAU,OAC/C,EAAK,CACZ,OAAOC,EAAY,EAAc,EAAK,CAAE,OAAA,EAAQ,QAAS,mBAAmB,EAAO,UAAW,CAAC,GAEjG,CAKF,EAAO,IAKL,IAAK,MAAO,EAAK,IAAQ,CACzB,GAAI,CACF,GAAM,CAAE,aAAc,EAAI,OACpB,CAAE,WAAU,cAAe,EAAI,MAM/B,EAAqB,CAAC,EAAa,oBAAoB,CAQvD,EAAa,MAAMC,EANX,CACZ,UAAW,EACX,GAAI,GAAsB,GAAY,CAAE,WAAU,CAClD,GAAI,GAAsB,GAAc,CAAE,aAAY,CACvD,CAEoD,CAErD,OAAO,EAAI,OAAO,EAAY,GAAG,CAAC,KAAK,CAAE,aAAY,CAAC,OAC/C,EAAK,CACZ,OAAOD,EAAY,EAAc,EAAK,CAAE,OAAA,EAAQ,QAAS,oBAAoB,EAAO,UAAW,CAAC,GAElG,CAKF,EAAO,IAAkE,gBAAiB,MAAO,EAAK,IAAQ,CAC5G,GAAI,CACF,GAAM,CAAE,cAAa,aAAc,EAAI,OAEjC,EAAa,MAAMC,EAAsB,CAAE,GAAI,EAAa,UAAW,EAAW,CAAE,CAAE,aAAc,GAAM,CAAC,CAEjH,GAAI,CAAC,EAAW,OACd,MAAM,IAAI,EAAsB,sBAAsB,CAGxD,OAAO,EAAI,OAAO,EAAY,GAAG,CAAC,KAAK,EAAW,GAAG,OAC9C,EAAK,CACZ,OAAOD,EAAY,EAAc,EAAK,CAAE,OAAA,EAAQ,QAAS,gBAAgB,EAAO,UAAW,CAAC,GAE9F,CAKF,EAAO,MAAoE,gBAAiB,MAAO,EAAK,IAAQ,CAC9G,GAAI,CACF,GAAM,CAAE,eAAgB,EAAI,OAGtB,EAAmB,MAAMF,EAAY,OAAO,cAAc,EAAI,KAAK,CASzE,GANI,EAAiB,QACnB,EAAwB,EAAiB,OAAO,CAK9C,EADuB,MAAMG,EAAsB,CAAE,GAAI,EAAa,CAAE,CAAE,aAAc,GAAM,CAAC,EAC3E,OACtB,MAAM,IAAI,EAAsB,sBAAsB,CAGxD,GAAM,CAAC,EAAO,GAAc,MAAMC,EAAqB,EAAa,EAAwB,CAE5F,GAAI,CAAC,EACH,MAAM,IAAI,EAAsB,sBAAsB,CAGxD,OAAO,EAAI,OAAO,EAAY,GAAG,CAAC,KAAK,EAAW,GAAG,OAC9C,EAAK,CACZ,OAAOF,EAAY,EAAc,EAAK,CAAE,OAAA,EAAQ,QAAS,mBAAmB,EAAO,UAAW,CAAC,GAEjG,CAKF,EAAO,OAAoD,gBAAiB,MAAO,EAAK,IAAQ,CAC9F,GAAI,CACF,GAAM,CAAE,eAAgB,EAAI,OAI5B,GAAI,EADuB,MAAMC,EAAsB,CAAE,GAAI,EAAa,CAAE,CAAE,aAAc,GAAM,CAAC,EAC3E,OACtB,MAAM,IAAI,EAAsB,sBAAsB,CAGxD,GAAM,CAAC,GAAS,MAAME,EAAsB,EAAY,CAExD,GAAI,CAAC,EACH,MAAM,IAAI,EAAsB,kCAAkC,CAGpE,OAAO,EAAI,OAAO,EAAY,WAAW,CAAC,MAAM,OACzC,EAAK,CACZ,OAAOH,EAAY,EAAc,EAAK,CAAE,OAAA,EAAQ,QAAS,mBAAmB,EAAO,UAAW,CAAC,GAEjG,CAEF,IAAA,EAAe"}
|
|
@@ -3,14 +3,16 @@ let e=function(e){return e.VALUES=`values`,e.ENTRIES=`entries`,e}({});const t=e=
|
|
|
3
3
|
${a?`${a} OR`:``}
|
|
4
4
|
ce.custom_fields @> '${i}'
|
|
5
5
|
)
|
|
6
|
-
`},y=(t,n,r)=>{switch(t){case e.VALUES:return
|
|
6
|
+
`},y=(t,n,r)=>{switch(t){case e.VALUES:return`
|
|
7
7
|
SELECT cv.model_id
|
|
8
8
|
FROM custom_field_values AS cv
|
|
9
9
|
INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
|
|
10
10
|
${l}cd.model_type = '${n}'
|
|
11
|
-
WHERE ${
|
|
11
|
+
WHERE ${r.join(u)}
|
|
12
12
|
${l}cv.deleted_at IS NULL${l}cd.deleted_at IS NULL
|
|
13
|
-
|
|
13
|
+
GROUP BY cv.model_id
|
|
14
|
+
HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${r.length}
|
|
15
|
+
`.replace(/\n/g,``);case e.ENTRIES:return`
|
|
14
16
|
SELECT ce.model_id
|
|
15
17
|
FROM custom_field_entries ce
|
|
16
18
|
JOIN custom_field_definitions cfd
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.helpers.cjs","names":["CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name`","CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value`","formattedValue: string | number | boolean"],"sources":["../../../src/scopes/helpers/filter.helpers.ts"],"sourcesContent":["import type { WhereOptions } from 'sequelize';\n\n/**\n * Type representing possible condition values.\n * Currently supporting strings and arrays of strings.\n * More types to be added (TBA).\n */\nexport interface ConditionWithOperator {\n operator: string;\n value: string;\n}\nexport type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];\n\nexport interface CustomFieldSort {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport interface CustomFieldFilterOptions {\n where?: WhereOptions;\n replacements?: Record<string, string>;\n}\n\nexport enum SubQueryType {\n VALUES = 'values',\n ENTRIES = 'entries',\n}\n\nexport const isConditionStringArray = (input: any): input is string[] => Array.isArray(input) && typeof input[0] === 'string';\nexport const isBooleanString = (input: string): boolean => ['true', 'false'].includes(input.toString());\nexport const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n\nexport const castValueToJsonb = (value: string, type: string) => `to_jsonb(${value}::${type})`;\nexport const castValueToJsonbText = (value: string): string => castValueToJsonb(value, 'text');\nexport const castValueToJsonbBoolean = (value: string): string => castValueToJsonb(value, 'boolean');\nexport const castValueToJsonbNumeric = (value: string): string => castValueToJsonb(value, 'numeric');\nexport const castIfNeeded = (columnName: string, conditionValue: string): string => {\n if (isDate(conditionValue)) {\n return castValueToJsonb(columnName, 'timestamp');\n }\n return columnName;\n};\n\nexport const AND_DELIMITER = ' AND ';\nexport const OR_DELIMITER = ' OR ';\nexport const CD_TABLE_ALIAS = 'cd';\nexport const CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name` = `${CD_TABLE_ALIAS}.name`;\nexport const CV_TABLE_ALIAS = 'cv';\nexport const CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value` = `${CV_TABLE_ALIAS}.value`;\nexport const CE_TABLE_ALIAS = 'ce';\n\nconst getSingleConditionWithOperator = (value: any, operator: string, replacementKey: string, reverseReplacementsMap: Map<string, string>) => {\n let type = 'text';\n if (isDate(value)) {\n type = 'date';\n } else if (!Number.isNaN(Number(value))) {\n type = 'numeric';\n } else if (isBooleanString(value)) {\n type = 'boolean';\n }\n const replacedValue = reverseReplacementsMap.get(value);\n\n return `(jsonb_extract_path_text(${CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;\n};\n\nconst getFormattedValue = (value: string) => {\n let formattedValue: string | number | boolean = value;\n if (isBooleanString(value)) {\n formattedValue = value === 'true';\n } else if (!Number.isNaN(Number(value))) {\n formattedValue = Number(value);\n }\n\n return formattedValue;\n};\n\nconst getJSONSubQuery = (value: string, key: string) => {\n const formattedValue = getFormattedValue(value);\n const jsonQuery = JSON.stringify({ [key]: formattedValue });\n let jsonQueryWithStringBoolean;\n if (isBooleanString(value)) {\n jsonQueryWithStringBoolean = `${CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;\n }\n return `\n (\n ${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}\n ${CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'\n )\n `;\n};\n\nexport const getFilterCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, conditionsStrings: (string | boolean)[]): string => {\n switch (queryType) {\n case SubQueryType.VALUES: {\n // INTERSECT of one SELECT per condition gives the same semantics as\n // `WHERE c1 OR c2 ... GROUP BY model_id HAVING COUNT(DISTINCT def_id) = N`\n // but lets the planner pick an index-driven plan per branch instead of\n // a single sequential scan of custom_field_values.\n const branches = conditionsStrings.map((condition) => `\n SELECT ${CV_TABLE_ALIAS}.model_id\n FROM custom_field_values AS ${CV_TABLE_ALIAS}\n INNER JOIN custom_field_definitions AS ${CD_TABLE_ALIAS} ON ${CV_TABLE_ALIAS}.custom_field_definition_id = ${CD_TABLE_ALIAS}.id\n ${AND_DELIMITER}${CD_TABLE_ALIAS}.model_type = '${modelType}'\n WHERE ${condition}\n ${AND_DELIMITER}${CV_TABLE_ALIAS}.deleted_at IS NULL${AND_DELIMITER}${CD_TABLE_ALIAS}.deleted_at IS NULL\n `);\n return branches.join(' INTERSECT ').replace(/\\n/g, '');\n }\n case SubQueryType.ENTRIES:\n return `\n SELECT ce.model_id\n FROM custom_field_entries ce\n JOIN custom_field_definitions cfd\n ON ce.model_type = cfd.model_type\n AND ce.entity_id = cfd.entity_id\n WHERE\n cfd.deleted_at IS NULL AND\n ${conditionsStrings.join(AND_DELIMITER)}\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, replacementKey: string): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `(\n SELECT value\n FROM (SELECT cv.model_id, cv.value\n FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd\n ON cv.custom_field_definition_id = cd.id\n ${AND_DELIMITER}cd.model_type = '${modelType}'\n WHERE cv.model_id = \"${modelType}\".\"id\"\n ${AND_DELIMITER}cd.name = :${replacementKey}\n ) AS CustomFieldAggregation\n )\n `;\n case SubQueryType.ENTRIES:\n return `(\n SELECT\n customFields.value\n FROM\n custom_field_entries AS ${CE_TABLE_ALIAS},\n jsonb_each_text(custom_fields) AS customFields\n WHERE\n customFields.key = :${replacementKey}${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_id = \"${modelType}\".\"id\"\n )\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const formatConditionsForValues = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n const columnCondition = `(${CD_NAME_COLUMN} = :${replacementKey})`;\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.flatMap((v) => {\n const valRandom = reverseReplacementsMap.get(v);\n if (isBooleanString(v)) {\n return [castValueToJsonbText(`:${valRandom}`), castValueToJsonbBoolean(`:${valRandom}`)];\n }\n if (!Number.isNaN(Number(v))) {\n return castValueToJsonbNumeric(`:${valRandom}`);\n }\n return castValueToJsonbText(`:${valRandom}`);\n }).join(',');\n return `(${columnCondition}${AND_DELIMITER}${CV_VALUE_COLUMN} IN (${values}))`;\n }\n return condition.map((c) => {\n const valRep = reverseReplacementsMap.get(c.value);\n const valueAsJsonb = castValueToJsonbText(`:${valRep}`);\n\n return `(${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;\n }).join(AND_DELIMITER);\n }\n if (typeof condition === 'string' || typeof condition === 'number') {\n const conditionRep = reverseReplacementsMap.get(condition);\n const valueAsJsonb = !Number.isNaN(Number(condition)) ? castValueToJsonbNumeric(`:${conditionRep}`) : castValueToJsonbText(`:${conditionRep}`);\n const valueAsJsonbBoolean = isBooleanString(condition) ? `${OR_DELIMITER}${CV_VALUE_COLUMN} = ${castValueToJsonbBoolean(`:${conditionRep}`)}` : '';\n return `(${columnCondition}${AND_DELIMITER}(${castIfNeeded(CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;\n }\n if (condition?.operator) {\n const valueRep = reverseReplacementsMap.get(condition.value);\n const valueAsJsonb = castValueToJsonbText(`:${valueRep}`);\n return `( ${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;\n }\n return false;\n};\n\nexport const formatConditionsForEntries = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.map(value => getJSONSubQuery(value, key)).join(`${OR_DELIMITER}\\n`);\n return `( ${values})`;\n }\n return condition.map(c => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(AND_DELIMITER);\n }\n\n if (typeof condition === 'string' || typeof condition === 'number') {\n return getJSONSubQuery(condition, key);\n }\n\n if (condition?.operator) {\n return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);\n }\n return false;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filter.helpers.cjs","names":["CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name`","CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value`","formattedValue: string | number | boolean"],"sources":["../../../src/scopes/helpers/filter.helpers.ts"],"sourcesContent":["import type { WhereOptions } from 'sequelize';\n\n/**\n * Type representing possible condition values.\n * Currently supporting strings and arrays of strings.\n * More types to be added (TBA).\n */\nexport interface ConditionWithOperator {\n operator: string;\n value: string;\n}\nexport type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];\n\nexport interface CustomFieldSort {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport interface CustomFieldFilterOptions {\n where?: WhereOptions;\n replacements?: Record<string, string>;\n}\n\nexport enum SubQueryType {\n VALUES = 'values',\n ENTRIES = 'entries',\n}\n\nexport const isConditionStringArray = (input: any): input is string[] => Array.isArray(input) && typeof input[0] === 'string';\nexport const isBooleanString = (input: string): boolean => ['true', 'false'].includes(input.toString());\nexport const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n\nexport const castValueToJsonb = (value: string, type: string) => `to_jsonb(${value}::${type})`;\nexport const castValueToJsonbText = (value: string): string => castValueToJsonb(value, 'text');\nexport const castValueToJsonbBoolean = (value: string): string => castValueToJsonb(value, 'boolean');\nexport const castValueToJsonbNumeric = (value: string): string => castValueToJsonb(value, 'numeric');\nexport const castIfNeeded = (columnName: string, conditionValue: string): string => {\n if (isDate(conditionValue)) {\n return castValueToJsonb(columnName, 'timestamp');\n }\n return columnName;\n};\n\nexport const AND_DELIMITER = ' AND ';\nexport const OR_DELIMITER = ' OR ';\nexport const CD_TABLE_ALIAS = 'cd';\nexport const CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name` = `${CD_TABLE_ALIAS}.name`;\nexport const CV_TABLE_ALIAS = 'cv';\nexport const CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value` = `${CV_TABLE_ALIAS}.value`;\nexport const CE_TABLE_ALIAS = 'ce';\n\nconst getSingleConditionWithOperator = (value: any, operator: string, replacementKey: string, reverseReplacementsMap: Map<string, string>) => {\n let type = 'text';\n if (isDate(value)) {\n type = 'date';\n } else if (!Number.isNaN(Number(value))) {\n type = 'numeric';\n } else if (isBooleanString(value)) {\n type = 'boolean';\n }\n const replacedValue = reverseReplacementsMap.get(value);\n\n return `(jsonb_extract_path_text(${CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;\n};\n\nconst getFormattedValue = (value: string) => {\n let formattedValue: string | number | boolean = value;\n if (isBooleanString(value)) {\n formattedValue = value === 'true';\n } else if (!Number.isNaN(Number(value))) {\n formattedValue = Number(value);\n }\n\n return formattedValue;\n};\n\nconst getJSONSubQuery = (value: string, key: string) => {\n const formattedValue = getFormattedValue(value);\n const jsonQuery = JSON.stringify({ [key]: formattedValue });\n let jsonQueryWithStringBoolean;\n if (isBooleanString(value)) {\n jsonQueryWithStringBoolean = `${CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;\n }\n return `\n (\n ${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}\n ${CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'\n )\n `;\n};\n\nexport const getFilterCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, conditionsStrings: (string | boolean)[]): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `\n SELECT ${CV_TABLE_ALIAS}.model_id\n FROM custom_field_values AS ${CV_TABLE_ALIAS}\n INNER JOIN custom_field_definitions AS ${CD_TABLE_ALIAS} ON ${CV_TABLE_ALIAS}.custom_field_definition_id = ${CD_TABLE_ALIAS}.id\n ${AND_DELIMITER}${CD_TABLE_ALIAS}.model_type = '${modelType}'\n WHERE ${conditionsStrings.join(OR_DELIMITER)}\n ${AND_DELIMITER}${CV_TABLE_ALIAS}.deleted_at IS NULL${AND_DELIMITER}${CD_TABLE_ALIAS}.deleted_at IS NULL\n GROUP BY ${CV_TABLE_ALIAS}.model_id\n HAVING COUNT(DISTINCT ${CV_TABLE_ALIAS}.custom_field_definition_id) = ${conditionsStrings.length}\n `.replace(/\\n/g, '');\n case SubQueryType.ENTRIES:\n return `\n SELECT ce.model_id\n FROM custom_field_entries ce\n JOIN custom_field_definitions cfd\n ON ce.model_type = cfd.model_type\n AND ce.entity_id = cfd.entity_id\n WHERE\n cfd.deleted_at IS NULL AND\n ${conditionsStrings.join(AND_DELIMITER)}\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, replacementKey: string): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `(\n SELECT value\n FROM (SELECT cv.model_id, cv.value\n FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd\n ON cv.custom_field_definition_id = cd.id\n ${AND_DELIMITER}cd.model_type = '${modelType}'\n WHERE cv.model_id = \"${modelType}\".\"id\"\n ${AND_DELIMITER}cd.name = :${replacementKey}\n ) AS CustomFieldAggregation\n )\n `;\n case SubQueryType.ENTRIES:\n return `(\n SELECT\n customFields.value\n FROM\n custom_field_entries AS ${CE_TABLE_ALIAS},\n jsonb_each_text(custom_fields) AS customFields\n WHERE\n customFields.key = :${replacementKey}${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_id = \"${modelType}\".\"id\"\n )\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const formatConditionsForValues = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n const columnCondition = `(${CD_NAME_COLUMN} = :${replacementKey})`;\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.flatMap((v) => {\n const valRandom = reverseReplacementsMap.get(v);\n if (isBooleanString(v)) {\n return [castValueToJsonbText(`:${valRandom}`), castValueToJsonbBoolean(`:${valRandom}`)];\n }\n if (!Number.isNaN(Number(v))) {\n return castValueToJsonbNumeric(`:${valRandom}`);\n }\n return castValueToJsonbText(`:${valRandom}`);\n }).join(',');\n return `(${columnCondition}${AND_DELIMITER}${CV_VALUE_COLUMN} IN (${values}))`;\n }\n return condition.map((c) => {\n const valRep = reverseReplacementsMap.get(c.value);\n const valueAsJsonb = castValueToJsonbText(`:${valRep}`);\n\n return `(${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;\n }).join(AND_DELIMITER);\n }\n if (typeof condition === 'string' || typeof condition === 'number') {\n const conditionRep = reverseReplacementsMap.get(condition);\n const valueAsJsonb = !Number.isNaN(Number(condition)) ? castValueToJsonbNumeric(`:${conditionRep}`) : castValueToJsonbText(`:${conditionRep}`);\n const valueAsJsonbBoolean = isBooleanString(condition) ? `${OR_DELIMITER}${CV_VALUE_COLUMN} = ${castValueToJsonbBoolean(`:${conditionRep}`)}` : '';\n return `(${columnCondition}${AND_DELIMITER}(${castIfNeeded(CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;\n }\n if (condition?.operator) {\n const valueRep = reverseReplacementsMap.get(condition.value);\n const valueAsJsonb = castValueToJsonbText(`:${valueRep}`);\n return `( ${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;\n }\n return false;\n};\n\nexport const formatConditionsForEntries = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.map(value => getJSONSubQuery(value, key)).join(`${OR_DELIMITER}\\n`);\n return `( ${values})`;\n }\n return condition.map(c => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(AND_DELIMITER);\n }\n\n if (typeof condition === 'string' || typeof condition === 'number') {\n return getJSONSubQuery(condition, key);\n }\n\n if (condition?.operator) {\n return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);\n }\n return false;\n};\n"],"mappings":"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"}
|
|
@@ -3,14 +3,16 @@ let e=function(e){return e.VALUES=`values`,e.ENTRIES=`entries`,e}({});const t=e=
|
|
|
3
3
|
${a?`${a} OR`:``}
|
|
4
4
|
ce.custom_fields @> '${i}'
|
|
5
5
|
)
|
|
6
|
-
`},h=(t,n,r)=>{switch(t){case e.VALUES:return
|
|
6
|
+
`},h=(t,n,r)=>{switch(t){case e.VALUES:return`
|
|
7
7
|
SELECT cv.model_id
|
|
8
8
|
FROM custom_field_values AS cv
|
|
9
9
|
INNER JOIN custom_field_definitions AS cd ON cv.custom_field_definition_id = cd.id
|
|
10
10
|
${l}cd.model_type = '${n}'
|
|
11
|
-
WHERE ${
|
|
11
|
+
WHERE ${r.join(u)}
|
|
12
12
|
${l}cv.deleted_at IS NULL${l}cd.deleted_at IS NULL
|
|
13
|
-
|
|
13
|
+
GROUP BY cv.model_id
|
|
14
|
+
HAVING COUNT(DISTINCT cv.custom_field_definition_id) = ${r.length}
|
|
15
|
+
`.replace(/\n/g,``);case e.ENTRIES:return`
|
|
14
16
|
SELECT ce.model_id
|
|
15
17
|
FROM custom_field_entries ce
|
|
16
18
|
JOIN custom_field_definitions cfd
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filter.helpers.js","names":["CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name`","CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value`","formattedValue: string | number | boolean"],"sources":["../../../src/scopes/helpers/filter.helpers.ts"],"sourcesContent":["import type { WhereOptions } from 'sequelize';\n\n/**\n * Type representing possible condition values.\n * Currently supporting strings and arrays of strings.\n * More types to be added (TBA).\n */\nexport interface ConditionWithOperator {\n operator: string;\n value: string;\n}\nexport type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];\n\nexport interface CustomFieldSort {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport interface CustomFieldFilterOptions {\n where?: WhereOptions;\n replacements?: Record<string, string>;\n}\n\nexport enum SubQueryType {\n VALUES = 'values',\n ENTRIES = 'entries',\n}\n\nexport const isConditionStringArray = (input: any): input is string[] => Array.isArray(input) && typeof input[0] === 'string';\nexport const isBooleanString = (input: string): boolean => ['true', 'false'].includes(input.toString());\nexport const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n\nexport const castValueToJsonb = (value: string, type: string) => `to_jsonb(${value}::${type})`;\nexport const castValueToJsonbText = (value: string): string => castValueToJsonb(value, 'text');\nexport const castValueToJsonbBoolean = (value: string): string => castValueToJsonb(value, 'boolean');\nexport const castValueToJsonbNumeric = (value: string): string => castValueToJsonb(value, 'numeric');\nexport const castIfNeeded = (columnName: string, conditionValue: string): string => {\n if (isDate(conditionValue)) {\n return castValueToJsonb(columnName, 'timestamp');\n }\n return columnName;\n};\n\nexport const AND_DELIMITER = ' AND ';\nexport const OR_DELIMITER = ' OR ';\nexport const CD_TABLE_ALIAS = 'cd';\nexport const CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name` = `${CD_TABLE_ALIAS}.name`;\nexport const CV_TABLE_ALIAS = 'cv';\nexport const CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value` = `${CV_TABLE_ALIAS}.value`;\nexport const CE_TABLE_ALIAS = 'ce';\n\nconst getSingleConditionWithOperator = (value: any, operator: string, replacementKey: string, reverseReplacementsMap: Map<string, string>) => {\n let type = 'text';\n if (isDate(value)) {\n type = 'date';\n } else if (!Number.isNaN(Number(value))) {\n type = 'numeric';\n } else if (isBooleanString(value)) {\n type = 'boolean';\n }\n const replacedValue = reverseReplacementsMap.get(value);\n\n return `(jsonb_extract_path_text(${CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;\n};\n\nconst getFormattedValue = (value: string) => {\n let formattedValue: string | number | boolean = value;\n if (isBooleanString(value)) {\n formattedValue = value === 'true';\n } else if (!Number.isNaN(Number(value))) {\n formattedValue = Number(value);\n }\n\n return formattedValue;\n};\n\nconst getJSONSubQuery = (value: string, key: string) => {\n const formattedValue = getFormattedValue(value);\n const jsonQuery = JSON.stringify({ [key]: formattedValue });\n let jsonQueryWithStringBoolean;\n if (isBooleanString(value)) {\n jsonQueryWithStringBoolean = `${CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;\n }\n return `\n (\n ${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}\n ${CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'\n )\n `;\n};\n\nexport const getFilterCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, conditionsStrings: (string | boolean)[]): string => {\n switch (queryType) {\n case SubQueryType.VALUES: {\n // INTERSECT of one SELECT per condition gives the same semantics as\n // `WHERE c1 OR c2 ... GROUP BY model_id HAVING COUNT(DISTINCT def_id) = N`\n // but lets the planner pick an index-driven plan per branch instead of\n // a single sequential scan of custom_field_values.\n const branches = conditionsStrings.map((condition) => `\n SELECT ${CV_TABLE_ALIAS}.model_id\n FROM custom_field_values AS ${CV_TABLE_ALIAS}\n INNER JOIN custom_field_definitions AS ${CD_TABLE_ALIAS} ON ${CV_TABLE_ALIAS}.custom_field_definition_id = ${CD_TABLE_ALIAS}.id\n ${AND_DELIMITER}${CD_TABLE_ALIAS}.model_type = '${modelType}'\n WHERE ${condition}\n ${AND_DELIMITER}${CV_TABLE_ALIAS}.deleted_at IS NULL${AND_DELIMITER}${CD_TABLE_ALIAS}.deleted_at IS NULL\n `);\n return branches.join(' INTERSECT ').replace(/\\n/g, '');\n }\n case SubQueryType.ENTRIES:\n return `\n SELECT ce.model_id\n FROM custom_field_entries ce\n JOIN custom_field_definitions cfd\n ON ce.model_type = cfd.model_type\n AND ce.entity_id = cfd.entity_id\n WHERE\n cfd.deleted_at IS NULL AND\n ${conditionsStrings.join(AND_DELIMITER)}\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, replacementKey: string): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `(\n SELECT value\n FROM (SELECT cv.model_id, cv.value\n FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd\n ON cv.custom_field_definition_id = cd.id\n ${AND_DELIMITER}cd.model_type = '${modelType}'\n WHERE cv.model_id = \"${modelType}\".\"id\"\n ${AND_DELIMITER}cd.name = :${replacementKey}\n ) AS CustomFieldAggregation\n )\n `;\n case SubQueryType.ENTRIES:\n return `(\n SELECT\n customFields.value\n FROM\n custom_field_entries AS ${CE_TABLE_ALIAS},\n jsonb_each_text(custom_fields) AS customFields\n WHERE\n customFields.key = :${replacementKey}${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_id = \"${modelType}\".\"id\"\n )\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const formatConditionsForValues = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n const columnCondition = `(${CD_NAME_COLUMN} = :${replacementKey})`;\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.flatMap((v) => {\n const valRandom = reverseReplacementsMap.get(v);\n if (isBooleanString(v)) {\n return [castValueToJsonbText(`:${valRandom}`), castValueToJsonbBoolean(`:${valRandom}`)];\n }\n if (!Number.isNaN(Number(v))) {\n return castValueToJsonbNumeric(`:${valRandom}`);\n }\n return castValueToJsonbText(`:${valRandom}`);\n }).join(',');\n return `(${columnCondition}${AND_DELIMITER}${CV_VALUE_COLUMN} IN (${values}))`;\n }\n return condition.map((c) => {\n const valRep = reverseReplacementsMap.get(c.value);\n const valueAsJsonb = castValueToJsonbText(`:${valRep}`);\n\n return `(${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;\n }).join(AND_DELIMITER);\n }\n if (typeof condition === 'string' || typeof condition === 'number') {\n const conditionRep = reverseReplacementsMap.get(condition);\n const valueAsJsonb = !Number.isNaN(Number(condition)) ? castValueToJsonbNumeric(`:${conditionRep}`) : castValueToJsonbText(`:${conditionRep}`);\n const valueAsJsonbBoolean = isBooleanString(condition) ? `${OR_DELIMITER}${CV_VALUE_COLUMN} = ${castValueToJsonbBoolean(`:${conditionRep}`)}` : '';\n return `(${columnCondition}${AND_DELIMITER}(${castIfNeeded(CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;\n }\n if (condition?.operator) {\n const valueRep = reverseReplacementsMap.get(condition.value);\n const valueAsJsonb = castValueToJsonbText(`:${valueRep}`);\n return `( ${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;\n }\n return false;\n};\n\nexport const formatConditionsForEntries = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.map(value => getJSONSubQuery(value, key)).join(`${OR_DELIMITER}\\n`);\n return `( ${values})`;\n }\n return condition.map(c => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(AND_DELIMITER);\n }\n\n if (typeof condition === 'string' || typeof condition === 'number') {\n return getJSONSubQuery(condition, key);\n }\n\n if (condition?.operator) {\n return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);\n }\n return false;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"filter.helpers.js","names":["CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name`","CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value`","formattedValue: string | number | boolean"],"sources":["../../../src/scopes/helpers/filter.helpers.ts"],"sourcesContent":["import type { WhereOptions } from 'sequelize';\n\n/**\n * Type representing possible condition values.\n * Currently supporting strings and arrays of strings.\n * More types to be added (TBA).\n */\nexport interface ConditionWithOperator {\n operator: string;\n value: string;\n}\nexport type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];\n\nexport interface CustomFieldSort {\n field: string;\n direction: 'ASC' | 'DESC';\n}\n\nexport interface CustomFieldFilterOptions {\n where?: WhereOptions;\n replacements?: Record<string, string>;\n}\n\nexport enum SubQueryType {\n VALUES = 'values',\n ENTRIES = 'entries',\n}\n\nexport const isConditionStringArray = (input: any): input is string[] => Array.isArray(input) && typeof input[0] === 'string';\nexport const isBooleanString = (input: string): boolean => ['true', 'false'].includes(input.toString());\nexport const isDate = (input: any): input is Date => input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';\n\nexport const castValueToJsonb = (value: string, type: string) => `to_jsonb(${value}::${type})`;\nexport const castValueToJsonbText = (value: string): string => castValueToJsonb(value, 'text');\nexport const castValueToJsonbBoolean = (value: string): string => castValueToJsonb(value, 'boolean');\nexport const castValueToJsonbNumeric = (value: string): string => castValueToJsonb(value, 'numeric');\nexport const castIfNeeded = (columnName: string, conditionValue: string): string => {\n if (isDate(conditionValue)) {\n return castValueToJsonb(columnName, 'timestamp');\n }\n return columnName;\n};\n\nexport const AND_DELIMITER = ' AND ';\nexport const OR_DELIMITER = ' OR ';\nexport const CD_TABLE_ALIAS = 'cd';\nexport const CD_NAME_COLUMN: `${typeof CD_TABLE_ALIAS}.name` = `${CD_TABLE_ALIAS}.name`;\nexport const CV_TABLE_ALIAS = 'cv';\nexport const CV_VALUE_COLUMN: `${typeof CV_TABLE_ALIAS}.value` = `${CV_TABLE_ALIAS}.value`;\nexport const CE_TABLE_ALIAS = 'ce';\n\nconst getSingleConditionWithOperator = (value: any, operator: string, replacementKey: string, reverseReplacementsMap: Map<string, string>) => {\n let type = 'text';\n if (isDate(value)) {\n type = 'date';\n } else if (!Number.isNaN(Number(value))) {\n type = 'numeric';\n } else if (isBooleanString(value)) {\n type = 'boolean';\n }\n const replacedValue = reverseReplacementsMap.get(value);\n\n return `(jsonb_extract_path_text(${CE_TABLE_ALIAS}.custom_fields, :${replacementKey})::${type}) ${operator} :${replacedValue}`;\n};\n\nconst getFormattedValue = (value: string) => {\n let formattedValue: string | number | boolean = value;\n if (isBooleanString(value)) {\n formattedValue = value === 'true';\n } else if (!Number.isNaN(Number(value))) {\n formattedValue = Number(value);\n }\n\n return formattedValue;\n};\n\nconst getJSONSubQuery = (value: string, key: string) => {\n const formattedValue = getFormattedValue(value);\n const jsonQuery = JSON.stringify({ [key]: formattedValue });\n let jsonQueryWithStringBoolean;\n if (isBooleanString(value)) {\n jsonQueryWithStringBoolean = `${CE_TABLE_ALIAS}.custom_fields @> '${JSON.stringify({ [key]: value })}'`;\n }\n return `\n (\n ${jsonQueryWithStringBoolean ? `${jsonQueryWithStringBoolean} OR` : ''}\n ${CE_TABLE_ALIAS}.custom_fields @> '${jsonQuery}'\n )\n `;\n};\n\nexport const getFilterCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, conditionsStrings: (string | boolean)[]): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `\n SELECT ${CV_TABLE_ALIAS}.model_id\n FROM custom_field_values AS ${CV_TABLE_ALIAS}\n INNER JOIN custom_field_definitions AS ${CD_TABLE_ALIAS} ON ${CV_TABLE_ALIAS}.custom_field_definition_id = ${CD_TABLE_ALIAS}.id\n ${AND_DELIMITER}${CD_TABLE_ALIAS}.model_type = '${modelType}'\n WHERE ${conditionsStrings.join(OR_DELIMITER)}\n ${AND_DELIMITER}${CV_TABLE_ALIAS}.deleted_at IS NULL${AND_DELIMITER}${CD_TABLE_ALIAS}.deleted_at IS NULL\n GROUP BY ${CV_TABLE_ALIAS}.model_id\n HAVING COUNT(DISTINCT ${CV_TABLE_ALIAS}.custom_field_definition_id) = ${conditionsStrings.length}\n `.replace(/\\n/g, '');\n case SubQueryType.ENTRIES:\n return `\n SELECT ce.model_id\n FROM custom_field_entries ce\n JOIN custom_field_definitions cfd\n ON ce.model_type = cfd.model_type\n AND ce.entity_id = cfd.entity_id\n WHERE\n cfd.deleted_at IS NULL AND\n ${conditionsStrings.join(AND_DELIMITER)}\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const getSortCustomFieldsSubQuery = (queryType: SubQueryType, modelType: string, replacementKey: string): string => {\n switch (queryType) {\n case SubQueryType.VALUES:\n return `(\n SELECT value\n FROM (SELECT cv.model_id, cv.value\n FROM custom_field_values AS cv INNER JOIN custom_field_definitions AS cd\n ON cv.custom_field_definition_id = cd.id\n ${AND_DELIMITER}cd.model_type = '${modelType}'\n WHERE cv.model_id = \"${modelType}\".\"id\"\n ${AND_DELIMITER}cd.name = :${replacementKey}\n ) AS CustomFieldAggregation\n )\n `;\n case SubQueryType.ENTRIES:\n return `(\n SELECT\n customFields.value\n FROM\n custom_field_entries AS ${CE_TABLE_ALIAS},\n jsonb_each_text(custom_fields) AS customFields\n WHERE\n customFields.key = :${replacementKey}${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_type = '${modelType}'${AND_DELIMITER}\n ${CE_TABLE_ALIAS}.model_id = \"${modelType}\".\"id\"\n )\n `;\n default:\n throw new Error('Invalid query type');\n }\n};\n\nexport const formatConditionsForValues = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n const columnCondition = `(${CD_NAME_COLUMN} = :${replacementKey})`;\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.flatMap((v) => {\n const valRandom = reverseReplacementsMap.get(v);\n if (isBooleanString(v)) {\n return [castValueToJsonbText(`:${valRandom}`), castValueToJsonbBoolean(`:${valRandom}`)];\n }\n if (!Number.isNaN(Number(v))) {\n return castValueToJsonbNumeric(`:${valRandom}`);\n }\n return castValueToJsonbText(`:${valRandom}`);\n }).join(',');\n return `(${columnCondition}${AND_DELIMITER}${CV_VALUE_COLUMN} IN (${values}))`;\n }\n return condition.map((c) => {\n const valRep = reverseReplacementsMap.get(c.value);\n const valueAsJsonb = castValueToJsonbText(`:${valRep}`);\n\n return `(${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, c.value)} ${c.operator} ${valueAsJsonb})`;\n }).join(AND_DELIMITER);\n }\n if (typeof condition === 'string' || typeof condition === 'number') {\n const conditionRep = reverseReplacementsMap.get(condition);\n const valueAsJsonb = !Number.isNaN(Number(condition)) ? castValueToJsonbNumeric(`:${conditionRep}`) : castValueToJsonbText(`:${conditionRep}`);\n const valueAsJsonbBoolean = isBooleanString(condition) ? `${OR_DELIMITER}${CV_VALUE_COLUMN} = ${castValueToJsonbBoolean(`:${conditionRep}`)}` : '';\n return `(${columnCondition}${AND_DELIMITER}(${castIfNeeded(CV_VALUE_COLUMN, condition)} = ${valueAsJsonb}${valueAsJsonbBoolean}))`;\n }\n if (condition?.operator) {\n const valueRep = reverseReplacementsMap.get(condition.value);\n const valueAsJsonb = castValueToJsonbText(`:${valueRep}`);\n return `( ${columnCondition}${AND_DELIMITER}${castIfNeeded(CV_VALUE_COLUMN, condition.value)} ${condition.operator} ${valueAsJsonb})`;\n }\n return false;\n};\n\nexport const formatConditionsForEntries = (key: string, condition: ConditionValue, reverseReplacementsMap: Map<string, string>): false | string => {\n const replacementKey = reverseReplacementsMap.get(key);\n if (!replacementKey) {\n return false;\n }\n\n if (Array.isArray(condition)) {\n if (condition.length === 0) {\n // if empty array, the condition is ignored\n return false;\n }\n\n if (isConditionStringArray(condition)) {\n const values = condition.map(value => getJSONSubQuery(value, key)).join(`${OR_DELIMITER}\\n`);\n return `( ${values})`;\n }\n return condition.map(c => getSingleConditionWithOperator(c.value, c.operator, replacementKey, reverseReplacementsMap)).join(AND_DELIMITER);\n }\n\n if (typeof condition === 'string' || typeof condition === 'number') {\n return getJSONSubQuery(condition, key);\n }\n\n if (condition?.operator) {\n return getSingleConditionWithOperator(condition.value, condition.operator, replacementKey, reverseReplacementsMap);\n }\n return false;\n};\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autofleet/sadot",
|
|
3
|
-
"version": "1.5.2
|
|
3
|
+
"version": "1.5.2",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,10 +52,10 @@
|
|
|
52
52
|
"express": "^4.21.2",
|
|
53
53
|
"npm-watch": "^0.11.0",
|
|
54
54
|
"supertest": "^7.0.0",
|
|
55
|
-
"@autofleet/
|
|
55
|
+
"@autofleet/logger": "^4.5.1",
|
|
56
56
|
"@autofleet/node-common": "^4.3.13",
|
|
57
|
-
"@autofleet/
|
|
58
|
-
"@autofleet/
|
|
57
|
+
"@autofleet/zehut": "^4.12.8",
|
|
58
|
+
"@autofleet/errors": "^3.1.53"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
61
|
"@autofleet/errors": "^3",
|