@aws-amplify/datastore 3.14.4 → 3.14.5-unstable.4
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/CHANGELOG.md +0 -8
- 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 +6 -64
- package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib/datastore/datastore.d.ts +207 -0
- package/lib/datastore/datastore.js +703 -297
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/index.d.ts +16 -0
- package/lib/index.js +6 -4
- 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 +301 -0
- package/lib/predicates/next.js +816 -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 +141 -382
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageDatabase.d.ts +39 -0
- package/lib/storage/adapter/AsyncStorageDatabase.js +37 -98
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.d.ts +11 -0
- package/lib/storage/adapter/InMemoryStore.js +16 -67
- package/lib/storage/adapter/InMemoryStore.js.map +1 -1
- package/lib/storage/adapter/InMemoryStore.native.d.ts +1 -0
- package/lib/storage/adapter/InMemoryStore.native.js +2 -4
- package/lib/storage/adapter/InMemoryStore.native.js.map +1 -1
- package/lib/storage/adapter/IndexedDBAdapter.d.ts +61 -0
- package/lib/storage/adapter/IndexedDBAdapter.js +275 -419
- 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 +3 -5
- 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/getDefaultAdapter/index.native.js +2 -4
- package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +1 -1
- 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 +72 -143
- package/lib/storage/storage.js.map +1 -1
- package/lib/sync/datastoreConnectivity.d.ts +16 -0
- package/lib/sync/datastoreConnectivity.js +6 -55
- 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/datastoreReachability/index.native.js +2 -4
- package/lib/sync/datastoreReachability/index.native.js.map +1 -1
- package/lib/sync/index.d.ts +89 -0
- package/lib/sync/index.js +49 -124
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/merger.d.ts +17 -0
- package/lib/sync/merger.js +8 -74
- package/lib/sync/merger.js.map +1 -1
- package/lib/sync/outbox.d.ts +27 -0
- package/lib/sync/outbox.js +24 -97
- package/lib/sync/outbox.js.map +1 -1
- package/lib/sync/processors/errorMaps.d.ts +17 -0
- package/lib/sync/processors/errorMaps.js +5 -35
- package/lib/sync/processors/errorMaps.js.map +1 -1
- package/lib/sync/processors/mutation.d.ts +58 -0
- package/lib/sync/processors/mutation.js +47 -131
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +33 -0
- package/lib/sync/processors/subscription.js +29 -102
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +28 -0
- package/lib/sync/processors/sync.js +26 -102
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +42 -0
- package/lib/sync/utils.js +40 -103
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +554 -0
- package/lib/types.js +9 -39
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +189 -0
- package/lib/util.js +192 -188
- package/lib/util.js.map +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js +2 -57
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib-esm/datastore/datastore.d.ts +59 -8
- package/lib-esm/datastore/datastore.js +642 -234
- 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 +301 -0
- package/lib-esm/predicates/next.js +812 -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 +112 -350
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +7 -68
- 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 +1 -52
- 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 +230 -367
- 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 +33 -101
- package/lib-esm/storage/storage.js.map +1 -1
- package/lib-esm/sync/datastoreConnectivity.js +1 -47
- package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
- package/lib-esm/sync/index.js +4 -76
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/merger.js +1 -67
- package/lib-esm/sync/merger.js.map +1 -1
- package/lib-esm/sync/outbox.js +1 -74
- package/lib-esm/sync/outbox.js.map +1 -1
- package/lib-esm/sync/processors/errorMaps.js +2 -32
- package/lib-esm/sync/processors/errorMaps.js.map +1 -1
- package/lib-esm/sync/processors/mutation.js +12 -93
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.js +6 -69
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.js +2 -75
- 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 +32 -95
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +63 -10
- package/lib-esm/types.js +7 -38
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +39 -6
- package/lib-esm/util.js +171 -171
- package/lib-esm/util.js.map +1 -1
- package/package.json +21 -14
- package/src/authModeStrategies/multiAuthStrategy.ts +2 -2
- package/src/datastore/datastore.ts +699 -206
- package/src/index.ts +4 -0
- package/src/predicates/index.ts +143 -17
- package/src/predicates/next.ts +967 -0
- package/src/predicates/sort.ts +8 -2
- package/src/storage/adapter/AsyncStorageAdapter.ts +59 -181
- package/src/storage/adapter/AsyncStorageDatabase.ts +16 -15
- package/src/storage/adapter/InMemoryStore.ts +5 -2
- package/src/storage/adapter/IndexedDBAdapter.ts +169 -192
- 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 +23 -19
- package/src/sync/processors/subscription.ts +20 -16
- package/src/sync/processors/sync.ts +17 -17
- package/src/sync/utils.ts +42 -48
- package/src/types.ts +128 -16
- package/src/util.ts +108 -150
- package/build.js +0 -5
- package/dist/aws-amplify-datastore.js +0 -92787
- package/dist/aws-amplify-datastore.js.map +0 -1
- package/dist/aws-amplify-datastore.min.js +0 -66
- package/dist/aws-amplify-datastore.min.js.map +0 -1
- package/index.js +0 -7
- package/webpack.config.dev.js +0 -6
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { isFieldAssociation, ModelFieldType, ModelMeta } from '../types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Defines a relationship from a LOCAL model.field to a REMOTE model.field and helps
|
|
5
|
+
* navigate the relationship, providing a simplified peek at the relationship details
|
|
6
|
+
* pertinent to setting FK's and constructing join conditions.
|
|
7
|
+
*
|
|
8
|
+
* Because I mean, relationships are tough.
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export class ModelRelationship<T> {
|
|
12
|
+
private localModel: ModelMeta<T>;
|
|
13
|
+
private _field: string;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param modelDefinition The "local" model.
|
|
17
|
+
* @param field The "local" model field.
|
|
18
|
+
*/
|
|
19
|
+
constructor(model: ModelMeta<T>, field: string) {
|
|
20
|
+
if (!isFieldAssociation(model.schema, field)) {
|
|
21
|
+
throw new Error(`${model.schema.name}.${field} is not a relationship.`);
|
|
22
|
+
}
|
|
23
|
+
this.localModel = model;
|
|
24
|
+
this._field = field;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Returns a ModelRelationship for the the given model and field if the pair
|
|
29
|
+
* indicates a relationship to another model. Else, returns `null`.
|
|
30
|
+
*
|
|
31
|
+
* @param model The model the relationship field exists in.
|
|
32
|
+
* @param field The field that may relates the local model to the remote model.
|
|
33
|
+
*/
|
|
34
|
+
static from<T>(model: ModelMeta<T>, field: string) {
|
|
35
|
+
if (isFieldAssociation(model.schema, field)) {
|
|
36
|
+
return new this(model, field);
|
|
37
|
+
} else {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Enumerates all valid `ModelRelationship`'s on the given model.
|
|
44
|
+
*
|
|
45
|
+
* @param model The model definition to enumerate relationships of.
|
|
46
|
+
*/
|
|
47
|
+
static allFrom<T>(model: ModelMeta<T>) {
|
|
48
|
+
const relationships: ModelRelationship<T>[] = [];
|
|
49
|
+
for (const field of Object.keys(model.schema.fields)) {
|
|
50
|
+
const relationship = ModelRelationship.from(model, field);
|
|
51
|
+
relationship && relationships.push(relationship);
|
|
52
|
+
}
|
|
53
|
+
return relationships;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private get localDefinition() {
|
|
57
|
+
return this.localModel.schema;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The virtual/computed field on the local model that should contain
|
|
62
|
+
* the related model.
|
|
63
|
+
*/
|
|
64
|
+
get field() {
|
|
65
|
+
return this._field;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* The constructor that can be used to query DataStore or create instance for
|
|
70
|
+
* the local model.
|
|
71
|
+
*/
|
|
72
|
+
get localConstructor() {
|
|
73
|
+
return this.localModel.builder;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The name/type of the relationship the local model has with the remote model
|
|
78
|
+
* via the defined local model field.
|
|
79
|
+
*/
|
|
80
|
+
get type() {
|
|
81
|
+
return this.localAssocation.connectionType;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Raw details about the local FK as-is from the local model's field definition in
|
|
86
|
+
* the schema. This field requires interpretation.
|
|
87
|
+
*
|
|
88
|
+
* @see localJoinFields
|
|
89
|
+
* @see localAssociatedWith
|
|
90
|
+
*/
|
|
91
|
+
private get localAssocation() {
|
|
92
|
+
return this.localDefinition.fields[this.field].association!;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The field names on the local model that can be used to query or queried to match
|
|
97
|
+
* with instances of the remote model.
|
|
98
|
+
*
|
|
99
|
+
* Fields are returned in-order to match the order of `this.remoteKeyFields`.
|
|
100
|
+
*/
|
|
101
|
+
get localJoinFields() {
|
|
102
|
+
/**
|
|
103
|
+
* This is relatively straightforward, actually.
|
|
104
|
+
*
|
|
105
|
+
* If we have explicitly stated targetNames, codegen is telling us authoritatively
|
|
106
|
+
* to use those fields for this relationship. The local model "points to" fields
|
|
107
|
+
* in the remote one.
|
|
108
|
+
*
|
|
109
|
+
* In other cases, the remote model points to this one's
|
|
110
|
+
*/
|
|
111
|
+
if (this.localAssocation.targetName) {
|
|
112
|
+
// This case is theoretically unnecessary going forward.
|
|
113
|
+
return [this.localAssocation.targetName];
|
|
114
|
+
} else if (this.localAssocation.targetNames) {
|
|
115
|
+
return this.localAssocation.targetNames;
|
|
116
|
+
} else {
|
|
117
|
+
return this.localPKFields;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* The field names on the local model that uniquely identify it.
|
|
123
|
+
*
|
|
124
|
+
* These fields may or may not be relevant to the join fields.
|
|
125
|
+
*/
|
|
126
|
+
get localPKFields() {
|
|
127
|
+
return this.localModel.pkField;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
get remoteDefinition() {
|
|
131
|
+
return this.remoteModelType.modelConstructor?.schema;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private get remoteModelType() {
|
|
135
|
+
return this.localDefinition.fields[this.field].type as ModelFieldType;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Constructor that can be used to query DataStore or create instances for
|
|
140
|
+
* the remote model.
|
|
141
|
+
*/
|
|
142
|
+
get remoteModelConstructor() {
|
|
143
|
+
return this.remoteModelType.modelConstructor!.builder!;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* The field names on the remote model that uniquely identify it.
|
|
148
|
+
*
|
|
149
|
+
* These fields may or may not be relevant to the join fields.
|
|
150
|
+
*/
|
|
151
|
+
get remotePKFields() {
|
|
152
|
+
return this.remoteModelType.modelConstructor?.pkField || ['id'];
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* The `associatedWith` fields from the local perspective.
|
|
157
|
+
*
|
|
158
|
+
* When present, these fields indicate which fields on the remote model to use
|
|
159
|
+
* when looking for a remote association and/or determining the final remote
|
|
160
|
+
* key fields.
|
|
161
|
+
*/
|
|
162
|
+
private get localAssociatedWith() {
|
|
163
|
+
if (
|
|
164
|
+
this.localAssocation.connectionType === 'HAS_MANY' ||
|
|
165
|
+
this.localAssocation.connectionType === 'HAS_ONE'
|
|
166
|
+
) {
|
|
167
|
+
// This de-arraying is theoretically unnecessary going forward.
|
|
168
|
+
return Array.isArray(this.localAssocation.associatedWith)
|
|
169
|
+
? this.localAssocation.associatedWith
|
|
170
|
+
: [this.localAssocation.associatedWith];
|
|
171
|
+
} else {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
private get explicitRemoteAssociation() {
|
|
177
|
+
if (this.localAssociatedWith) {
|
|
178
|
+
if (this.localAssociatedWith.length === 1) {
|
|
179
|
+
return this.remoteDefinition!.fields[this.localAssociatedWith[0]]
|
|
180
|
+
?.association;
|
|
181
|
+
} else {
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* The field names on the remote model that can used to query or queried to match
|
|
189
|
+
* with instances of the local model.
|
|
190
|
+
*
|
|
191
|
+
* Fields are returned in-order to match the order of `this.localKeyFields`.
|
|
192
|
+
*/
|
|
193
|
+
get remoteJoinFields() {
|
|
194
|
+
/**
|
|
195
|
+
* If the local relationship explicitly names "associated with" fields, we
|
|
196
|
+
* need to see if this points direction to a reciprocating assocation. If it
|
|
197
|
+
* does, the remote assocation indicates what fields to use.
|
|
198
|
+
*/
|
|
199
|
+
|
|
200
|
+
if (this.explicitRemoteAssociation?.targetName) {
|
|
201
|
+
// This case is theoretically unnecessary going forward.
|
|
202
|
+
return [this.explicitRemoteAssociation.targetName!];
|
|
203
|
+
} else if (this.explicitRemoteAssociation?.targetNames) {
|
|
204
|
+
return this.explicitRemoteAssociation?.targetNames!;
|
|
205
|
+
} else if (this.localAssociatedWith) {
|
|
206
|
+
return this.localAssociatedWith;
|
|
207
|
+
} else {
|
|
208
|
+
return this.remotePKFields;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Whether this relationship everything necessary to get, set, and query from
|
|
214
|
+
* the perspective of the local model provided at instantiation.
|
|
215
|
+
*/
|
|
216
|
+
get isComplete() {
|
|
217
|
+
return this.localJoinFields.length > 0 && this.remoteJoinFields.length > 0;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Creates an FK mapper object with respect to the given related instance.
|
|
222
|
+
*
|
|
223
|
+
* E.g., if the local FK fields are `[parentId, parentName]` and point to
|
|
224
|
+
* `[customId, name]` on the remote model, `createLocalFKObject(remote)`
|
|
225
|
+
* will return:
|
|
226
|
+
*
|
|
227
|
+
* ```
|
|
228
|
+
* {
|
|
229
|
+
* parentId: remote.customId,
|
|
230
|
+
* parentName: remote.name
|
|
231
|
+
* }
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @param remote The remote related instance.
|
|
235
|
+
*/
|
|
236
|
+
createLocalFKObject(remote: any) {
|
|
237
|
+
const fk = {} as Record<string, string>;
|
|
238
|
+
for (let i = 0; i < this.localJoinFields.length; i++) {
|
|
239
|
+
fk[this.localJoinFields[i]] = remote[this.remoteJoinFields[i]];
|
|
240
|
+
}
|
|
241
|
+
return fk;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Creates an query mapper object to help fetch the remote instance(s) or
|
|
246
|
+
* `null` if any of the necessary local fields are `null` or `undefined`.
|
|
247
|
+
*
|
|
248
|
+
* E.g., if the local FK fields are `[parentId, parentName]` and point to
|
|
249
|
+
* `[customId, name]` on the remote model, `createLocalFKObject(remote)`
|
|
250
|
+
* will return:
|
|
251
|
+
*
|
|
252
|
+
* ```
|
|
253
|
+
* {
|
|
254
|
+
* customId: local.parentId
|
|
255
|
+
* name: local.parentName
|
|
256
|
+
* }
|
|
257
|
+
* ```
|
|
258
|
+
*
|
|
259
|
+
* If the local fields are not populated, returns
|
|
260
|
+
*
|
|
261
|
+
* @param local The local instance.
|
|
262
|
+
*/
|
|
263
|
+
createRemoteQueryObject(local: T) {
|
|
264
|
+
const query = {} as Record<string, string>;
|
|
265
|
+
for (let i = 0; i < this.remoteJoinFields.length; i++) {
|
|
266
|
+
const localValue = local[this.localJoinFields[i]];
|
|
267
|
+
if (localValue === null || localValue === undefined) return null;
|
|
268
|
+
query[this.remoteJoinFields[i]] = local[this.localJoinFields[i]];
|
|
269
|
+
}
|
|
270
|
+
return query;
|
|
271
|
+
}
|
|
272
|
+
}
|
package/src/storage/storage.ts
CHANGED
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
STORAGE,
|
|
26
26
|
validatePredicate,
|
|
27
27
|
valuesEqual,
|
|
28
|
+
NAMESPACES,
|
|
28
29
|
} from '../util';
|
|
29
30
|
import { getIdentifierValue } from '../sync/utils';
|
|
30
31
|
import { Adapter } from './adapter';
|
|
@@ -40,7 +41,7 @@ export type Storage = InstanceType<typeof StorageClass>;
|
|
|
40
41
|
|
|
41
42
|
const logger = new Logger('DataStore');
|
|
42
43
|
class StorageClass implements StorageFacade {
|
|
43
|
-
private initialized: Promise<void
|
|
44
|
+
private initialized: Promise<void> | undefined;
|
|
44
45
|
private readonly pushStream: {
|
|
45
46
|
observable: Observable<StorageSubscriptionMessage<PersistentModel>>;
|
|
46
47
|
} & Required<
|
|
@@ -51,7 +52,7 @@ class StorageClass implements StorageFacade {
|
|
|
51
52
|
private readonly schema: InternalSchema,
|
|
52
53
|
private readonly namespaceResolver: NamespaceResolver,
|
|
53
54
|
private readonly getModelConstructorByModelName: (
|
|
54
|
-
namsespaceName:
|
|
55
|
+
namsespaceName: NAMESPACES,
|
|
55
56
|
modelName: string
|
|
56
57
|
) => PersistentModelConstructor<any>,
|
|
57
58
|
private readonly modelInstanceCreator: ModelInstanceCreator,
|
|
@@ -59,7 +60,7 @@ class StorageClass implements StorageFacade {
|
|
|
59
60
|
private readonly sessionId?: string
|
|
60
61
|
) {
|
|
61
62
|
this.adapter = this.adapter || getDefaultAdapter();
|
|
62
|
-
this.pushStream = new PushStream();
|
|
63
|
+
this.pushStream = new PushStream() as any;
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
static getNamespace() {
|
|
@@ -89,15 +90,13 @@ class StorageClass implements StorageFacade {
|
|
|
89
90
|
reject = rej;
|
|
90
91
|
});
|
|
91
92
|
|
|
92
|
-
this.adapter
|
|
93
|
-
.
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
)
|
|
100
|
-
.then(resolve, reject);
|
|
93
|
+
this.adapter!.setUp(
|
|
94
|
+
this.schema,
|
|
95
|
+
this.namespaceResolver,
|
|
96
|
+
this.modelInstanceCreator,
|
|
97
|
+
this.getModelConstructorByModelName,
|
|
98
|
+
this.sessionId
|
|
99
|
+
).then(resolve!, reject!);
|
|
101
100
|
|
|
102
101
|
await this.initialized;
|
|
103
102
|
}
|
|
@@ -109,6 +108,9 @@ class StorageClass implements StorageFacade {
|
|
|
109
108
|
patchesTuple?: [Patch[], PersistentModel]
|
|
110
109
|
): Promise<[T, OpType.INSERT | OpType.UPDATE][]> {
|
|
111
110
|
await this.init();
|
|
111
|
+
if (!this.adapter) {
|
|
112
|
+
throw new Error('Storage adapter is missing');
|
|
113
|
+
}
|
|
112
114
|
|
|
113
115
|
const result = await this.adapter.save(model, condition);
|
|
114
116
|
|
|
@@ -152,11 +154,14 @@ class StorageClass implements StorageFacade {
|
|
|
152
154
|
.constructor as PersistentModelConstructor<T>;
|
|
153
155
|
|
|
154
156
|
this.pushStream.next({
|
|
155
|
-
model: modelConstructor,
|
|
157
|
+
model: modelConstructor as any,
|
|
156
158
|
opType,
|
|
157
159
|
element,
|
|
158
160
|
mutator,
|
|
159
|
-
condition:
|
|
161
|
+
condition:
|
|
162
|
+
(condition &&
|
|
163
|
+
ModelPredicateCreator.getPredicates(condition, false)) ||
|
|
164
|
+
null,
|
|
160
165
|
savedElement,
|
|
161
166
|
});
|
|
162
167
|
});
|
|
@@ -180,9 +185,12 @@ class StorageClass implements StorageFacade {
|
|
|
180
185
|
mutator?: Symbol
|
|
181
186
|
): Promise<[T[], T[]]> {
|
|
182
187
|
await this.init();
|
|
188
|
+
if (!this.adapter) {
|
|
189
|
+
throw new Error('Storage adapter is missing');
|
|
190
|
+
}
|
|
183
191
|
|
|
184
|
-
let deleted: T[];
|
|
185
192
|
let models: T[];
|
|
193
|
+
let deleted: T[] | undefined;
|
|
186
194
|
|
|
187
195
|
[models, deleted] = await this.adapter.delete(
|
|
188
196
|
modelOrModelConstructor,
|
|
@@ -216,21 +224,21 @@ class StorageClass implements StorageFacade {
|
|
|
216
224
|
const modelConstructor = (Object.getPrototypeOf(model) as Object)
|
|
217
225
|
.constructor as PersistentModelConstructor<T>;
|
|
218
226
|
|
|
219
|
-
let theCondition: PredicatesGroup<any
|
|
227
|
+
let theCondition: PredicatesGroup<any> | undefined;
|
|
220
228
|
|
|
221
229
|
if (!isModelConstructor(modelOrModelConstructor)) {
|
|
222
230
|
const modelId = getIdentifierValue(modelDefinition, model);
|
|
223
231
|
theCondition = modelIds.has(modelId)
|
|
224
|
-
? ModelPredicateCreator.getPredicates(condition
|
|
232
|
+
? ModelPredicateCreator.getPredicates(condition!, false)
|
|
225
233
|
: undefined;
|
|
226
234
|
}
|
|
227
235
|
|
|
228
236
|
this.pushStream.next({
|
|
229
|
-
model: modelConstructor,
|
|
237
|
+
model: modelConstructor as any,
|
|
230
238
|
opType: OpType.DELETE,
|
|
231
239
|
element: model,
|
|
232
240
|
mutator,
|
|
233
|
-
condition: theCondition,
|
|
241
|
+
condition: theCondition || null,
|
|
234
242
|
});
|
|
235
243
|
});
|
|
236
244
|
|
|
@@ -243,6 +251,9 @@ class StorageClass implements StorageFacade {
|
|
|
243
251
|
pagination?: PaginationInput<T>
|
|
244
252
|
): Promise<T[]> {
|
|
245
253
|
await this.init();
|
|
254
|
+
if (!this.adapter) {
|
|
255
|
+
throw new Error('Storage adapter is missing');
|
|
256
|
+
}
|
|
246
257
|
|
|
247
258
|
return await this.adapter.query(modelConstructor, predicate, pagination);
|
|
248
259
|
}
|
|
@@ -250,22 +261,24 @@ class StorageClass implements StorageFacade {
|
|
|
250
261
|
async queryOne<T extends PersistentModel>(
|
|
251
262
|
modelConstructor: PersistentModelConstructor<T>,
|
|
252
263
|
firstOrLast: QueryOne = QueryOne.FIRST
|
|
253
|
-
): Promise<T> {
|
|
264
|
+
): Promise<T | undefined> {
|
|
254
265
|
await this.init();
|
|
266
|
+
if (!this.adapter) {
|
|
267
|
+
throw new Error('Storage adapter is missing');
|
|
268
|
+
}
|
|
255
269
|
|
|
256
|
-
|
|
257
|
-
return record;
|
|
270
|
+
return await this.adapter.queryOne(modelConstructor, firstOrLast);
|
|
258
271
|
}
|
|
259
272
|
|
|
260
273
|
observe<T extends PersistentModel>(
|
|
261
|
-
modelConstructor?: PersistentModelConstructor<T
|
|
262
|
-
predicate?: ModelPredicate<T
|
|
274
|
+
modelConstructor?: PersistentModelConstructor<T> | null,
|
|
275
|
+
predicate?: ModelPredicate<T> | null,
|
|
263
276
|
skipOwn?: Symbol
|
|
264
277
|
): Observable<SubscriptionMessage<T>> {
|
|
265
278
|
const listenToAll = !modelConstructor;
|
|
266
279
|
const { predicates, type } =
|
|
267
|
-
ModelPredicateCreator.getPredicates(predicate, false) ||
|
|
268
|
-
|
|
280
|
+
(predicate && ModelPredicateCreator.getPredicates(predicate, false)) ||
|
|
281
|
+
{};
|
|
269
282
|
|
|
270
283
|
let result = this.pushStream.observable
|
|
271
284
|
.filter(({ mutator }) => {
|
|
@@ -281,7 +294,7 @@ class StorageClass implements StorageFacade {
|
|
|
281
294
|
return false;
|
|
282
295
|
}
|
|
283
296
|
|
|
284
|
-
if (
|
|
297
|
+
if (!!predicates && !!type) {
|
|
285
298
|
return validatePredicate(element, type, predicates);
|
|
286
299
|
}
|
|
287
300
|
|
|
@@ -294,6 +307,9 @@ class StorageClass implements StorageFacade {
|
|
|
294
307
|
|
|
295
308
|
async clear(completeObservable = true) {
|
|
296
309
|
this.initialized = undefined;
|
|
310
|
+
if (!this.adapter) {
|
|
311
|
+
throw new Error('Storage adapter is missing');
|
|
312
|
+
}
|
|
297
313
|
|
|
298
314
|
await this.adapter.clear();
|
|
299
315
|
|
|
@@ -308,6 +324,9 @@ class StorageClass implements StorageFacade {
|
|
|
308
324
|
mutator?: Symbol
|
|
309
325
|
): Promise<[T, OpType][]> {
|
|
310
326
|
await this.init();
|
|
327
|
+
if (!this.adapter) {
|
|
328
|
+
throw new Error('Storage adapter is missing');
|
|
329
|
+
}
|
|
311
330
|
|
|
312
331
|
const result = await this.adapter.batchSave(modelConstructor, items);
|
|
313
332
|
|
|
@@ -317,7 +336,7 @@ class StorageClass implements StorageFacade {
|
|
|
317
336
|
opType,
|
|
318
337
|
element,
|
|
319
338
|
mutator,
|
|
320
|
-
condition:
|
|
339
|
+
condition: null,
|
|
321
340
|
});
|
|
322
341
|
});
|
|
323
342
|
|
|
@@ -335,7 +354,7 @@ class StorageClass implements StorageFacade {
|
|
|
335
354
|
return null;
|
|
336
355
|
}
|
|
337
356
|
|
|
338
|
-
const [patches, source] = patchesTuple
|
|
357
|
+
const [patches, source] = patchesTuple!;
|
|
339
358
|
const updatedElement = {};
|
|
340
359
|
// extract array of updated fields from patches
|
|
341
360
|
const updatedFields = <string[]>(
|
|
@@ -349,7 +368,7 @@ class StorageClass implements StorageFacade {
|
|
|
349
368
|
const { fields } =
|
|
350
369
|
this.schema.namespaces[namespace].models[modelConstructor.name];
|
|
351
370
|
const { primaryKey, compositeKeys = [] } =
|
|
352
|
-
this.schema.namespaces[namespace].keys[modelConstructor.name];
|
|
371
|
+
this.schema.namespaces[namespace].keys?.[modelConstructor.name] || {};
|
|
353
372
|
|
|
354
373
|
// set original values for these fields
|
|
355
374
|
updatedFields.forEach((field: string) => {
|
|
@@ -440,7 +459,7 @@ class ExclusiveStorage implements StorageFacade {
|
|
|
440
459
|
schema: InternalSchema,
|
|
441
460
|
namespaceResolver: NamespaceResolver,
|
|
442
461
|
getModelConstructorByModelName: (
|
|
443
|
-
namsespaceName:
|
|
462
|
+
namsespaceName: NAMESPACES,
|
|
444
463
|
modelName: string
|
|
445
464
|
) => PersistentModelConstructor<any>,
|
|
446
465
|
modelInstanceCreator: ModelInstanceCreator,
|
|
@@ -491,11 +510,11 @@ class ExclusiveStorage implements StorageFacade {
|
|
|
491
510
|
if (isModelConstructor(modelOrModelConstructor)) {
|
|
492
511
|
const modelConstructor = modelOrModelConstructor;
|
|
493
512
|
|
|
494
|
-
return storage.delete(modelConstructor, condition, mutator);
|
|
513
|
+
return storage.delete(modelConstructor as any, condition, mutator);
|
|
495
514
|
} else {
|
|
496
515
|
const model = modelOrModelConstructor;
|
|
497
516
|
|
|
498
|
-
return storage.delete(model, condition, mutator);
|
|
517
|
+
return storage.delete(model as any, condition, mutator);
|
|
499
518
|
}
|
|
500
519
|
});
|
|
501
520
|
}
|
|
@@ -513,8 +532,8 @@ class ExclusiveStorage implements StorageFacade {
|
|
|
513
532
|
async queryOne<T extends PersistentModel>(
|
|
514
533
|
modelConstructor: PersistentModelConstructor<T>,
|
|
515
534
|
firstOrLast: QueryOne = QueryOne.FIRST
|
|
516
|
-
): Promise<T> {
|
|
517
|
-
return this.runExclusive<T>(storage =>
|
|
535
|
+
): Promise<T | undefined> {
|
|
536
|
+
return this.runExclusive<T | undefined>(storage =>
|
|
518
537
|
storage.queryOne<T>(modelConstructor, firstOrLast)
|
|
519
538
|
);
|
|
520
539
|
}
|
|
@@ -524,8 +543,8 @@ class ExclusiveStorage implements StorageFacade {
|
|
|
524
543
|
}
|
|
525
544
|
|
|
526
545
|
observe<T extends PersistentModel>(
|
|
527
|
-
modelConstructor?: PersistentModelConstructor<T
|
|
528
|
-
predicate?: ModelPredicate<T
|
|
546
|
+
modelConstructor?: PersistentModelConstructor<T> | null,
|
|
547
|
+
predicate?: ModelPredicate<T> | null,
|
|
529
548
|
skipOwn?: Symbol
|
|
530
549
|
): Observable<SubscriptionMessage<T>> {
|
|
531
550
|
return this.storage.observe(modelConstructor, predicate, skipOwn);
|
|
@@ -13,9 +13,9 @@ type ConnectionStatus = {
|
|
|
13
13
|
|
|
14
14
|
export default class DataStoreConnectivity {
|
|
15
15
|
private connectionStatus: ConnectionStatus;
|
|
16
|
-
private observer
|
|
17
|
-
private subscription
|
|
18
|
-
private timeout
|
|
16
|
+
private observer!: ZenObservable.SubscriptionObserver<ConnectionStatus>;
|
|
17
|
+
private subscription!: ZenObservable.Subscription;
|
|
18
|
+
private timeout!: ReturnType<typeof setTimeout>;
|
|
19
19
|
constructor() {
|
|
20
20
|
this.connectionStatus = {
|
|
21
21
|
online: false,
|
|
@@ -26,7 +26,7 @@ export default class DataStoreConnectivity {
|
|
|
26
26
|
if (this.observer) {
|
|
27
27
|
throw new Error('Subscriber already exists');
|
|
28
28
|
}
|
|
29
|
-
return new Observable(observer => {
|
|
29
|
+
return new Observable((observer) => {
|
|
30
30
|
this.observer = observer;
|
|
31
31
|
// Will be used to forward socket connection changes, enhancing Reachability
|
|
32
32
|
|
package/src/sync/index.ts
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
// tslint:disable:no-duplicate-imports
|
|
33
33
|
import type { __modelMeta__ } from '../types';
|
|
34
34
|
|
|
35
|
-
import {
|
|
35
|
+
import { getNow, SYNC, USER } from '../util';
|
|
36
36
|
import DataStoreConnectivity from './datastoreConnectivity';
|
|
37
37
|
import { ModelMerger } from './merger';
|
|
38
38
|
import { MutationEventOutbox } from './outbox';
|
|
@@ -122,7 +122,7 @@ export class SyncEngine {
|
|
|
122
122
|
public getModelSyncedStatus(
|
|
123
123
|
modelConstructor: PersistentModelConstructor<any>
|
|
124
124
|
): boolean {
|
|
125
|
-
return this.modelSyncedStatus.get(modelConstructor)
|
|
125
|
+
return this.modelSyncedStatus.get(modelConstructor)!;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
128
|
constructor(
|
|
@@ -235,14 +235,8 @@ export class SyncEngine {
|
|
|
235
235
|
);
|
|
236
236
|
} else {
|
|
237
237
|
//#region GraphQL Subscriptions
|
|
238
|
-
[
|
|
239
|
-
|
|
240
|
-
ctlSubsObservable,
|
|
241
|
-
// const dataObservable: Observable<[TransformerMutationType, SchemaModel, Readonly<{
|
|
242
|
-
// id: string;
|
|
243
|
-
// } & Record<string, any>>]>
|
|
244
|
-
dataSubsObservable,
|
|
245
|
-
] = this.subscriptionsProcessor.start();
|
|
238
|
+
[ctlSubsObservable, dataSubsObservable] =
|
|
239
|
+
this.subscriptionsProcessor.start();
|
|
246
240
|
|
|
247
241
|
try {
|
|
248
242
|
await new Promise((resolve, reject) => {
|
|
@@ -362,7 +356,7 @@ export class SyncEngine {
|
|
|
362
356
|
// TODO: extract to function
|
|
363
357
|
if (!isNode) {
|
|
364
358
|
subscriptions.push(
|
|
365
|
-
dataSubsObservable
|
|
359
|
+
dataSubsObservable!.subscribe(
|
|
366
360
|
([_transformerMutationType, modelDefinition, item]) =>
|
|
367
361
|
this.runningProcesses.add(async () => {
|
|
368
362
|
const modelConstructor = this.userModelClasses[
|
|
@@ -421,11 +415,11 @@ export class SyncEngine {
|
|
|
421
415
|
] as PersistentModelConstructor<MutationEvent>;
|
|
422
416
|
const modelDefinition = this.getModelDefinition(model);
|
|
423
417
|
const graphQLCondition = predicateToGraphQLCondition(
|
|
424
|
-
condition
|
|
418
|
+
condition!,
|
|
425
419
|
modelDefinition
|
|
426
420
|
);
|
|
427
421
|
const mutationEvent = createMutationInstanceFromModelOperation(
|
|
428
|
-
namespace.relationships
|
|
422
|
+
namespace.relationships!,
|
|
429
423
|
this.getModelDefinition(model),
|
|
430
424
|
opType,
|
|
431
425
|
model,
|
|
@@ -500,7 +494,7 @@ export class SyncEngine {
|
|
|
500
494
|
fullSyncInterval,
|
|
501
495
|
lastSyncPredicate,
|
|
502
496
|
}) => {
|
|
503
|
-
const nextFullSync = lastFullSync + fullSyncInterval;
|
|
497
|
+
const nextFullSync = lastFullSync! + fullSyncInterval;
|
|
504
498
|
const syncFrom =
|
|
505
499
|
!lastFullSync || nextFullSync < currentTimeStamp
|
|
506
500
|
? 0 // perform full sync if expired
|
|
@@ -508,7 +502,7 @@ export class SyncEngine {
|
|
|
508
502
|
|
|
509
503
|
return [
|
|
510
504
|
this.schema.namespaces[namespace].models[model],
|
|
511
|
-
[namespace, syncFrom],
|
|
505
|
+
[namespace, syncFrom!],
|
|
512
506
|
];
|
|
513
507
|
}
|
|
514
508
|
)
|
|
@@ -631,7 +625,7 @@ export class SyncEngine {
|
|
|
631
625
|
))
|
|
632
626
|
);
|
|
633
627
|
|
|
634
|
-
const counts = count.get(modelConstructor)
|
|
628
|
+
const counts = count.get(modelConstructor)!;
|
|
635
629
|
|
|
636
630
|
opTypeCount.forEach(([, opType]) => {
|
|
637
631
|
switch (opType) {
|
|
@@ -645,7 +639,7 @@ export class SyncEngine {
|
|
|
645
639
|
counts.deleted++;
|
|
646
640
|
break;
|
|
647
641
|
default:
|
|
648
|
-
|
|
642
|
+
throw new Error(`Invalid opType ${opType}`);
|
|
649
643
|
}
|
|
650
644
|
});
|
|
651
645
|
});
|
|
@@ -665,10 +659,10 @@ export class SyncEngine {
|
|
|
665
659
|
|
|
666
660
|
newestFullSyncStartedAt =
|
|
667
661
|
newestFullSyncStartedAt === undefined
|
|
668
|
-
? lastFullSync
|
|
662
|
+
? lastFullSync!
|
|
669
663
|
: Math.max(
|
|
670
664
|
newestFullSyncStartedAt,
|
|
671
|
-
isFullSync ? startedAt : lastFullSync
|
|
665
|
+
isFullSync ? startedAt : lastFullSync!
|
|
672
666
|
);
|
|
673
667
|
|
|
674
668
|
modelMetadata = (
|
|
@@ -728,9 +722,9 @@ export class SyncEngine {
|
|
|
728
722
|
});
|
|
729
723
|
|
|
730
724
|
const msNextFullSync =
|
|
731
|
-
newestFullSyncStartedAt +
|
|
732
|
-
theInterval -
|
|
733
|
-
(newestStartedAt + duration);
|
|
725
|
+
newestFullSyncStartedAt! +
|
|
726
|
+
theInterval! -
|
|
727
|
+
(newestStartedAt! + duration!);
|
|
734
728
|
|
|
735
729
|
logger.debug(
|
|
736
730
|
`Next fullSync in ${msNextFullSync / 1000} seconds. (${new Date(
|
|
@@ -843,7 +837,7 @@ export class SyncEngine {
|
|
|
843
837
|
const promises = models.map(async ([namespace, model]) => {
|
|
844
838
|
const modelMetadata = await this.getModelMetadata(namespace, model.name);
|
|
845
839
|
const syncPredicate = ModelPredicateCreator.getPredicates(
|
|
846
|
-
this.syncPredicates.get(model)
|
|
840
|
+
this.syncPredicates.get(model)!,
|
|
847
841
|
false
|
|
848
842
|
);
|
|
849
843
|
const lastSyncPredicate = syncPredicate
|
|
@@ -855,9 +849,9 @@ export class SyncEngine {
|
|
|
855
849
|
this.modelInstanceCreator(ModelMetadataConstructor, {
|
|
856
850
|
model: model.name,
|
|
857
851
|
namespace,
|
|
858
|
-
lastSync: null
|
|
852
|
+
lastSync: null!,
|
|
859
853
|
fullSyncInterval,
|
|
860
|
-
lastFullSync: null
|
|
854
|
+
lastFullSync: null!,
|
|
861
855
|
lastSyncPredicate,
|
|
862
856
|
}),
|
|
863
857
|
undefined,
|
|
@@ -875,9 +869,9 @@ export class SyncEngine {
|
|
|
875
869
|
// perform a base sync if the syncPredicate changed in between calls to DataStore.start
|
|
876
870
|
// ensures that the local store contains all the data specified by the syncExpression
|
|
877
871
|
if (syncPredicateUpdated) {
|
|
878
|
-
draft.lastSync = null
|
|
879
|
-
draft.lastFullSync = null
|
|
880
|
-
draft.lastSyncPredicate = lastSyncPredicate;
|
|
872
|
+
draft.lastSync = null!;
|
|
873
|
+
draft.lastFullSync = null!;
|
|
874
|
+
(draft.lastSyncPredicate as any) = lastSyncPredicate;
|
|
881
875
|
}
|
|
882
876
|
})
|
|
883
877
|
);
|