@@ -51,31 +51,20 @@ export type GroupBy<T> = {
51
51
transform ?: Transform < T > ;
52
52
}
53
53
54
- export type Value = {
55
- type : 'raw' | 'guid' | 'duration' | 'binary' | 'json' | 'alias' ;
56
- value : any ;
57
- }
58
-
59
- export type Alias = Value & {
60
- name : string ;
61
- handleName ( ) : string ;
62
- handleValue ( ) : string ;
63
- }
64
-
65
- export const raw = ( value : string ) : Value => ( { type : 'raw' , value} ) ;
66
- export const guid = ( value : string ) : Value => ( { type : 'guid' , value} ) ;
67
- export const duration = ( value : string ) : Value => ( { type : 'duration' , value} ) ;
68
- export const binary = ( value : string ) : Value => ( { type : 'binary' , value} ) ;
69
- export const json = ( value : PlainObject ) : Value => ( { type : 'json' , value} ) ;
70
- export const alias = ( name : string , value : PlainObject ) : Alias => ( {
71
- type : 'alias' , name, value,
72
- handleName ( ) {
73
- return `@${ this . name } ` ;
74
- } ,
75
- handleValue ( ) {
76
- return handleValue ( this . value ) ;
77
- }
78
- } ) ;
54
+ export type Raw = { type : 'raw' ; value : any ; }
55
+ export type Guid = { type : 'guid' ; value : any ; }
56
+ export type Duration = { type : 'duration' ; value : any ; }
57
+ export type Binary = { type : 'binary' ; value : any ; }
58
+ export type Json = { type : 'json' ; value : any ; }
59
+ export type Alias = { type : 'alias' ; name : string ; value : any ; }
60
+ export type Value = string | Date | number | boolean | Raw | Guid | Duration | Binary | Json | Alias ;
61
+
62
+ export const raw = ( value : string ) : Raw => ( { type : 'raw' , value } ) ;
63
+ export const guid = ( value : string ) : Guid => ( { type : 'guid' , value } ) ;
64
+ export const duration = ( value : string ) : Duration => ( { type : 'duration' , value } ) ;
65
+ export const binary = ( value : string ) : Binary => ( { type : 'binary' , value } ) ;
66
+ export const json = ( value : PlainObject ) : Json => ( { type : 'json' , value } ) ;
67
+ export const alias = ( name : string , value : PlainObject ) : Alias => ( { type : 'alias' , name, value } ) ;
79
68
80
69
export type QueryOptions < T > = ExpandOptions < T > & {
81
70
search : string ;
@@ -106,26 +95,20 @@ export default function <T>({
106
95
count,
107
96
expand,
108
97
action,
109
- func,
110
- aliases
98
+ func
111
99
} : Partial < QueryOptions < T > > = { } ) {
112
- let path = '' ;
100
+ let path : string = '' ;
101
+ let aliases : Alias [ ] = [ ] ;
113
102
114
103
const params : any = { } ;
115
104
116
- if ( key ) {
117
- if ( typeof key === 'object' ) {
118
- const keys = Object . keys ( key )
119
- . map ( k => `${ k } =${ key [ k ] } ` )
120
- . join ( ',' ) ;
121
- path += `(${ keys } )` ;
122
- } else {
123
- path += `(${ key } )` ;
105
+ // key is not (null, undefined)
106
+ if ( key != undefined ) {
107
+ path += `(${ handleValue ( key as Value , aliases ) } )` ;
124
108
}
125
- }
126
109
127
110
if ( filter || typeof count === 'object' )
128
- params . $filter = buildFilter ( typeof count === 'object' ? count : filter ) ;
111
+ params . $filter = buildFilter ( typeof count === 'object' ? count : filter , aliases ) ;
129
112
130
113
if ( transform )
131
114
params . $apply = buildTransforms ( transform ) ;
@@ -161,43 +144,41 @@ export default function <T>({
161
144
path += `/${ func } ` ;
162
145
} else if ( typeof func === 'object' ) {
163
146
const [ funcName ] = Object . keys ( func ) ;
164
- const funcArgs = Object . keys ( func [ funcName ] ) . reduce (
165
- ( acc : string [ ] , item ) => [ ...acc , `${ item } =${ handleValue ( func [ funcName ] [ item ] ) } ` ] ,
166
- [ ]
167
- ) ;
147
+ const funcArgs = handleValue ( func [ funcName ] as Value , aliases ) ;
168
148
169
149
path += `/${ funcName } ` ;
170
- if ( funcArgs . length ) {
171
- path += `(${ funcArgs . join ( ',' ) } )` ;
150
+ if ( funcArgs !== "" ) {
151
+ path += `(${ funcArgs } )` ;
172
152
}
173
153
}
174
154
}
175
155
176
- if ( aliases ) {
177
- aliases
178
- . reduce ( ( acc , alias ) => Object . assign ( acc , { [ alias . handleName ( ) ] : alias . handleValue ( ) } ) , params ) ;
156
+ if ( aliases . length > 0 ) {
157
+ Object . assign ( params , aliases . reduce ( ( acc , alias ) =>
158
+ Object . assign ( acc , { [ `@${ alias . name } ` ] : handleValue ( alias . value ) } )
159
+ , { } ) ) ;
179
160
}
180
161
181
162
return buildUrl ( path , { $select, $search, $skiptoken, $format, ...params } ) ;
182
163
}
183
164
184
- function renderPrimitiveValue ( key : string , val : any ) {
185
- return `${ key } eq ${ handleValue ( val ) } `
165
+ function renderPrimitiveValue ( key : string , val : any , aliases : Alias [ ] = [ ] ) {
166
+ return `${ key } eq ${ handleValue ( val , aliases ) } `
186
167
}
187
168
188
- function buildFilter ( filters : Filter = { } , propPrefix = '' ) : string {
169
+ function buildFilter ( filters : Filter = { } , aliases : Alias [ ] = [ ] , propPrefix = '' ) : string {
189
170
return ( ( Array . isArray ( filters ) ? filters : [ filters ] )
190
171
. reduce ( ( acc : string [ ] , filter ) => {
191
172
if ( filter ) {
192
- const builtFilter = buildFilterCore ( filter , propPrefix ) ;
173
+ const builtFilter = buildFilterCore ( filter , aliases , propPrefix ) ;
193
174
if ( builtFilter ) {
194
175
acc . push ( builtFilter ) ;
195
176
}
196
177
}
197
178
return acc ;
198
179
} , [ ] ) as string [ ] ) . join ( ' and ' ) ;
199
180
200
- function buildFilterCore ( filter : Filter = { } , propPrefix = '' ) {
181
+ function buildFilterCore ( filter : Filter = { } , aliases : Alias [ ] = [ ] , propPrefix = '' ) {
201
182
let filterExpr = "" ;
202
183
if ( typeof filter === 'string' ) {
203
184
// Use raw filter string
@@ -233,11 +214,11 @@ function buildFilter(filters: Filter = {}, propPrefix = ''): string {
233
214
value === null
234
215
) {
235
216
// Simple key/value handled as equals operator
236
- result . push ( renderPrimitiveValue ( propName , value ) ) ;
217
+ result . push ( renderPrimitiveValue ( propName , value , aliases ) ) ;
237
218
} else if ( Array . isArray ( value ) ) {
238
219
const op = filterKey ;
239
220
const builtFilters = value
240
- . map ( v => buildFilter ( v , propPrefix ) )
221
+ . map ( v => buildFilter ( v , aliases , propPrefix ) )
241
222
. filter ( f => f )
242
223
. map ( f => ( LOGICAL_OPERATORS . indexOf ( op ) !== - 1 ? `(${ f } )` : f ) ) ;
243
224
if ( builtFilters . length ) {
@@ -265,27 +246,29 @@ function buildFilter(filters: Filter = {}, propPrefix = ''): string {
265
246
result . push ( `${ builtFilters . join ( ` ${ op } ` ) } ` ) ;
266
247
}
267
248
}
268
- } else if ( value instanceof Object ) {
249
+ } else if ( typeof value === 'object' ) {
269
250
if ( 'type' in value ) {
270
- result . push ( renderPrimitiveValue ( propName , value ) ) ;
251
+ result . push ( renderPrimitiveValue ( propName , value , aliases ) ) ;
271
252
} else {
272
253
const operators = Object . keys ( value ) ;
273
254
operators . forEach ( op => {
274
255
if ( COMPARISON_OPERATORS . indexOf ( op ) !== - 1 ) {
275
- result . push ( `${ propName } ${ op } ${ handleValue ( value [ op ] ) } ` ) ;
256
+ result . push ( `${ propName } ${ op } ${ handleValue ( value [ op ] , aliases ) } ` ) ;
276
257
} else if ( LOGICAL_OPERATORS . indexOf ( op ) !== - 1 ) {
277
258
if ( Array . isArray ( value [ op ] ) ) {
278
259
result . push (
279
260
value [ op ]
280
- . map ( ( v : any ) => '(' + buildFilterCore ( v , propName ) + ')' )
261
+ . map ( ( v : any ) => '(' + buildFilterCore ( v , aliases , propName ) + ')' )
281
262
. join ( ` ${ op } ` )
282
263
) ;
283
264
} else {
284
- result . push ( '(' + buildFilterCore ( value [ op ] , propName ) + ')' ) ;
265
+ result . push ( '(' + buildFilterCore ( value [ op ] , aliases , propName ) + ')' ) ;
285
266
}
286
267
} else if ( COLLECTION_OPERATORS . indexOf ( op ) !== - 1 ) {
287
268
const collectionClause = buildCollectionClause ( filterKey . toLowerCase ( ) , value [ op ] , op , propName ) ;
288
269
if ( collectionClause ) { result . push ( collectionClause ) ; }
270
+ } else if ( op === 'has' ) {
271
+ result . push ( `${ propName } ${ op } ${ handleValue ( value [ op ] , aliases ) } ` ) ;
289
272
} else if ( op === 'in' ) {
290
273
const resultingValues = Array . isArray ( value [ op ] )
291
274
? value [ op ]
@@ -295,14 +278,14 @@ function buildFilter(filters: Filter = {}, propPrefix = ''): string {
295
278
} ) ) ;
296
279
297
280
result . push (
298
- propName + ' in (' + resultingValues . map ( ( v : any ) => handleValue ( v ) ) . join ( ',' ) + ')'
281
+ propName + ' in (' + resultingValues . map ( ( v : any ) => handleValue ( v , aliases ) ) . join ( ',' ) + ')'
299
282
) ;
300
283
} else if ( BOOLEAN_FUNCTIONS . indexOf ( op ) !== - 1 ) {
301
284
// Simple boolean functions (startswith, endswith, contains)
302
- result . push ( `${ op } (${ propName } ,${ handleValue ( value [ op ] ) } )` ) ;
285
+ result . push ( `${ op } (${ propName } ,${ handleValue ( value [ op ] , aliases ) } )` ) ;
303
286
} else {
304
287
// Nested property
305
- const filter = buildFilterCore ( value , propName ) ;
288
+ const filter = buildFilterCore ( value , aliases , propName ) ;
306
289
if ( filter ) {
307
290
result . push ( filter ) ;
308
291
}
@@ -347,7 +330,7 @@ function buildFilter(filters: Filter = {}, propPrefix = ''): string {
347
330
return { ...acc , ...item }
348
331
} , { } ) : value ;
349
332
350
- const filter = buildFilterCore ( filterValue , lambdaParameter ) ;
333
+ const filter = buildFilterCore ( filterValue , aliases , lambdaParameter ) ;
351
334
clause = `${ propName } /${ op } (${ filter ? `${ lambdaParameter } :${ filter } ` : '' } )` ;
352
335
}
353
336
return clause ;
@@ -373,36 +356,41 @@ function escapeIllegalChars(string: string) {
373
356
return string ;
374
357
}
375
358
376
- function handleValue ( value : any ) {
359
+ function handleValue ( value : Value , aliases ?: Alias [ ] ) : any {
377
360
if ( typeof value === 'string' ) {
378
361
return `'${ escapeIllegalChars ( value ) } '` ;
379
362
} else if ( value instanceof Date ) {
380
363
return value . toISOString ( ) ;
381
- } else if ( value instanceof Number ) {
364
+ } else if ( typeof value === 'number' ) {
382
365
return value ;
383
366
} else if ( Array . isArray ( value ) ) {
384
- // Double quote strings to keep them after ` .join`
385
- const arr = value . map ( d => ( typeof d === 'string' ? `' ${ d } '` : d ) ) ;
386
- return `[ ${ arr . join ( ',' ) } ]` ;
387
- } else {
388
- // TODO: Figure out how best to specify types. See: https://github.com/devnixs/ODataAngularResources/blob/master/src/odatavalue.js
389
- switch ( value && value . type ) {
390
- case 'guid' :
367
+ return `[ ${ value . map ( d => handleValue ( d ) ) . join ( ',' ) } ]` ;
368
+ } else if ( value === null ) {
369
+ return value ;
370
+ } else if ( typeof value === 'object' ) {
371
+ if ( value . type === 'raw' ) {
372
+ return value . value ;
373
+ } else if ( value . type === 'guid' ) {
391
374
return value . value ;
392
- case 'duration' :
375
+ } else if ( value . type === 'duration' ) {
393
376
return `duration'${ value . value } '` ;
394
- case 'raw' :
395
- return value . value ;
396
- case 'binary' :
377
+ } else if ( value . type === 'binary' ) {
397
378
return `binary'${ value . value } '` ;
398
- case 'alias' :
399
- return ( value as Alias ) . handleName ( ) ;
400
- case 'json' :
379
+ } else if ( value . type === 'alias' ) {
380
+ // Store
381
+ if ( Array . isArray ( aliases ) )
382
+ aliases . push ( value as Alias ) ;
383
+ return `@${ ( value as Alias ) . name } ` ;
384
+ } else if ( value . type === 'json' ) {
401
385
return escape ( JSON . stringify ( value . value ) ) ;
386
+ } else {
387
+ return Object . entries ( value )
388
+ . filter ( ( [ , v ] ) => v !== undefined )
389
+ . map ( ( [ k , v ] ) => `${ k } =${ handleValue ( v as Value , aliases ) } ` ) . join ( ',' ) ;
390
+ }
402
391
}
403
392
return value ;
404
393
}
405
- }
406
394
407
395
function buildExpand < T > ( expands : Expand < T > ) : string {
408
396
if ( typeof expands === 'number' ) {
0 commit comments