@aws-amplify/datastore 3.12.6-next.32 → 3.12.6-next.41
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/authModeStrategies/defaultAuthStrategy.d.ts +2 -0
- package/lib/authModeStrategies/index.d.ts +2 -0
- package/lib/authModeStrategies/multiAuthStrategy.d.ts +13 -0
- package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib/datastore/datastore.d.ts +207 -0
- package/lib/datastore/datastore.js +641 -144
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/index.d.ts +16 -0
- package/lib/index.js +4 -0
- package/lib/index.js.map +1 -1
- package/lib/predicates/index.d.ts +30 -0
- package/lib/predicates/index.js +127 -6
- package/lib/predicates/index.js.map +1 -1
- package/lib/predicates/next.d.ts +342 -0
- package/lib/predicates/next.js +801 -0
- package/lib/predicates/next.js.map +1 -0
- package/lib/predicates/sort.d.ts +8 -0
- package/lib/predicates/sort.js +10 -4
- package/lib/predicates/sort.js.map +1 -1
- package/lib/ssr/index.d.ts +3 -0
- package/lib/storage/adapter/AsyncStorageAdapter.d.ts +42 -0
- package/lib/storage/adapter/AsyncStorageAdapter.js +106 -293
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageDatabase.d.ts +39 -0
- package/lib/storage/adapter/AsyncStorageDatabase.js +6 -5
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.d.ts +11 -0
- package/lib/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.native.d.ts +1 -0
- package/lib/storage/adapter/IndexedDBAdapter.d.ts +61 -0
- package/lib/storage/adapter/IndexedDBAdapter.js +223 -289
- package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib/storage/adapter/getDefaultAdapter/index.d.ts +3 -0
- package/lib/storage/adapter/getDefaultAdapter/index.js.map +1 -1
- package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +3 -0
- package/lib/storage/adapter/index.d.ts +9 -0
- package/lib/storage/relationship.d.ts +140 -0
- package/lib/storage/relationship.js +335 -0
- package/lib/storage/relationship.js.map +1 -0
- package/lib/storage/storage.d.ts +50 -0
- package/lib/storage/storage.js +32 -16
- package/lib/storage/storage.js.map +1 -1
- package/lib/sync/datastoreConnectivity.d.ts +16 -0
- package/lib/sync/datastoreConnectivity.js.map +1 -1
- package/lib/sync/datastoreReachability/index.d.ts +3 -0
- package/lib/sync/datastoreReachability/index.native.d.ts +3 -0
- package/lib/sync/index.d.ts +89 -0
- package/lib/sync/index.js +2 -8
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/merger.d.ts +17 -0
- package/lib/sync/merger.js.map +1 -1
- package/lib/sync/outbox.d.ts +27 -0
- package/lib/sync/outbox.js.map +1 -1
- package/lib/sync/processors/errorMaps.d.ts +17 -0
- package/lib/sync/processors/errorMaps.js +1 -1
- package/lib/sync/processors/errorMaps.js.map +1 -1
- package/lib/sync/processors/mutation.d.ts +58 -0
- package/lib/sync/processors/mutation.js +9 -6
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +33 -0
- package/lib/sync/processors/subscription.js +4 -1
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +28 -0
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +42 -0
- package/lib/sync/utils.js +30 -31
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +553 -0
- package/lib/types.js +6 -1
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +189 -0
- package/lib/util.js +174 -104
- package/lib/util.js.map +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib-esm/datastore/datastore.d.ts +59 -8
- package/lib-esm/datastore/datastore.js +643 -147
- package/lib-esm/datastore/datastore.js.map +1 -1
- package/lib-esm/index.d.ts +3 -2
- package/lib-esm/index.js +2 -1
- package/lib-esm/index.js.map +1 -1
- package/lib-esm/predicates/index.d.ts +16 -2
- package/lib-esm/predicates/index.js +128 -7
- package/lib-esm/predicates/index.js.map +1 -1
- package/lib-esm/predicates/next.d.ts +342 -0
- package/lib-esm/predicates/next.js +797 -0
- package/lib-esm/predicates/next.js.map +1 -0
- package/lib-esm/predicates/sort.js +10 -4
- package/lib-esm/predicates/sort.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +2 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +108 -295
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +6 -5
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib-esm/storage/adapter/InMemoryStore.d.ts +1 -1
- package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +4 -2
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +226 -292
- package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/getDefaultAdapter/index.js.map +1 -1
- package/lib-esm/storage/relationship.d.ts +140 -0
- package/lib-esm/storage/relationship.js +333 -0
- package/lib-esm/storage/relationship.js.map +1 -0
- package/lib-esm/storage/storage.d.ts +7 -6
- package/lib-esm/storage/storage.js +32 -16
- package/lib-esm/storage/storage.js.map +1 -1
- package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
- package/lib-esm/sync/index.js +3 -9
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/merger.js.map +1 -1
- package/lib-esm/sync/outbox.js.map +1 -1
- package/lib-esm/sync/processors/errorMaps.js +1 -1
- package/lib-esm/sync/processors/errorMaps.js.map +1 -1
- package/lib-esm/sync/processors/mutation.js +10 -7
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.js +4 -1
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.js.map +1 -1
- package/lib-esm/sync/utils.d.ts +1 -1
- package/lib-esm/sync/utils.js +31 -32
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +59 -7
- package/lib-esm/types.js +6 -2
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +39 -6
- package/lib-esm/util.js +170 -104
- package/lib-esm/util.js.map +1 -1
- package/package.json +14 -11
- package/src/authModeStrategies/multiAuthStrategy.ts +1 -1
- package/src/datastore/datastore.ts +680 -204
- package/src/index.ts +4 -0
- package/src/predicates/index.ts +143 -17
- package/src/predicates/next.ts +1016 -0
- package/src/predicates/sort.ts +8 -2
- package/src/storage/adapter/AsyncStorageAdapter.ts +56 -178
- package/src/storage/adapter/AsyncStorageDatabase.ts +16 -15
- package/src/storage/adapter/InMemoryStore.ts +5 -2
- package/src/storage/adapter/IndexedDBAdapter.ts +166 -191
- package/src/storage/adapter/getDefaultAdapter/index.ts +2 -2
- package/src/storage/relationship.ts +272 -0
- package/src/storage/storage.ts +56 -37
- package/src/sync/datastoreConnectivity.ts +4 -4
- package/src/sync/index.ts +22 -28
- package/src/sync/merger.ts +1 -1
- package/src/sync/outbox.ts +6 -6
- package/src/sync/processors/errorMaps.ts +1 -1
- package/src/sync/processors/mutation.ts +22 -17
- package/src/sync/processors/subscription.ts +19 -15
- package/src/sync/processors/sync.ts +16 -16
- package/src/sync/utils.ts +42 -48
- package/src/types.ts +116 -11
- package/src/util.ts +108 -150
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { API } from '@aws-amplify/api';
|
|
2
2
|
import { Auth } from '@aws-amplify/auth';
|
|
3
|
-
import {
|
|
3
|
+
import { Cache } from '@aws-amplify/cache';
|
|
4
4
|
import {
|
|
5
5
|
Amplify,
|
|
6
6
|
ConsoleLogger as Logger,
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from '../predicates';
|
|
28
28
|
import { Adapter } from '../storage/adapter';
|
|
29
29
|
import { ExclusiveStorage as Storage } from '../storage/storage';
|
|
30
|
+
import { ModelRelationship } from '../storage/relationship';
|
|
30
31
|
import { ControlMessage, SyncEngine } from '../sync';
|
|
31
32
|
import {
|
|
32
33
|
AuthModeStrategy,
|
|
@@ -40,6 +41,7 @@ import {
|
|
|
40
41
|
ModelInit,
|
|
41
42
|
ModelInstanceMetadata,
|
|
42
43
|
ModelPredicate,
|
|
44
|
+
ModelField,
|
|
43
45
|
SortPredicate,
|
|
44
46
|
MutableModel,
|
|
45
47
|
NamespaceResolver,
|
|
@@ -69,6 +71,7 @@ import {
|
|
|
69
71
|
IdentifierFieldOrIdentifierObject,
|
|
70
72
|
isIdentifierObject,
|
|
71
73
|
AmplifyContext,
|
|
74
|
+
isFieldAssociation,
|
|
72
75
|
} from '../types';
|
|
73
76
|
// tslint:disable:no-duplicate-imports
|
|
74
77
|
import type { __modelMeta__ } from '../types';
|
|
@@ -77,7 +80,6 @@ import {
|
|
|
77
80
|
DATASTORE,
|
|
78
81
|
errorMessages,
|
|
79
82
|
establishRelationAndKeys,
|
|
80
|
-
exhaustiveCheck,
|
|
81
83
|
isModelConstructor,
|
|
82
84
|
monotonicUlidFactory,
|
|
83
85
|
NAMESPACES,
|
|
@@ -88,13 +90,20 @@ import {
|
|
|
88
90
|
registerNonModelClass,
|
|
89
91
|
sortCompareFunction,
|
|
90
92
|
DeferredCallbackResolver,
|
|
93
|
+
inMemoryPagination,
|
|
91
94
|
extractPrimaryKeyFieldNames,
|
|
92
95
|
extractPrimaryKeysAndValues,
|
|
93
96
|
isIdManaged,
|
|
94
97
|
isIdOptionallyManaged,
|
|
95
|
-
validatePredicate,
|
|
96
98
|
mergePatches,
|
|
97
99
|
} from '../util';
|
|
100
|
+
import {
|
|
101
|
+
RecursiveModelPredicateExtender,
|
|
102
|
+
ModelPredicateExtender,
|
|
103
|
+
recursivePredicateFor,
|
|
104
|
+
predicateFor,
|
|
105
|
+
GroupCondition,
|
|
106
|
+
} from '../predicates/next';
|
|
98
107
|
import { getIdentifierValue } from '../sync/utils';
|
|
99
108
|
import DataStoreConnectivity from '../sync/datastoreConnectivity';
|
|
100
109
|
|
|
@@ -140,19 +149,98 @@ const modelPatchesMap = new WeakMap<
|
|
|
140
149
|
const getModelDefinition = (
|
|
141
150
|
modelConstructor: PersistentModelConstructor<any>
|
|
142
151
|
) => {
|
|
143
|
-
const namespace = modelNamespaceMap.get(modelConstructor)
|
|
152
|
+
const namespace = modelNamespaceMap.get(modelConstructor)!;
|
|
153
|
+
const definition = namespace
|
|
154
|
+
? schema.namespaces[namespace].models[modelConstructor.name]
|
|
155
|
+
: undefined;
|
|
156
|
+
|
|
157
|
+
// compatibility with legacy/pre-PK codegen for lazy loading to inject
|
|
158
|
+
// index fields into the model definition.
|
|
159
|
+
if (definition) {
|
|
160
|
+
const indexes =
|
|
161
|
+
schema.namespaces[namespace].relationships![modelConstructor.name]
|
|
162
|
+
.indexes;
|
|
163
|
+
|
|
164
|
+
const indexFields = new Set<string>();
|
|
165
|
+
for (const index of indexes) {
|
|
166
|
+
for (const indexField of index[1]) {
|
|
167
|
+
indexFields.add(indexField);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
144
170
|
|
|
145
|
-
|
|
171
|
+
definition.fields = {
|
|
172
|
+
...Object.fromEntries(
|
|
173
|
+
[...indexFields.values()].map(
|
|
174
|
+
name => [
|
|
175
|
+
name,
|
|
176
|
+
{
|
|
177
|
+
name,
|
|
178
|
+
type: 'ID',
|
|
179
|
+
isArray: false,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
[]
|
|
183
|
+
)
|
|
184
|
+
),
|
|
185
|
+
...definition.fields,
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return definition;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
const getModelPKFieldName = (
|
|
193
|
+
modelConstructor: PersistentModelConstructor<any>
|
|
194
|
+
) => {
|
|
195
|
+
const namespace = modelNamespaceMap.get(modelConstructor);
|
|
196
|
+
return (
|
|
197
|
+
(namespace &&
|
|
198
|
+
schema.namespaces?.[namespace]?.keys?.[modelConstructor.name]
|
|
199
|
+
.primaryKey) || ['id']
|
|
200
|
+
);
|
|
146
201
|
};
|
|
147
202
|
|
|
148
203
|
const isValidModelConstructor = <T extends PersistentModel>(
|
|
149
204
|
obj: any
|
|
150
205
|
): obj is PersistentModelConstructor<T> => {
|
|
151
|
-
|
|
206
|
+
if (isModelConstructor(obj) && modelNamespaceMap.has(obj)) {
|
|
207
|
+
return true;
|
|
208
|
+
} else {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const namespaceResolver: NamespaceResolver = modelConstructor => {
|
|
214
|
+
const resolver = modelNamespaceMap.get(modelConstructor);
|
|
215
|
+
if (!resolver) {
|
|
216
|
+
throw new Error(
|
|
217
|
+
`Namespace Resolver for '${modelConstructor.name}' not found! This is probably a bug in '@amplify-js/datastore'.`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
return resolver;
|
|
152
221
|
};
|
|
153
222
|
|
|
154
|
-
const
|
|
155
|
-
|
|
223
|
+
const buildSeedPredicate = <T extends PersistentModel>(
|
|
224
|
+
modelConstructor: PersistentModelConstructor<T>
|
|
225
|
+
) => {
|
|
226
|
+
if (!modelConstructor) throw new Error('Missing modelConstructor');
|
|
227
|
+
|
|
228
|
+
const modelSchema = getModelDefinition(
|
|
229
|
+
modelConstructor as PersistentModelConstructor<T>
|
|
230
|
+
);
|
|
231
|
+
if (!modelSchema) throw new Error('Missing modelSchema');
|
|
232
|
+
|
|
233
|
+
const pks = getModelPKFieldName(
|
|
234
|
+
modelConstructor as PersistentModelConstructor<T>
|
|
235
|
+
);
|
|
236
|
+
if (!pks) throw new Error('Could not determine PK');
|
|
237
|
+
|
|
238
|
+
return recursivePredicateFor<T>({
|
|
239
|
+
builder: modelConstructor as PersistentModelConstructor<T>,
|
|
240
|
+
schema: modelSchema,
|
|
241
|
+
pkField: pks,
|
|
242
|
+
});
|
|
243
|
+
};
|
|
156
244
|
|
|
157
245
|
// exporting syncClasses for testing outbox.test.ts
|
|
158
246
|
export let syncClasses: TypeConstructorMap;
|
|
@@ -160,6 +248,78 @@ let userClasses: TypeConstructorMap;
|
|
|
160
248
|
let dataStoreClasses: TypeConstructorMap;
|
|
161
249
|
let storageClasses: TypeConstructorMap;
|
|
162
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Maps a model to its related models for memoization/immutability.
|
|
253
|
+
*/
|
|
254
|
+
const modelInstanceAssociationsMap = new WeakMap<PersistentModel, object>();
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Describes whether and to what a model is attached for lazy loading purposes.
|
|
258
|
+
*/
|
|
259
|
+
enum ModelAttachment {
|
|
260
|
+
/**
|
|
261
|
+
* Model doesn't lazy load from any data source.
|
|
262
|
+
*
|
|
263
|
+
* Related entity properties provided at instantiation are returned
|
|
264
|
+
* via the respective lazy interfaces when their properties are invoked.
|
|
265
|
+
*/
|
|
266
|
+
Detached = 'Detached',
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Model lazy loads from the global DataStore.
|
|
270
|
+
*/
|
|
271
|
+
DataStore = 'DataStore',
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Demonstrative. Not yet implemented.
|
|
275
|
+
*/
|
|
276
|
+
API = 'API',
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Tells us which data source a model is attached to (lazy loads from).
|
|
281
|
+
*
|
|
282
|
+
* If `Deatched`, the model's lazy properties will only ever return properties
|
|
283
|
+
* from memory provided at construction time.
|
|
284
|
+
*/
|
|
285
|
+
const attachedModelInstances = new WeakMap<PersistentModel, ModelAttachment>();
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Registers a model instance against a data source (DataStore, API, or
|
|
289
|
+
* Detached/None).
|
|
290
|
+
*
|
|
291
|
+
* The API option is demonstrative. Lazy loading against API is not yet
|
|
292
|
+
* implemented.
|
|
293
|
+
*
|
|
294
|
+
* @param result A model instance or array of instances
|
|
295
|
+
* @param attachment A ModelAttachment data source
|
|
296
|
+
* @returns passes the `result` back through after attachment
|
|
297
|
+
*/
|
|
298
|
+
export function attached<T extends PersistentModel | PersistentModel[]>(
|
|
299
|
+
result: T,
|
|
300
|
+
attachment: ModelAttachment
|
|
301
|
+
): T {
|
|
302
|
+
if (Array.isArray(result)) {
|
|
303
|
+
result.map(record => attached(record, attachment)) as T;
|
|
304
|
+
} else {
|
|
305
|
+
result && attachedModelInstances.set(result, attachment);
|
|
306
|
+
}
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Determines what source a model instance should lazy load from.
|
|
312
|
+
*
|
|
313
|
+
* If the instace was never explicitly registered, it is detached by default.
|
|
314
|
+
*
|
|
315
|
+
* @param instance A model instance
|
|
316
|
+
*/
|
|
317
|
+
export const getAttachment = (instance: PersistentModel) => {
|
|
318
|
+
return attachedModelInstances.has(instance)
|
|
319
|
+
? attachedModelInstances.get(instance)
|
|
320
|
+
: ModelAttachment.Detached;
|
|
321
|
+
};
|
|
322
|
+
|
|
163
323
|
const initSchema = (userSchema: Schema) => {
|
|
164
324
|
if (schema !== undefined) {
|
|
165
325
|
console.warn('The schema has already been initialized');
|
|
@@ -169,6 +329,8 @@ const initSchema = (userSchema: Schema) => {
|
|
|
169
329
|
|
|
170
330
|
logger.log('validating schema', { schema: userSchema });
|
|
171
331
|
|
|
332
|
+
checkSchemaCodegenVersion(userSchema.codegenVersion);
|
|
333
|
+
|
|
172
334
|
const internalUserNamespace: SchemaNamespace = {
|
|
173
335
|
name: USER,
|
|
174
336
|
...userSchema,
|
|
@@ -194,6 +356,7 @@ const initSchema = (userSchema: Schema) => {
|
|
|
194
356
|
[syncNamespace.name]: syncNamespace,
|
|
195
357
|
},
|
|
196
358
|
version: userSchema.version,
|
|
359
|
+
codegenVersion: userSchema.codegenVersion,
|
|
197
360
|
};
|
|
198
361
|
|
|
199
362
|
Object.keys(schema.namespaces).forEach(namespace => {
|
|
@@ -221,6 +384,33 @@ const initSchema = (userSchema: Schema) => {
|
|
|
221
384
|
);
|
|
222
385
|
|
|
223
386
|
modelAssociations.set(model.name, connectedModels);
|
|
387
|
+
|
|
388
|
+
Object.values(model.fields).forEach(field => {
|
|
389
|
+
if (
|
|
390
|
+
typeof field.type === 'object' &&
|
|
391
|
+
!Object.getOwnPropertyDescriptor(
|
|
392
|
+
<ModelFieldType>field.type,
|
|
393
|
+
'modelConstructor'
|
|
394
|
+
)
|
|
395
|
+
) {
|
|
396
|
+
Object.defineProperty(field.type, 'modelConstructor', {
|
|
397
|
+
get: () => {
|
|
398
|
+
return {
|
|
399
|
+
builder: userClasses[(<ModelFieldType>field.type).model],
|
|
400
|
+
schema:
|
|
401
|
+
schema.namespaces[namespace].models[
|
|
402
|
+
(<ModelFieldType>field.type).model
|
|
403
|
+
],
|
|
404
|
+
pkField: getModelPKFieldName(
|
|
405
|
+
userClasses[
|
|
406
|
+
(<ModelFieldType>field.type).model
|
|
407
|
+
] as PersistentModelConstructor<any>
|
|
408
|
+
),
|
|
409
|
+
};
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
});
|
|
224
414
|
});
|
|
225
415
|
|
|
226
416
|
const result = new Map<string, string[]>();
|
|
@@ -240,7 +430,7 @@ const initSchema = (userSchema: Schema) => {
|
|
|
240
430
|
for (const modelName of Array.from(modelAssociations.keys())) {
|
|
241
431
|
const parents = modelAssociations.get(modelName);
|
|
242
432
|
|
|
243
|
-
if (parents
|
|
433
|
+
if (parents?.every(x => result.has(x))) {
|
|
244
434
|
result.set(modelName, parents);
|
|
245
435
|
}
|
|
246
436
|
}
|
|
@@ -272,6 +462,47 @@ const checkSchemaInitialized = () => {
|
|
|
272
462
|
}
|
|
273
463
|
};
|
|
274
464
|
|
|
465
|
+
/**
|
|
466
|
+
* Throws an exception if the schema is using a codegen version that is not supported.
|
|
467
|
+
*
|
|
468
|
+
* Set the supported version by setting majorVersion and minorVersion
|
|
469
|
+
* This functions similar to ^ version range.
|
|
470
|
+
* The tested codegenVersion major version must exactly match the set majorVersion
|
|
471
|
+
* The tested codegenVersion minor version must be gt or equal to the set minorVersion
|
|
472
|
+
* Example: For a min supported version of 5.4.0 set majorVersion = 5 and minorVersion = 4
|
|
473
|
+
*
|
|
474
|
+
* This regex will not work when setting a supported range with minor version
|
|
475
|
+
* of 2 or more digits.
|
|
476
|
+
* i.e. minorVersion = 10 will not work
|
|
477
|
+
* The regex will work for testing a codegenVersion with multi digit minor
|
|
478
|
+
* versions as long as the minimum minorVersion is single digit.
|
|
479
|
+
* i.e. codegenVersion = 5.30.1, majorVersion = 5, minorVersion = 4 PASSES
|
|
480
|
+
*
|
|
481
|
+
* @param codegenVersion schema codegenVersion
|
|
482
|
+
*/
|
|
483
|
+
const checkSchemaCodegenVersion = (codegenVersion: string) => {
|
|
484
|
+
// TODO: set to correct version when released in codegen
|
|
485
|
+
const majorVersion = 3;
|
|
486
|
+
const minorVersion = 2;
|
|
487
|
+
let isValid = false;
|
|
488
|
+
|
|
489
|
+
try {
|
|
490
|
+
const versionParts = codegenVersion.split('.');
|
|
491
|
+
const [major, minor, patch, patchrevision] = versionParts;
|
|
492
|
+
isValid = Number(major) === majorVersion && Number(minor) >= minorVersion;
|
|
493
|
+
} catch (err) {
|
|
494
|
+
console.log(`Error parsing codegen version: ${codegenVersion}\n${err}`);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (!isValid) {
|
|
498
|
+
const message = `Models were generated with an unsupported version of codegen. Codegen artifacts are from ${
|
|
499
|
+
codegenVersion || 'an unknown version'
|
|
500
|
+
}, whereas ^${majorVersion}.${minorVersion}.0 is required. Update to the latest CLI and rerun codegen.`;
|
|
501
|
+
logger.error(message);
|
|
502
|
+
throw new Error(message);
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
275
506
|
const createTypeClasses: (
|
|
276
507
|
namespace: SchemaNamespace
|
|
277
508
|
) => TypeConstructorMap = namespace => {
|
|
@@ -286,7 +517,7 @@ const createTypeClasses: (
|
|
|
286
517
|
|
|
287
518
|
Object.entries(namespace.nonModels || {}).forEach(
|
|
288
519
|
([typeName, typeDefinition]) => {
|
|
289
|
-
const clazz = createNonModelClass(typeDefinition);
|
|
520
|
+
const clazz = createNonModelClass(typeDefinition) as any;
|
|
290
521
|
classes[typeName] = clazz;
|
|
291
522
|
}
|
|
292
523
|
);
|
|
@@ -310,7 +541,7 @@ export declare type ModelInstanceCreator = typeof modelInstanceCreator;
|
|
|
310
541
|
* the model visible to the consuming app -- in case the app doesn't have
|
|
311
542
|
* metadata fields (_version, _deleted, etc.) exposed on the model itself.
|
|
312
543
|
*/
|
|
313
|
-
const instancesMetadata = new WeakSet<ModelInit<
|
|
544
|
+
const instancesMetadata = new WeakSet<ModelInit<any, any>>();
|
|
314
545
|
|
|
315
546
|
function modelInstanceCreator<T extends PersistentModel>(
|
|
316
547
|
modelConstructor: PersistentModelConstructor<T>,
|
|
@@ -418,7 +649,7 @@ const validateModelFields =
|
|
|
418
649
|
} else if (
|
|
419
650
|
!isNullOrUndefined(v) &&
|
|
420
651
|
validateScalar &&
|
|
421
|
-
!validateScalar(v)
|
|
652
|
+
!validateScalar(v as never) // TODO: why never, TS ... why ...
|
|
422
653
|
) {
|
|
423
654
|
throw new Error(
|
|
424
655
|
`Field ${name} should be of type ${type}, validation failed. ${v}`
|
|
@@ -428,7 +659,7 @@ const validateModelFields =
|
|
|
428
659
|
// do not check non model fields if undefined or null
|
|
429
660
|
if (!isNullOrUndefined(v)) {
|
|
430
661
|
const subNonModelDefinition =
|
|
431
|
-
schema.namespaces.user.nonModels[type.nonModel];
|
|
662
|
+
schema.namespaces.user.nonModels![type.nonModel];
|
|
432
663
|
const modelValidator = validateModelFields(subNonModelDefinition);
|
|
433
664
|
|
|
434
665
|
if (isArray) {
|
|
@@ -608,7 +839,8 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
608
839
|
|
|
609
840
|
if (patches.length || hasExistingPatches) {
|
|
610
841
|
if (hasExistingPatches) {
|
|
611
|
-
const [existingPatches, existingSource] =
|
|
842
|
+
const [existingPatches, existingSource] =
|
|
843
|
+
modelPatchesMap.get(source)!;
|
|
612
844
|
const mergedPatches = mergePatches(
|
|
613
845
|
existingSource,
|
|
614
846
|
existingPatches,
|
|
@@ -622,7 +854,7 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
622
854
|
}
|
|
623
855
|
}
|
|
624
856
|
|
|
625
|
-
return model;
|
|
857
|
+
return attached(model, ModelAttachment.DataStore);
|
|
626
858
|
}
|
|
627
859
|
|
|
628
860
|
// "private" method (that's hidden via `Setting`) for `withSSRContext` to use
|
|
@@ -640,7 +872,7 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
640
872
|
modelValidator(k, v);
|
|
641
873
|
});
|
|
642
874
|
|
|
643
|
-
return instance;
|
|
875
|
+
return attached(instance, ModelAttachment.DataStore);
|
|
644
876
|
}
|
|
645
877
|
});
|
|
646
878
|
|
|
@@ -648,9 +880,169 @@ const createModelClass = <T extends PersistentModel>(
|
|
|
648
880
|
|
|
649
881
|
Object.defineProperty(clazz, 'name', { value: modelDefinition.name });
|
|
650
882
|
|
|
883
|
+
for (const field in modelDefinition.fields) {
|
|
884
|
+
if (!isFieldAssociation(modelDefinition, field)) {
|
|
885
|
+
continue;
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
const {
|
|
889
|
+
type,
|
|
890
|
+
association: localAssociation,
|
|
891
|
+
association: { targetName, targetNames },
|
|
892
|
+
} = modelDefinition.fields[field] as Required<ModelField>;
|
|
893
|
+
|
|
894
|
+
const relationship = new ModelRelationship(
|
|
895
|
+
{
|
|
896
|
+
builder: clazz,
|
|
897
|
+
schema: modelDefinition,
|
|
898
|
+
pkField: extractPrimaryKeyFieldNames(modelDefinition),
|
|
899
|
+
},
|
|
900
|
+
field
|
|
901
|
+
);
|
|
902
|
+
|
|
903
|
+
Object.defineProperty(clazz.prototype, modelDefinition.fields[field].name, {
|
|
904
|
+
set(model: PersistentModel) {
|
|
905
|
+
if (!model || !(typeof model === 'object')) return;
|
|
906
|
+
|
|
907
|
+
// Avoid validation error when processing AppSync response with nested
|
|
908
|
+
// selection set. Nested entitites lack version field and can not be validated
|
|
909
|
+
// TODO: explore a more reliable method to solve this
|
|
910
|
+
if (model.hasOwnProperty('_version')) {
|
|
911
|
+
const modelConstructor = Object.getPrototypeOf(model || {})
|
|
912
|
+
.constructor as PersistentModelConstructor<T>;
|
|
913
|
+
|
|
914
|
+
if (!isValidModelConstructor(modelConstructor)) {
|
|
915
|
+
const msg = `Value passed to ${modelDefinition.name}.${field} is not a valid instance of a model`;
|
|
916
|
+
logger.error(msg, { model });
|
|
917
|
+
|
|
918
|
+
throw new Error(msg);
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
if (
|
|
922
|
+
modelConstructor.name.toLowerCase() !==
|
|
923
|
+
relationship.remoteModelConstructor.name.toLowerCase()
|
|
924
|
+
) {
|
|
925
|
+
const msg = `Value passed to ${modelDefinition.name}.${field} is not an instance of ${relationship.remoteModelConstructor.name}`;
|
|
926
|
+
logger.error(msg, { model });
|
|
927
|
+
|
|
928
|
+
throw new Error(msg);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
if (relationship.isComplete) {
|
|
933
|
+
for (let i = 0; i < relationship.localJoinFields.length; i++) {
|
|
934
|
+
this[relationship.localJoinFields[i]] =
|
|
935
|
+
model[relationship.remoteJoinFields[i]];
|
|
936
|
+
}
|
|
937
|
+
const instanceMemos = modelInstanceAssociationsMap.has(this)
|
|
938
|
+
? modelInstanceAssociationsMap.get(this)!
|
|
939
|
+
: modelInstanceAssociationsMap.set(this, {}).get(this)!;
|
|
940
|
+
instanceMemos[field] = model;
|
|
941
|
+
}
|
|
942
|
+
},
|
|
943
|
+
get() {
|
|
944
|
+
const instanceMemos = modelInstanceAssociationsMap.has(this)
|
|
945
|
+
? modelInstanceAssociationsMap.get(this)!
|
|
946
|
+
: modelInstanceAssociationsMap.set(this, {}).get(this)!;
|
|
947
|
+
|
|
948
|
+
if (!instanceMemos.hasOwnProperty(field)) {
|
|
949
|
+
if (getAttachment(this) === ModelAttachment.DataStore) {
|
|
950
|
+
const resultPromise = instance.query(
|
|
951
|
+
relationship.remoteModelConstructor as PersistentModelConstructor<T>,
|
|
952
|
+
base =>
|
|
953
|
+
base.and(q => {
|
|
954
|
+
return relationship.remoteJoinFields.map((field, index) => {
|
|
955
|
+
return (q[field] as any).eq(
|
|
956
|
+
this[relationship.localJoinFields[index]]
|
|
957
|
+
);
|
|
958
|
+
});
|
|
959
|
+
})
|
|
960
|
+
);
|
|
961
|
+
|
|
962
|
+
if (relationship.type === 'HAS_MANY') {
|
|
963
|
+
instanceMemos[field] = new AsyncCollection(resultPromise);
|
|
964
|
+
} else {
|
|
965
|
+
instanceMemos[field] = resultPromise.then(rows => {
|
|
966
|
+
if (rows.length > 1) {
|
|
967
|
+
// should never happen for a HAS_ONE or BELONGS_TO.
|
|
968
|
+
const err = new Error(`
|
|
969
|
+
Data integrity error.
|
|
970
|
+
Too many records found for a HAS_ONE/BELONGS_TO field '${modelDefinition.name}.${field}'
|
|
971
|
+
`);
|
|
972
|
+
console.error(err);
|
|
973
|
+
throw err;
|
|
974
|
+
} else {
|
|
975
|
+
return rows[0];
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
} else if (getAttachment(this) === ModelAttachment.API) {
|
|
980
|
+
throw new Error('Lazy loading from API is not yet supported!');
|
|
981
|
+
} else {
|
|
982
|
+
if (relationship.type === 'HAS_MANY') {
|
|
983
|
+
return new AsyncCollection([]);
|
|
984
|
+
} else {
|
|
985
|
+
return Promise.resolve(undefined);
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
|
|
990
|
+
return instanceMemos[field];
|
|
991
|
+
},
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
|
|
651
995
|
return clazz;
|
|
652
996
|
};
|
|
653
997
|
|
|
998
|
+
export class AsyncItem<T> extends Promise<T> {}
|
|
999
|
+
|
|
1000
|
+
export class AsyncCollection<T> implements AsyncIterable<T> {
|
|
1001
|
+
values: Array<any> | Promise<Array<any>>;
|
|
1002
|
+
|
|
1003
|
+
constructor(values: Array<any> | Promise<Array<any>>) {
|
|
1004
|
+
this.values = values;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
[Symbol.asyncIterator](): AsyncIterator<T> {
|
|
1008
|
+
let values;
|
|
1009
|
+
let index = 0;
|
|
1010
|
+
return {
|
|
1011
|
+
next: async () => {
|
|
1012
|
+
if (!values) values = await this.values;
|
|
1013
|
+
if (index < values.length) {
|
|
1014
|
+
const result = {
|
|
1015
|
+
value: values[index],
|
|
1016
|
+
done: false,
|
|
1017
|
+
};
|
|
1018
|
+
index++;
|
|
1019
|
+
return result;
|
|
1020
|
+
}
|
|
1021
|
+
return {
|
|
1022
|
+
value: null,
|
|
1023
|
+
done: true,
|
|
1024
|
+
};
|
|
1025
|
+
},
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
async toArray({
|
|
1030
|
+
max = Number.MAX_SAFE_INTEGER,
|
|
1031
|
+
}: { max?: number } = {}): Promise<T[]> {
|
|
1032
|
+
const output: T[] = [];
|
|
1033
|
+
let i = 0;
|
|
1034
|
+
for await (const element of this) {
|
|
1035
|
+
if (i < max) {
|
|
1036
|
+
output.push(element);
|
|
1037
|
+
i++;
|
|
1038
|
+
} else {
|
|
1039
|
+
break;
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
return output;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
|
|
654
1046
|
const checkReadOnlyPropertyOnCreate = <T extends PersistentModel>(
|
|
655
1047
|
draft: T,
|
|
656
1048
|
modelDefinition: SchemaModel
|
|
@@ -740,8 +1132,7 @@ function getModelConstructorByModelName(
|
|
|
740
1132
|
result = storageClasses[modelName];
|
|
741
1133
|
break;
|
|
742
1134
|
default:
|
|
743
|
-
|
|
744
|
-
break;
|
|
1135
|
+
throw new Error(`Invalid namespace: ${namespaceName}`);
|
|
745
1136
|
}
|
|
746
1137
|
|
|
747
1138
|
if (isValidModelConstructor(result)) {
|
|
@@ -858,23 +1249,31 @@ class DataStore {
|
|
|
858
1249
|
private API = API;
|
|
859
1250
|
private Cache = Cache;
|
|
860
1251
|
|
|
1252
|
+
// Non-null assertions (bang operator) have been added to most of these properties
|
|
1253
|
+
// to make TS happy. These properties are all expected to be set immediately after
|
|
1254
|
+
// construction.
|
|
1255
|
+
|
|
1256
|
+
// TODO: Refactor to use proper DI if possible. If not possible, change these to
|
|
1257
|
+
// optionals and implement conditional checks throughout. Rinse/repeat on all
|
|
1258
|
+
// sync engine processors, storage engine, adapters, etc..
|
|
1259
|
+
|
|
861
1260
|
private amplifyConfig: Record<string, any> = {};
|
|
862
|
-
private authModeStrategy
|
|
863
|
-
private conflictHandler
|
|
864
|
-
private errorHandler
|
|
865
|
-
private fullSyncInterval
|
|
1261
|
+
private authModeStrategy!: AuthModeStrategy;
|
|
1262
|
+
private conflictHandler!: ConflictHandler;
|
|
1263
|
+
private errorHandler!: (error: SyncError<PersistentModel>) => void;
|
|
1264
|
+
private fullSyncInterval!: number;
|
|
866
1265
|
private initialized?: Promise<void>;
|
|
867
|
-
private initReject
|
|
868
|
-
private initResolve
|
|
869
|
-
private maxRecordsToSync
|
|
1266
|
+
private initReject!: Function;
|
|
1267
|
+
private initResolve!: Function;
|
|
1268
|
+
private maxRecordsToSync!: number;
|
|
870
1269
|
private storage?: Storage;
|
|
871
1270
|
private sync?: SyncEngine;
|
|
872
|
-
private syncPageSize
|
|
873
|
-
private syncExpressions
|
|
1271
|
+
private syncPageSize!: number;
|
|
1272
|
+
private syncExpressions!: SyncExpression[];
|
|
874
1273
|
private syncPredicates: WeakMap<SchemaModel, ModelPredicate<any>> =
|
|
875
1274
|
new WeakMap<SchemaModel, ModelPredicate<any>>();
|
|
876
|
-
private sessionId
|
|
877
|
-
private storageAdapter
|
|
1275
|
+
private sessionId?: string;
|
|
1276
|
+
private storageAdapter!: Adapter;
|
|
878
1277
|
// object that gets passed to descendent classes. Allows us to pass these down by reference
|
|
879
1278
|
private amplifyContext: AmplifyContext = {
|
|
880
1279
|
Auth: this.Auth,
|
|
@@ -992,10 +1391,8 @@ class DataStore {
|
|
|
992
1391
|
);
|
|
993
1392
|
|
|
994
1393
|
await this.storage.init();
|
|
995
|
-
|
|
996
1394
|
checkSchemaInitialized();
|
|
997
1395
|
await checkSchemaVersion(this.storage, schema.version);
|
|
998
|
-
|
|
999
1396
|
const { aws_appsync_graphqlEndpoint } = this.amplifyConfig;
|
|
1000
1397
|
|
|
1001
1398
|
if (aws_appsync_graphqlEndpoint) {
|
|
@@ -1075,27 +1472,36 @@ class DataStore {
|
|
|
1075
1472
|
): Promise<T | undefined>;
|
|
1076
1473
|
<T extends PersistentModel>(
|
|
1077
1474
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1078
|
-
criteria?:
|
|
1475
|
+
criteria?:
|
|
1476
|
+
| RecursiveModelPredicateExtender<T>
|
|
1477
|
+
| typeof PredicateAll
|
|
1478
|
+
| null,
|
|
1079
1479
|
paginationProducer?: ProducerPaginationInput<T>
|
|
1080
1480
|
): Promise<T[]>;
|
|
1081
1481
|
} = async <T extends PersistentModel>(
|
|
1082
1482
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1083
1483
|
identifierOrCriteria?:
|
|
1084
1484
|
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
1085
|
-
|
|
|
1086
|
-
| typeof PredicateAll
|
|
1485
|
+
| RecursiveModelPredicateExtender<T>
|
|
1486
|
+
| typeof PredicateAll
|
|
1487
|
+
| null,
|
|
1087
1488
|
paginationProducer?: ProducerPaginationInput<T>
|
|
1088
1489
|
): Promise<T | T[] | undefined> => {
|
|
1089
1490
|
return this.runningProcesses
|
|
1090
1491
|
.add(async () => {
|
|
1091
1492
|
await this.start();
|
|
1092
1493
|
|
|
1494
|
+
let result: T[];
|
|
1495
|
+
|
|
1496
|
+
if (!this.storage) {
|
|
1497
|
+
throw new Error('No storage to query');
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1093
1500
|
//#region Input validation
|
|
1094
1501
|
|
|
1095
1502
|
if (!isValidModelConstructor(modelConstructor)) {
|
|
1096
1503
|
const msg = 'Constructor is not for a valid model';
|
|
1097
1504
|
logger.error(msg, { modelConstructor });
|
|
1098
|
-
|
|
1099
1505
|
throw new Error(msg);
|
|
1100
1506
|
}
|
|
1101
1507
|
|
|
@@ -1106,9 +1512,16 @@ class DataStore {
|
|
|
1106
1512
|
}
|
|
1107
1513
|
|
|
1108
1514
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1109
|
-
|
|
1515
|
+
if (!modelDefinition) {
|
|
1516
|
+
throw new Error('Invalid model definition provided!');
|
|
1517
|
+
}
|
|
1110
1518
|
|
|
1111
|
-
|
|
1519
|
+
const pagination = this.processPagination(
|
|
1520
|
+
modelDefinition,
|
|
1521
|
+
paginationProducer
|
|
1522
|
+
);
|
|
1523
|
+
|
|
1524
|
+
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1112
1525
|
|
|
1113
1526
|
if (isQueryOne(identifierOrCriteria)) {
|
|
1114
1527
|
if (keyFields.length > 1) {
|
|
@@ -1118,71 +1531,78 @@ class DataStore {
|
|
|
1118
1531
|
throw new Error(msg);
|
|
1119
1532
|
}
|
|
1120
1533
|
|
|
1121
|
-
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1534
|
+
const predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1122
1535
|
modelDefinition,
|
|
1123
1536
|
keyFields[0],
|
|
1124
1537
|
identifierOrCriteria
|
|
1125
1538
|
);
|
|
1539
|
+
|
|
1540
|
+
result = await this.storage.query<T>(
|
|
1541
|
+
modelConstructor,
|
|
1542
|
+
predicate,
|
|
1543
|
+
pagination
|
|
1544
|
+
);
|
|
1126
1545
|
} else {
|
|
1127
1546
|
// Object is being queried using object literal syntax
|
|
1128
1547
|
if (isIdentifierObject(<T>identifierOrCriteria, modelDefinition)) {
|
|
1129
|
-
predicate = ModelPredicateCreator.createForPk<T>(
|
|
1548
|
+
const predicate = ModelPredicateCreator.createForPk<T>(
|
|
1130
1549
|
modelDefinition,
|
|
1131
1550
|
<T>identifierOrCriteria
|
|
1132
1551
|
);
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1552
|
+
result = await this.storage.query<T>(
|
|
1553
|
+
modelConstructor,
|
|
1554
|
+
predicate,
|
|
1555
|
+
pagination
|
|
1556
|
+
);
|
|
1557
|
+
} else if (
|
|
1558
|
+
!identifierOrCriteria ||
|
|
1559
|
+
isPredicatesAll(identifierOrCriteria)
|
|
1560
|
+
) {
|
|
1561
|
+
result = await this.storage?.query<T>(
|
|
1562
|
+
modelConstructor,
|
|
1563
|
+
undefined,
|
|
1564
|
+
pagination
|
|
1140
1565
|
);
|
|
1566
|
+
} else {
|
|
1567
|
+
const seedPredicate = recursivePredicateFor<T>({
|
|
1568
|
+
builder: modelConstructor,
|
|
1569
|
+
schema: modelDefinition,
|
|
1570
|
+
pkField: getModelPKFieldName(modelConstructor),
|
|
1571
|
+
});
|
|
1572
|
+
const predicate = (
|
|
1573
|
+
identifierOrCriteria as RecursiveModelPredicateExtender<T>
|
|
1574
|
+
)(seedPredicate).__query;
|
|
1575
|
+
result = (await predicate.fetch(this.storage)) as T[];
|
|
1576
|
+
result = inMemoryPagination(result, pagination);
|
|
1141
1577
|
}
|
|
1142
1578
|
}
|
|
1143
1579
|
|
|
1144
|
-
const pagination = this.processPagination(
|
|
1145
|
-
modelDefinition,
|
|
1146
|
-
paginationProducer
|
|
1147
|
-
);
|
|
1148
|
-
|
|
1149
1580
|
//#endregion
|
|
1150
1581
|
|
|
1151
|
-
logger.debug('params ready', {
|
|
1152
|
-
modelConstructor,
|
|
1153
|
-
predicate: ModelPredicateCreator.getPredicates(predicate, false),
|
|
1154
|
-
pagination: {
|
|
1155
|
-
...pagination,
|
|
1156
|
-
sort: ModelSortPredicateCreator.getPredicates(
|
|
1157
|
-
pagination && pagination.sort,
|
|
1158
|
-
false
|
|
1159
|
-
),
|
|
1160
|
-
},
|
|
1161
|
-
});
|
|
1162
|
-
|
|
1163
|
-
const result = await this.storage.query(
|
|
1164
|
-
modelConstructor,
|
|
1165
|
-
predicate,
|
|
1166
|
-
pagination
|
|
1167
|
-
);
|
|
1168
|
-
|
|
1169
1582
|
const returnOne =
|
|
1170
1583
|
isQueryOne(identifierOrCriteria) ||
|
|
1171
1584
|
isIdentifierObject(identifierOrCriteria, modelDefinition);
|
|
1172
1585
|
|
|
1173
|
-
return
|
|
1586
|
+
return attached(
|
|
1587
|
+
returnOne ? result[0] : result,
|
|
1588
|
+
ModelAttachment.DataStore
|
|
1589
|
+
);
|
|
1174
1590
|
}, 'datastore query')
|
|
1175
1591
|
.catch(this.handleAddProcError('DataStore.query()'));
|
|
1176
1592
|
};
|
|
1177
1593
|
|
|
1178
1594
|
save = async <T extends PersistentModel>(
|
|
1179
1595
|
model: T,
|
|
1180
|
-
condition?:
|
|
1596
|
+
condition?: ModelPredicateExtender<T>
|
|
1181
1597
|
): Promise<T> => {
|
|
1182
1598
|
return this.runningProcesses
|
|
1183
1599
|
.add(async () => {
|
|
1184
1600
|
await this.start();
|
|
1185
1601
|
|
|
1602
|
+
if (!this.storage) {
|
|
1603
|
+
throw new Error('No storage to save to');
|
|
1604
|
+
}
|
|
1605
|
+
|
|
1186
1606
|
// Immer patches for constructing a correct update mutation input
|
|
1187
1607
|
// Allows us to only include changed fields for updates
|
|
1188
1608
|
const patchesTuple = modelPatchesMap.get(model);
|
|
@@ -1198,22 +1618,67 @@ class DataStore {
|
|
|
1198
1618
|
}
|
|
1199
1619
|
|
|
1200
1620
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1621
|
+
if (!modelDefinition) {
|
|
1622
|
+
throw new Error('Model Definition could not be found for model');
|
|
1623
|
+
}
|
|
1201
1624
|
|
|
1202
|
-
const
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1625
|
+
const modelMeta = {
|
|
1626
|
+
builder: modelConstructor as PersistentModelConstructor<T>,
|
|
1627
|
+
schema: modelDefinition,
|
|
1628
|
+
pkField: extractPrimaryKeyFieldNames(modelDefinition),
|
|
1629
|
+
};
|
|
1206
1630
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1631
|
+
await this.storage.runExclusive(async s => {
|
|
1632
|
+
// no enforcement for HAS_MANY on save, because the ~related~ entities
|
|
1633
|
+
// hold the FK in that case.
|
|
1634
|
+
const nonHasManyRelationships = ModelRelationship.allFrom(
|
|
1635
|
+
modelMeta
|
|
1636
|
+
).filter(r => r.type === 'BELONGS_TO');
|
|
1637
|
+
for (const relationship of nonHasManyRelationships) {
|
|
1638
|
+
const queryObject = relationship.createRemoteQueryObject(model);
|
|
1639
|
+
if (queryObject !== null) {
|
|
1640
|
+
// console.log({ queryObject });
|
|
1641
|
+
const related = await s.query(
|
|
1642
|
+
relationship.remoteModelConstructor,
|
|
1643
|
+
ModelPredicateCreator.createFromFlatEqualities(
|
|
1644
|
+
relationship.remoteDefinition!,
|
|
1645
|
+
queryObject
|
|
1646
|
+
)
|
|
1647
|
+
);
|
|
1648
|
+
if (related.length === 0) {
|
|
1649
|
+
throw new Error(
|
|
1650
|
+
[
|
|
1651
|
+
`Data integrity error. You tried to save a ${
|
|
1652
|
+
modelDefinition.name
|
|
1653
|
+
} (${JSON.stringify(model)})`,
|
|
1654
|
+
`but the instance assigned to the "${relationship.field}" property`,
|
|
1655
|
+
`does not exist in the local database. If you're trying to create the related`,
|
|
1656
|
+
`"${relationship.remoteDefinition?.name}", you must save it independently first.`,
|
|
1657
|
+
].join(' ')
|
|
1658
|
+
);
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
}
|
|
1662
|
+
});
|
|
1209
1663
|
|
|
1664
|
+
const producedCondition = condition
|
|
1665
|
+
? condition(predicateFor(modelMeta)).__query.toStoragePredicate<T>()
|
|
1666
|
+
: undefined;
|
|
1667
|
+
|
|
1668
|
+
const [savedModel] = await this.storage.runExclusive(async s => {
|
|
1669
|
+
const saved = await s.save(
|
|
1670
|
+
model,
|
|
1671
|
+
producedCondition,
|
|
1672
|
+
undefined,
|
|
1673
|
+
patchesTuple
|
|
1674
|
+
);
|
|
1210
1675
|
return s.query<T>(
|
|
1211
1676
|
modelConstructor,
|
|
1212
1677
|
ModelPredicateCreator.createForPk(modelDefinition, model)
|
|
1213
1678
|
);
|
|
1214
1679
|
});
|
|
1215
1680
|
|
|
1216
|
-
return savedModel;
|
|
1681
|
+
return attached(savedModel, ModelAttachment.DataStore);
|
|
1217
1682
|
}, 'datastore save')
|
|
1218
1683
|
.catch(this.handleAddProcError('DataStore.save()'));
|
|
1219
1684
|
};
|
|
@@ -1260,24 +1725,28 @@ class DataStore {
|
|
|
1260
1725
|
): Promise<T[]>;
|
|
1261
1726
|
<T extends PersistentModel>(
|
|
1262
1727
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1263
|
-
condition:
|
|
1728
|
+
condition: ModelPredicateExtender<T> | typeof PredicateAll
|
|
1264
1729
|
): Promise<T[]>;
|
|
1265
1730
|
<T extends PersistentModel>(
|
|
1266
1731
|
model: T,
|
|
1267
|
-
condition?:
|
|
1732
|
+
condition?: ModelPredicateExtender<T>
|
|
1268
1733
|
): Promise<T>;
|
|
1269
1734
|
} = async <T extends PersistentModel>(
|
|
1270
1735
|
modelOrConstructor: T | PersistentModelConstructor<T>,
|
|
1271
1736
|
identifierOrCriteria?:
|
|
1272
1737
|
| IdentifierFieldOrIdentifierObject<T, PersistentModelMetaData<T>>
|
|
1273
|
-
|
|
|
1738
|
+
| ModelPredicateExtender<T>
|
|
1274
1739
|
| typeof PredicateAll
|
|
1275
1740
|
): Promise<T | T[]> => {
|
|
1276
1741
|
return this.runningProcesses
|
|
1277
1742
|
.add(async () => {
|
|
1278
1743
|
await this.start();
|
|
1279
1744
|
|
|
1280
|
-
|
|
1745
|
+
if (!this.storage) {
|
|
1746
|
+
throw new Error('No storage to delete from');
|
|
1747
|
+
}
|
|
1748
|
+
|
|
1749
|
+
let condition: ModelPredicate<T> | undefined;
|
|
1281
1750
|
|
|
1282
1751
|
if (!modelOrConstructor) {
|
|
1283
1752
|
const msg = 'Model or Model Constructor required';
|
|
@@ -1299,6 +1768,12 @@ class DataStore {
|
|
|
1299
1768
|
|
|
1300
1769
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1301
1770
|
|
|
1771
|
+
if (!modelDefinition) {
|
|
1772
|
+
throw new Error(
|
|
1773
|
+
'Could not find model definition for modelConstructor.'
|
|
1774
|
+
);
|
|
1775
|
+
}
|
|
1776
|
+
|
|
1302
1777
|
if (typeof identifierOrCriteria === 'string') {
|
|
1303
1778
|
const keyFields = extractPrimaryKeyFieldNames(modelDefinition);
|
|
1304
1779
|
|
|
@@ -1310,7 +1785,7 @@ class DataStore {
|
|
|
1310
1785
|
}
|
|
1311
1786
|
|
|
1312
1787
|
condition = ModelPredicateCreator.createForSingleField<T>(
|
|
1313
|
-
|
|
1788
|
+
modelDefinition,
|
|
1314
1789
|
keyFields[0],
|
|
1315
1790
|
identifierOrCriteria
|
|
1316
1791
|
);
|
|
@@ -1321,14 +1796,13 @@ class DataStore {
|
|
|
1321
1796
|
<T>identifierOrCriteria
|
|
1322
1797
|
);
|
|
1323
1798
|
} else {
|
|
1324
|
-
condition =
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
);
|
|
1799
|
+
condition = (identifierOrCriteria as ModelPredicateExtender<T>)(
|
|
1800
|
+
predicateFor({
|
|
1801
|
+
builder: modelConstructor as PersistentModelConstructor<T>,
|
|
1802
|
+
schema: modelDefinition,
|
|
1803
|
+
pkField: extractPrimaryKeyFieldNames(modelDefinition),
|
|
1804
|
+
})
|
|
1805
|
+
)?.__query.toStoragePredicate<T>();
|
|
1332
1806
|
}
|
|
1333
1807
|
|
|
1334
1808
|
if (
|
|
@@ -1348,7 +1822,7 @@ class DataStore {
|
|
|
1348
1822
|
condition
|
|
1349
1823
|
);
|
|
1350
1824
|
|
|
1351
|
-
return deleted;
|
|
1825
|
+
return attached(deleted, ModelAttachment.DataStore);
|
|
1352
1826
|
} else {
|
|
1353
1827
|
const model = modelOrConstructor;
|
|
1354
1828
|
const modelConstructor = Object.getPrototypeOf(model || {})
|
|
@@ -1363,6 +1837,12 @@ class DataStore {
|
|
|
1363
1837
|
|
|
1364
1838
|
const modelDefinition = getModelDefinition(modelConstructor);
|
|
1365
1839
|
|
|
1840
|
+
if (!modelDefinition) {
|
|
1841
|
+
throw new Error(
|
|
1842
|
+
'Could not find model definition for modelConstructor.'
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1366
1846
|
const pkPredicate = ModelPredicateCreator.createForPk<T>(
|
|
1367
1847
|
modelDefinition,
|
|
1368
1848
|
model
|
|
@@ -1376,16 +1856,20 @@ class DataStore {
|
|
|
1376
1856
|
throw new Error(msg);
|
|
1377
1857
|
}
|
|
1378
1858
|
|
|
1379
|
-
condition = (<
|
|
1380
|
-
|
|
1381
|
-
|
|
1859
|
+
condition = (identifierOrCriteria as ModelPredicateExtender<T>)(
|
|
1860
|
+
predicateFor({
|
|
1861
|
+
builder: modelConstructor as PersistentModelConstructor<T>,
|
|
1862
|
+
schema: modelDefinition,
|
|
1863
|
+
pkField: extractPrimaryKeyFieldNames(modelDefinition),
|
|
1864
|
+
})
|
|
1865
|
+
).__query.toStoragePredicate<T>(pkPredicate);
|
|
1382
1866
|
} else {
|
|
1383
1867
|
condition = pkPredicate;
|
|
1384
1868
|
}
|
|
1385
1869
|
|
|
1386
1870
|
const [[deleted]] = await this.storage.delete(model, condition);
|
|
1387
1871
|
|
|
1388
|
-
return deleted;
|
|
1872
|
+
return attached(deleted, ModelAttachment.DataStore);
|
|
1389
1873
|
}
|
|
1390
1874
|
}, 'datastore delete')
|
|
1391
1875
|
.catch(this.handleAddProcError('DataStore.delete()'));
|
|
@@ -1401,7 +1885,7 @@ class DataStore {
|
|
|
1401
1885
|
|
|
1402
1886
|
<T extends PersistentModel>(
|
|
1403
1887
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1404
|
-
criteria?:
|
|
1888
|
+
criteria?: RecursiveModelPredicateExtender<T> | typeof PredicateAll
|
|
1405
1889
|
): Observable<SubscriptionMessage<T>>;
|
|
1406
1890
|
|
|
1407
1891
|
<T extends PersistentModel>(model: T): Observable<SubscriptionMessage<T>>;
|
|
@@ -1409,10 +1893,10 @@ class DataStore {
|
|
|
1409
1893
|
modelOrConstructor?: T | PersistentModelConstructor<T>,
|
|
1410
1894
|
identifierOrCriteria?:
|
|
1411
1895
|
| string
|
|
1412
|
-
|
|
|
1896
|
+
| RecursiveModelPredicateExtender<T>
|
|
1413
1897
|
| typeof PredicateAll
|
|
1414
1898
|
): Observable<SubscriptionMessage<T>> => {
|
|
1415
|
-
let
|
|
1899
|
+
let executivePredicate: GroupCondition;
|
|
1416
1900
|
|
|
1417
1901
|
const modelConstructor: PersistentModelConstructor<T> | undefined =
|
|
1418
1902
|
modelOrConstructor && isValidModelConstructor<T>(modelOrConstructor)
|
|
@@ -1448,7 +1932,7 @@ class DataStore {
|
|
|
1448
1932
|
modelConstructor &&
|
|
1449
1933
|
isIdentifierObject(
|
|
1450
1934
|
identifierOrCriteria,
|
|
1451
|
-
getModelDefinition(modelConstructor)
|
|
1935
|
+
getModelDefinition(modelConstructor!)!
|
|
1452
1936
|
)
|
|
1453
1937
|
) {
|
|
1454
1938
|
const msg = errorMessages.observeWithObjectLiteral;
|
|
@@ -1470,30 +1954,19 @@ class DataStore {
|
|
|
1470
1954
|
throw new Error(msg);
|
|
1471
1955
|
}
|
|
1472
1956
|
|
|
1473
|
-
if (typeof identifierOrCriteria === 'string') {
|
|
1474
|
-
const
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
identifierOrCriteria
|
|
1481
|
-
);
|
|
1482
|
-
} else {
|
|
1483
|
-
if (isPredicatesAll(identifierOrCriteria)) {
|
|
1484
|
-
predicate = undefined;
|
|
1485
|
-
} else {
|
|
1486
|
-
predicate =
|
|
1487
|
-
modelConstructor &&
|
|
1488
|
-
ModelPredicateCreator.createFromExisting<T>(
|
|
1489
|
-
getModelDefinition(modelConstructor),
|
|
1490
|
-
identifierOrCriteria
|
|
1491
|
-
);
|
|
1492
|
-
}
|
|
1957
|
+
if (modelConstructor && typeof identifierOrCriteria === 'string') {
|
|
1958
|
+
const buildIdPredicate = seed => seed.id.eq(identifierOrCriteria);
|
|
1959
|
+
executivePredicate = buildIdPredicate(
|
|
1960
|
+
buildSeedPredicate(modelConstructor)
|
|
1961
|
+
).__query;
|
|
1962
|
+
} else if (modelConstructor && typeof identifierOrCriteria === 'function') {
|
|
1963
|
+
executivePredicate = (
|
|
1964
|
+
identifierOrCriteria as RecursiveModelPredicateExtender<T>
|
|
1965
|
+
)(buildSeedPredicate(modelConstructor) as any).__query;
|
|
1493
1966
|
}
|
|
1494
1967
|
|
|
1495
1968
|
return new Observable<SubscriptionMessage<T>>(observer => {
|
|
1496
|
-
let
|
|
1969
|
+
let source: ZenObservable.Subscription;
|
|
1497
1970
|
|
|
1498
1971
|
this.runningProcesses
|
|
1499
1972
|
.add(async () => {
|
|
@@ -1501,8 +1974,7 @@ class DataStore {
|
|
|
1501
1974
|
|
|
1502
1975
|
// Filter the events returned by Storage according to namespace,
|
|
1503
1976
|
// append original element data, and subscribe to the observable
|
|
1504
|
-
|
|
1505
|
-
.observe(modelConstructor, predicate)
|
|
1977
|
+
source = this.storage!.observe(modelConstructor)
|
|
1506
1978
|
.filter(({ model }) => namespaceResolver(model) === USER)
|
|
1507
1979
|
.subscribe({
|
|
1508
1980
|
next: item =>
|
|
@@ -1518,8 +1990,9 @@ class DataStore {
|
|
|
1518
1990
|
// item from storage to ensure it's fully populated.
|
|
1519
1991
|
if (item.opType !== 'DELETE') {
|
|
1520
1992
|
const modelDefinition = getModelDefinition(item.model);
|
|
1521
|
-
const keyFields =
|
|
1522
|
-
|
|
1993
|
+
const keyFields = extractPrimaryKeyFieldNames(
|
|
1994
|
+
modelDefinition!
|
|
1995
|
+
);
|
|
1523
1996
|
const primaryKeysAndValues = extractPrimaryKeysAndValues(
|
|
1524
1997
|
item.element,
|
|
1525
1998
|
keyFields
|
|
@@ -1534,7 +2007,12 @@ class DataStore {
|
|
|
1534
2007
|
};
|
|
1535
2008
|
}
|
|
1536
2009
|
|
|
1537
|
-
|
|
2010
|
+
if (
|
|
2011
|
+
!executivePredicate ||
|
|
2012
|
+
(await executivePredicate.matches(message.element))
|
|
2013
|
+
) {
|
|
2014
|
+
observer.next(message as SubscriptionMessage<T>);
|
|
2015
|
+
}
|
|
1538
2016
|
}, 'datastore observe message handler'),
|
|
1539
2017
|
error: err => observer.error(err),
|
|
1540
2018
|
complete: () => observer.complete(),
|
|
@@ -1549,8 +2027,8 @@ class DataStore {
|
|
|
1549
2027
|
// complete() message async and not registering with the context,
|
|
1550
2028
|
// this will still be problematic.
|
|
1551
2029
|
return this.runningProcesses.addCleaner(async () => {
|
|
1552
|
-
if (
|
|
1553
|
-
|
|
2030
|
+
if (source) {
|
|
2031
|
+
source.unsubscribe();
|
|
1554
2032
|
}
|
|
1555
2033
|
}, 'DataStore.observe() cleanup');
|
|
1556
2034
|
});
|
|
@@ -1559,12 +2037,12 @@ class DataStore {
|
|
|
1559
2037
|
observeQuery: {
|
|
1560
2038
|
<T extends PersistentModel>(
|
|
1561
2039
|
modelConstructor: PersistentModelConstructor<T>,
|
|
1562
|
-
criteria?:
|
|
2040
|
+
criteria?: RecursiveModelPredicateExtender<T> | typeof PredicateAll,
|
|
1563
2041
|
paginationProducer?: ObserveQueryOptions<T>
|
|
1564
2042
|
): Observable<DataStoreSnapshot<T>>;
|
|
1565
2043
|
} = <T extends PersistentModel>(
|
|
1566
2044
|
model: PersistentModelConstructor<T>,
|
|
1567
|
-
criteria?:
|
|
2045
|
+
criteria?: RecursiveModelPredicateExtender<T> | typeof PredicateAll,
|
|
1568
2046
|
options?: ObserveQueryOptions<T>
|
|
1569
2047
|
): Observable<DataStoreSnapshot<T>> => {
|
|
1570
2048
|
return new Observable<DataStoreSnapshot<T>>(observer => {
|
|
@@ -1572,7 +2050,8 @@ class DataStore {
|
|
|
1572
2050
|
const itemsChanged = new Map<string, T>();
|
|
1573
2051
|
let deletedItemIds: string[] = [];
|
|
1574
2052
|
let handle: ZenObservable.Subscription;
|
|
1575
|
-
let predicate: ModelPredicate<T
|
|
2053
|
+
// let predicate: ModelPredicate<T> | undefined;
|
|
2054
|
+
let executivePredicate: GroupCondition | undefined;
|
|
1576
2055
|
|
|
1577
2056
|
/**
|
|
1578
2057
|
* As the name suggests, this geneates a snapshot in the form of
|
|
@@ -1601,29 +2080,17 @@ class DataStore {
|
|
|
1601
2080
|
const sortOptions = sort ? { sort } : undefined;
|
|
1602
2081
|
|
|
1603
2082
|
const modelDefinition = getModelDefinition(model);
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
if (isQueryOne(criteria)) {
|
|
1607
|
-
predicate = ModelPredicateCreator.createForSingleField<T>(
|
|
1608
|
-
modelDefinition,
|
|
1609
|
-
keyFields[0],
|
|
1610
|
-
criteria
|
|
1611
|
-
);
|
|
1612
|
-
} else {
|
|
1613
|
-
if (isPredicatesAll(criteria)) {
|
|
1614
|
-
// Predicates.ALL means "all records", so no predicate (undefined)
|
|
1615
|
-
predicate = undefined;
|
|
1616
|
-
} else {
|
|
1617
|
-
predicate = ModelPredicateCreator.createFromExisting(
|
|
1618
|
-
modelDefinition,
|
|
1619
|
-
criteria
|
|
1620
|
-
);
|
|
1621
|
-
}
|
|
2083
|
+
if (!modelDefinition) {
|
|
2084
|
+
throw new Error('Could not find model definition.');
|
|
1622
2085
|
}
|
|
1623
2086
|
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
2087
|
+
if (model && typeof criteria === 'function') {
|
|
2088
|
+
executivePredicate = (criteria as RecursiveModelPredicateExtender<T>)(
|
|
2089
|
+
buildSeedPredicate(model)
|
|
2090
|
+
).__query;
|
|
2091
|
+
} else if (isPredicatesAll(criteria)) {
|
|
2092
|
+
executivePredicate = undefined;
|
|
2093
|
+
}
|
|
1627
2094
|
|
|
1628
2095
|
this.runningProcesses
|
|
1629
2096
|
.add(async () => {
|
|
@@ -1631,7 +2098,7 @@ class DataStore {
|
|
|
1631
2098
|
// first, query and return any locally-available records
|
|
1632
2099
|
(await this.query(model, criteria, sortOptions)).forEach(item => {
|
|
1633
2100
|
const itemModelDefinition = getModelDefinition(model);
|
|
1634
|
-
const idOrPk = getIdentifierValue(itemModelDefinition
|
|
2101
|
+
const idOrPk = getIdentifierValue(itemModelDefinition!, item);
|
|
1635
2102
|
items.set(idOrPk, item);
|
|
1636
2103
|
});
|
|
1637
2104
|
|
|
@@ -1640,52 +2107,57 @@ class DataStore {
|
|
|
1640
2107
|
// to have visibility into items that move from in-set to out-of-set.
|
|
1641
2108
|
// We need to explicitly remove those items from the existing snapshot.
|
|
1642
2109
|
handle = this.observe(model).subscribe(
|
|
1643
|
-
({ element, model, opType }) =>
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
2110
|
+
({ element, model, opType }) =>
|
|
2111
|
+
this.runningProcesses.isOpen &&
|
|
2112
|
+
this.runningProcesses.add(async () => {
|
|
2113
|
+
const itemModelDefinition = getModelDefinition(model)!;
|
|
2114
|
+
const idOrPk = getIdentifierValue(
|
|
2115
|
+
itemModelDefinition,
|
|
2116
|
+
element
|
|
2117
|
+
);
|
|
1650
2118
|
if (
|
|
1651
|
-
|
|
1652
|
-
(
|
|
2119
|
+
executivePredicate &&
|
|
2120
|
+
!(await executivePredicate.matches(element))
|
|
1653
2121
|
) {
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
2122
|
+
if (
|
|
2123
|
+
opType === 'UPDATE' &&
|
|
2124
|
+
(items.has(idOrPk) || itemsChanged.has(idOrPk))
|
|
2125
|
+
) {
|
|
2126
|
+
// tracking as a "deleted item" will include the item in
|
|
2127
|
+
// page limit calculations and ensure it is removed from the
|
|
2128
|
+
// final items collection, regardless of which collection(s)
|
|
2129
|
+
// it is currently in. (I mean, it could be in both, right!?)
|
|
2130
|
+
deletedItemIds.push(idOrPk);
|
|
2131
|
+
} else {
|
|
2132
|
+
// ignore updates for irrelevant/filtered items.
|
|
2133
|
+
return;
|
|
2134
|
+
}
|
|
2135
|
+
}
|
|
2136
|
+
|
|
2137
|
+
// Flag items which have been recently deleted
|
|
2138
|
+
// NOTE: Merging of separate operations to the same model instance is handled upstream
|
|
2139
|
+
// in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
|
|
2140
|
+
// depends on the LATEST record (for a given id).
|
|
2141
|
+
if (opType === 'DELETE') {
|
|
1658
2142
|
deletedItemIds.push(idOrPk);
|
|
1659
2143
|
} else {
|
|
1660
|
-
|
|
1661
|
-
return;
|
|
2144
|
+
itemsChanged.set(idOrPk, element);
|
|
1662
2145
|
}
|
|
1663
|
-
}
|
|
1664
2146
|
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
// in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
|
|
1668
|
-
// depends on the LATEST record (for a given id).
|
|
1669
|
-
if (opType === 'DELETE') {
|
|
1670
|
-
deletedItemIds.push(idOrPk);
|
|
1671
|
-
} else {
|
|
1672
|
-
itemsChanged.set(idOrPk, element);
|
|
1673
|
-
}
|
|
2147
|
+
const isSynced =
|
|
2148
|
+
this.sync?.getModelSyncedStatus(model) ?? false;
|
|
1674
2149
|
|
|
1675
|
-
|
|
1676
|
-
|
|
2150
|
+
const limit =
|
|
2151
|
+
itemsChanged.size - deletedItemIds.length >=
|
|
2152
|
+
this.syncPageSize;
|
|
1677
2153
|
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
if (limit || isSynced) {
|
|
1683
|
-
limitTimerRace.resolve();
|
|
1684
|
-
}
|
|
2154
|
+
if (limit || isSynced) {
|
|
2155
|
+
limitTimerRace.resolve();
|
|
2156
|
+
}
|
|
1685
2157
|
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
2158
|
+
// kicks off every subsequent race as results sync down
|
|
2159
|
+
limitTimerRace.start();
|
|
2160
|
+
}, 'handle observeQuery observed event')
|
|
1689
2161
|
);
|
|
1690
2162
|
|
|
1691
2163
|
// returns a set of initial/locally-available results
|
|
@@ -1719,7 +2191,7 @@ class DataStore {
|
|
|
1719
2191
|
items.clear();
|
|
1720
2192
|
itemsArray.forEach(item => {
|
|
1721
2193
|
const itemModelDefinition = getModelDefinition(model);
|
|
1722
|
-
const idOrPk = getIdentifierValue(itemModelDefinition
|
|
2194
|
+
const idOrPk = getIdentifierValue(itemModelDefinition!, item);
|
|
1723
2195
|
items.set(idOrPk, item);
|
|
1724
2196
|
});
|
|
1725
2197
|
|
|
@@ -1743,6 +2215,7 @@ class DataStore {
|
|
|
1743
2215
|
const emitSnapshot = (snapshot: DataStoreSnapshot<T>): void => {
|
|
1744
2216
|
// send the generated snapshot to the primary subscription.
|
|
1745
2217
|
// NOTE: This observer's handler *could* be async ...
|
|
2218
|
+
|
|
1746
2219
|
observer.next(snapshot);
|
|
1747
2220
|
|
|
1748
2221
|
// reset the changed items sets
|
|
@@ -1758,10 +2231,10 @@ class DataStore {
|
|
|
1758
2231
|
*/
|
|
1759
2232
|
const sortItems = (itemsToSort: T[]): void => {
|
|
1760
2233
|
const modelDefinition = getModelDefinition(model);
|
|
1761
|
-
const pagination = this.processPagination(modelDefinition
|
|
2234
|
+
const pagination = this.processPagination(modelDefinition!, options);
|
|
1762
2235
|
|
|
1763
2236
|
const sortPredicates = ModelSortPredicateCreator.getPredicates(
|
|
1764
|
-
pagination
|
|
2237
|
+
pagination!.sort!
|
|
1765
2238
|
);
|
|
1766
2239
|
|
|
1767
2240
|
if (sortPredicates.length) {
|
|
@@ -1962,9 +2435,9 @@ class DataStore {
|
|
|
1962
2435
|
*/
|
|
1963
2436
|
private processPagination<T extends PersistentModel>(
|
|
1964
2437
|
modelDefinition: SchemaModel,
|
|
1965
|
-
paginationProducer
|
|
2438
|
+
paginationProducer?: ProducerPaginationInput<T>
|
|
1966
2439
|
): PaginationInput<T> | undefined {
|
|
1967
|
-
let sortPredicate: SortPredicate<T
|
|
2440
|
+
let sortPredicate: SortPredicate<T> | undefined;
|
|
1968
2441
|
const { limit, page, sort } = paginationProducer || {};
|
|
1969
2442
|
|
|
1970
2443
|
if (limit === undefined && page === undefined && sort === undefined) {
|
|
@@ -1998,7 +2471,7 @@ class DataStore {
|
|
|
1998
2471
|
if (sort) {
|
|
1999
2472
|
sortPredicate = ModelSortPredicateCreator.createFromExisting(
|
|
2000
2473
|
modelDefinition,
|
|
2001
|
-
|
|
2474
|
+
sort
|
|
2002
2475
|
);
|
|
2003
2476
|
}
|
|
2004
2477
|
|
|
@@ -2026,21 +2499,24 @@ class DataStore {
|
|
|
2026
2499
|
syncExpression: SyncExpression
|
|
2027
2500
|
): Promise<[SchemaModel, ModelPredicate<any>]> => {
|
|
2028
2501
|
const { modelConstructor, conditionProducer } = await syncExpression;
|
|
2029
|
-
const modelDefinition = getModelDefinition(modelConstructor)
|
|
2502
|
+
const modelDefinition = getModelDefinition(modelConstructor)!;
|
|
2030
2503
|
|
|
2031
2504
|
// conditionProducer is either a predicate, e.g. (c) => c.field('eq', 1)
|
|
2032
2505
|
// OR a function/promise that returns a predicate
|
|
2033
2506
|
const condition = await this.unwrapPromise(conditionProducer);
|
|
2034
2507
|
if (isPredicatesAll(condition)) {
|
|
2035
|
-
return [modelDefinition, null];
|
|
2508
|
+
return [modelDefinition as any, null as any];
|
|
2036
2509
|
}
|
|
2037
2510
|
|
|
2038
|
-
const predicate =
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2511
|
+
const predicate = condition(
|
|
2512
|
+
predicateFor({
|
|
2513
|
+
builder: modelConstructor,
|
|
2514
|
+
schema: modelDefinition,
|
|
2515
|
+
pkField: extractPrimaryKeyFieldNames(modelDefinition),
|
|
2516
|
+
})
|
|
2517
|
+
).__query.toStoragePredicate<any>();
|
|
2042
2518
|
|
|
2043
|
-
return [modelDefinition, predicate];
|
|
2519
|
+
return [modelDefinition as any, predicate as any];
|
|
2044
2520
|
}
|
|
2045
2521
|
)
|
|
2046
2522
|
);
|
|
@@ -2065,7 +2541,7 @@ class DataStore {
|
|
|
2065
2541
|
|
|
2066
2542
|
private async unwrapPromise<T extends PersistentModel>(
|
|
2067
2543
|
conditionProducer
|
|
2068
|
-
): Promise<
|
|
2544
|
+
): Promise<ModelPredicateExtender<T>> {
|
|
2069
2545
|
try {
|
|
2070
2546
|
const condition = await conditionProducer();
|
|
2071
2547
|
return condition;
|