@autofleet/sheilta 2.2.1-beta-576f10d3.0 → 2.2.1

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