entropic-bond 1.50.0 → 1.50.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.
Files changed (111) hide show
  1. package/lib/auth/auth-mock.d.ts +22 -0
  2. package/lib/auth/auth-mock.spec.d.ts +1 -0
  3. package/lib/auth/auth.d.ts +131 -0
  4. package/lib/auth/user-auth-types.d.ts +19 -0
  5. package/lib/cloud-functions/cloud-functions-mock.d.ts +11 -0
  6. package/lib/cloud-functions/cloud-functions-mock.spec.d.ts +1 -0
  7. package/lib/cloud-functions/cloud-functions.d.ts +19 -0
  8. package/lib/cloud-storage/cloud-storage.d.ts +24 -0
  9. package/lib/cloud-storage/cloud-storage.spec.d.ts +1 -0
  10. package/lib/cloud-storage/mock-cloud-storage.d.ts +20 -0
  11. package/lib/cloud-storage/stored-file.d.ts +39 -0
  12. package/lib/entropic-bond.js +1667 -0
  13. package/lib/entropic-bond.umd.cjs +7 -0
  14. package/lib/index.d.ts +19 -0
  15. package/lib/observable/observable.d.ts +52 -0
  16. package/lib/observable/observable.spec.d.ts +1 -0
  17. package/lib/persistent/entropic-component.d.ts +76 -0
  18. package/lib/persistent/entropic-component.spec.d.ts +1 -0
  19. package/lib/persistent/persistent.d.ts +281 -0
  20. package/lib/persistent/persistent.spec.d.ts +67 -0
  21. package/lib/server-auth/server-auth-mock.d.ts +12 -0
  22. package/lib/server-auth/server-auth-mock.spec.d.ts +1 -0
  23. package/lib/server-auth/server-auth.d.ts +24 -0
  24. package/lib/store/data-source.d.ts +137 -0
  25. package/lib/store/json-data-source.d.ts +68 -0
  26. package/lib/store/json-data-source.spec.d.ts +1 -0
  27. package/lib/store/mocks/test-user.d.ts +49 -0
  28. package/lib/store/model.d.ts +238 -0
  29. package/lib/store/model.spec.d.ts +1 -0
  30. package/lib/store/store.d.ts +62 -0
  31. package/lib/store/store.spec.d.ts +1 -0
  32. package/lib/types/utility-types.d.ts +45 -0
  33. package/lib/types/utility-types.spec.d.ts +1 -0
  34. package/lib/utils/test-utils/test-person.d.ts +33 -0
  35. package/{src/utils/utils.ts → lib/utils/utils.d.ts} +10 -34
  36. package/lib/utils/utils.spec.d.ts +1 -0
  37. package/package.json +7 -4
  38. package/.github/workflows/release.yml +0 -26
  39. package/CHANGELOG.md +0 -1151
  40. package/docs/.nojekyll +0 -1
  41. package/docs/README.md +0 -94
  42. package/docs/classes/Auth.md +0 -391
  43. package/docs/classes/AuthMock.md +0 -278
  44. package/docs/classes/AuthService.md +0 -188
  45. package/docs/classes/CloudFunctions.md +0 -123
  46. package/docs/classes/CloudFunctionsMock.md +0 -97
  47. package/docs/classes/CloudStorage.md +0 -215
  48. package/docs/classes/DataSource.md +0 -248
  49. package/docs/classes/EntropicComponent.md +0 -666
  50. package/docs/classes/JsonDataSource.md +0 -328
  51. package/docs/classes/MockCloudStorage.md +0 -279
  52. package/docs/classes/Model.md +0 -274
  53. package/docs/classes/Observable.md +0 -120
  54. package/docs/classes/Persistent.md +0 -420
  55. package/docs/classes/ServerAuth.md +0 -211
  56. package/docs/classes/ServerAuthMock.md +0 -176
  57. package/docs/classes/ServerAuthService.md +0 -130
  58. package/docs/classes/Store.md +0 -218
  59. package/docs/classes/StoredFile.md +0 -636
  60. package/docs/enums/StoredFileEvent.md +0 -41
  61. package/docs/interfaces/AuthError.md +0 -30
  62. package/docs/interfaces/CloudFunctionsService.md +0 -69
  63. package/docs/interfaces/Collection.md +0 -13
  64. package/docs/interfaces/CustomCredentials.md +0 -7
  65. package/docs/interfaces/DocumentReference.md +0 -49
  66. package/docs/interfaces/JsonRawData.md +0 -7
  67. package/docs/interfaces/SignData.md +0 -63
  68. package/docs/interfaces/StoreParams.md +0 -52
  69. package/docs/interfaces/StoredFileChange.md +0 -41
  70. package/docs/interfaces/UploadControl.md +0 -90
  71. package/docs/interfaces/UserCredentials.md +0 -113
  72. package/docs/interfaces/Values.md +0 -17
  73. package/docs/modules.md +0 -1273
  74. package/src/auth/auth-mock.spec.ts +0 -168
  75. package/src/auth/auth-mock.ts +0 -129
  76. package/src/auth/auth.ts +0 -185
  77. package/src/auth/user-auth-types.ts +0 -21
  78. package/src/cloud-functions/cloud-functions-mock.spec.ts +0 -136
  79. package/src/cloud-functions/cloud-functions-mock.ts +0 -23
  80. package/src/cloud-functions/cloud-functions.ts +0 -83
  81. package/src/cloud-storage/cloud-storage.spec.ts +0 -207
  82. package/src/cloud-storage/cloud-storage.ts +0 -60
  83. package/src/cloud-storage/mock-cloud-storage.ts +0 -72
  84. package/src/cloud-storage/stored-file.ts +0 -102
  85. package/src/index.ts +0 -19
  86. package/src/observable/observable.spec.ts +0 -105
  87. package/src/observable/observable.ts +0 -67
  88. package/src/persistent/entropic-component.spec.ts +0 -143
  89. package/src/persistent/entropic-component.ts +0 -135
  90. package/src/persistent/persistent.spec.ts +0 -828
  91. package/src/persistent/persistent.ts +0 -650
  92. package/src/server-auth/server-auth-mock.spec.ts +0 -53
  93. package/src/server-auth/server-auth-mock.ts +0 -45
  94. package/src/server-auth/server-auth.ts +0 -49
  95. package/src/store/data-source.ts +0 -186
  96. package/src/store/json-data-source.spec.ts +0 -100
  97. package/src/store/json-data-source.ts +0 -256
  98. package/src/store/mocks/mock-data.json +0 -155
  99. package/src/store/mocks/test-user.ts +0 -122
  100. package/src/store/model.spec.ts +0 -659
  101. package/src/store/model.ts +0 -462
  102. package/src/store/store.spec.ts +0 -30
  103. package/src/store/store.ts +0 -113
  104. package/src/types/utility-types.spec.ts +0 -117
  105. package/src/types/utility-types.ts +0 -116
  106. package/src/utils/test-utils/test-person.ts +0 -44
  107. package/src/utils/utils.spec.ts +0 -95
  108. package/tsconfig-build.json +0 -7
  109. package/tsconfig-cjs.json +0 -9
  110. package/tsconfig.json +0 -33
  111. package/vite.config.ts +0 -22
@@ -1,462 +0,0 @@
1
- import { Persistent, PersistentObject } from '../persistent/persistent'
2
- import { ClassPropNames, PropPath, PropPathType } from '../types/utility-types'
3
- import { DataSource, QueryOperator, QueryObject, QueryOrder, DocumentObject, QueryOperation } from './data-source'
4
-
5
- /**
6
- * Provides abstraction to the database access. You should gain access to a Model
7
- * object through the Store.getModel method instead of its constructor.
8
- */
9
- export class Model<T extends Persistent>{
10
- static error = {
11
- persistentNeedForSubCollection: 'The document parameter for a sub-collection should be a Persistent instace',
12
- invalidQueryOrder: 'Cannot add where calls after or calls'
13
- }
14
-
15
- constructor( stream: DataSource, persistentClass: Persistent | string, subCollection?: string ) {
16
- if ( subCollection ) {
17
- if( !( persistentClass instanceof Persistent ) ) throw new Error( Model.error.persistentNeedForSubCollection )
18
-
19
- this.collectionName = `${ persistentClass.className }/${ persistentClass.id }/${ subCollection }`
20
- }
21
- else {
22
- this.collectionName = persistentClass instanceof Persistent
23
- ? persistentClass.className
24
- : persistentClass
25
- }
26
-
27
- this._stream = stream
28
- }
29
-
30
- /**
31
- * Finds an stored object in the database by its id. The field id is provided
32
- * by the Persistent parent class and it is automatically managed. Therefore,
33
- * you should obtain the id by looking at the id field of the object.
34
- *
35
- * @param id the id to look for
36
- * @param instance you can pass an instace that will be filled with the found data
37
- * @returns a promise resolving to an instance with the found data
38
- */
39
- findById<D extends T>( id: string, instance?: D ): Promise<D | undefined> {
40
- return new Promise<D | undefined>( ( resolve, reject ) => {
41
- this._stream.findById( id, this.collectionName )
42
- .then(( data: PersistentObject<D> ) => {
43
- if ( data ) {
44
-
45
- if ( !instance ) instance = Persistent.createInstance( data )
46
- else instance.fromObject( data )
47
-
48
- resolve( instance )
49
- }
50
- else resolve( undefined )
51
- })
52
- .catch( error => reject( error ) )
53
- })
54
- }
55
-
56
- /**
57
- * Stores an object in the database
58
- *
59
- * @param instance the object instance to store
60
- * @returns a promise
61
- */
62
- save( instance: T ): Promise<void> {
63
- const obj = instance.toObject() as PersistentObject<T> & { __rootCollections: DocumentObject }
64
-
65
- if ( this.collectionName !== obj.__className ) {
66
- obj.__rootCollections[ this.collectionName ] = obj.__rootCollections[ obj.__className ]
67
- delete obj.__rootCollections[ obj.__className ]
68
- }
69
-
70
- return new Promise<void>( ( resolve, reject ) => {
71
- this._stream.save( obj.__rootCollections )
72
- .then( () => resolve() )
73
- .catch( error => reject( error ) )
74
- })
75
- }
76
-
77
- /**
78
- * Removes an element from the database by id
79
- * @param id the id of the element to be removed
80
- * @returns a promise
81
- */
82
- delete( id: string ): Promise<void> {
83
- return new Promise<void>( ( resolve, reject ) => {
84
- this._stream.delete( id, this.collectionName )
85
- .then( () => resolve() )
86
- .catch( error => reject( error ) )
87
- })
88
- }
89
-
90
- /**
91
- * Call find to retrieve a Query object used to define the search conditions
92
- * @returns a Query object
93
- */
94
- find<U extends T>(): Query<U> {
95
- return new Query<U>( this as unknown as Model<U> )
96
- }
97
-
98
- /**
99
- * Define the search conditions. You pass query operations and how the query
100
- * results are returned to the QueryObject
101
- * @param queryObject the QueryObject with the search constrains
102
- * @param objectType Deprecated! - restricts the search to a specific instances of the class type
103
- * @returns a promise resolving to a collection of matched documents
104
- */
105
- query<U extends T>( queryObject: QueryObject<U> = {}, /** @deprecated */ objectType?: U | string ): Promise<U[]> {
106
- if ( objectType ) {
107
- const className = objectType instanceof Persistent ? objectType.className : objectType
108
- if ( !queryObject.operations ) queryObject.operations = []
109
- queryObject.operations.push(
110
- { property: '__className', operator: '==', value: className } as any
111
- )
112
- }
113
-
114
- return this.mapToInstance(
115
- () => this._stream.find( this.preprocessQueryObject( queryObject ), this.collectionName )
116
- )
117
- }
118
-
119
- /**
120
- * Get the amount of documents matching the query
121
- * @param queryObject the QueryObject with the search constrains
122
- * @returns a promise resolving to the amount of matched documents
123
- */
124
- count( queryObject: QueryObject<T> ): Promise<number> {
125
- return this._stream.count( queryObject as unknown as QueryObject<DocumentObject>, this.collectionName )
126
- }
127
-
128
- /**
129
- * Get the next bunch of documents matching the last query
130
- * @param limit the max amount of documents to retrieve. If not set, uses the
131
- * last limit set
132
- * @returns a promise resolving to a collection of matched documents
133
- */
134
- next<U extends T>( limit?: number ): Promise<U[]> {
135
- return this.mapToInstance( () => this._stream.next( limit ) )
136
- }
137
-
138
- // /**
139
- // * Get the previous bunch of documents matching the last query
140
- // * @param limit the max amount of documents to retrieve. If not set, uses the
141
- // * last limit set
142
- // * @returns a promise resolving to a collection of matched documents
143
- // */
144
- // prev<U extends T>( limit?: number ): Promise<U[]> {
145
- // return this.mapToInstance( () => this._stream.prev( limit ) )
146
- // }
147
-
148
- private mapToInstance<U extends T>( from: ()=>Promise<DocumentObject[]> ): Promise<U[]> {
149
- return new Promise<U[]>( ( resolve, reject ) => {
150
- from()
151
- .then( data => resolve(
152
- data.map( obj => Persistent.createInstance( obj as any ))
153
- ))
154
- .catch( error => reject( error ) )
155
- })
156
- }
157
-
158
- /**
159
- * Normalizes the query object to match the data source requirements.
160
- * Call this method before you do any query operation on the concrete data source
161
- * @param queryObject the query object containing the query operations
162
- * @param operatorConversor a function that converts the query operators to the
163
- * operators supported by the concrete data source
164
- * @returns the normalized query object
165
- */
166
- private preprocessQueryObject<U>( queryObject: QueryObject<U> ): QueryObject<DocumentObject> {
167
- if ( Object.values( queryObject ).length === 0 ) return queryObject as unknown as QueryObject<DocumentObject>
168
-
169
- const operations = queryObject.operations?.map( operation => {
170
- const value = operation.value[0] ?? operation.value
171
-
172
- if ( DataSource.isArrayOperator( operation.operator ) && value instanceof Persistent ) {
173
- return {
174
- property: Persistent.searchableArrayNameFor( operation.property as string ),
175
- operator: operation.operator,
176
- value: Array.isArray( operation.value )? operation.value.map( v => v.id ) : value.id,
177
- aggregate: operation.aggregate
178
- }
179
- }
180
- else {
181
- return {
182
- property: operation.property,
183
- operator: operation.operator,
184
- value: operation.value instanceof Persistent ? { id: operation.value.id } : operation.value,
185
- aggregate: operation.aggregate
186
- }
187
- }
188
- }) ?? []
189
-
190
- return {
191
- ...queryObject,
192
- operations
193
- } as QueryObject<DocumentObject>
194
- }
195
-
196
- readonly collectionName: string
197
- private _stream: DataSource
198
- }
199
-
200
- /**
201
- * The Query class is used to define the search conditions. You can chain
202
- * where operations to define the search conditions. The where operations
203
- * are stored in a QueryObject that is passed to the query method of the
204
- * Model class.
205
- */
206
- export class Query<T extends Persistent> {
207
- constructor( model: Model<T> ) {
208
- this.model = model
209
- }
210
-
211
- /**
212
- * Matches all documents that the value of the property satisfies the condition
213
- * in the operator parameter. Subsequent `where` calls will be operated to the
214
- * previous ones using the AND operator
215
- * @param property the property to be compared
216
- * @param operator the operator to be used in the comparison. The available
217
- * operators are: ==, !=, >, >=, < and <=
218
- * @param value the value to be compared
219
- * @param aggregate if true, the query will use the logical or operator and
220
- * aggregate the results to the previous query
221
- * @returns this Query object to make chained calls possible
222
- * @example
223
- * query.where( 'name', '==', 'John' )
224
- * query.where( 'age', '>', 18 )
225
- * query.where( 'age', '==', 18 ).where( 'name', '==', 'John' )
226
- * @see whereDeepProp
227
- * @see or
228
- * @see orDeepProp
229
- */
230
- where<P extends ClassPropNames<T>>( property: P, operator: QueryOperator, value: Partial<T[P]> | Persistent, aggregate?: boolean ) {
231
- if ( this.queryObject.operations?.at(-1)?.aggregate && !aggregate ) throw new Error( Model.error.invalidQueryOrder )
232
-
233
- this.queryObject.operations?.push({
234
- property,
235
- operator,
236
- value: value as any,
237
- aggregate
238
- })
239
-
240
- return this
241
- }
242
-
243
- // where2<P extends PropPath<T>>( property: P, operator: QueryOperator, value: PropPathType<T, P> ) {
244
- // if ( property.indexOf( '.' ) > 0 ) return this.whereDeepProp( property, operator, value )
245
-
246
- // let val = value instanceof Persistent? { id: value.id } : value
247
-
248
- // this.queryObject.operations.push({
249
- // property,
250
- // operator,
251
- // value: val
252
- // })
253
-
254
- // return this
255
- // }
256
-
257
- /**
258
- * Matches all documents that the value of the deep property satisfies the condition
259
- * in the operator parameter
260
- * @param propertyPath the path to the property to be compared
261
- * @param operator the operator to be used in the comparison. The available
262
- * operators are: ==, !=, >, >=, < and <=
263
- * @param value the value to be compared
264
- * @returns this Query object to make chained calls possible
265
- * @example
266
- * query.whereDeepProp( 'address.street', '==', 'Main Street' )
267
- * @see where
268
- * @see or
269
- * @see orDeepProp
270
- */
271
- whereDeepProp( propertyPath: PropPath<T>, operator: QueryOperator, value: PropPathType<T, typeof propertyPath>, aggregate?: boolean ) {
272
- if ( this.queryObject.operations?.at(-1)?.aggregate && !aggregate ) throw new Error( Model.error.invalidQueryOrder )
273
-
274
- const props = propertyPath.split( '.' )
275
- let obj = {}
276
- let result = props.length > 1? obj : value // TODO: review
277
-
278
- props.slice(1).forEach(( prop, i ) => {
279
- obj[ prop ] = i < props.length - 2? {} : value
280
- obj = obj[ prop ]
281
- })
282
-
283
- this.queryObject.operations?.push({
284
- property: props[0],
285
- operator,
286
- value: result,
287
- aggregate
288
- } as QueryOperation<T>)
289
-
290
- return this
291
- }
292
-
293
- /**
294
- * Matches all documents that the value of the property satisfies the condition
295
- * in the operator parameter and aggregates the results to the previous query
296
- * @param property the property to be compared
297
- * @param operator the operator to be used in the comparison. The available
298
- * operators are: ==, !=, >, >=, < and <=
299
- * @returns this Query object to make chained calls possible
300
- * @example
301
- * query.where( 'name', '==', 'John' ).and( 'age', '>', 18 )
302
- * @see andDeepProp
303
- * @see where
304
- * @see whereDeepProp
305
- * @see or
306
- * @see orDeepProp
307
- */
308
- and<P extends ClassPropNames<T>>( property: P, operator: QueryOperator, value: Partial<T[P]> | Persistent ) {
309
- return this.where( property, operator, value )
310
- }
311
-
312
- /**
313
- * Matches all documents that the value of the deep property satisfies the condition
314
- * in the operator parameter and aggregates the results to the previous query
315
- * @param propertyPath the path to the property to be compared
316
- * @param operator the operator to be used in the comparison. The available
317
- * operators are: ==, !=, >, >=, < and <=
318
- * @param value the value to be compared
319
- * @returns this Query object to make chained calls possible
320
- * @example
321
- * query.whereDeepProp( 'address.street', '==', 'Main Street' ).andDeepProp( 'address.city', '==', 'New York' )
322
- * @see and
323
- * @see where
324
- * @see whereDeepProp
325
- * @see or
326
- * @see orDeepProp
327
- */
328
- andDeepProp( propertyPath: PropPath<T>, operator: QueryOperator, value: PropPathType<T, typeof propertyPath> ) {
329
- return this.whereDeepProp( propertyPath, operator, value )
330
- }
331
-
332
- /**
333
- * Matches all documents that the value of the property satisfies the condition
334
- * in the operator parameter and aggregates the results to the previous query
335
- * @param property the property to be compared
336
- * @param operator the operator to be used in the comparison. The available
337
- * operators are: ==, !=, >, >=, < and <=
338
- * @returns this Query object to make chained calls possible
339
- * @example
340
- * query.or( 'name', '==', 'John' )
341
- * query.or( 'age', '>', 18 )
342
- * @see orDeepProp
343
- * @see where
344
- * @see whereDeepProp
345
- */
346
- or<P extends ClassPropNames<T>>( property: P, operator: QueryOperator, value: Partial<T[P]> | Persistent ) {
347
- return this.where( property, operator, value, true )
348
- }
349
-
350
- /**
351
- * Matches all documents that the value of the deep property satisfies the condition
352
- * in the operator parameter and aggregates the results to the previous query
353
- * @param propertyPath the path to the property to be compared
354
- * @param operator the operator to be used in the comparison. The available
355
- * operators are: ==, !=, >, >=, < and <=
356
- * @param value the value to be compared
357
- * @returns this Query object to make chained calls possible
358
- * @example
359
- * query.orDeepProp( 'address.street', '==', 'Main Street' )
360
- * @see or
361
- * @see where
362
- * @see whereDeepProp
363
- */
364
- orDeepProp( propertyPath: PropPath<T>, operator: QueryOperator, value: PropPathType<T, typeof propertyPath> ) {
365
- return this.whereDeepProp( propertyPath, operator, value, true )
366
- }
367
-
368
- /**
369
- * Defines a where condition to match documents that are instances of the
370
- * given class
371
- * @param classId the class name or an instance to match
372
- * @returns this Query object to make chained calls possible
373
- * @example
374
- * query.instanceOf( 'Person' )
375
- * query.instanceOf( Person )
376
- * query.instanceOf( Person ).where( 'age', '>', 18 )
377
- */
378
- instanceOf<U extends T>( classId: U | string ) {
379
- const className = classId instanceof Persistent? classId.className : classId
380
- this.queryObject.operations?.push({
381
- property: '__className' as any,
382
- operator: '==',
383
- value: className as any
384
- })
385
- return this
386
- }
387
-
388
- /**
389
- * Executes the query and returns the result
390
- * @param limit the max amount of documents to retrieve. If not set, uses the
391
- * last limit set or all the matching documents
392
- * @returns a promise resolving to a collection of matched documents
393
- * @example
394
- * const namedJohn = await query.where( 'name', '==', 'John' ).get()
395
- */
396
- get<U extends T>( limit?: number ): Promise<U[]> {
397
- if ( limit ) {
398
- this.queryObject.limit = limit
399
- }
400
- return this.model.query( this.queryObject as unknown as QueryObject<U> )
401
- }
402
-
403
- /**
404
- * Limits the number of documents to retrieve
405
- * @param maxDocs the max amount of documents to retrieve
406
- * @returns this Query object to make chained calls possible
407
- * @example
408
- * query.where( 'name', '==', 'John' ).limit( 10 )
409
- */
410
- limit( maxDocs: number ) {
411
- this.queryObject.limit = maxDocs
412
- return this
413
- }
414
-
415
- /**
416
- * Orders the result set by a property.
417
- * @param propertyName The name of the property to order by
418
- * @param order The sort direction. Possible values are 'asc' and 'desc'
419
- * @returns a chainable query object
420
- * @example
421
- * query.orderBy( 'name', 'asc' )
422
- * query.orderBy( 'age', 'desc' )
423
- */
424
- orderBy<P extends ClassPropNames<T>>( propertyName: P, order: QueryOrder = 'asc' ) {
425
- this.queryObject.sort = {
426
- propertyName,
427
- order
428
- }
429
-
430
- return this
431
- }
432
-
433
- /**
434
- * Orders the result set by a deep property
435
- *
436
- * @param propertyPath The full path of the deep property. It should be
437
- * separated by dots like person.name.firstName.
438
- * @param order The sort direction. Possible values are 'asc' and 'desc'
439
- * @returns a chainable query object
440
- */
441
- orderByDeepProp( propertyPath: string, order: QueryOrder = 'asc' ) {
442
- this.queryObject.sort = {
443
- propertyName: propertyPath,
444
- order
445
- }
446
-
447
- return this
448
- }
449
-
450
- /**
451
- * Returns the number of documents that match the query
452
- * @returns a promise resolving to the number of documents that match the query
453
- * @example
454
- * const count = await query.where( 'name', '==', 'John' ).count()
455
- */
456
- count() {
457
- return this.model.count( this.queryObject )
458
- }
459
-
460
- private queryObject: QueryObject<T> = { operations: [] } as QueryObject<T>
461
- private model: Model<T>
462
- }
@@ -1,30 +0,0 @@
1
- import { JsonDataSource } from './json-data-source'
2
- import { TestUser } from './mocks/test-user'
3
- import { Store } from './store'
4
- import type { Equal, Expect } from '@type-challenges/utils'
5
-
6
- describe( 'Store', ()=>{
7
- it( 'should throw if not registered data source', ()=>{
8
- expect(
9
- ()=>Store.getModel( '' )
10
- ).toThrow( Store.error.shouldBeRegistered )
11
- })
12
-
13
- it( 'should allow to register a concrete data source', ()=>{
14
- Store.useDataSource( new JsonDataSource() )
15
-
16
- expect( ()=>Store.getModel( '' ) ).not.toThrow( Store.error.shouldBeRegistered )
17
- expect( Store.dataSource ).toBeInstanceOf( JsonDataSource )
18
- })
19
-
20
- it( 'should return the proper type when populating', async ()=>{
21
- const populatedArray = await Store.populate([ new TestUser() ])
22
- const populatedInstance = await Store.populate( new TestUser() )
23
-
24
- type cases = [
25
- Expect<Equal<typeof populatedArray, TestUser[]>>,
26
- Expect<Equal<typeof populatedInstance, TestUser>>
27
- ]
28
- expect( true ).toBeTruthy()
29
- })
30
- })
@@ -1,113 +0,0 @@
1
- import { DocumentReference, Persistent } from '../persistent/persistent';
2
- import { DataSource } from './data-source';
3
- import { Model } from './model';
4
-
5
- /**
6
- * The store is the main entry point for the data access layer.
7
- * It provides methods to retrieve models for collections and subcollections.
8
- * It also provides methods to populate property references with actual data from the store.
9
- * You need to register a data source before using the store.
10
- * @example
11
- * // Register a data source
12
- * Store.useDataSource( new FirestoreDataSource( firebase.firestore() ) )
13
- * // Retrieve a model for a collection
14
- * const model = Store.getModel( 'User' )
15
- * // Retrieve a model for a subcollection
16
- * const model = Store.getModelForSubCollection( user, 'Posts' )
17
- * // Populate property references
18
- * const user = await Store.populate( user )
19
- */
20
- export class Store {
21
- private constructor(){}
22
-
23
- static error = { shouldBeRegistered: 'You should register a data source before using the data Store.' }
24
-
25
- /**
26
- * Registers a data source to be used by the store.
27
- * You need to register a data source before using the store.
28
- * @param dataSource the data source to be used by the store
29
- */
30
- static useDataSource( dataSource: DataSource ) {
31
- this._dataSource = dataSource
32
- }
33
-
34
- /**
35
- * The data source currently used by the store
36
- * @returns the data source
37
- */
38
- static get dataSource() {
39
- return Store._dataSource
40
- }
41
-
42
- /**
43
- * Retrieves a model for a collection
44
- * @param classId the class name or an instance of the document type stored in the collection
45
- * @returns the model for the collection
46
- */
47
- static getModel< T extends Persistent>( classId: T | string ): Model<T> {
48
- if ( !Store._dataSource ) throw new Error( this.error.shouldBeRegistered )
49
- return new Model<T>( Store._dataSource, classId )
50
- }
51
-
52
- /**
53
- * Retrieves a model for a subcollection
54
- * @param document the persistent object that owns the subcollection
55
- * @param subCollection the name of the subcollection
56
- * @returns the model for the subcollection
57
- */
58
- static getModelForSubCollection< T extends Persistent>( document: Persistent, subCollection: string ): Model<T> {
59
- if ( !Store._dataSource ) throw new Error( this.error.shouldBeRegistered )
60
- return new Model<T>( Store._dataSource, document, subCollection )
61
- }
62
-
63
- /**
64
- * Populates property references with actual data from the store.
65
- * It will not retrieve data if the instance is already populated
66
- * @param instance the data to be populated.
67
- * @returns the populated instance
68
- */
69
- static async populate<T extends Persistent | Persistent[]>( instance: T ): Promise<T> {
70
- if ( !instance ) return undefined as any
71
-
72
- const populateItem = async ( item: Persistent ) => {
73
- const ref: DocumentReference = item as any
74
- if ( !ref.__documentReference ) return item
75
- const model = this.getModel( ref.__documentReference.storedInCollection )
76
-
77
- const populated = await model.findById( ref.id, item )
78
- if ( populated ) {
79
- populated['__documentReference' ] = undefined
80
- }
81
- return populated
82
- }
83
-
84
- if ( Array.isArray( instance ) ) {
85
- const items = await Promise.all(
86
- instance.map( item => populateItem( item ) )
87
- )
88
- return items.filter( item => item ) as T
89
- }
90
- else {
91
- return populateItem( instance ) as Promise<T>
92
- }
93
- }
94
-
95
- /**
96
- * Checks if an instance is populated
97
- * @param instance the instance or array of instances to be checked
98
- * @returns true if the instance is populated
99
- */
100
- static isPopulated< T extends Persistent>( instance: T | readonly T[] ): boolean {
101
- if ( Array.isArray( instance ) ) {
102
- return instance.reduce(
103
- ( prevVal, item ) => prevVal && item['__documentReference'] === undefined,
104
- true
105
- )
106
- }
107
- else {
108
- return instance['__documentReference'] === undefined
109
- }
110
- }
111
-
112
- private static _dataSource: DataSource
113
- }