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.
- package/lib/auth/auth-mock.d.ts +22 -0
- package/lib/auth/auth-mock.spec.d.ts +1 -0
- package/lib/auth/auth.d.ts +131 -0
- package/lib/auth/user-auth-types.d.ts +19 -0
- package/lib/cloud-functions/cloud-functions-mock.d.ts +11 -0
- package/lib/cloud-functions/cloud-functions-mock.spec.d.ts +1 -0
- package/lib/cloud-functions/cloud-functions.d.ts +19 -0
- package/lib/cloud-storage/cloud-storage.d.ts +24 -0
- package/lib/cloud-storage/cloud-storage.spec.d.ts +1 -0
- package/lib/cloud-storage/mock-cloud-storage.d.ts +20 -0
- package/lib/cloud-storage/stored-file.d.ts +39 -0
- package/lib/entropic-bond.js +1667 -0
- package/lib/entropic-bond.umd.cjs +7 -0
- package/lib/index.d.ts +19 -0
- package/lib/observable/observable.d.ts +52 -0
- package/lib/observable/observable.spec.d.ts +1 -0
- package/lib/persistent/entropic-component.d.ts +76 -0
- package/lib/persistent/entropic-component.spec.d.ts +1 -0
- package/lib/persistent/persistent.d.ts +281 -0
- package/lib/persistent/persistent.spec.d.ts +67 -0
- package/lib/server-auth/server-auth-mock.d.ts +12 -0
- package/lib/server-auth/server-auth-mock.spec.d.ts +1 -0
- package/lib/server-auth/server-auth.d.ts +24 -0
- package/lib/store/data-source.d.ts +137 -0
- package/lib/store/json-data-source.d.ts +68 -0
- package/lib/store/json-data-source.spec.d.ts +1 -0
- package/lib/store/mocks/test-user.d.ts +49 -0
- package/lib/store/model.d.ts +238 -0
- package/lib/store/model.spec.d.ts +1 -0
- package/lib/store/store.d.ts +62 -0
- package/lib/store/store.spec.d.ts +1 -0
- package/lib/types/utility-types.d.ts +45 -0
- package/lib/types/utility-types.spec.d.ts +1 -0
- package/lib/utils/test-utils/test-person.d.ts +33 -0
- package/{src/utils/utils.ts → lib/utils/utils.d.ts} +10 -34
- package/lib/utils/utils.spec.d.ts +1 -0
- package/package.json +7 -4
- package/.github/workflows/release.yml +0 -26
- package/CHANGELOG.md +0 -1151
- package/docs/.nojekyll +0 -1
- package/docs/README.md +0 -94
- package/docs/classes/Auth.md +0 -391
- package/docs/classes/AuthMock.md +0 -278
- package/docs/classes/AuthService.md +0 -188
- package/docs/classes/CloudFunctions.md +0 -123
- package/docs/classes/CloudFunctionsMock.md +0 -97
- package/docs/classes/CloudStorage.md +0 -215
- package/docs/classes/DataSource.md +0 -248
- package/docs/classes/EntropicComponent.md +0 -666
- package/docs/classes/JsonDataSource.md +0 -328
- package/docs/classes/MockCloudStorage.md +0 -279
- package/docs/classes/Model.md +0 -274
- package/docs/classes/Observable.md +0 -120
- package/docs/classes/Persistent.md +0 -420
- package/docs/classes/ServerAuth.md +0 -211
- package/docs/classes/ServerAuthMock.md +0 -176
- package/docs/classes/ServerAuthService.md +0 -130
- package/docs/classes/Store.md +0 -218
- package/docs/classes/StoredFile.md +0 -636
- package/docs/enums/StoredFileEvent.md +0 -41
- package/docs/interfaces/AuthError.md +0 -30
- package/docs/interfaces/CloudFunctionsService.md +0 -69
- package/docs/interfaces/Collection.md +0 -13
- package/docs/interfaces/CustomCredentials.md +0 -7
- package/docs/interfaces/DocumentReference.md +0 -49
- package/docs/interfaces/JsonRawData.md +0 -7
- package/docs/interfaces/SignData.md +0 -63
- package/docs/interfaces/StoreParams.md +0 -52
- package/docs/interfaces/StoredFileChange.md +0 -41
- package/docs/interfaces/UploadControl.md +0 -90
- package/docs/interfaces/UserCredentials.md +0 -113
- package/docs/interfaces/Values.md +0 -17
- package/docs/modules.md +0 -1273
- package/src/auth/auth-mock.spec.ts +0 -168
- package/src/auth/auth-mock.ts +0 -129
- package/src/auth/auth.ts +0 -185
- package/src/auth/user-auth-types.ts +0 -21
- package/src/cloud-functions/cloud-functions-mock.spec.ts +0 -136
- package/src/cloud-functions/cloud-functions-mock.ts +0 -23
- package/src/cloud-functions/cloud-functions.ts +0 -83
- package/src/cloud-storage/cloud-storage.spec.ts +0 -207
- package/src/cloud-storage/cloud-storage.ts +0 -60
- package/src/cloud-storage/mock-cloud-storage.ts +0 -72
- package/src/cloud-storage/stored-file.ts +0 -102
- package/src/index.ts +0 -19
- package/src/observable/observable.spec.ts +0 -105
- package/src/observable/observable.ts +0 -67
- package/src/persistent/entropic-component.spec.ts +0 -143
- package/src/persistent/entropic-component.ts +0 -135
- package/src/persistent/persistent.spec.ts +0 -828
- package/src/persistent/persistent.ts +0 -650
- package/src/server-auth/server-auth-mock.spec.ts +0 -53
- package/src/server-auth/server-auth-mock.ts +0 -45
- package/src/server-auth/server-auth.ts +0 -49
- package/src/store/data-source.ts +0 -186
- package/src/store/json-data-source.spec.ts +0 -100
- package/src/store/json-data-source.ts +0 -256
- package/src/store/mocks/mock-data.json +0 -155
- package/src/store/mocks/test-user.ts +0 -122
- package/src/store/model.spec.ts +0 -659
- package/src/store/model.ts +0 -462
- package/src/store/store.spec.ts +0 -30
- package/src/store/store.ts +0 -113
- package/src/types/utility-types.spec.ts +0 -117
- package/src/types/utility-types.ts +0 -116
- package/src/utils/test-utils/test-person.ts +0 -44
- package/src/utils/utils.spec.ts +0 -95
- package/tsconfig-build.json +0 -7
- package/tsconfig-cjs.json +0 -9
- package/tsconfig.json +0 -33
- package/vite.config.ts +0 -22
package/src/store/model.ts
DELETED
|
@@ -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
|
-
}
|
package/src/store/store.spec.ts
DELETED
|
@@ -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
|
-
})
|
package/src/store/store.ts
DELETED
|
@@ -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
|
-
}
|