@@ -28,6 +28,10 @@ import {
28
28
UriInfo
29
29
} from './interfaces' ;
30
30
31
+ export interface IDictionary {
32
+ [ index : string ] : string ;
33
+ }
34
+
31
35
/**
32
36
* Base clas
F438
s for in-memory web api back-ends
33
37
* Simulate the behavior of a RESTy web api
@@ -36,6 +40,7 @@ import {
36
40
* http://www.restapitutorial.com/lessons/httpmethods.html
37
41
*/
38
42
export abstract class BackendService {
43
+ protected fieldIds = { } as IDictionary ;
39
44
protected config : InMemoryBackendConfigArgs = new InMemoryBackendConfig ( ) ;
40
45
protected db : Object ;
41
46
protected dbReadySubject : BehaviorSubject < boolean > ;
@@ -211,28 +216,28 @@ export abstract class BackendService {
211
216
212
217
protected collectionHandler ( reqInfo : RequestInfo ) : ResponseOptions {
213
218
// const req = reqInfo.req;
214
- let resOptions : ResponseOptions ;
215
- switch ( reqInfo . method ) {
216
- case 'get' :
217
- resOptions = this . get ( reqInfo ) ;
218
- break ;
219
- case 'post' :
220
- resOptions = this . post ( reqInfo ) ;
221
- break ;
222
- case 'put' :
223
- resOptions = this . put ( reqInfo ) ;
224
- break ;
225
- case 'delete' :
226
- resOptions = this . delete ( reqInfo ) ;
227
- break ;
228
- default :
229
- resOptions = this . createErrorResponseOptions ( reqInfo . url , STATUS . METHOD_NOT_ALLOWED , 'Method not allowed' ) ;
230
- break ;
231
- }
219
+ let resOptions : ResponseOptions ;
220
+ switch ( reqInfo . method ) {
221
+ case 'get' :
222
+ resOptions = this . get ( reqInfo ) ;
223
+ break ;
224
+ case 'post' :
225
+ resOptions = this . post ( reqInfo ) ;
226
+ break ;
227
+ case 'put' :
228
+ resOptions = this . put ( reqInfo ) ;
229
+ break ;
230
+ case 'delete' :
231
+ resOptions = this . delete ( reqInfo ) ;
232
+ break ;
233
+ default :
234
+ resOptions = this . createErrorResponseOptions ( reqInfo . url , STATUS . METHOD_NOT_ALLOWED , 'Method not allowed' ) ;
235
+ break ;
236
+ }
232
237
233
- // If `inMemDbService.responseInterceptor` exists, let it morph the response options
234
- const interceptor = this . bind ( 'responseInterceptor' ) ;
235
- return interceptor ? interceptor ( resOptions , reqInfo ) : resOptions ;
238
+ // If `inMemDbService.responseInterceptor` exists, let it morph the response options
239
+ const interceptor = this . bind ( 'responseInterceptor' ) ;
240
+ return interceptor ? interceptor ( resOptions , reqInfo ) : resOptions ;
236
241
}
237
242
238
243
/**
@@ -272,7 +277,7 @@ export abstract class BackendService {
272
277
resOptions . status = STATUS . OK ;
273
278
resOptions . body = this . clone ( this . config ) ;
274
279
275
- // any other HTTP method is assumed to be a config update
280
+ // any other HTTP method is assumed to be a config update
276
281
} else {
277
282
const body = this . getJsonBody ( reqInfo . req ) ;
278
283
Object . assign ( this . config , body ) ;
@@ -381,7 +386,32 @@ export abstract class BackendService {
381
386
* @param id
382
387
*/
383
388
protected findById < T extends { id : any } > ( collection : T [ ] , id : any ) : T {
384
- return collection . find ( ( item : T ) => item . id === id ) ;
389
+ return collection . find ( ( item : T ) => this . getItemId ( item ) === id ) ;
390
+ }
391
+
392
+ /**
393
+ * define for your in-mem database what is the name of your id field
394
+ * return the name of the id field
395
+ */
396
+ protected defineId ( collectionName = 'default_id' ) : string {
397
+ const defineId = this . bind ( 'defineId' ) ;
398
+ if ( defineId ) {
399
+ const id = defineId ( collectionName ) ;
400
+ if ( ( id !== undefined ) && id !== '' ) { return id ; }
401
+ }
402
+ return 'id' ;
403
+ }
404
+
405
+ protected getItemId < T extends { id : any } > ( item : T , collectionName = 'default_id' ) : any {
406
+ return item [ this . fieldIds [ collectionName ] ] ;
407
+ }
408
+
409
+ protected setItemId < T extends { id : any } > ( item : T , id : any , collectionName = 'default_id' ) : any {
410
+ return item [ this . fieldIds [ collectionName ] ] = id ;
411
+ }
412
+
413
+ protected setFieldId ( id : any , collectionName = 'default_id' ) {
414
+ this . fieldIds [ collectionName ] = this . defineId ( collectionName ) ;
385
415
}
386
416
387
417
/**
@@ -414,7 +444,7 @@ export abstract class BackendService {
414
444
415
445
let maxId = 0 ;
416
446
collection . reduce ( ( prev : any , item : any ) => {
417
- maxId = Math . max ( maxId , typeof item . id === 'number' ? item . id : maxId ) ;
447
+ maxId = Math . max ( maxId , typeof this . getItemId ( item ) === 'number' ? this . getItemId ( item ) : maxId ) ;
418
448
} , undefined ) ;
419
449
return maxId + 1 ;
420
450
}
@@ -493,7 +523,7 @@ export abstract class BackendService {
493
523
protected abstract getRequestMethod ( req : any ) : string ;
494
524
495
525
protected indexOf ( collection : any [ ] , id : number ) {
496
- return collection . findIndex ( ( item : any ) => item . id === id ) ;
526
+ return collection . findIndex ( ( item : any ) => this . getItemId ( item ) === id ) ;
497
527
}
498
528
499
529
/** Parse the id as a number. Return original value if not a number. */
@@ -588,9 +618,9 @@ export abstract class BackendService {
588
618
const item = this . getJsonBody ( req ) ;
589
619
590
620
// tslint:disable-next-line:triple-equals
591
- if ( item . id == undefined ) {
621
+ if ( this . getItemId ( item ) == undefined ) {
592
622
try {
593
- item . id = id || this . genId ( collection , collectionName ) ;
623
+ this . setItemId ( item , id || this . genId ( collection , collectionName ) ) ;
594
624
} catch ( err ) {
595
625
const emsg : string = err . message || '' ;
596
626
if ( / i d t y p e i s n o n - n u m e r i c / . test ( emsg ) ) {
@@ -603,10 +633,10 @@ export abstract class BackendService {
603
633
}
604
634
}
605
635
606
- if ( id && id !== item . id ) {
636
+ if ( id && id !== this . getItemId ( item ) ) {
607
637
return this . createErrorResponseOptions ( url , STATUS . BAD_REQUEST , `Request id does not match item.id` ) ;
608
638
} else {
609
- id = item . id ;
639
+ id = this . getItemId ( item ) ;
610
640
}
611
641
const existingIx = this . indexOf ( collection , id ) ;
612
642
const body = this . bodify ( item ) ;
@@ -621,8 +651,8 @@ export abstract class BackendService {
621
651
} else {
622
652
collection [ existingIx ] = item ;
623
653
return this . config . post204 ?
624
- { headers, status : STATUS . NO_CONTENT } : // successful; no content
625
- { headers, body, status : STATUS . OK } ; // successful; return entity
654
+ { headers, status : STATUS . NO_CONTENT } : // successful; no content
655
+ { headers, body, status : STATUS . OK } ; // successful; return entity
626
656
}
627
657
}
628
658
@@ -631,23 +661,23 @@ export abstract class BackendService {
631
661
protected put ( { collection, collectionName, headers, id, req, url } : RequestInfo ) : ResponseOptions {
632
662
const item = this . getJsonBody ( req ) ;
633
663
// tslint:disable-next-line:triple-equals
634
- if ( item . id == undefined ) {
664
+ if ( this . getItemId ( item ) == undefined ) {
635
665
return this . createErrorResponseOptions ( url , STATUS . NOT_FOUND , `Missing '${ collectionName } ' id` ) ;
636
666
}
637
- if ( id && id !== item . id ) {
667
+ if ( id && id !== this . getItemId ( item ) ) {
638
668
return this . createErrorResponseOptions ( url , STATUS . BAD_REQUEST ,
639
669
`Request for '${ collectionName } ' id does not match item.id` ) ;
640
670
} else {
641
- id = item . id ;
671
+ id = this . getItemId ( item ) ;
642
672
}
643
673
const existingIx = this . indexOf ( collection , id ) ;
644
674
const body = this . bodify ( item ) ;
645
675
646
676
if ( existingIx > - 1 ) {
647
677
collection [ existingIx ] = item ;
648
678
return this . config . put204 ?
649
- { headers, status : STATUS . NO_CONTENT } : // successful; no content
650
- { headers, body, status : STATUS . OK } ; // successful; return entity
679
+ { headers, status : STATUS . NO_CONTENT } : // successful; no content
680
+ { headers, body, status : STATUS . OK } ; // successful; return entity
651
681
} else if ( this . config . put404 ) {
652
682
// item to update not found; use POST to create new item for this id.
653
683
return this . createErrorResponseOptions ( url , STATUS . NOT_FOUND ,
@@ -676,12 +706,15 @@ export abstract class BackendService {
676
706
this . dbReadySubject . next ( false ) ;
677
707
const db = this . inMemDbService . createDb ( reqInfo ) ;
678
708
const db$ = db instanceof Observable ? db :
679
- isPromise ( db ) ? fromPromise ( db ) :
680
- of ( db ) ;
709
+ isPromise ( db ) ? fromPromise ( db ) :
710
+ of ( db ) ;
681
711
first . call ( db$ ) . subscribe ( ( d : { } ) => {
682
712
this . db = d ;
683
713
this . dbReadySubject . next ( true ) ;
684
714
} ) ;
715
+
716
+ this . setFieldId ( this . defineId ( ) ) ;
717
+
685
718
return this . dbReady ;
686
719
}
687
720
0 commit comments