1
- import { Injectable , Optional , Inject } from '@angular/core' ;
1
+ import { Injectable , Inject } from '@angular/core' ;
2
2
import { Observable , ReplaySubject , fromEvent , of , throwError , race } from 'rxjs' ;
3
3
import { map , mergeMap , first , tap , filter } from 'rxjs/operators' ;
4
4
5
5
import { LocalDatabase } from './local-database' ;
6
- import { PREFIX , IDB_DB_NAME , DEFAULT_IDB_DB_NAME , IDB_STORE_NAME , DEFAULT_IDB_STORE_NAME } from '../tokens' ;
6
+ import {
7
+ PREFIX , IDB_DB_NAME , DEFAULT_IDB_DB_NAME , IDB_STORE_NAME , DEFAULT_IDB_STORE_NAME ,
8
+ COMPATIBILITY_PRIOR_TO_V8 , DEFAULT_PREFIX , DEFAULT_COMPATIBILITY_PRIOR_TO_V8
9
+ } from '../tokens' ;
7
10
import { IDBBrokenError } from '../exceptions' ;
8
11
9
12
@Injectable ( {
@@ -14,18 +17,23 @@ export class IndexedDBDatabase implements LocalDatabase {
14
17
/**
15
18
* `indexedDB` database name
16
19
*/
17
- protected dbName : string ;
20
+ private readonly dbName : string ;
18
21
19
22
/**
20
23
* `indexedDB` object store name
21
24
*/
22
- protected storeName : string ;
25
+ private readonly storeName : string ;
23
26
24
27
/**
25
28
* `indexedDB` data path name for local storage (where items' value will be stored)
26
29
*/
27
30
private readonly dataPath = 'value' ;
28
31
32
+ /**
33
+ * Flag to keep storing behavior prior to version 8.
34
+ */
35
+ private readonly compatibilityPriorToV8 : boolean ;
36
+
29
37
/**
30
38
* `indexedDB` database connection, wrapped in a RxJS `ReplaySubject` to be able to access the connection
31
39
* even after the connection success event happened
@@ -59,11 +67,13 @@ export class IndexedDBDatabase implements LocalDatabase {
59
67
* @param prefix Optional user prefix to avoid collision for multiple apps on the same subdomain
60
68
* @param dbName `indexedDB` database name
61
69
* @param storeName `indexedDB` store name
70
+ * @param compatibilityPriorToV8 Flag to keep storing behavior prior to version 8
62
71
*/
63
72
constructor (
64
- @Optional ( ) @Inject ( PREFIX ) prefix : string | null = null ,
65
- @Optional ( ) @Inject ( IDB_DB_NAME ) dbName = DEFAULT_IDB_DB_NAME ,
66
- @Optional ( ) @Inject ( IDB_STORE_NAME ) storeName = DEFAULT_IDB_STORE_NAME ,
73
+ @Inject ( PREFIX ) prefix = DEFAULT_PREFIX ,
74
+ @Inject ( IDB_DB_NAME ) dbName = DEFAULT_IDB_DB_NAME ,
75
+ @Inject ( IDB_STORE_NAME ) storeName = DEFAULT_IDB_STORE_NAME ,
76
+ @Inject ( COMPATIBILITY_PRIOR_TO_V8 ) compatibilityPriorToV8 = DEFAULT_COMPATIBILITY_PRIOR_TO_V8 ,
67
77
) {
68
78
69
79
/* Initialize `indexedDB` database name, with prefix if provided by the user */
@@ -72,8 +82,10 @@ export class IndexedDBDatabase implements LocalDatabase {
72
82
/* Initialize `indexedDB` store name */
73
83
this . storeName = storeName ;
74
84
85
+ this . compatibilityPriorToV8 = compatibilityPriorToV8 ;
86
+
75
87
/* Creating the RxJS ReplaySubject */
76
- this . database = new ReplaySubject < IDBDatabase > ( ) ;
88
+ this . database = new ReplaySubject < IDBDatabase > ( 1 ) ;
77
89
78
90
/* Connect to `indexedDB`, with prefix if provided by the user */
79
91
this . connect ( ) ;
@@ -97,24 +109,20 @@ export class IndexedDBDatabase implements LocalDatabase {
97
109
/* Manage success and error events, and get the result */
98
110
return this . requestEventsAndMapTo ( request , ( ) => {
99
111
100
- /* Currently, the lib is wrapping the value in a `{ value: ... }` object, so test this case */
101
- // TODO: add a check to see if the object has only one key
102
- // TODO: stop wrapping
103
- if ( ( request . result !== undefined )
112
+ if ( ! this . compatibilityPriorToV8 && ( request . result !== undefined ) && ( request . result !== null ) ) {
113
+
114
+ /* Cast to the wanted type */
115
+ return request . result as T ;
116
+
117
+ } else if ( this . compatibilityPriorToV8
118
+ && ( request . result !== undefined )
104
119
&& ( request . result !== null )
105
- && ( typeof request . result === 'object' )
106
- && ( this . dataPath in request . result )
107
120
&& ( request . result [ this . dataPath ] !== undefined )
108
121
&& ( request . result [ this . dataPath ] !== null ) ) {
109
122
110
- /* If so, unwrap the value and cast it to the wanted type */
123
+ /* Prior to v8, the value was wrapped in an `{ value: ...}` object */
111
124
return ( request . result [ this . dataPath ] as T ) ;
112
125
113
- } else if ( ( request . result !== undefined ) && ( request . result !== null ) ) {
114
-
115
- /* Otherwise, return the value directly, casted to the wanted type */
116
- return request . result as T ;
117
-
118
126
}
119
127
120
128
/* Return `null` if the value is `null` or `undefined` */
@@ -165,11 +173,13 @@ export class IndexedDBDatabase implements LocalDatabase {
165
173
* otherwise it could lead to concurrency failures
166
174
* Avoid https://github.com/cyrilletuzi/angular-async-local-storage/issues/47 */
167
175
176
+ /* Prior to v8, data was wrapped in a `{ value: ... }` object */
177
+ const dataToStore = ! this . compatibilityPriorToV8 ? data : { [ this . dataPath ] : data } ;
178
+
168
179
/* Add if the item is not existing yet, or update otherwise */
169
- // TODO: stop wrapping
170
180
const request2 = ( existingEntry === undefined ) ?
171
- store . add ( { [ this . dataPath ] : data } , key ) :
172
- store . put ( { [ this . dataPath ] : data } , key ) ;
181
+ store . add ( dataToStore , key ) :
182
+ store . put ( dataToStore , key ) ;
173
183
174
184
/* Manage success and error events, and map to `true` */
175
185
return this . requestEventsAndMapTo ( request2 , ( ) => true ) ;
0 commit comments