@aws-amplify/datastore 3.12.6-next.20 → 3.12.6-next.36
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 +58 -0
- package/lib/authModeStrategies/multiAuthStrategy.d.ts +11 -0
- package/lib/authModeStrategies/multiAuthStrategy.js +13 -2
- package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib/datastore/datastore.d.ts +107 -17
- package/lib/datastore/datastore.js +648 -344
- package/lib/datastore/datastore.js.map +1 -1
- package/lib/index.d.ts +3 -19
- package/lib/predicates/index.d.ts +3 -2
- package/lib/predicates/index.js +12 -2
- package/lib/predicates/index.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
- package/lib/storage/adapter/AsyncStorageAdapter.js +354 -203
- package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
- package/lib/storage/adapter/AsyncStorageDatabase.js +65 -28
- package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib/storage/adapter/IndexedDBAdapter.d.ts +26 -4
- package/lib/storage/adapter/IndexedDBAdapter.js +444 -271
- package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib/storage/adapter/index.d.ts +1 -1
- package/lib/storage/storage.d.ts +1 -1
- package/lib/storage/storage.js +93 -28
- package/lib/storage/storage.js.map +1 -1
- package/lib/sync/datastoreConnectivity.d.ts +1 -0
- package/lib/sync/datastoreConnectivity.js +9 -0
- package/lib/sync/datastoreConnectivity.js.map +1 -1
- package/lib/sync/index.d.ts +31 -5
- package/lib/sync/index.js +522 -397
- package/lib/sync/index.js.map +1 -1
- package/lib/sync/merger.d.ts +9 -3
- package/lib/sync/merger.js +13 -6
- package/lib/sync/merger.js.map +1 -1
- package/lib/sync/outbox.d.ts +2 -2
- package/lib/sync/outbox.js +77 -71
- package/lib/sync/outbox.js.map +1 -1
- package/lib/sync/processors/mutation.d.ts +2 -0
- package/lib/sync/processors/mutation.js +269 -209
- package/lib/sync/processors/mutation.js.map +1 -1
- package/lib/sync/processors/subscription.d.ts +2 -0
- package/lib/sync/processors/subscription.js +213 -178
- package/lib/sync/processors/subscription.js.map +1 -1
- package/lib/sync/processors/sync.d.ts +2 -1
- package/lib/sync/processors/sync.js +126 -121
- package/lib/sync/processors/sync.js.map +1 -1
- package/lib/sync/utils.d.ts +3 -2
- package/lib/sync/utils.js +43 -8
- package/lib/sync/utils.js.map +1 -1
- package/lib/types.d.ts +65 -26
- package/lib/types.js +10 -1
- package/lib/types.js.map +1 -1
- package/lib/util.d.ts +67 -24
- package/lib/util.js +419 -166
- package/lib/util.js.map +1 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
- package/lib-esm/authModeStrategies/multiAuthStrategy.js +12 -1
- package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
- package/lib-esm/datastore/datastore.d.ts +107 -17
- package/lib-esm/datastore/datastore.js +648 -344
- package/lib-esm/datastore/datastore.js.map +1 -1
- package/lib-esm/index.d.ts +3 -19
- package/lib-esm/predicates/index.d.ts +3 -2
- package/lib-esm/predicates/index.js +13 -3
- package/lib-esm/predicates/index.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js +355 -204
- package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js +66 -29
- package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
- package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +26 -4
- package/lib-esm/storage/adapter/IndexedDBAdapter.js +445 -272
- package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
- package/lib-esm/storage/adapter/index.d.ts +1 -1
- package/lib-esm/storage/storage.d.ts +1 -1
- package/lib-esm/storage/storage.js +93 -28
- package/lib-esm/storage/storage.js.map +1 -1
- package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
- package/lib-esm/sync/datastoreConnectivity.js +10 -1
- package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
- package/lib-esm/sync/index.d.ts +31 -5
- package/lib-esm/sync/index.js +524 -399
- package/lib-esm/sync/index.js.map +1 -1
- package/lib-esm/sync/merger.d.ts +9 -3
- package/lib-esm/sync/merger.js +13 -6
- package/lib-esm/sync/merger.js.map +1 -1
- package/lib-esm/sync/outbox.d.ts +2 -2
- package/lib-esm/sync/outbox.js +78 -72
- package/lib-esm/sync/outbox.js.map +1 -1
- package/lib-esm/sync/processors/mutation.d.ts +2 -0
- package/lib-esm/sync/processors/mutation.js +270 -210
- package/lib-esm/sync/processors/mutation.js.map +1 -1
- package/lib-esm/sync/processors/subscription.d.ts +2 -0
- package/lib-esm/sync/processors/subscription.js +213 -178
- package/lib-esm/sync/processors/subscription.js.map +1 -1
- package/lib-esm/sync/processors/sync.d.ts +2 -1
- package/lib-esm/sync/processors/sync.js +126 -121
- package/lib-esm/sync/processors/sync.js.map +1 -1
- package/lib-esm/sync/utils.d.ts +3 -2
- package/lib-esm/sync/utils.js +45 -11
- package/lib-esm/sync/utils.js.map +1 -1
- package/lib-esm/types.d.ts +65 -26
- package/lib-esm/types.js +9 -2
- package/lib-esm/types.js.map +1 -1
- package/lib-esm/util.d.ts +67 -24
- package/lib-esm/util.js +419 -166
- package/lib-esm/util.js.map +1 -1
- package/package.json +16 -9
- package/src/authModeStrategies/multiAuthStrategy.ts +12 -1
- package/src/datastore/datastore.ts +798 -397
- package/src/predicates/index.ts +32 -10
- package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
- package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
- package/src/storage/adapter/IndexedDBAdapter.ts +358 -134
- package/src/storage/adapter/index.ts +1 -1
- package/src/storage/storage.ts +69 -22
- package/src/sync/datastoreConnectivity.ts +6 -0
- package/src/sync/index.ts +521 -412
- package/src/sync/merger.ts +20 -4
- package/src/sync/outbox.ts +22 -9
- package/src/sync/processors/mutation.ts +188 -150
- package/src/sync/processors/subscription.ts +289 -253
- package/src/sync/processors/sync.ts +151 -138
- package/src/sync/utils.ts +67 -12
- package/src/types.ts +182 -30
- package/src/util.ts +505 -176
- package/build.js +0 -5
- package/dist/aws-amplify-datastore.js +0 -83311
- package/dist/aws-amplify-datastore.js.map +0 -1
- package/dist/aws-amplify-datastore.min.js +0 -168
- package/dist/aws-amplify-datastore.min.js.map +0 -1
- package/index.js +0 -7
- package/webpack.config.dev.js +0 -6
package/lib/util.js
CHANGED
|
@@ -7,6 +7,27 @@ var uuid_1 = require("uuid");
|
|
|
7
7
|
var immer_1 = require("immer");
|
|
8
8
|
var types_1 = require("./types");
|
|
9
9
|
var amazon_cognito_identity_js_1 = require("amazon-cognito-identity-js");
|
|
10
|
+
exports.ID = 'id';
|
|
11
|
+
/**
|
|
12
|
+
* Used by the Async Storage Adapter to concatenate key values
|
|
13
|
+
* for a record. For instance, if a model has the following keys:
|
|
14
|
+
* `customId: ID! @primaryKey(sortKeyFields: ["createdAt"])`,
|
|
15
|
+
* we concatenate the `customId` and `createdAt` as:
|
|
16
|
+
* `12-234-5#2022-09-28T00:00:00.000Z`
|
|
17
|
+
*/
|
|
18
|
+
exports.DEFAULT_PRIMARY_KEY_VALUE_SEPARATOR = '#';
|
|
19
|
+
/**
|
|
20
|
+
* Used for generating spinal-cased index name from an array of
|
|
21
|
+
* key field names.
|
|
22
|
+
* E.g. for keys `[id, title]` => 'id-title'
|
|
23
|
+
*/
|
|
24
|
+
exports.IDENTIFIER_KEY_SEPARATOR = '-';
|
|
25
|
+
exports.errorMessages = {
|
|
26
|
+
idEmptyString: 'An index field cannot contain an empty string value',
|
|
27
|
+
queryByPkWithCompositeKeyPresent: 'Models with composite primary keys cannot be queried by a single key value. Use object literal syntax for composite keys instead: https://docs.amplify.aws/lib/datastore/advanced-workflows/q/platform/js/#querying-records-with-custom-primary-keys',
|
|
28
|
+
deleteByPkWithCompositeKeyPresent: 'Models with composite primary keys cannot be deleted by a single key value, unless using a predicate. Use object literal syntax for composite keys instead: https://docs.amplify.aws/lib/datastore/advanced-workflows/q/platform/js/#querying-records-with-custom-primary-keys',
|
|
29
|
+
observeWithObjectLiteral: 'Object literal syntax cannot be used with observe. Use a predicate instead: https://docs.amplify.aws/lib/datastore/data-access/q/platform/js/#predicates',
|
|
30
|
+
};
|
|
10
31
|
var NAMESPACES;
|
|
11
32
|
(function (NAMESPACES) {
|
|
12
33
|
NAMESPACES["DATASTORE"] = "datastore";
|
|
@@ -108,148 +129,6 @@ exports.registerNonModelClass = registerNonModelClass;
|
|
|
108
129
|
exports.isNonModelConstructor = function (obj) {
|
|
109
130
|
return nonModelClasses.has(obj);
|
|
110
131
|
};
|
|
111
|
-
/*
|
|
112
|
-
When we have GSI(s) with composite sort keys defined on a model
|
|
113
|
-
There are some very particular rules regarding which fields must be included in the update mutation input
|
|
114
|
-
The field selection becomes more complex as the number of GSIs with composite sort keys grows
|
|
115
|
-
|
|
116
|
-
To summarize: any time we update a field that is part of the composite sort key of a GSI, we must include:
|
|
117
|
-
1. all of the other fields in that composite sort key
|
|
118
|
-
2. all of the fields from any other composite sort key that intersect with the fields from 1.
|
|
119
|
-
|
|
120
|
-
E.g.,
|
|
121
|
-
Model @model
|
|
122
|
-
@key(name: 'key1' fields: ['hk', 'a', 'b', 'c'])
|
|
123
|
-
@key(name: 'key2' fields: ['hk', 'a', 'b', 'd'])
|
|
124
|
-
@key(name: 'key3' fields: ['hk', 'x', 'y', 'z'])
|
|
125
|
-
|
|
126
|
-
Model.a is updated => include ['a', 'b', 'c', 'd']
|
|
127
|
-
Model.c is updated => include ['a', 'b', 'c', 'd']
|
|
128
|
-
Model.d is updated => include ['a', 'b', 'c', 'd']
|
|
129
|
-
Model.x is updated => include ['x', 'y', 'z']
|
|
130
|
-
|
|
131
|
-
This function accepts a model's attributes and returns grouped sets of composite key fields
|
|
132
|
-
Using our example Model above, the function will return:
|
|
133
|
-
[
|
|
134
|
-
Set('a', 'b', 'c', 'd'),
|
|
135
|
-
Set('x', 'y', 'z'),
|
|
136
|
-
]
|
|
137
|
-
|
|
138
|
-
This gives us the opportunity to correctly include the required fields for composite keys
|
|
139
|
-
When crafting the mutation input in Storage.getUpdateMutationInput
|
|
140
|
-
|
|
141
|
-
See 'processCompositeKeys' test in util.test.ts for more examples
|
|
142
|
-
*/
|
|
143
|
-
exports.processCompositeKeys = function (attributes) {
|
|
144
|
-
var extractCompositeSortKey = function (_c) {
|
|
145
|
-
var
|
|
146
|
-
// ignore the HK (fields[0]) we only need to include the composite sort key fields[1...n]
|
|
147
|
-
_d = tslib_1.__read(_c.properties.fields), sortKeyFields = _d.slice(1);
|
|
148
|
-
return sortKeyFields;
|
|
149
|
-
};
|
|
150
|
-
var compositeKeyFields = attributes
|
|
151
|
-
.filter(types_1.isModelAttributeCompositeKey)
|
|
152
|
-
.map(extractCompositeSortKey);
|
|
153
|
-
/*
|
|
154
|
-
if 2 sets of fields have any intersecting fields => combine them into 1 union set
|
|
155
|
-
e.g., ['a', 'b', 'c'] and ['a', 'b', 'd'] => ['a', 'b', 'c', 'd']
|
|
156
|
-
*/
|
|
157
|
-
var combineIntersecting = function (fields) {
|
|
158
|
-
return fields.reduce(function (combined, sortKeyFields) {
|
|
159
|
-
var sortKeyFieldsSet = new Set(sortKeyFields);
|
|
160
|
-
if (combined.length === 0) {
|
|
161
|
-
combined.push(sortKeyFieldsSet);
|
|
162
|
-
return combined;
|
|
163
|
-
}
|
|
164
|
-
// does the current set share values with another set we've already added to `combined`?
|
|
165
|
-
var intersectingSetIdx = combined.findIndex(function (existingSet) {
|
|
166
|
-
return tslib_1.__spread(existingSet).some(function (f) { return sortKeyFieldsSet.has(f); });
|
|
167
|
-
});
|
|
168
|
-
if (intersectingSetIdx > -1) {
|
|
169
|
-
var union = new Set(tslib_1.__spread(combined[intersectingSetIdx], sortKeyFieldsSet));
|
|
170
|
-
// combine the current set with the intersecting set we found above
|
|
171
|
-
combined[intersectingSetIdx] = union;
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
// none of the sets in `combined` have intersecting values with the current set
|
|
175
|
-
combined.push(sortKeyFieldsSet);
|
|
176
|
-
}
|
|
177
|
-
return combined;
|
|
178
|
-
}, []);
|
|
179
|
-
};
|
|
180
|
-
var initial = combineIntersecting(compositeKeyFields);
|
|
181
|
-
// a single pass pay not be enough to correctly combine all the fields
|
|
182
|
-
// call the function once more to get a final merged list of sets
|
|
183
|
-
var combined = combineIntersecting(initial);
|
|
184
|
-
return combined;
|
|
185
|
-
};
|
|
186
|
-
exports.establishRelationAndKeys = function (namespace) {
|
|
187
|
-
var relationship = {};
|
|
188
|
-
var keys = {};
|
|
189
|
-
Object.keys(namespace.models).forEach(function (mKey) {
|
|
190
|
-
var e_1, _c, e_2, _d;
|
|
191
|
-
relationship[mKey] = { indexes: [], relationTypes: [] };
|
|
192
|
-
keys[mKey] = {};
|
|
193
|
-
var model = namespace.models[mKey];
|
|
194
|
-
Object.keys(model.fields).forEach(function (attr) {
|
|
195
|
-
var fieldAttribute = model.fields[attr];
|
|
196
|
-
if (typeof fieldAttribute.type === 'object' &&
|
|
197
|
-
'model' in fieldAttribute.type) {
|
|
198
|
-
var connectionType = fieldAttribute.association.connectionType;
|
|
199
|
-
relationship[mKey].relationTypes.push({
|
|
200
|
-
fieldName: fieldAttribute.name,
|
|
201
|
-
modelName: fieldAttribute.type.model,
|
|
202
|
-
relationType: connectionType,
|
|
203
|
-
targetName: fieldAttribute.association['targetName'],
|
|
204
|
-
associatedWith: fieldAttribute.association['associatedWith'],
|
|
205
|
-
});
|
|
206
|
-
if (connectionType === 'BELONGS_TO') {
|
|
207
|
-
relationship[mKey].indexes.push(fieldAttribute.association['targetName']);
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
if (model.attributes) {
|
|
212
|
-
keys[mKey].compositeKeys = exports.processCompositeKeys(model.attributes);
|
|
213
|
-
try {
|
|
214
|
-
for (var _e = tslib_1.__values(model.attributes), _f = _e.next(); !_f.done; _f = _e.next()) {
|
|
215
|
-
var attribute = _f.value;
|
|
216
|
-
if (!types_1.isModelAttributeKey(attribute)) {
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
219
|
-
if (types_1.isModelAttributePrimaryKey(attribute)) {
|
|
220
|
-
keys[mKey].primaryKey = attribute.properties.fields;
|
|
221
|
-
}
|
|
222
|
-
var fields = attribute.properties.fields;
|
|
223
|
-
try {
|
|
224
|
-
for (var fields_1 = (e_2 = void 0, tslib_1.__values(fields)), fields_1_1 = fields_1.next(); !fields_1_1.done; fields_1_1 = fields_1.next()) {
|
|
225
|
-
var field = fields_1_1.value;
|
|
226
|
-
// only add index if it hasn't already been added
|
|
227
|
-
var exists = relationship[mKey].indexes.includes(field);
|
|
228
|
-
if (!exists) {
|
|
229
|
-
relationship[mKey].indexes.push(field);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
234
|
-
finally {
|
|
235
|
-
try {
|
|
236
|
-
if (fields_1_1 && !fields_1_1.done && (_d = fields_1.return)) _d.call(fields_1);
|
|
237
|
-
}
|
|
238
|
-
finally { if (e_2) throw e_2.error; }
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
243
|
-
finally {
|
|
244
|
-
try {
|
|
245
|
-
if (_f && !_f.done && (_c = _e.return)) _c.call(_e);
|
|
246
|
-
}
|
|
247
|
-
finally { if (e_1) throw e_1.error; }
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
});
|
|
251
|
-
return [relationship, keys];
|
|
252
|
-
};
|
|
253
132
|
var topologicallySortedModels = new WeakMap();
|
|
254
133
|
exports.traverseModel = function (srcModelName, instance, namespace, modelInstanceCreator, getModelConstructorByModelName) {
|
|
255
134
|
var relationships = namespace.relationships;
|
|
@@ -275,12 +154,26 @@ exports.traverseModel = function (srcModelName, instance, namespace, modelInstan
|
|
|
275
154
|
item: instance[rItem.fieldName],
|
|
276
155
|
instance: modelInstance,
|
|
277
156
|
});
|
|
278
|
-
|
|
157
|
+
var targetNames = exports.extractTargetNamesFromSrc(rItem);
|
|
158
|
+
// `targetName` will be defined for Has One if feature flag
|
|
279
159
|
// https://docs.amplify.aws/cli/reference/feature-flags/#useAppsyncModelgenPlugin
|
|
280
160
|
// is true (default as of 5/7/21)
|
|
281
161
|
// Making this conditional for backward-compatibility
|
|
282
|
-
if (
|
|
283
|
-
|
|
162
|
+
if (targetNames) {
|
|
163
|
+
targetNames.forEach(function (targetName, idx) {
|
|
164
|
+
// Get the connected record
|
|
165
|
+
var relatedRecordInProxy = (draftInstance[rItem.fieldName]);
|
|
166
|
+
// Previously, we used the hardcoded 'id' as they key,
|
|
167
|
+
// now we need the value of the key to get the PK (and SK)
|
|
168
|
+
// values from the related record
|
|
169
|
+
var primaryKey = namespace.keys[modelConstructor.name].primaryKey;
|
|
170
|
+
var keyField = primaryKey && primaryKey[idx];
|
|
171
|
+
// Get the value
|
|
172
|
+
var relatedRecordInProxyPkValue = relatedRecordInProxy[keyField];
|
|
173
|
+
// Set the targetName value
|
|
174
|
+
draftInstance[targetName] = relatedRecordInProxyPkValue;
|
|
175
|
+
});
|
|
176
|
+
// Delete the instance from the proxy
|
|
284
177
|
delete draftInstance[rItem.fieldName];
|
|
285
178
|
}
|
|
286
179
|
else {
|
|
@@ -307,8 +200,25 @@ exports.traverseModel = function (srcModelName, instance, namespace, modelInstan
|
|
|
307
200
|
}
|
|
308
201
|
}
|
|
309
202
|
if (draftInstance[rItem.fieldName]) {
|
|
310
|
-
|
|
311
|
-
|
|
203
|
+
var targetNames = exports.extractTargetNamesFromSrc(rItem);
|
|
204
|
+
if (targetNames) {
|
|
205
|
+
targetNames.forEach(function (targetName, idx) {
|
|
206
|
+
// Get the connected record
|
|
207
|
+
var relatedRecordInProxy = (draftInstance[rItem.fieldName]);
|
|
208
|
+
// Previously, we used the hardcoded `id` for the key.
|
|
209
|
+
// Now, we need the value of the key to get the PK (and SK)
|
|
210
|
+
// values from the related record
|
|
211
|
+
var primaryKey = namespace.keys[modelConstructor.name].primaryKey;
|
|
212
|
+
// fall back to ID if
|
|
213
|
+
var keyField = primaryKey && primaryKey[idx];
|
|
214
|
+
// Get the value
|
|
215
|
+
var relatedRecordInProxyPkValue = relatedRecordInProxy[keyField];
|
|
216
|
+
// Set the targetName value
|
|
217
|
+
draftInstance[targetName] = relatedRecordInProxyPkValue;
|
|
218
|
+
});
|
|
219
|
+
// Delete the instance from the proxy
|
|
220
|
+
delete draftInstance[rItem.fieldName];
|
|
221
|
+
}
|
|
312
222
|
}
|
|
313
223
|
break;
|
|
314
224
|
case 'HAS_MANY':
|
|
@@ -334,19 +244,6 @@ exports.traverseModel = function (srcModelName, instance, namespace, modelInstan
|
|
|
334
244
|
});
|
|
335
245
|
return result;
|
|
336
246
|
};
|
|
337
|
-
exports.getIndex = function (rel, src) {
|
|
338
|
-
var index = '';
|
|
339
|
-
rel.some(function (relItem) {
|
|
340
|
-
if (relItem.modelName === src) {
|
|
341
|
-
index = relItem.targetName;
|
|
342
|
-
}
|
|
343
|
-
});
|
|
344
|
-
return index;
|
|
345
|
-
};
|
|
346
|
-
exports.getIndexFromAssociation = function (indexes, src) {
|
|
347
|
-
var index = indexes.find(function (idx) { return idx === src; });
|
|
348
|
-
return index;
|
|
349
|
-
};
|
|
350
247
|
var privateModeCheckResult;
|
|
351
248
|
exports.isPrivateMode = function () {
|
|
352
249
|
return new Promise(function (resolve) {
|
|
@@ -386,6 +283,95 @@ exports.isPrivateMode = function () {
|
|
|
386
283
|
db.onsuccess = isNotPrivate;
|
|
387
284
|
});
|
|
388
285
|
};
|
|
286
|
+
var safariCompatabilityModeResult;
|
|
287
|
+
/**
|
|
288
|
+
* Whether the browser's implementation of IndexedDB breaks on array lookups
|
|
289
|
+
* against composite indexes whose keypath contains a single column.
|
|
290
|
+
*
|
|
291
|
+
* E.g., Whether `store.createIndex(indexName, ['id'])` followed by
|
|
292
|
+
* `store.index(indexName).get([1])` will *ever* return records.
|
|
293
|
+
*
|
|
294
|
+
* In all known, modern Safari browsers as of Q4 2022, the query against an index like
|
|
295
|
+
* this will *always* return `undefined`. So, the index needs to be created as a scalar.
|
|
296
|
+
*/
|
|
297
|
+
exports.isSafariCompatabilityMode = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
|
|
298
|
+
var dbName_1, storeName_1, indexName_1, db_1, rwTx, rwStore, result, error_1;
|
|
299
|
+
return tslib_1.__generator(this, function (_c) {
|
|
300
|
+
switch (_c.label) {
|
|
301
|
+
case 0:
|
|
302
|
+
_c.trys.push([0, 6, , 7]);
|
|
303
|
+
dbName_1 = uuid_1.v4();
|
|
304
|
+
storeName_1 = 'indexedDBFeatureProbeStore';
|
|
305
|
+
indexName_1 = 'idx';
|
|
306
|
+
if (indexedDB === null)
|
|
307
|
+
return [2 /*return*/, false];
|
|
308
|
+
if (safariCompatabilityModeResult !== undefined) {
|
|
309
|
+
return [2 /*return*/, safariCompatabilityModeResult];
|
|
310
|
+
}
|
|
311
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
312
|
+
var dbOpenRequest = indexedDB.open(dbName_1);
|
|
313
|
+
dbOpenRequest.onerror = function () { return resolve(false); };
|
|
314
|
+
dbOpenRequest.onsuccess = function () {
|
|
315
|
+
var db = dbOpenRequest.result;
|
|
316
|
+
resolve(db);
|
|
317
|
+
};
|
|
318
|
+
dbOpenRequest.onupgradeneeded = function (event) {
|
|
319
|
+
var _c;
|
|
320
|
+
var db = (_c = event === null || event === void 0 ? void 0 : event.target) === null || _c === void 0 ? void 0 : _c.result;
|
|
321
|
+
db.onerror = function () { return resolve(false); };
|
|
322
|
+
var store = db.createObjectStore(storeName_1, {
|
|
323
|
+
autoIncrement: true,
|
|
324
|
+
});
|
|
325
|
+
store.createIndex(indexName_1, ['id']);
|
|
326
|
+
};
|
|
327
|
+
})];
|
|
328
|
+
case 1:
|
|
329
|
+
db_1 = _c.sent();
|
|
330
|
+
if (!db_1) {
|
|
331
|
+
throw new Error('Could not open probe DB');
|
|
332
|
+
}
|
|
333
|
+
rwTx = db_1.transaction(storeName_1, 'readwrite');
|
|
334
|
+
rwStore = rwTx.objectStore(storeName_1);
|
|
335
|
+
rwStore.add({
|
|
336
|
+
id: 1,
|
|
337
|
+
});
|
|
338
|
+
rwTx.commit();
|
|
339
|
+
return [4 /*yield*/, new Promise(function (resolve) {
|
|
340
|
+
var tx = db_1.transaction(storeName_1, 'readonly');
|
|
341
|
+
var store = tx.objectStore(storeName_1);
|
|
342
|
+
var index = store.index(indexName_1);
|
|
343
|
+
var getRequest = index.get([1]);
|
|
344
|
+
getRequest.onerror = function () { return resolve(false); };
|
|
345
|
+
getRequest.onsuccess = function (event) {
|
|
346
|
+
var _c;
|
|
347
|
+
resolve((_c = event === null || event === void 0 ? void 0 : event.target) === null || _c === void 0 ? void 0 : _c.result);
|
|
348
|
+
};
|
|
349
|
+
})];
|
|
350
|
+
case 2:
|
|
351
|
+
result = _c.sent();
|
|
352
|
+
if (!(db_1 && typeof db_1.close === 'function')) return [3 /*break*/, 4];
|
|
353
|
+
return [4 /*yield*/, db_1.close()];
|
|
354
|
+
case 3:
|
|
355
|
+
_c.sent();
|
|
356
|
+
_c.label = 4;
|
|
357
|
+
case 4: return [4 /*yield*/, indexedDB.deleteDatabase(dbName_1)];
|
|
358
|
+
case 5:
|
|
359
|
+
_c.sent();
|
|
360
|
+
if (result === undefined) {
|
|
361
|
+
safariCompatabilityModeResult = true;
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
safariCompatabilityModeResult = false;
|
|
365
|
+
}
|
|
366
|
+
return [3 /*break*/, 7];
|
|
367
|
+
case 6:
|
|
368
|
+
error_1 = _c.sent();
|
|
369
|
+
safariCompatabilityModeResult = false;
|
|
370
|
+
return [3 /*break*/, 7];
|
|
371
|
+
case 7: return [2 /*return*/, safariCompatabilityModeResult];
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
}); };
|
|
389
375
|
var randomBytes = function (nBytes) {
|
|
390
376
|
return buffer_1.Buffer.from(new amazon_cognito_identity_js_1.WordArray().random(nBytes).toString(), 'hex');
|
|
391
377
|
};
|
|
@@ -422,7 +408,7 @@ function getNow() {
|
|
|
422
408
|
exports.getNow = getNow;
|
|
423
409
|
function sortCompareFunction(sortPredicates) {
|
|
424
410
|
return function compareFunction(a, b) {
|
|
425
|
-
var
|
|
411
|
+
var e_1, _c;
|
|
426
412
|
try {
|
|
427
413
|
// enable multi-field sort by iterating over predicates until
|
|
428
414
|
// a comparison returns -1 or 1
|
|
@@ -439,12 +425,12 @@ function sortCompareFunction(sortPredicates) {
|
|
|
439
425
|
}
|
|
440
426
|
}
|
|
441
427
|
}
|
|
442
|
-
catch (
|
|
428
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
443
429
|
finally {
|
|
444
430
|
try {
|
|
445
431
|
if (sortPredicates_1_1 && !sortPredicates_1_1.done && (_c = sortPredicates_1.return)) _c.call(sortPredicates_1);
|
|
446
432
|
}
|
|
447
|
-
finally { if (
|
|
433
|
+
finally { if (e_1) throw e_1.error; }
|
|
448
434
|
}
|
|
449
435
|
return 0;
|
|
450
436
|
};
|
|
@@ -456,7 +442,7 @@ exports.sortCompareFunction = sortCompareFunction;
|
|
|
456
442
|
// if nullish is true, treat undefined and null values as equal
|
|
457
443
|
// to normalize for GQL response values for undefined fields
|
|
458
444
|
function valuesEqual(valA, valB, nullish) {
|
|
459
|
-
var
|
|
445
|
+
var e_2, _c;
|
|
460
446
|
if (nullish === void 0) { nullish = false; }
|
|
461
447
|
var a = valA;
|
|
462
448
|
var b = valB;
|
|
@@ -508,12 +494,12 @@ function valuesEqual(valA, valB, nullish) {
|
|
|
508
494
|
}
|
|
509
495
|
}
|
|
510
496
|
}
|
|
511
|
-
catch (
|
|
497
|
+
catch (e_2_1) { e_2 = { error: e_2_1 }; }
|
|
512
498
|
finally {
|
|
513
499
|
try {
|
|
514
500
|
if (keys_1_1 && !keys_1_1.done && (_c = keys_1.return)) _c.call(keys_1);
|
|
515
501
|
}
|
|
516
|
-
finally { if (
|
|
502
|
+
finally { if (e_2) throw e_2.error; }
|
|
517
503
|
}
|
|
518
504
|
return true;
|
|
519
505
|
}
|
|
@@ -661,4 +647,271 @@ function mergePatches(originalSource, oldPatches, newPatches) {
|
|
|
661
647
|
return patches;
|
|
662
648
|
}
|
|
663
649
|
exports.mergePatches = mergePatches;
|
|
650
|
+
exports.getStorename = function (namespace, modelName) {
|
|
651
|
+
var storeName = namespace + "_" + modelName;
|
|
652
|
+
return storeName;
|
|
653
|
+
};
|
|
654
|
+
//#region Key Utils
|
|
655
|
+
/*
|
|
656
|
+
When we have GSI(s) with composite sort keys defined on a model
|
|
657
|
+
There are some very particular rules regarding which fields must be included in the update mutation input
|
|
658
|
+
The field selection becomes more complex as the number of GSIs with composite sort keys grows
|
|
659
|
+
|
|
660
|
+
To summarize: any time we update a field that is part of the composite sort key of a GSI, we must include:
|
|
661
|
+
1. all of the other fields in that composite sort key
|
|
662
|
+
2. all of the fields from any other composite sort key that intersect with the fields from 1.
|
|
663
|
+
|
|
664
|
+
E.g.,
|
|
665
|
+
Model @model
|
|
666
|
+
@key(name: 'key1' fields: ['hk', 'a', 'b', 'c'])
|
|
667
|
+
@key(name: 'key2' fields: ['hk', 'a', 'b', 'd'])
|
|
668
|
+
@key(name: 'key3' fields: ['hk', 'x', 'y', 'z'])
|
|
669
|
+
|
|
670
|
+
Model.a is updated => include ['a', 'b', 'c', 'd']
|
|
671
|
+
Model.c is updated => include ['a', 'b', 'c', 'd']
|
|
672
|
+
Model.d is updated => include ['a', 'b', 'c', 'd']
|
|
673
|
+
Model.x is updated => include ['x', 'y', 'z']
|
|
674
|
+
|
|
675
|
+
This function accepts a model's attributes and returns grouped sets of composite key fields
|
|
676
|
+
Using our example Model above, the function will return:
|
|
677
|
+
[
|
|
678
|
+
Set('a', 'b', 'c', 'd'),
|
|
679
|
+
Set('x', 'y', 'z'),
|
|
680
|
+
]
|
|
681
|
+
|
|
682
|
+
This gives us the opportunity to correctly include the required fields for composite keys
|
|
683
|
+
When crafting the mutation input in Storage.getUpdateMutationInput
|
|
684
|
+
|
|
685
|
+
See 'processCompositeKeys' test in util.test.ts for more examples
|
|
686
|
+
*/
|
|
687
|
+
exports.processCompositeKeys = function (attributes) {
|
|
688
|
+
var extractCompositeSortKey = function (_c) {
|
|
689
|
+
var
|
|
690
|
+
// ignore the HK (fields[0]) we only need to include the composite sort key fields[1...n]
|
|
691
|
+
_d = tslib_1.__read(_c.properties.fields), sortKeyFields = _d.slice(1);
|
|
692
|
+
return sortKeyFields;
|
|
693
|
+
};
|
|
694
|
+
var compositeKeyFields = attributes
|
|
695
|
+
.filter(types_1.isModelAttributeCompositeKey)
|
|
696
|
+
.map(extractCompositeSortKey);
|
|
697
|
+
/*
|
|
698
|
+
if 2 sets of fields have any intersecting fields => combine them into 1 union set
|
|
699
|
+
e.g., ['a', 'b', 'c'] and ['a', 'b', 'd'] => ['a', 'b', 'c', 'd']
|
|
700
|
+
*/
|
|
701
|
+
var combineIntersecting = function (fields) {
|
|
702
|
+
return fields.reduce(function (combined, sortKeyFields) {
|
|
703
|
+
var sortKeyFieldsSet = new Set(sortKeyFields);
|
|
704
|
+
if (combined.length === 0) {
|
|
705
|
+
combined.push(sortKeyFieldsSet);
|
|
706
|
+
return combined;
|
|
707
|
+
}
|
|
708
|
+
// does the current set share values with another set we've already added to `combined`?
|
|
709
|
+
var intersectingSetIdx = combined.findIndex(function (existingSet) {
|
|
710
|
+
return tslib_1.__spread(existingSet).some(function (f) { return sortKeyFieldsSet.has(f); });
|
|
711
|
+
});
|
|
712
|
+
if (intersectingSetIdx > -1) {
|
|
713
|
+
var union = new Set(tslib_1.__spread(combined[intersectingSetIdx], sortKeyFieldsSet));
|
|
714
|
+
// combine the current set with the intersecting set we found above
|
|
715
|
+
combined[intersectingSetIdx] = union;
|
|
716
|
+
}
|
|
717
|
+
else {
|
|
718
|
+
// none of the sets in `combined` have intersecting values with the current set
|
|
719
|
+
combined.push(sortKeyFieldsSet);
|
|
720
|
+
}
|
|
721
|
+
return combined;
|
|
722
|
+
}, []);
|
|
723
|
+
};
|
|
724
|
+
var initial = combineIntersecting(compositeKeyFields);
|
|
725
|
+
// a single pass pay not be enough to correctly combine all the fields
|
|
726
|
+
// call the function once more to get a final merged list of sets
|
|
727
|
+
var combined = combineIntersecting(initial);
|
|
728
|
+
return combined;
|
|
729
|
+
};
|
|
730
|
+
exports.extractKeyIfExists = function (modelDefinition) {
|
|
731
|
+
var _c;
|
|
732
|
+
var keyAttribute = (_c = modelDefinition === null || modelDefinition === void 0 ? void 0 : modelDefinition.attributes) === null || _c === void 0 ? void 0 : _c.find(types_1.isModelAttributeKey);
|
|
733
|
+
return keyAttribute;
|
|
734
|
+
};
|
|
735
|
+
exports.extractPrimaryKeyFieldNames = function (modelDefinition) {
|
|
736
|
+
var keyAttribute = exports.extractKeyIfExists(modelDefinition);
|
|
737
|
+
if (keyAttribute && types_1.isModelAttributePrimaryKey(keyAttribute)) {
|
|
738
|
+
return keyAttribute.properties.fields;
|
|
739
|
+
}
|
|
740
|
+
return [exports.ID];
|
|
741
|
+
};
|
|
742
|
+
exports.extractPrimaryKeyValues = function (model, keyFields) {
|
|
743
|
+
return keyFields.map(function (key) { return model[key]; });
|
|
744
|
+
};
|
|
745
|
+
exports.extractPrimaryKeysAndValues = function (model, keyFields) {
|
|
746
|
+
var primaryKeysAndValues = {};
|
|
747
|
+
keyFields.forEach(function (key) { return (primaryKeysAndValues[key] = model[key]); });
|
|
748
|
+
return primaryKeysAndValues;
|
|
749
|
+
};
|
|
750
|
+
// IdentifierFields<ManagedIdentifier>
|
|
751
|
+
// Default behavior without explicit @primaryKey defined
|
|
752
|
+
exports.isIdManaged = function (modelDefinition) {
|
|
753
|
+
var keyAttribute = exports.extractKeyIfExists(modelDefinition);
|
|
754
|
+
if (keyAttribute && types_1.isModelAttributePrimaryKey(keyAttribute)) {
|
|
755
|
+
return false;
|
|
756
|
+
}
|
|
757
|
+
return true;
|
|
758
|
+
};
|
|
759
|
+
// IdentifierFields<OptionallyManagedIdentifier>
|
|
760
|
+
// @primaryKey with explicit `id` in the PK. Single key or composite
|
|
761
|
+
exports.isIdOptionallyManaged = function (modelDefinition) {
|
|
762
|
+
var keyAttribute = exports.extractKeyIfExists(modelDefinition);
|
|
763
|
+
if (keyAttribute && types_1.isModelAttributePrimaryKey(keyAttribute)) {
|
|
764
|
+
return keyAttribute.properties.fields[0] === exports.ID;
|
|
765
|
+
}
|
|
766
|
+
return false;
|
|
767
|
+
};
|
|
768
|
+
exports.establishRelationAndKeys = function (namespace) {
|
|
769
|
+
var relationship = {};
|
|
770
|
+
var keys = {};
|
|
771
|
+
Object.keys(namespace.models).forEach(function (mKey) {
|
|
772
|
+
var e_3, _c;
|
|
773
|
+
relationship[mKey] = { indexes: [], relationTypes: [] };
|
|
774
|
+
keys[mKey] = {};
|
|
775
|
+
var model = namespace.models[mKey];
|
|
776
|
+
Object.keys(model.fields).forEach(function (attr) {
|
|
777
|
+
var fieldAttribute = model.fields[attr];
|
|
778
|
+
if (typeof fieldAttribute.type === 'object' &&
|
|
779
|
+
'model' in fieldAttribute.type) {
|
|
780
|
+
var connectionType = fieldAttribute.association.connectionType;
|
|
781
|
+
relationship[mKey].relationTypes.push({
|
|
782
|
+
fieldName: fieldAttribute.name,
|
|
783
|
+
modelName: fieldAttribute.type.model,
|
|
784
|
+
relationType: connectionType,
|
|
785
|
+
targetName: fieldAttribute.association['targetName'],
|
|
786
|
+
targetNames: fieldAttribute.association['targetNames'],
|
|
787
|
+
associatedWith: fieldAttribute.association['associatedWith'],
|
|
788
|
+
});
|
|
789
|
+
if (connectionType === 'BELONGS_TO') {
|
|
790
|
+
var targetNames = exports.extractTargetNamesFromSrc(fieldAttribute.association);
|
|
791
|
+
if (targetNames) {
|
|
792
|
+
var idxName = exports.indexNameFromKeys(targetNames);
|
|
793
|
+
relationship[mKey].indexes.push([idxName, targetNames]);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
if (model.attributes) {
|
|
799
|
+
keys[mKey].compositeKeys = exports.processCompositeKeys(model.attributes);
|
|
800
|
+
var _loop_1 = function (attribute) {
|
|
801
|
+
if (!types_1.isModelAttributeKey(attribute)) {
|
|
802
|
+
return "continue";
|
|
803
|
+
}
|
|
804
|
+
var fields = attribute.properties.fields;
|
|
805
|
+
if (types_1.isModelAttributePrimaryKey(attribute)) {
|
|
806
|
+
keys[mKey].primaryKey = fields;
|
|
807
|
+
return "continue";
|
|
808
|
+
}
|
|
809
|
+
// create indexes for all other keys
|
|
810
|
+
var idxName = exports.indexNameFromKeys(fields);
|
|
811
|
+
var idxExists = relationship[mKey].indexes.find(function (_c) {
|
|
812
|
+
var _d = tslib_1.__read(_c, 1), index = _d[0];
|
|
813
|
+
return index === idxName;
|
|
814
|
+
});
|
|
815
|
+
if (!idxExists) {
|
|
816
|
+
relationship[mKey].indexes.push([idxName, fields]);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
try {
|
|
820
|
+
for (var _d = tslib_1.__values(model.attributes), _e = _d.next(); !_e.done; _e = _d.next()) {
|
|
821
|
+
var attribute = _e.value;
|
|
822
|
+
_loop_1(attribute);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
catch (e_3_1) { e_3 = { error: e_3_1 }; }
|
|
826
|
+
finally {
|
|
827
|
+
try {
|
|
828
|
+
if (_e && !_e.done && (_c = _d.return)) _c.call(_d);
|
|
829
|
+
}
|
|
830
|
+
finally { if (e_3) throw e_3.error; }
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// set 'id' as the PK for models without a custom PK explicitly defined
|
|
834
|
+
if (!keys[mKey].primaryKey) {
|
|
835
|
+
keys[mKey].primaryKey = [exports.ID];
|
|
836
|
+
}
|
|
837
|
+
// create primary index
|
|
838
|
+
relationship[mKey].indexes.push([
|
|
839
|
+
'byPk',
|
|
840
|
+
keys[mKey].primaryKey,
|
|
841
|
+
{ unique: true },
|
|
842
|
+
]);
|
|
843
|
+
});
|
|
844
|
+
return [relationship, keys];
|
|
845
|
+
};
|
|
846
|
+
exports.getIndex = function (rel, src) {
|
|
847
|
+
var indexName;
|
|
848
|
+
rel.some(function (relItem) {
|
|
849
|
+
if (relItem.modelName === src) {
|
|
850
|
+
var targetNames = exports.extractTargetNamesFromSrc(relItem);
|
|
851
|
+
indexName = targetNames && exports.indexNameFromKeys(targetNames);
|
|
852
|
+
return true;
|
|
853
|
+
}
|
|
854
|
+
});
|
|
855
|
+
return indexName;
|
|
856
|
+
};
|
|
857
|
+
exports.getIndexFromAssociation = function (indexes, src) {
|
|
858
|
+
var indexName;
|
|
859
|
+
if (Array.isArray(src)) {
|
|
860
|
+
indexName = exports.indexNameFromKeys(src);
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
indexName = src;
|
|
864
|
+
}
|
|
865
|
+
var associationIndex = indexes.find(function (_c) {
|
|
866
|
+
var _d = tslib_1.__read(_c, 1), idxName = _d[0];
|
|
867
|
+
return idxName === indexName;
|
|
868
|
+
});
|
|
869
|
+
return associationIndex && associationIndex[0];
|
|
870
|
+
};
|
|
871
|
+
/**
|
|
872
|
+
* Backwards-compatability for schema generated prior to custom primary key support:
|
|
873
|
+
the single field `targetName` has been replaced with an array of `targetNames`.
|
|
874
|
+
`targetName` and `targetNames` are exclusive (will never exist on the same schema)
|
|
875
|
+
* @param src {RelationType | ModelAssociation | undefined}
|
|
876
|
+
* @returns array of targetNames, or `undefined`
|
|
877
|
+
*/
|
|
878
|
+
exports.extractTargetNamesFromSrc = function (src) {
|
|
879
|
+
var targetName = src === null || src === void 0 ? void 0 : src.targetName;
|
|
880
|
+
var targetNames = src === null || src === void 0 ? void 0 : src.targetNames;
|
|
881
|
+
if (Array.isArray(targetNames)) {
|
|
882
|
+
return targetNames;
|
|
883
|
+
}
|
|
884
|
+
else if (typeof targetName === 'string') {
|
|
885
|
+
return [targetName];
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
return undefined;
|
|
889
|
+
}
|
|
890
|
+
};
|
|
891
|
+
// Generates spinal-cased index name from an array of key field names
|
|
892
|
+
// E.g. for keys `[id, title]` => 'id-title'
|
|
893
|
+
exports.indexNameFromKeys = function (keys) {
|
|
894
|
+
return keys.reduce(function (prev, cur, idx) {
|
|
895
|
+
if (idx === 0) {
|
|
896
|
+
return cur;
|
|
897
|
+
}
|
|
898
|
+
return "" + prev + exports.IDENTIFIER_KEY_SEPARATOR + cur;
|
|
899
|
+
}, '');
|
|
900
|
+
};
|
|
901
|
+
exports.keysEqual = function (keysA, keysB) {
|
|
902
|
+
if (keysA.length !== keysB.length) {
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
return keysA.every(function (key, idx) { return key === keysB[idx]; });
|
|
906
|
+
};
|
|
907
|
+
// Returns primary keys for a model
|
|
908
|
+
exports.getIndexKeys = function (namespace, modelName) {
|
|
909
|
+
var _c;
|
|
910
|
+
var keyPath = (_c = namespace === null || namespace === void 0 ? void 0 : namespace.keys[modelName]) === null || _c === void 0 ? void 0 : _c.primaryKey;
|
|
911
|
+
if (keyPath) {
|
|
912
|
+
return keyPath;
|
|
913
|
+
}
|
|
914
|
+
return [exports.ID];
|
|
915
|
+
};
|
|
916
|
+
//#endregion
|
|
664
917
|
//# sourceMappingURL=util.js.map
|