@autofleet/sheilta 2.2.1-beta-576f10d3.4 → 2.2.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/lib/index.d.ts CHANGED
@@ -1,112 +1,207 @@
1
- import { Handler } from 'express';
2
- import { LoggerInstanceManager } from '@autofleet/logger';
1
+ import { Op, literal } from "sequelize";
2
+ import { LoggerInstanceManager } from "@autofleet/logger";
3
+ import { Handler } from "express";
3
4
 
4
- declare const formatOperators: (Sequelize: any) => {};
5
+ //#region src/operators/index.d.ts
5
6
 
7
+ declare const formatOperators: (sequelize?: {
8
+ Op: typeof Op;
9
+ }) => Record<string, symbol>;
10
+ //#endregion
11
+ //#region src/formatter/jsonAttributesFormater.d.ts
12
+ declare const ComputedActions: {
13
+ readonly length: "length";
14
+ };
15
+ interface JsonSelectAttribute {
16
+ columnName: string;
17
+ keys: string[];
18
+ alias?: string;
19
+ }
20
+ interface JsonComputedAttribute {
21
+ columnName: string;
22
+ action: keyof typeof ComputedActions;
23
+ alias: string;
24
+ }
25
+ interface JsonAttributes {
26
+ select?: JsonSelectAttribute[];
27
+ computed?: JsonComputedAttribute[];
28
+ }
29
+ /**
30
+ * Return a single array combining selected and computed attributes.
31
+ * Format: [[literal, alias], [literal, alias], ...]
32
+ */
33
+ //#endregion
34
+ //#region src/formatter/index.d.ts
6
35
  type OrderItem = string | [string, string];
7
36
  type SequelizeOrder = string | OrderItem[];
8
- type FormatPayloadOptions = {
9
- includeRawPayload?: boolean;
10
- literalAttributes?: LiteralAttribute[];
11
- DBFormatter?: any;
12
- skipSearchTermFormat?: boolean;
13
- additionalAllowedAttributes?: string[];
14
- };
15
- type ConditionWithOperator = {
16
- operator: string;
17
- value: string;
18
- };
37
+ interface FormatPayloadOptions {
38
+ includeRawPayload?: boolean;
39
+ literalAttributes?: LiteralAttribute[];
40
+ DBFormatter?: any;
41
+ skipSearchTermFormat?: boolean;
42
+ additionalAllowedAttributes?: string[];
43
+ }
44
+ interface ConditionWithOperator {
45
+ operator: string;
46
+ value: string;
47
+ }
19
48
  type ConditionValue = ConditionWithOperator | ConditionWithOperator[] | string | string[];
20
49
  /**
21
- * Generates replacements for the given conditions.
22
- *
23
- * @param conditions - The conditions to generate replacements for.
24
- * @returns The replacements object.
25
- */
50
+ * Generates replacements for the given conditions.
51
+ *
52
+ * @param conditions - The conditions to generate replacements for.
53
+ * @returns The replacements object.
54
+ */
26
55
  declare const generateFilterReplacements: (conditions: Record<string, ConditionValue>) => Record<string, string>;
27
- declare const formatPayload: ({ order, page, perPage, include, query, attributes, searchTerm, jsonAttributes, }: {
28
- order?: any[];
29
- page?: number;
30
- perPage?: number;
31
- include?: any[];
32
- query?: {};
33
- attributes?: any;
34
- searchTerm?: any;
35
- jsonAttributes?: {};
36
- }, model?: any, options?: FormatPayloadOptions) => {
37
- externalQueryValues: Record<string, unknown>;
38
- attributes: any[] | {
39
- include: any[];
40
- };
41
- query: Record<string, unknown>;
42
- order: SequelizeOrder[];
43
- page: number;
44
- perPage: number;
45
- include: any;
46
- scopes: (string | {
47
- method: (string | {
48
- replacementsMap: Record<string, string>;
49
- scopeValue: any;
50
- })[];
51
- })[];
52
- };
56
+ /**
57
+ * Generates replacements for the given order array.
58
+ *
59
+ * @param order - The order array to generate replacements for.
60
+ * @returns The replacements object.
61
+ */
53
62
 
54
- type literal = any;
55
- type LiteralQuery = (literal | string)[] | literal;
56
- type LiteralAttribute = {
57
- attribute: string;
58
- literal: LiteralQuery;
59
- };
60
- type MiddlewareValidationOption = {
61
- literalAttributes?: LiteralAttribute[];
62
- enrichmentAttributes?: string[];
63
- additionalAllowedAttributes?: string[];
64
- logger?: LoggerInstanceManager;
65
- };
66
- type ReqKeys = 'body' | 'query';
63
+ interface Include {
64
+ association?: string;
65
+ model?: string;
66
+ required?: boolean;
67
+ include?: Include[];
68
+ }
69
+ interface FormatPayloadData {
70
+ order?: string[];
71
+ page?: number;
72
+ perPage?: number;
73
+ include?: (string | Include)[];
74
+ query?: Record<string, unknown>;
75
+ attributes?: string[] | null;
76
+ searchTerm?: string | null;
77
+ jsonAttributes?: JsonAttributes;
78
+ }
79
+ type Literal = ReturnType<typeof literal>;
80
+ interface FormattedPayload {
81
+ query: Record<string, unknown>;
82
+ externalQueryValues?: Record<string, unknown>;
83
+ attributes: (SequelizeOrder | (string | Literal)[])[] | {
84
+ include: (SequelizeOrder | (string | Literal)[])[];
85
+ };
86
+ order: SequelizeOrder[];
87
+ page: number;
88
+ perPage: number;
89
+ include: any;
90
+ scopes: (string | {
91
+ method: (string | {
92
+ replacementsMap: Record<string, string>;
93
+ scopeValue: any;
94
+ })[];
95
+ })[];
96
+ }
97
+ declare const formatPayload: ({
98
+ order,
99
+ page,
100
+ perPage,
101
+ include,
102
+ query,
103
+ attributes,
104
+ searchTerm,
105
+ jsonAttributes
106
+ }: FormatPayloadData, model?: any, options?: FormatPayloadOptions) => FormattedPayload;
107
+ //#endregion
108
+ //#region src/middleware/index.d.ts
109
+ type literal$1 = any;
110
+ type LiteralQuery = (literal$1 | string)[] | literal$1;
111
+ interface LiteralAttribute {
112
+ attribute: string;
113
+ literal: LiteralQuery;
114
+ }
115
+ interface MiddlewareValidationOption {
116
+ literalAttributes?: LiteralAttribute[];
117
+ enrichmentAttributes?: string[];
118
+ additionalAllowedAttributes?: string[];
119
+ logger?: LoggerInstanceManager;
120
+ }
121
+ type ReqKeys = "body" | "query";
67
122
  /** consider using @see {@link queryHandler} directly */
68
123
  declare const queryValidationMiddleware: (model: any, options?: MiddlewareValidationOption, inner?: ReqKeys) => Handler;
69
124
  /** consider using @see {@link queryHandler} directly */
70
125
  declare const queryFormatMiddleware: (model: any, options?: FormatPayloadOptions, inner?: ReqKeys) => Handler;
71
-
72
- declare const validatePayload: ({ query, order, attributes, include, page, perPage, enrichments, group, jsonAttributes, }: {
73
- query?: {};
74
- order?: any[];
75
- attributes?: any[];
76
- include?: any[];
77
- page?: number;
78
- perPage?: number;
79
- enrichments?: any[];
80
- group?: any[];
81
- jsonAttributes?: {};
82
- }, model?: any, options?: MiddlewareValidationOption) => boolean;
83
-
126
+ //#endregion
127
+ //#region src/validations/index.d.ts
128
+ interface PayloadValidationData {
129
+ query?: object;
130
+ order?: string[];
131
+ attributes?: string[];
132
+ include?: any[];
133
+ page?: number;
134
+ perPage?: number;
135
+ enrichments?: string[] | {
136
+ [enrichmentName: string]: {
137
+ exclude?: string[];
138
+ };
139
+ };
140
+ group?: string[];
141
+ jsonAttributes?: {
142
+ select?: {
143
+ columnName: string;
144
+ keys: string[];
145
+ alias?: string;
146
+ }[];
147
+ computed?: {
148
+ columnName: string;
149
+ action: "length";
150
+ alias: string;
151
+ }[];
152
+ };
153
+ }
154
+ declare const validatePayload: ({
155
+ query,
156
+ order,
157
+ attributes,
158
+ include,
159
+ page,
160
+ perPage,
161
+ enrichments,
162
+ group,
163
+ jsonAttributes
164
+ }: PayloadValidationData, model?: any, options?: MiddlewareValidationOption) => boolean;
165
+ //#endregion
166
+ //#region src/handler/index.d.ts
84
167
  interface QueryValues extends ReturnType<typeof formatPayload> {
85
- enrichments?: string[] | Record<string, {
86
- exclude: string[];
87
- }>;
88
- distinct: boolean;
168
+ enrichments?: string[] | Record<string, {
169
+ exclude: string[];
170
+ }>;
171
+ distinct: boolean;
172
+ searchTerm?: string;
89
173
  }
90
174
  interface QueryHandlerOptions {
91
- /** The sequelize model too which querying abilities are added. */
92
- model: any;
93
- /** Optional settings for validation. */
94
- validationOptions?: Omit<MiddlewareValidationOption, 'logger'>;
95
- /** Optional settings for payload formatting */
96
- formatOptions?: FormatPayloadOptions;
97
- logger: LoggerInstanceManager;
98
- /** The name of model to be printed in logs. defaults to `model`s constructor name. */
99
- modelName?: string;
100
- /** Sequelize scopes of the model to be used within the query. @example ['userScope'] */
101
- additionalScopes?: string[];
102
- /** Callback to allow modifying the query values prior to querying the DB */
103
- modifyQueryValues?: (queryValues: QueryValues) => QueryValues;
104
- /** Optional callback to modify endpoint's response based on the DBs response. */
105
- onRowsRetrieved?: (data: {
106
- rows: any[];
107
- count: number;
108
- }, queryValues: QueryValues) => any;
175
+ /** The sequelize model too which querying abilities are added. */
176
+ model: any;
177
+ /** Optional settings for validation. */
178
+ validationOptions?: Omit<MiddlewareValidationOption, "logger">;
179
+ /** Optional settings for payload formatting */
180
+ formatOptions?: FormatPayloadOptions;
181
+ logger: LoggerInstanceManager;
182
+ /** The name of model to be printed in logs. defaults to `model`s constructor name. */
183
+ modelName?: string;
184
+ /** Sequelize scopes of the model to be used within the query. @example ['userScope'] */
185
+ additionalScopes?: string[];
186
+ /** Callback to allow modifying the query values prior to querying the DB */
187
+ modifyQueryValues?: (queryValues: QueryValues) => QueryValues;
188
+ /** Optional callback to modify endpoint's response based on the DBs response. */
189
+ onRowsRetrieved?: (data: {
190
+ rows: any[];
191
+ count: number;
192
+ }, queryValues: QueryValues) => any;
109
193
  }
110
- declare const queryHandler: ({ model, logger, validationOptions, formatOptions, modelName, additionalScopes, modifyQueryValues, onRowsRetrieved, }: QueryHandlerOptions) => Handler;
111
-
194
+ type Asyncify<T extends (...a: any[]) => any> = (...a: Parameters<T>) => Promise<Awaited<ReturnType<T>>>;
195
+ declare const queryHandler: ({
196
+ model,
197
+ logger,
198
+ validationOptions,
199
+ formatOptions,
200
+ modelName,
201
+ additionalScopes,
202
+ modifyQueryValues,
203
+ onRowsRetrieved
204
+ }: QueryHandlerOptions) => Asyncify<Handler>;
205
+ //#endregion
112
206
  export { type LiteralAttribute, type MiddlewareValidationOption, formatOperators, generateFilterReplacements, queryFormatMiddleware, queryHandler, queryValidationMiddleware, validatePayload };
207
+ //# sourceMappingURL=index.d.ts.map
package/lib/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import Jt from'@autofleet/logger';import {handleError,UnexpectedError,BadRequest}from'@autofleet/errors';import p from'joi';import {customFields}from'@autofleet/common-types';import {literal}from'sequelize';var k=["eq","ne","gte","gt","lte","lt","not","in","notIn","is","like","iLike","notLike","between","and","or","overlap","contains"],E="$",tt={$eq:"=",$ne:"!=",$gte:">=",$gt:">",$lte:"<=",$lt:"<",$not:"NOT",$in:"IN",$notIn:"NOT IN",$is:"IS",$like:"LIKE",$iLike:"ILIKE",$notLike:"NOT LIKE",$and:"AND",$or:"OR"},bt=t=>{let{Op:e}=t;return k.reduce((o,r)=>(o[`${E+r}`]=e[r],o),{})};var Ot=t=>Math.floor(Math.random()*Math.floor(t)),y="-",f=".",V="$",T=20,q=1,N=100,v=1,et=1,rt=t=>`${E}${t}${E}`,R=(t,e)=>t.includes(f)&&e.includes(t.split(f)[0]),L=(t,e)=>{let o=t;return t.includes(y)&&(o=o.split(y)[1]),R(o,e)&&([o]=o.split(f)),o},$=t=>t.includes(y),m=t=>{throw new BadRequest([new Error(t)])},ot=t=>t.split(f)[1],A=(t=5)=>{let e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";return Array.from({length:t},()=>e.charAt(Ot(e.length))).join("")},D=(t,e)=>Object.fromEntries(e.map(o=>[o,t[o]]));var Q={length:"length"};function it(t){return t.replace(/(?!^)[A-Z]/g,e=>`_${e.toLowerCase()}`)}function Pt(t){switch(t.action){case Q.length:{let e=`jsonb_array_length(${it(t.columnName)})`;return [literal(e),t.alias]}default:return t.action,[]}}function ht(t){return t.map(e=>Pt(e))}function Et(t){return t.map(e=>{let o=it(e.columnName),r=`json_build_object(${e.keys.map(n=>`'${n}', ${o} -> '${n}'`).join(", ")})`,i=e.alias||e.columnName;return [literal(r),i]})}function J({select:t=[],computed:e=[]}={}){let o=Et(t),r=ht(e);return [...o,...r]}var St="id",st="DESC",xt="ASC",b="customFields.",{CUSTOM_FIELDS_FILTER_SCOPE:G,CUSTOM_FIELDS_SORT_SCOPE:K}=customFields,_t=t=>["string","number"].includes(typeof t)||Array.isArray(t)?t:Object.entries(t).map(([e,o])=>({operator:tt[e],value:o})),It=(t,e={})=>{let{literalAttributes:o=[],DBFormatter:r=void 0}=e,[i,n]=t.reduce((s,l)=>{let[a,c="ASC"]=Array.isArray(l)?l:[l],d=o?.find(u=>u.attribute===a);return d?(s[1].push(d.literal),s[0].push([r?r(`"${d.attribute}" ${c}`):`${d.attribute} ${c}`])):s[0].push(l),s},[[],[]]);return [i,n]},at=t=>{let e={};return Object.entries(t).forEach(([o,r])=>{let i=A();if(e[i]=o.split(b)[1],Array.isArray(r))r.forEach(n=>{let s=A();e[s]=typeof n=="string"?n:n.value;});else if(typeof r=="string"||typeof r=="number"){let n=A();e[n]=r;}else if(r?.operator){let n=A();e[n]=r.value;}}),e},wt=t=>{let e={};return t.forEach(o=>{if(o.startsWith(b)){let r=A();e[r]=o.split(b)[1];}else if(o.substring(1).startsWith(b)){let r=A();e[r]=o.substring(1).split(b)[1];}}),e},Ft=(t,e)=>({...wt(t),...at(e)}),Tt=({order:t,associationModels:e=[],replacementsMap:o={}})=>{let r=[],i=new Map;return t.forEach(n=>{if([n,n.substring(1)].some(c=>c.startsWith(b))){i.has(K)||i.set(K,{});let c=n.split(b)[1];i.get(K)[c]=$(n)?st:xt;return}let s=[L(n,e)],l=$(n);R(l?n.split(y)[1]:n,e)&&s.push(ot(n)),l&&s.push(st),r.push(s);}),{formattedOrders:r,replacementsMap:o,orderScopes:Array.from(i.entries()).map(([n,s])=>s?{method:[n,{replacementsMap:o,scopeValue:s}]}:n)}},qt=t=>t||q,$t=t=>t||T,ct=(t,e={})=>{let o=t.map(r=>{let i=e[typeof r=="string"?r:r.association||r.model];return {...typeof r!="string"&&r,association:i,required:typeof r=="string"||r.required!==false,...typeof r!="string"&&r.include&&{include:ct(r.include,i?.target?.associations)}}});return o=o.map(({model:r,...i})=>i),o},Mt=(t,e,o,r=[])=>{let i={},n={},s=new Map;Object.entries(t).forEach(([a,c])=>{if(a.startsWith(b)){s.has(G)||s.set(G,{});let u=a.split(b)[1];s.get(G)[u]=_t(c);return}if(r.includes(a)){n[a]=c;return}let d=R(a,e)?rt(a):a;i[d]=c;});let l=Array.from(s.entries()).map(([a,c])=>c?{method:[a,{replacementsMap:o,scopeValue:c}]}:a);return {formattedQuery:i,externalQueryValues:n,formattedScopes:l}},Lt=(t,e,o)=>({$and:t.split(" ").map(r=>({$or:e.filter(i=>o[i].type.key==="STRING").map(i=>({[i]:{$iLike:`%${r}%`}}))}))}),Ct=({order:t=[],page:e=q,perPage:o=T,include:r=[],query:i={},attributes:n=null,searchTerm:s=null,jsonAttributes:l={}},a,c)=>{let d=Ft(t,i),u=Object.keys(a?.associations||{}),{formattedOrders:g,orderScopes:x}=Tt({order:[...t,St],associationModels:u,replacementsMap:d}),[P,_]=It(g,c),M=J(l),I=[..._,...n||[],...M],h=n?.length?I:{include:I},w=ct(r,a?.associations),j=qt(e),gt=$t(o),z=Mt(i,u,d,c?.additionalAllowedAttributes),{formattedScopes:yt,externalQueryValues:Y}=z,{formattedQuery:F}=z;if(s&&!c?.skipSearchTermFormat){let ft=n?.length?n:Object.keys(a.rawAttributes),Z=Lt(s,ft,a.rawAttributes);F=!F||Object.keys(F).length===0?Z:{$and:[F,Z]};}return {query:F,order:P,page:j,perPage:gt,include:w,scopes:[...yt,...x],...h&&{attributes:h},...Object.keys(Y).length>0&&{externalQueryValues:Y}}},lt=Ct;var jt=t=>k.includes(t.split(E)[1]),dt=(t,e=[],o=[],r=[])=>{let i=t.startsWith(V)&&t.endsWith(V)?t.slice(1,-1):t;return [...e,...o].includes(i.includes(f)?i.split(f)[0]:i)||r.includes(i)},kt=(t,e,o,r={})=>{let i=$(t);i&&t[0]!==y&&m(`${y} must be only at the beginning of the word`);let n=i?t.split(y)[1]:t,s=R(n,o),l=L(t,o),a=r?.literalAttributes?.map(c=>c.attribute)?.includes(n);!s&&l.includes(f)&&([l]=l.split(f)),e.includes(l)||s||a||m(`${t} is invalid. isLiteralAttribute: ${a}`);},Vt=(t,e)=>{e.includes(t)||m(`${t} is invalid`);},ut=(t,e,o=[],r={})=>{t.forEach(i=>kt(i,e,o,r));},W=(t,e)=>{t.forEach(o=>Vt(o,e));},Nt=(t,e)=>{let o=[...t.select?.map(r=>r.columnName)||[],...t.computed?.map(r=>r.columnName)||[]];W(o,e);},vt=(t,e)=>{let o=Array.isArray(t)?t:Object.keys(t);if(!o?.length)return;let r=o.find(i=>!e?.enrichmentAttributes?.includes(i));r&&m(`enrichment attribute ${r} is invalid`);},C=(t,e,o=[],r=[])=>{Object.entries(t).forEach(([i,n])=>{Array.isArray(n)?n[0]&&typeof n[0]=="object"&&n.map(s=>C(s,e,o,r)):jt(i)||dt(i,e,o,r)?n&&typeof n=="object"&&C(n,e,[],r):m(`invalid key: ${i}`);});},Dt=({page:t,perPage:e})=>{t<et&&m("Page must be greater than 0"),(e>N||e<v)&&m(`PerPage must be between ${v} to ${N}`);},Qt=(t,e)=>{let o=Object.keys(e);t.forEach(r=>{dt(r.model,o);let i=e[r.model]?.target;i||m("model not found in associations");let{rawAttributes:n}=i,s=Object.keys(n);r.where&&C(r.where,s),r.order&&ut(r.order,s),r.attributes&&W(r.attributes,s),[null,void 0,true,false].includes(r.required)||m("include.required must be a boolean");});},U=({query:t={},order:e=[],attributes:o=[],include:r=[],page:i=q,perPage:n=T,enrichments:s=[],group:l=[],jsonAttributes:a={}},c,d={})=>{let u=Object.keys(c.rawAttributes),g=Object.keys(c?.associations||{});return !o||o.length===0?o=u:W(o,u),ut(e,u,g,d),C(t,u,g,d.additionalAllowedAttributes),vt(s,d),Nt(a,u),Array.isArray(l)||m("group must be an array"),r.length&&typeof r=="object"?Qt(r,c?.associations):r&&typeof r!="object"&&m("include must be an array"),Dt({page:i,perPage:n}),true};var {object:H,string:O,number:pt,any:Wt,array:S,alternatives:Ut}=p.types(),Ht=Jt(),Xt=H.keys({query:H,attributes:S.items(O),order:S.items(O),page:pt,perPage:pt,include:S.items(Wt),searchTerm:O,group:S.items(O),enrichments:Ut.try(S.items(O),H.pattern(O,{exclude:S.items(O)})),jsonAttributes:p.object({select:p.array().items(p.object({columnName:p.string().required(),keys:p.array().items(p.string().required()).required(),alias:p.string().optional()})).default([]),computed:p.array().items(p.object({columnName:p.string().required(),action:p.string().valid(...Object.values(Q)).required(),alias:p.string().required()})).default([])}).default({})}),X=(t,e,o={})=>{let{query:r,attributes:i,order:n,page:s,perPage:l,include:a,group:c,enrichments:d,jsonAttributes:u}=e,g=Xt.validate(e);if(g.error)throw new BadRequest([g.error],null);U({query:r,attributes:i,order:n,page:s,perPage:l,include:a,enrichments:d,group:c,jsonAttributes:u},t,o);},Bt=(t,e={},o="body")=>async(r,i,n)=>{try{X(t,r[o],e),n();}catch(s){let{query:l,attributes:a,order:c}=r[o];handleError(s,i,{logger:e.logger||Ht,message:"error in query middleware",payload:{error:s,query:l,attributes:a,order:c}});}},B=(t,e,o={})=>{let{order:r,page:i,perPage:n,include:s,query:l,attributes:a,searchTerm:c,jsonAttributes:d}=e,{query:u,externalQueryValues:g,order:x,page:P,perPage:_,include:M,scopes:I,attributes:h}=lt({query:l,order:r,page:i,perPage:n,include:s,attributes:a,searchTerm:c,jsonAttributes:d},t,o);e.query=u,e.externalQueryValues=g,e.order=x,e.attributes=h,e.page=P,e.perPage=_,e.include=M,e.scopes=I,o.includeRawPayload&&(e.rawPayload={order:r,page:i,perPage:n,include:s,query:l,attributes:a,searchTerm:c});},zt=(t,e={},o="body")=>async(r,i,n)=>{B(t,r[o],e),n();};var Zt=({model:t,logger:e,validationOptions:o,formatOptions:r,modelName:i=t.constructor?.name,additionalScopes:n=[],modifyQueryValues:s,onRowsRetrieved:l})=>async(a,c)=>{try{X(t,a.body,{...o,logger:e});}catch(d){let u=D(a.body,["query","order","attributes"]);handleError(d,c,{logger:e,message:"error in query endpoint",payload:u});return}try{B(t,a.body,r);let d=Object.assign(D(a.body,["query","externalQueryValues","order","attributes","page","perPage","include","scopes","enrichments"]),{distinct:!0});e.info(`querying ${i}`,{queryValues:d});let u=s?.(d)??d,{scopes:g=[],query:x,perPage:P,page:_,enrichments:M,externalQueryValues:I,...h}=u,w=await t.scope([...n,...g]).findAndCountAll({where:x,limit:P,offset:(_-1)*P,...h});if(!w.rows.length||!l){c.json(w);return}let j=await l(w,u);c.json(j);}catch(d){handleError(new UnexpectedError(d),c,{logger:e,message:`Error while querying ${i}`,payload:{query:a.body}});}};export{bt as formatOperators,at as generateFilterReplacements,zt as queryFormatMiddleware,Zt as queryHandler,Bt as queryValidationMiddleware,U as validatePayload};//# sourceMappingURL=index.js.map
1
+ import{Op as e,literal as t}from"sequelize";import n from"@autofleet/logger";import{BadRequest as r,UnexpectedError as i,handleError as a}from"@autofleet/errors";import o from"joi";import{customFields as s}from"@autofleet/common-types";import{randomInt as c}from"node:crypto";const l=[`eq`,`ne`,`gte`,`gt`,`lte`,`lt`,`not`,`in`,`notIn`,`is`,`like`,`iLike`,`notLike`,`between`,`and`,`or`,`overlap`,`contains`],u={$eq:`=`,$ne:`!=`,$gte:`>=`,$gt:`>`,$lte:`<=`,$lt:`<`,$not:`NOT`,$in:`IN`,$notIn:`NOT IN`,$is:`IS`,$like:`LIKE`,$iLike:`ILIKE`,$notLike:`NOT LIKE`,$and:`AND`,$or:`OR`},d=(t={Op:e})=>{let{Op:n}=t;return Object.fromEntries(l.map(e=>[`${`$`+e}`,n[e]]))},f=e=>`\$${e}\$`,p=(e,t)=>e.includes(`.`)&&t.includes(e.split(`.`,1)[0]),m=(e,t)=>{let n=e;return e.includes(`-`)&&([,n]=n.split(`-`,2)),p(n,t)&&([n]=n.split(`.`,1)),n},h=e=>e.includes(`-`),g=e=>{throw new r([Error(e)])},_=e=>e.split(`.`,2)[1],v=(e=5)=>Array.from({length:e},()=>`ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`.charAt(c(52))).join(``),y=(e,t)=>Object.fromEntries(t.map(t=>[t,e[t]])),b={length:`length`};function x(e){return e.replace(/(?!^)[A-Z]/g,e=>`_${e.toLowerCase()}`)}function S(e){switch(e.action){case b.length:{let n=`jsonb_array_length(${x(e.columnName)})`;return[t(n),e.alias]}default:return e.action,[]}}function C(e){return e.map(e=>S(e))}function w(e){return e.map(e=>{let n=x(e.columnName),r=`json_build_object(${e.keys.map(e=>`'${e}', ${n} -> '${e}'`).join(`, `)})`,i=e.alias||e.columnName;return[t(r),i]})}function T({select:e=[],computed:t=[]}={}){let n=w(e),r=C(t);return[...n,...r]}const E=`DESC`,D=`customFields.`,{CUSTOM_FIELDS_FILTER_SCOPE:O,CUSTOM_FIELDS_SORT_SCOPE:k}=s,ee=e=>[`string`,`number`].includes(typeof e)||Array.isArray(e)?e:Object.entries(e).map(([e,t])=>({operator:u[e],value:t})),te=(e,t={})=>{let{literalAttributes:n=[],DBFormatter:r=void 0}=t,[i,a]=e.reduce((e,t)=>{let[i,a=`ASC`]=Array.isArray(t)?t:[t],o=n?.find(e=>e.attribute===i);return o?(e[1].push(o.literal),e[0].push([r?r(`"${o.attribute}" ${a}`):`${o.attribute} ${a}`])):e[0].push(t),e},[[],[]]);return[i,a]},A=e=>{let t={};return Object.entries(e).forEach(([e,n])=>{let r=v();if(t[r]=e.split(D,2)[1],Array.isArray(n))n.forEach(e=>{let n=v();t[n]=typeof e==`string`?e:e.value});else if(typeof n==`string`||typeof n==`number`){let e=v();t[e]=n}else if(n?.operator){let e=v();t[e]=n.value}}),t},ne=e=>{let t={};return e.forEach(e=>{if(e.startsWith(D)){let n=v();t[n]=e.split(D,2)[1]}else if(e.substring(1).startsWith(D)){let n=v();t[n]=e.substring(1).split(D,2)[1]}}),t},j=(e,t)=>({...ne(e),...A(t)}),M=({order:e,associationModels:t=[],replacementsMap:n={}})=>{let r=[],i=new Map;return e.forEach(e=>{if([e,e.substring(1)].some(e=>e.startsWith(D))){i.has(k)||i.set(k,{});let t=e.split(D,2)[1];i.get(k)[t]=h(e)?E:`ASC`;return}let n=[m(e,t)],a=h(e),o=p(a?e.split(`-`,2)[1]:e,t);o&&n.push(_(e)),a&&n.push(E),r.push(n)}),{formattedOrders:r,replacementsMap:n,orderScopes:Array.from(i.entries()).map(([e,t])=>t?{method:[e,{replacementsMap:n,scopeValue:t}]}:e)}},N=e=>e||1,P=e=>e||20,F=(e,t={})=>{let n=e.map(e=>{let n=t[typeof e==`string`?e:e.association||e.model];return{...typeof e!=`string`&&e,association:n,required:typeof e==`string`||e.required!==!1,...typeof e!=`string`&&e.include&&{include:F(e.include,n?.target?.associations)}}});return n=n.map(({model:e,...t})=>t),n},I=(e,t,n,r=[])=>{let i={},a={},o=new Map;Object.entries(e).forEach(([e,n])=>{if(e.startsWith(D)){o.has(O)||o.set(O,{});let t=e.split(D,2)[1];o.get(O)[t]=ee(n);return}if(r.includes(e)){a[e]=n;return}let s=p(e,t)?f(e):e;i[s]=n});let s=Array.from(o.entries()).map(([e,t])=>t?{method:[e,{replacementsMap:n,scopeValue:t}]}:e);return{formattedQuery:i,externalQueryValues:a,formattedScopes:s}},re=(e,t,n)=>({$and:e.split(` `).map(e=>({$or:t.filter(e=>n[e].type.key===`STRING`).map(t=>({[t]:{$iLike:`%${e}%`}}))}))}),ie=({order:e=[],page:t=1,perPage:n=20,include:r=[],query:i={},attributes:a=null,searchTerm:o=null,jsonAttributes:s={}},c,l)=>{let u=j(e,i),d=Object.keys(c?.associations||{}),{formattedOrders:f,orderScopes:p}=M({order:[...e,`id`],associationModels:d,replacementsMap:u}),[m,h]=te(f,l),g=T(s),_=[...h,...a??[],...g],v=a?.length?_:{include:_},y=F(r,c?.associations),b=N(t),x=P(n),S=I(i,d,u,l?.additionalAllowedAttributes),{formattedScopes:C,externalQueryValues:w}=S,{formattedQuery:E}=S;if(o&&!l?.skipSearchTermFormat){let e=a?.length?a:Object.keys(c.rawAttributes||{}),t=re(o,e,c.rawAttributes);E=!E||Object.keys(E).length===0?t:{$and:[E,t]}}return{query:E,order:m,page:b,perPage:x,include:y,scopes:[...C,...p],...v&&{attributes:v},...Object.keys(w).length>0&&{externalQueryValues:w}}};var ae=ie;const oe=e=>l.includes(e.split(`$`,2)[1]),L=(e,t=[],n=[],r=[])=>{let i=e.startsWith(`$`)&&e.endsWith(`$`)?e.slice(1,-1):e;return[...t,...n].includes(i.includes(`.`)?i.split(`.`,1)[0]:i)||r.includes(i)},R=(e,t,n,r={})=>{let i=h(e);i&&!e.startsWith(`-`)&&g(`- must be only at the beginning of the word`);let a=i?e.split(`-`,2)[1]:e,o=p(a,n),s=m(e,n),c=r?.literalAttributes?.map(e=>e.attribute)?.includes(a);!o&&s.includes(`.`)&&([s]=s.split(`.`,1)),t.includes(s)||o||c||g(`${e} is invalid. isLiteralAttribute: ${c}`)},z=(e,t)=>{t.includes(e)||g(`${e} is invalid`)},B=(e,t,n=[],r={})=>{e.forEach(e=>R(e,t,n,r))},V=(e,t)=>{e.forEach(e=>z(e,t))},H=(e,t)=>{let n=[...e.select?.map(e=>e.columnName)??[],...e.computed?.map(e=>e.columnName)??[]];V(n,t)},U=(e,t)=>{let n=Array.isArray(e)?e:Object.keys(e);if(!n?.length)return;let r=n.find(e=>!t?.enrichmentAttributes?.includes(e));r&&g(`enrichment attribute ${r} is invalid`)},W=(e,t,n=[],r=[])=>{Object.entries(e).forEach(([e,i])=>{Array.isArray(i)?i[0]&&typeof i[0]==`object`&&i.map(e=>W(e,t,n,r)):oe(e)||L(e,t,n,r)?i&&typeof i==`object`&&W(i,t,[],r):g(`invalid key: ${e}`)})},G=({page:e,perPage:t})=>{e<1&&g(`Page must be greater than 0`),(t>100||t<1)&&g(`PerPage must be between 1 to 100`)},K=(e,t)=>{let n=Object.keys(t);e.forEach(e=>{L(e.model,n);let r=t[e.model]?.target;r||g(`model not found in associations`);let{rawAttributes:i}=r,a=Object.keys(i);e.where&&W(e.where,a),e.order&&B(e.order,a),e.attributes&&V(e.attributes,a),[null,void 0,!0,!1].includes(e.required)||g(`include.required must be a boolean`)})},q=({query:e={},order:t=[],attributes:n=[],include:r=[],page:i=1,perPage:a=20,enrichments:o=[],group:s=[],jsonAttributes:c={}},l,u={})=>{let d=Object.keys(l.rawAttributes),f=Object.keys(l?.associations||{});return!n||n.length===0?n=d:V(n,d),B(t,d,f,u),W(e,d,f,u.additionalAllowedAttributes),U(o,u),H(c,d),Array.isArray(s)||g(`group must be an array`),r.length&&typeof r==`object`?K(r,l?.associations):r&&typeof r!=`object`&&g(`include must be an array`),G({page:i,perPage:a}),!0},{object:J,string:Y,number:X,any:se,array:Z,alternatives:ce}=o.types(),le=n(),ue=J.keys({query:J,attributes:Z.items(Y),order:Z.items(Y),page:X,perPage:X,include:Z.items(se),searchTerm:Y,group:Z.items(Y),enrichments:ce.try(Z.items(Y),J.pattern(Y,{exclude:Z.items(Y)})),jsonAttributes:o.object({select:o.array().items(o.object({columnName:o.string().required(),keys:o.array().items(o.string().required()).required(),alias:o.string().optional()})).default([]),computed:o.array().items(o.object({columnName:o.string().required(),action:o.string().valid(...Object.values(b)).required(),alias:o.string().required()})).default([])}).default({})}),Q=(e,t,n={})=>{let{query:i,attributes:a,order:o,page:s,perPage:c,include:l,group:u,enrichments:d,jsonAttributes:f}=t,p=ue.validate(t);if(p.error)throw new r([p.error]);q({query:i,attributes:a,order:o,page:s,perPage:c,include:l,enrichments:d,group:u,jsonAttributes:f},e,n)},de=(e,t={},n=`body`)=>(r,i,o)=>{try{Q(e,r[n],t),o()}catch(e){let{query:o,attributes:s,order:c}=r[n];a(e,i,{logger:t.logger??le,message:`error in query middleware`,payload:{error:e,query:o,attributes:s,order:c}})}},$=(e,t,n={})=>{let{order:r,page:i,perPage:a,include:o,query:s,attributes:c,searchTerm:l,jsonAttributes:u}=t,{query:d,externalQueryValues:f,order:p,page:m,perPage:h,include:g,scopes:_,attributes:v}=ae({query:s,order:r,page:i,perPage:a,include:o,attributes:c,searchTerm:l,jsonAttributes:u},e,n);t.query=d,t.externalQueryValues=f,t.order=p,t.attributes=v,t.page=m,t.perPage=h,t.include=g,t.scopes=_,n.includeRawPayload&&(t.rawPayload={order:r,page:i,perPage:a,include:o,query:s,attributes:c,searchTerm:l})},fe=(e,t={},n=`body`)=>(r,i,a)=>{$(e,r[n],t),a()},pe=({model:e,logger:t,validationOptions:n,formatOptions:r,modelName:o=e.constructor?.name,additionalScopes:s=[],modifyQueryValues:c,onRowsRetrieved:l})=>async(u,d)=>{try{Q(e,u.body,{...n,logger:t})}catch(e){let n=y(u.body,[`query`,`order`,`attributes`]);a(e,d,{logger:t,message:`error in query endpoint`,payload:n});return}try{$(e,u.body,r);let n=Object.assign(y(u.body,[`query`,`externalQueryValues`,`order`,`attributes`,`page`,`perPage`,`include`,`scopes`,`enrichments`]),{distinct:!0});t.info(`querying ${o}`,{queryValues:n});let i=c?.(n)??n,{scopes:a=[],query:f,perPage:p,page:m,enrichments:h,externalQueryValues:g,..._}=i,v=await e.scope([...s,...a]).findAndCountAll({where:f,limit:p,offset:(m-1)*p,..._});if(!v.rows.length||!l){d.json(v);return}let b=await l(v,i);d.json(b)}catch(e){a(new i(e),d,{logger:t,message:`Error while querying ${o}`,payload:{query:u.body}})}};export{d as formatOperators,A as generateFilterReplacements,fe as queryFormatMiddleware,pe as queryHandler,de as queryValidationMiddleware,q as validatePayload};
2
2
  //# sourceMappingURL=index.js.map