@aws-amplify/datastore 3.12.6-next.13 → 3.12.6-next.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/lib/authModeStrategies/multiAuthStrategy.js +17 -64
  3. package/lib/authModeStrategies/multiAuthStrategy.js.map +1 -1
  4. package/lib/datastore/datastore.js +682 -469
  5. package/lib/datastore/datastore.js.map +1 -1
  6. package/lib/index.js +2 -4
  7. package/lib/index.js.map +1 -1
  8. package/lib/predicates/index.js +12 -2
  9. package/lib/predicates/index.js.map +1 -1
  10. package/lib/storage/adapter/AsyncStorageAdapter.js +393 -298
  11. package/lib/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  12. package/lib/storage/adapter/AsyncStorageDatabase.js +97 -122
  13. package/lib/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  14. package/lib/storage/adapter/InMemoryStore.js +16 -67
  15. package/lib/storage/adapter/InMemoryStore.js.map +1 -1
  16. package/lib/storage/adapter/InMemoryStore.native.js +2 -4
  17. package/lib/storage/adapter/InMemoryStore.native.js.map +1 -1
  18. package/lib/storage/adapter/IndexedDBAdapter.js +497 -404
  19. package/lib/storage/adapter/IndexedDBAdapter.js.map +1 -1
  20. package/lib/storage/adapter/getDefaultAdapter/index.js +3 -5
  21. package/lib/storage/adapter/getDefaultAdapter/index.js.map +1 -1
  22. package/lib/storage/adapter/getDefaultAdapter/index.native.js +2 -4
  23. package/lib/storage/adapter/getDefaultAdapter/index.native.js.map +1 -1
  24. package/lib/storage/storage.js +129 -151
  25. package/lib/storage/storage.js.map +1 -1
  26. package/lib/sync/datastoreConnectivity.js +13 -17
  27. package/lib/sync/datastoreConnectivity.js.map +1 -1
  28. package/lib/sync/datastoreReachability/index.native.js +2 -4
  29. package/lib/sync/datastoreReachability/index.native.js.map +1 -1
  30. package/lib/sync/index.js +544 -488
  31. package/lib/sync/index.js.map +1 -1
  32. package/lib/sync/merger.js +21 -80
  33. package/lib/sync/merger.js.map +1 -1
  34. package/lib/sync/outbox.js +95 -162
  35. package/lib/sync/outbox.js.map +1 -1
  36. package/lib/sync/processors/errorMaps.js +4 -34
  37. package/lib/sync/processors/errorMaps.js.map +1 -1
  38. package/lib/sync/processors/mutation.js +285 -312
  39. package/lib/sync/processors/mutation.js.map +1 -1
  40. package/lib/sync/processors/subscription.js +218 -259
  41. package/lib/sync/processors/subscription.js.map +1 -1
  42. package/lib/sync/processors/sync.js +141 -212
  43. package/lib/sync/processors/sync.js.map +1 -1
  44. package/lib/sync/utils.js +50 -61
  45. package/lib/sync/utils.js.map +1 -1
  46. package/lib/types.js +13 -39
  47. package/lib/types.js.map +1 -1
  48. package/lib/util.js +429 -242
  49. package/lib/util.js.map +1 -1
  50. package/lib-esm/authModeStrategies/multiAuthStrategy.d.ts +11 -0
  51. package/lib-esm/authModeStrategies/multiAuthStrategy.js +13 -57
  52. package/lib-esm/authModeStrategies/multiAuthStrategy.js.map +1 -1
  53. package/lib-esm/datastore/datastore.d.ts +107 -17
  54. package/lib-esm/datastore/datastore.js +649 -433
  55. package/lib-esm/datastore/datastore.js.map +1 -1
  56. package/lib-esm/index.d.ts +3 -19
  57. package/lib-esm/predicates/index.d.ts +3 -2
  58. package/lib-esm/predicates/index.js +13 -3
  59. package/lib-esm/predicates/index.js.map +1 -1
  60. package/lib-esm/storage/adapter/AsyncStorageAdapter.d.ts +4 -3
  61. package/lib-esm/storage/adapter/AsyncStorageAdapter.js +356 -258
  62. package/lib-esm/storage/adapter/AsyncStorageAdapter.js.map +1 -1
  63. package/lib-esm/storage/adapter/AsyncStorageDatabase.d.ts +14 -4
  64. package/lib-esm/storage/adapter/AsyncStorageDatabase.js +67 -92
  65. package/lib-esm/storage/adapter/AsyncStorageDatabase.js.map +1 -1
  66. package/lib-esm/storage/adapter/InMemoryStore.js +1 -52
  67. package/lib-esm/storage/adapter/InMemoryStore.js.map +1 -1
  68. package/lib-esm/storage/adapter/IndexedDBAdapter.d.ts +26 -4
  69. package/lib-esm/storage/adapter/IndexedDBAdapter.js +446 -346
  70. package/lib-esm/storage/adapter/IndexedDBAdapter.js.map +1 -1
  71. package/lib-esm/storage/adapter/index.d.ts +1 -1
  72. package/lib-esm/storage/storage.d.ts +1 -1
  73. package/lib-esm/storage/storage.js +94 -113
  74. package/lib-esm/storage/storage.js.map +1 -1
  75. package/lib-esm/sync/datastoreConnectivity.d.ts +1 -0
  76. package/lib-esm/sync/datastoreConnectivity.js +10 -11
  77. package/lib-esm/sync/datastoreConnectivity.js.map +1 -1
  78. package/lib-esm/sync/index.d.ts +31 -5
  79. package/lib-esm/sync/index.js +525 -466
  80. package/lib-esm/sync/index.js.map +1 -1
  81. package/lib-esm/sync/merger.d.ts +9 -3
  82. package/lib-esm/sync/merger.js +14 -73
  83. package/lib-esm/sync/merger.js.map +1 -1
  84. package/lib-esm/sync/outbox.d.ts +2 -2
  85. package/lib-esm/sync/outbox.js +79 -146
  86. package/lib-esm/sync/outbox.js.map +1 -1
  87. package/lib-esm/sync/processors/errorMaps.js +1 -31
  88. package/lib-esm/sync/processors/errorMaps.js.map +1 -1
  89. package/lib-esm/sync/processors/mutation.d.ts +2 -0
  90. package/lib-esm/sync/processors/mutation.js +271 -295
  91. package/lib-esm/sync/processors/mutation.js.map +1 -1
  92. package/lib-esm/sync/processors/subscription.d.ts +2 -0
  93. package/lib-esm/sync/processors/subscription.js +214 -245
  94. package/lib-esm/sync/processors/subscription.js.map +1 -1
  95. package/lib-esm/sync/processors/sync.d.ts +2 -1
  96. package/lib-esm/sync/processors/sync.js +127 -195
  97. package/lib-esm/sync/processors/sync.js.map +1 -1
  98. package/lib-esm/sync/utils.d.ts +3 -2
  99. package/lib-esm/sync/utils.js +45 -57
  100. package/lib-esm/sync/utils.js.map +1 -1
  101. package/lib-esm/types.d.ts +65 -26
  102. package/lib-esm/types.js +10 -38
  103. package/lib-esm/types.js.map +1 -1
  104. package/lib-esm/util.d.ts +67 -24
  105. package/lib-esm/util.js +420 -233
  106. package/lib-esm/util.js.map +1 -1
  107. package/package.json +14 -7
  108. package/src/authModeStrategies/multiAuthStrategy.ts +12 -1
  109. package/src/datastore/datastore.ts +798 -397
  110. package/src/predicates/index.ts +32 -10
  111. package/src/storage/adapter/AsyncStorageAdapter.ts +309 -93
  112. package/src/storage/adapter/AsyncStorageDatabase.ts +74 -26
  113. package/src/storage/adapter/IndexedDBAdapter.ts +358 -134
  114. package/src/storage/adapter/index.ts +1 -1
  115. package/src/storage/storage.ts +69 -22
  116. package/src/sync/datastoreConnectivity.ts +6 -0
  117. package/src/sync/index.ts +521 -412
  118. package/src/sync/merger.ts +20 -4
  119. package/src/sync/outbox.ts +22 -9
  120. package/src/sync/processors/mutation.ts +188 -150
  121. package/src/sync/processors/subscription.ts +289 -253
  122. package/src/sync/processors/sync.ts +151 -138
  123. package/src/sync/utils.ts +67 -12
  124. package/src/types.ts +182 -30
  125. package/src/util.ts +505 -176
  126. package/build.js +0 -5
  127. package/dist/aws-amplify-datastore.js +0 -98255
  128. package/dist/aws-amplify-datastore.js.map +0 -1
  129. package/dist/aws-amplify-datastore.min.js +0 -66
  130. package/dist/aws-amplify-datastore.min.js.map +0 -1
  131. package/index.js +0 -7
  132. package/lib/authModeStrategies/defaultAuthStrategy.d.ts +0 -2
  133. package/lib/authModeStrategies/index.d.ts +0 -2
  134. package/lib/authModeStrategies/multiAuthStrategy.d.ts +0 -2
  135. package/lib/datastore/datastore.d.ts +0 -66
  136. package/lib/index.d.ts +0 -31
  137. package/lib/predicates/index.d.ts +0 -15
  138. package/lib/predicates/sort.d.ts +0 -8
  139. package/lib/ssr/index.d.ts +0 -3
  140. package/lib/storage/adapter/AsyncStorageAdapter.d.ts +0 -40
  141. package/lib/storage/adapter/AsyncStorageDatabase.d.ts +0 -29
  142. package/lib/storage/adapter/InMemoryStore.d.ts +0 -11
  143. package/lib/storage/adapter/InMemoryStore.native.d.ts +0 -1
  144. package/lib/storage/adapter/IndexedDBAdapter.d.ts +0 -37
  145. package/lib/storage/adapter/getDefaultAdapter/index.d.ts +0 -3
  146. package/lib/storage/adapter/getDefaultAdapter/index.native.d.ts +0 -3
  147. package/lib/storage/adapter/index.d.ts +0 -9
  148. package/lib/storage/storage.d.ts +0 -49
  149. package/lib/sync/datastoreConnectivity.d.ts +0 -15
  150. package/lib/sync/datastoreReachability/index.d.ts +0 -3
  151. package/lib/sync/datastoreReachability/index.native.d.ts +0 -3
  152. package/lib/sync/index.d.ts +0 -63
  153. package/lib/sync/merger.d.ts +0 -11
  154. package/lib/sync/outbox.d.ts +0 -27
  155. package/lib/sync/processors/errorMaps.d.ts +0 -17
  156. package/lib/sync/processors/mutation.d.ts +0 -56
  157. package/lib/sync/processors/subscription.d.ts +0 -31
  158. package/lib/sync/processors/sync.d.ts +0 -27
  159. package/lib/sync/utils.d.ts +0 -41
  160. package/lib/types.d.ts +0 -462
  161. package/lib/util.d.ts +0 -113
  162. package/webpack.config.dev.js +0 -6
@@ -1,115 +1,25 @@
1
1
  "use strict";
2
- var __assign = (this && this.__assign) || function () {
3
- __assign = Object.assign || function(t) {
4
- for (var s, i = 1, n = arguments.length; i < n; i++) {
5
- s = arguments[i];
6
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
7
- t[p] = s[p];
8
- }
9
- return t;
10
- };
11
- return __assign.apply(this, arguments);
12
- };
13
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
14
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
15
- return new (P || (P = Promise))(function (resolve, reject) {
16
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
17
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
18
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
19
- step((generator = generator.apply(thisArg, _arguments || [])).next());
20
- });
21
- };
22
- var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
- function verb(n) { return function (v) { return step([n, v]); }; }
26
- function step(op) {
27
- if (f) throw new TypeError("Generator is already executing.");
28
- while (_) try {
29
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
30
- if (y = 0, t) op = [op[0] & 2, t.value];
31
- switch (op[0]) {
32
- case 0: case 1: t = op; break;
33
- case 4: _.label++; return { value: op[1], done: false };
34
- case 5: _.label++; y = op[1]; op = [0]; continue;
35
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
36
- default:
37
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
38
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
39
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
40
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
41
- if (t[2]) _.ops.pop();
42
- _.trys.pop(); continue;
43
- }
44
- op = body.call(thisArg, _);
45
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
46
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
- }
48
- };
49
- var __rest = (this && this.__rest) || function (s, e) {
50
- var t = {};
51
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
52
- t[p] = s[p];
53
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
54
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
55
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
56
- t[p[i]] = s[p[i]];
57
- }
58
- return t;
59
- };
60
- var __read = (this && this.__read) || function (o, n) {
61
- var m = typeof Symbol === "function" && o[Symbol.iterator];
62
- if (!m) return o;
63
- var i = m.call(o), r, ar = [], e;
64
- try {
65
- while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
66
- }
67
- catch (error) { e = { error: error }; }
68
- finally {
69
- try {
70
- if (r && !r.done && (m = i["return"])) m.call(i);
71
- }
72
- finally { if (e) throw e.error; }
73
- }
74
- return ar;
75
- };
76
- var __values = (this && this.__values) || function(o) {
77
- var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
78
- if (m) return m.call(o);
79
- if (o && typeof o.length === "number") return {
80
- next: function () {
81
- if (o && i >= o.length) o = void 0;
82
- return { value: o && o[i++], done: !o };
83
- }
84
- };
85
- throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
86
- };
87
- var __spread = (this && this.__spread) || function () {
88
- for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
89
- return ar;
90
- };
91
- var __importDefault = (this && this.__importDefault) || function (mod) {
92
- return (mod && mod.__esModule) ? mod : { "default": mod };
93
- };
94
2
  Object.defineProperty(exports, "__esModule", { value: true });
95
- var api_1 = __importDefault(require("@aws-amplify/api"));
96
- var core_1 = require("@aws-amplify/core");
3
+ var tslib_1 = require("tslib");
4
+ var api_1 = require("@aws-amplify/api");
97
5
  var auth_1 = require("@aws-amplify/auth");
98
- var cache_1 = __importDefault(require("@aws-amplify/cache"));
6
+ var cache_1 = require("@aws-amplify/cache");
7
+ var core_1 = require("@aws-amplify/core");
99
8
  var immer_1 = require("immer");
100
9
  var uuid_1 = require("uuid");
101
- var zen_observable_ts_1 = __importDefault(require("zen-observable-ts"));
10
+ var zen_observable_ts_1 = tslib_1.__importDefault(require("zen-observable-ts"));
102
11
  var authModeStrategies_1 = require("../authModeStrategies");
103
12
  var predicates_1 = require("../predicates");
104
13
  var storage_1 = require("../storage/storage");
105
14
  var sync_1 = require("../sync");
106
15
  var types_1 = require("../types");
107
16
  var util_1 = require("../util");
17
+ var utils_1 = require("../sync/utils");
108
18
  immer_1.setAutoFreeze(true);
109
19
  immer_1.enablePatches();
110
20
  var logger = new core_1.ConsoleLogger('DataStore');
111
21
  var ulid = util_1.monotonicUlidFactory(Date.now());
112
- var isNode = core_1.JS.browserOrNode().isNode;
22
+ var isNode = core_1.browserOrNode().isNode;
113
23
  var SETTING_SCHEMA_VERSION = 'schemaVersion';
114
24
  var schema;
115
25
  var modelNamespaceMap = new WeakMap();
@@ -137,7 +47,7 @@ var initSchema = function (userSchema) {
137
47
  return userClasses;
138
48
  }
139
49
  logger.log('validating schema', { schema: userSchema });
140
- var internalUserNamespace = __assign({ name: util_1.USER }, userSchema);
50
+ var internalUserNamespace = tslib_1.__assign({ name: util_1.USER }, userSchema);
141
51
  logger.log('DataStore', 'Init models');
142
52
  userClasses = createTypeClasses(internalUserNamespace);
143
53
  logger.log('DataStore', 'Models initialized');
@@ -158,7 +68,7 @@ var initSchema = function (userSchema) {
158
68
  };
159
69
  Object.keys(schema.namespaces).forEach(function (namespace) {
160
70
  var e_1, _a;
161
- var _b = __read(util_1.establishRelationAndKeys(schema.namespaces[namespace]), 2), relations = _b[0], keys = _b[1];
71
+ var _b = tslib_1.__read(util_1.establishRelationAndKeys(schema.namespaces[namespace]), 2), relations = _b[0], keys = _b[1];
162
72
  schema.namespaces[namespace].relationships = relations;
163
73
  schema.namespaces[namespace].keys = keys;
164
74
  var modelAssociations = new Map();
@@ -186,7 +96,7 @@ var initSchema = function (userSchema) {
186
96
  throw new Error('Models are not topologically sortable. Please verify your schema.');
187
97
  }
188
98
  try {
189
- for (var _c = (e_1 = void 0, __values(Array.from(modelAssociations.keys()))), _d = _c.next(); !_d.done; _d = _c.next()) {
99
+ for (var _c = (e_1 = void 0, tslib_1.__values(Array.from(modelAssociations.keys()))), _d = _c.next(); !_d.done; _d = _c.next()) {
190
100
  var modelName = _d.value;
191
101
  var parents = modelAssociations.get(modelName);
192
102
  if (parents.every(function (x) { return result.has(x); })) {
@@ -208,10 +118,14 @@ var initSchema = function (userSchema) {
208
118
  return userClasses;
209
119
  };
210
120
  exports.initSchema = initSchema;
211
- /* Checks if the schema has been initialized by initSchema().
121
+ /**
122
+ * Throws an exception if the schema has *not* been initialized
123
+ * by `initSchema()`.
212
124
  *
213
- * Call this function before accessing schema.
214
- * Currently this only needs to be called in start() and clear() because all other functions will call start first.
125
+ * **To be called before trying to access schema.**
126
+ *
127
+ * Currently this only needs to be called in `start()` and `clear()` because
128
+ * all other functions will call start first.
215
129
  */
216
130
  var checkSchemaInitialized = function () {
217
131
  if (schema === undefined) {
@@ -223,18 +137,23 @@ var checkSchemaInitialized = function () {
223
137
  var createTypeClasses = function (namespace) {
224
138
  var classes = {};
225
139
  Object.entries(namespace.models).forEach(function (_a) {
226
- var _b = __read(_a, 2), modelName = _b[0], modelDefinition = _b[1];
140
+ var _b = tslib_1.__read(_a, 2), modelName = _b[0], modelDefinition = _b[1];
227
141
  var clazz = createModelClass(modelDefinition);
228
142
  classes[modelName] = clazz;
229
143
  modelNamespaceMap.set(clazz, namespace.name);
230
144
  });
231
145
  Object.entries(namespace.nonModels || {}).forEach(function (_a) {
232
- var _b = __read(_a, 2), typeName = _b[0], typeDefinition = _b[1];
146
+ var _b = tslib_1.__read(_a, 2), typeName = _b[0], typeDefinition = _b[1];
233
147
  var clazz = createNonModelClass(typeDefinition);
234
148
  classes[typeName] = clazz;
235
149
  });
236
150
  return classes;
237
151
  };
152
+ /**
153
+ * Collection of instantiated models to allow storage of metadata apart from
154
+ * the model visible to the consuming app -- in case the app doesn't have
155
+ * metadata fields (_version, _deleted, etc.) exposed on the model itself.
156
+ */
238
157
  var instancesMetadata = new WeakSet();
239
158
  function modelInstanceCreator(modelConstructor, init) {
240
159
  instancesMetadata.add(init);
@@ -243,15 +162,23 @@ function modelInstanceCreator(modelConstructor, init) {
243
162
  var validateModelFields = function (modelDefinition) { return function (k, v) {
244
163
  var fieldDefinition = modelDefinition.fields[k];
245
164
  if (fieldDefinition !== undefined) {
246
- var type = fieldDefinition.type, isRequired_1 = fieldDefinition.isRequired, isArrayNullable = fieldDefinition.isArrayNullable, name_1 = fieldDefinition.name, isArray = fieldDefinition.isArray;
165
+ var type_1 = fieldDefinition.type, isRequired_1 = fieldDefinition.isRequired, isArrayNullable = fieldDefinition.isArrayNullable, name_1 = fieldDefinition.name, isArray = fieldDefinition.isArray;
247
166
  if (((!isArray && isRequired_1) || (isArray && !isArrayNullable)) &&
248
167
  (v === null || v === undefined)) {
249
168
  throw new Error("Field " + name_1 + " is required");
250
169
  }
251
- if (types_1.isGraphQLScalarType(type)) {
252
- var jsType_1 = types_1.GraphQLScalarType.getJSType(type);
253
- var validateScalar_1 = types_1.GraphQLScalarType.getValidationFunction(type);
254
- if (type === 'AWSJSON') {
170
+ if (types_1.isSchemaModelWithAttributes(modelDefinition) &&
171
+ !util_1.isIdManaged(modelDefinition)) {
172
+ var keys = util_1.extractPrimaryKeyFieldNames(modelDefinition);
173
+ if (keys.includes(k) && v === '') {
174
+ logger.error(util_1.errorMessages.idEmptyString, { k: k, value: v });
175
+ throw new Error(util_1.errorMessages.idEmptyString);
176
+ }
177
+ }
178
+ if (types_1.isGraphQLScalarType(type_1)) {
179
+ var jsType_1 = types_1.GraphQLScalarType.getJSType(type_1);
180
+ var validateScalar_1 = types_1.GraphQLScalarType.getValidationFunction(type_1);
181
+ if (type_1 === 'AWSJSON') {
255
182
  if (typeof v === jsType_1) {
256
183
  return;
257
184
  }
@@ -295,7 +222,7 @@ var validateModelFields = function (modelDefinition) { return function (k, v) {
295
222
  }
296
223
  });
297
224
  if (!validationStatus.every(function (s) { return s; })) {
298
- throw new Error("All elements in the " + name_1 + " array should be of type " + type + ", validation failed for one or more elements. " + v);
225
+ throw new Error("All elements in the " + name_1 + " array should be of type " + type_1 + ", validation failed for one or more elements. " + v);
299
226
  }
300
227
  }
301
228
  }
@@ -308,7 +235,42 @@ var validateModelFields = function (modelDefinition) { return function (k, v) {
308
235
  else if (!util_1.isNullOrUndefined(v) &&
309
236
  validateScalar_1 &&
310
237
  !validateScalar_1(v)) {
311
- throw new Error("Field " + name_1 + " should be of type " + type + ", validation failed. " + v);
238
+ throw new Error("Field " + name_1 + " should be of type " + type_1 + ", validation failed. " + v);
239
+ }
240
+ }
241
+ else if (types_1.isNonModelFieldType(type_1)) {
242
+ // do not check non model fields if undefined or null
243
+ if (!util_1.isNullOrUndefined(v)) {
244
+ var subNonModelDefinition_1 = schema.namespaces.user.nonModels[type_1.nonModel];
245
+ var modelValidator_1 = validateModelFields(subNonModelDefinition_1);
246
+ if (isArray) {
247
+ var errorTypeText = type_1.nonModel;
248
+ if (!isRequired_1) {
249
+ errorTypeText = type_1.nonModel + " | null | undefined";
250
+ }
251
+ if (!Array.isArray(v)) {
252
+ throw new Error("Field " + name_1 + " should be of type [" + errorTypeText + "], " + typeof v + " received. " + v);
253
+ }
254
+ v.forEach(function (item) {
255
+ if ((util_1.isNullOrUndefined(item) && isRequired_1) ||
256
+ (typeof item !== 'object' && typeof item !== 'undefined')) {
257
+ throw new Error("All elements in the " + name_1 + " array should be of type " + type_1.nonModel + ", [" + typeof item + "] received. " + item);
258
+ }
259
+ if (!util_1.isNullOrUndefined(item)) {
260
+ Object.keys(subNonModelDefinition_1.fields).forEach(function (subKey) {
261
+ modelValidator_1(subKey, item[subKey]);
262
+ });
263
+ }
264
+ });
265
+ }
266
+ else {
267
+ if (typeof v !== 'object') {
268
+ throw new Error("Field " + name_1 + " should be of type " + type_1.nonModel + ", " + typeof v + " recieved. " + v);
269
+ }
270
+ Object.keys(subNonModelDefinition_1.fields).forEach(function (subKey) {
271
+ modelValidator_1(subKey, v[subKey]);
272
+ });
273
+ }
312
274
  }
313
275
  }
314
276
  }
@@ -337,7 +299,7 @@ var castInstanceType = function (modelDefinition, k, v) {
337
299
  var initializeInstance = function (init, modelDefinition, draft) {
338
300
  var modelValidator = validateModelFields(modelDefinition);
339
301
  Object.entries(init).forEach(function (_a) {
340
- var _b = __read(_a, 2), k = _b[0], v = _b[1];
302
+ var _b = tslib_1.__read(_a, 2), k = _b[0], v = _b[1];
341
303
  var parsedValue = castInstanceType(modelDefinition, k, v);
342
304
  modelValidator(k, parsedValue);
343
305
  draft[k] = parsedValue;
@@ -348,21 +310,29 @@ var createModelClass = function (modelDefinition) {
348
310
  function Model(init) {
349
311
  var instance = immer_1.produce(this, function (draft) {
350
312
  initializeInstance(init, modelDefinition, draft);
351
- var modelInstanceMetadata = instancesMetadata.has(init)
313
+ // model is initialized inside a DataStore component (e.g. by Sync Engine, Storage Engine, etc.)
314
+ var isInternallyInitialized = instancesMetadata.has(init);
315
+ var modelInstanceMetadata = isInternallyInitialized
352
316
  ? init
353
317
  : {};
354
- var _id = modelInstanceMetadata.id, _version = modelInstanceMetadata._version, _lastChangedAt = modelInstanceMetadata._lastChangedAt, _deleted = modelInstanceMetadata._deleted;
355
- // instancesIds are set by modelInstanceCreator, it is accessible only internally
356
- var isInternal = _id !== null && _id !== undefined;
357
- var id = isInternal
358
- ? _id
359
- : modelDefinition.syncable
360
- ? uuid_1.v4()
361
- : ulid();
362
- if (!isInternal) {
318
+ var _id = modelInstanceMetadata.id;
319
+ if (util_1.isIdManaged(modelDefinition)) {
320
+ var isInternalModel = _id !== null && _id !== undefined;
321
+ var id = isInternalModel
322
+ ? _id
323
+ : modelDefinition.syncable
324
+ ? uuid_1.v4()
325
+ : ulid();
326
+ draft.id = id;
327
+ }
328
+ else if (util_1.isIdOptionallyManaged(modelDefinition)) {
329
+ // only auto-populate if the id was not provided
330
+ draft.id = draft.id || uuid_1.v4();
331
+ }
332
+ if (!isInternallyInitialized) {
363
333
  checkReadOnlyPropertyOnCreate(draft, modelDefinition);
364
334
  }
365
- draft.id = id;
335
+ var _version = modelInstanceMetadata._version, _lastChangedAt = modelInstanceMetadata._lastChangedAt, _deleted = modelInstanceMetadata._deleted;
366
336
  if (modelDefinition.syncable) {
367
337
  draft._version = _version;
368
338
  draft._lastChangedAt = _lastChangedAt;
@@ -381,10 +351,12 @@ var createModelClass = function (modelDefinition) {
381
351
  var patches;
382
352
  var model = immer_1.produce(source, function (draft) {
383
353
  fn(draft);
384
- draft.id = source.id;
354
+ var keyNames = util_1.extractPrimaryKeyFieldNames(modelDefinition);
355
+ // Keys are immutable
356
+ keyNames.forEach(function (key) { return (draft[key] = source[key]); });
385
357
  var modelValidator = validateModelFields(modelDefinition);
386
358
  Object.entries(draft).forEach(function (_a) {
387
- var _b = __read(_a, 2), k = _b[0], v = _b[1];
359
+ var _b = tslib_1.__read(_a, 2), k = _b[0], v = _b[1];
388
360
  var parsedValue = castInstanceType(modelDefinition, k, v);
389
361
  modelValidator(k, parsedValue);
390
362
  });
@@ -392,7 +364,7 @@ var createModelClass = function (modelDefinition) {
392
364
  var hasExistingPatches = modelPatchesMap.has(source);
393
365
  if (patches.length || hasExistingPatches) {
394
366
  if (hasExistingPatches) {
395
- var _a = __read(modelPatchesMap.get(source), 2), existingPatches = _a[0], existingSource = _a[1];
367
+ var _a = tslib_1.__read(modelPatchesMap.get(source), 2), existingPatches = _a[0], existingSource = _a[1];
396
368
  var mergedPatches = util_1.mergePatches(existingSource, existingPatches, patches);
397
369
  modelPatchesMap.set(model, [mergedPatches, existingSource]);
398
370
  checkReadOnlyPropertyOnUpdate(mergedPatches, modelDefinition);
@@ -414,7 +386,7 @@ var createModelClass = function (modelDefinition) {
414
386
  var instance = modelInstanceCreator(clazz, json);
415
387
  var modelValidator = validateModelFields(modelDefinition);
416
388
  Object.entries(instance).forEach(function (_a) {
417
- var _b = __read(_a, 2), k = _b[0], v = _b[1];
389
+ var _b = tslib_1.__read(_a, 2), k = _b[0], v = _b[1];
418
390
  modelValidator(k, v);
419
391
  });
420
392
  return instance;
@@ -438,7 +410,7 @@ var checkReadOnlyPropertyOnUpdate = function (patches, modelDefinition) {
438
410
  var patchArray = patches.map(function (p) { return [p.path[0], p.value]; });
439
411
  var fields = modelDefinition.fields;
440
412
  patchArray.forEach(function (_a) {
441
- var _b = __read(_a, 2), key = _b[0], val = _b[1];
413
+ var _b = tslib_1.__read(_a, 2), key = _b[0], val = _b[1];
442
414
  if (!val || !fields[key])
443
415
  return;
444
416
  if (fields[key].isReadOnly) {
@@ -467,7 +439,7 @@ function isQueryOne(obj) {
467
439
  function defaultConflictHandler(conflictData) {
468
440
  var localModel = conflictData.localModel, modelConstructor = conflictData.modelConstructor, remoteModel = conflictData.remoteModel;
469
441
  var _version = remoteModel._version;
470
- return modelInstanceCreator(modelConstructor, __assign(__assign({}, localModel), { _version: _version }));
442
+ return modelInstanceCreator(modelConstructor, tslib_1.__assign(tslib_1.__assign({}, localModel), { _version: _version }));
471
443
  }
472
444
  function defaultErrorHandler(error) {
473
445
  logger.warn(error);
@@ -500,25 +472,36 @@ function getModelConstructorByModelName(namespaceName, modelName) {
500
472
  throw new Error(msg);
501
473
  }
502
474
  }
475
+ /**
476
+ * Queries the DataStore metadata tables to see if they are the expected
477
+ * version. If not, clobbers the whole DB. If so, leaves them alone.
478
+ * Otherwise, simply writes the schema version.
479
+ *
480
+ * SIDE EFFECT:
481
+ * 1. Creates a transaction
482
+ * 1. Updates data.
483
+ *
484
+ * @param storage Storage adapter containing the metadata.
485
+ * @param version The expected schema version.
486
+ */
503
487
  function checkSchemaVersion(storage, version) {
504
- return __awaiter(this, void 0, void 0, function () {
488
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
505
489
  var Setting, modelDefinition;
506
490
  var _this = this;
507
- return __generator(this, function (_a) {
491
+ return tslib_1.__generator(this, function (_a) {
508
492
  switch (_a.label) {
509
493
  case 0:
510
494
  Setting = dataStoreClasses.Setting;
511
495
  modelDefinition = schema.namespaces[util_1.DATASTORE].models.Setting;
512
- return [4 /*yield*/, storage.runExclusive(function (s) { return __awaiter(_this, void 0, void 0, function () {
496
+ return [4 /*yield*/, storage.runExclusive(function (s) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
513
497
  var _a, schemaVersionSetting, storedValue;
514
- return __generator(this, function (_b) {
498
+ return tslib_1.__generator(this, function (_b) {
515
499
  switch (_b.label) {
516
500
  case 0: return [4 /*yield*/, s.query(Setting, predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition, function (c) {
517
- // @ts-ignore Argument of type '"eq"' is not assignable to parameter of type 'never'.
518
501
  return c.key('eq', SETTING_SCHEMA_VERSION);
519
502
  }), { page: 0, limit: 1 })];
520
503
  case 1:
521
- _a = __read.apply(void 0, [_b.sent(), 1]), schemaVersionSetting = _a[0];
504
+ _a = tslib_1.__read.apply(void 0, [_b.sent(), 1]), schemaVersionSetting = _a[0];
522
505
  if (!(schemaVersionSetting !== undefined &&
523
506
  schemaVersionSetting.value !== undefined)) return [3 /*break*/, 4];
524
507
  storedValue = JSON.parse(schemaVersionSetting.value);
@@ -583,13 +566,21 @@ function getNamespace() {
583
566
  };
584
567
  return namespace;
585
568
  }
569
+ var DataStoreState;
570
+ (function (DataStoreState) {
571
+ DataStoreState["NotRunning"] = "Not Running";
572
+ DataStoreState["Starting"] = "Starting";
573
+ DataStoreState["Running"] = "Running";
574
+ DataStoreState["Stopping"] = "Stopping";
575
+ DataStoreState["Clearing"] = "Clearing";
576
+ })(DataStoreState || (DataStoreState = {}));
586
577
  var DataStore = /** @class */ (function () {
587
578
  function DataStore() {
588
579
  var _this = this;
589
580
  // reference to configured category instances. Used for preserving SSR context
590
581
  this.Auth = auth_1.Auth;
591
- this.API = api_1.default;
592
- this.Cache = cache_1.default;
582
+ this.API = api_1.API;
583
+ this.Cache = cache_1.BrowserStorageCache;
593
584
  this.amplifyConfig = {};
594
585
  this.syncPredicates = new WeakMap();
595
586
  // object that gets passed to descendent classes. Allows us to pass these down by reference
@@ -598,156 +589,235 @@ var DataStore = /** @class */ (function () {
598
589
  API: this.API,
599
590
  Cache: this.Cache,
600
591
  };
601
- this.start = function () { return __awaiter(_this, void 0, void 0, function () {
602
- var aws_appsync_graphqlEndpoint, _a, fullSyncIntervalInMilliseconds;
592
+ /**
593
+ * **IMPORTANT!**
594
+ *
595
+ * Accumulator for background things that can **and MUST** be called when
596
+ * DataStore stops.
597
+ *
598
+ * These jobs **MUST** be *idempotent promises* that resolve ONLY
599
+ * once the intended jobs are completely finished and/or otherwise destroyed
600
+ * and cleaned up with ZERO outstanding:
601
+ *
602
+ * 1. side effects (e.g., state changes)
603
+ * 1. callbacks
604
+ * 1. subscriptions
605
+ * 1. calls to storage
606
+ * 1. *etc.*
607
+ *
608
+ * Methods that create pending promises, subscriptions, callbacks, or any
609
+ * type of side effect **MUST** be registered with the manager. And, a new
610
+ * manager must be created after each `exit()`.
611
+ *
612
+ * Failure to comply will put DataStore into a highly unpredictable state
613
+ * when it needs to stop or clear -- which occurs when restarting with new
614
+ * sync expressions, during testing, and potentially during app code
615
+ * recovery handling, etc..
616
+ *
617
+ * It is up to the discretion of each disposer whether to wait for job
618
+ * completion or to cancel operations and issue failures *as long as the
619
+ * disposer returns in a reasonable amount of time.*
620
+ *
621
+ * (Reasonable = *seconds*, not minutes.)
622
+ */
623
+ this.runningProcesses = new core_1.BackgroundProcessManager();
624
+ /**
625
+ * Indicates what state DataStore is in.
626
+ *
627
+ * Not [yet?] used for actual state management; but for messaging
628
+ * when errors occur, to help troubleshoot.
629
+ */
630
+ this.state = DataStoreState.NotRunning;
631
+ /**
632
+ * If not already done:
633
+ * 1. Attaches and initializes storage.
634
+ * 1. Loads the schema and records metadata.
635
+ * 1. If `this.amplifyConfig.aws_appsync_graphqlEndpoint` contains a URL,
636
+ * attaches a sync engine, starts it, and subscribes.
637
+ */
638
+ this.start = function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
603
639
  var _this = this;
604
- return __generator(this, function (_b) {
605
- switch (_b.label) {
606
- case 0:
607
- if (!(this.initialized === undefined)) return [3 /*break*/, 1];
608
- logger.debug('Starting DataStore');
609
- this.initialized = new Promise(function (res, rej) {
610
- _this.initResolve = res;
611
- _this.initReject = rej;
612
- });
613
- return [3 /*break*/, 3];
614
- case 1: return [4 /*yield*/, this.initialized];
615
- case 2:
616
- _b.sent();
617
- return [2 /*return*/];
618
- case 3:
619
- this.storage = new storage_1.ExclusiveStorage(schema, namespaceResolver, getModelConstructorByModelName, modelInstanceCreator, this.storageAdapter, this.sessionId);
620
- return [4 /*yield*/, this.storage.init()];
621
- case 4:
622
- _b.sent();
623
- checkSchemaInitialized();
624
- return [4 /*yield*/, checkSchemaVersion(this.storage, schema.version)];
625
- case 5:
626
- _b.sent();
627
- aws_appsync_graphqlEndpoint = this.amplifyConfig.aws_appsync_graphqlEndpoint;
628
- if (!aws_appsync_graphqlEndpoint) return [3 /*break*/, 7];
629
- logger.debug('GraphQL endpoint available', aws_appsync_graphqlEndpoint);
630
- _a = this;
631
- return [4 /*yield*/, this.processSyncExpressions()];
632
- case 6:
633
- _a.syncPredicates = _b.sent();
634
- this.sync = new sync_1.SyncEngine(schema, namespaceResolver, exports.syncClasses, userClasses, this.storage, modelInstanceCreator, this.conflictHandler, this.errorHandler, this.syncPredicates, this.amplifyConfig, this.authModeStrategy, this.amplifyContext);
635
- fullSyncIntervalInMilliseconds = this.fullSyncInterval * 1000 * 60;
636
- syncSubscription = this.sync
637
- .start({ fullSyncInterval: fullSyncIntervalInMilliseconds })
638
- .subscribe({
639
- next: function (_a) {
640
- var type = _a.type, data = _a.data;
641
- // In Node, we need to wait for queries to be synced to prevent returning empty arrays.
642
- // In the Browser, we can begin returning data once subscriptions are in place.
643
- var readyType = isNode
644
- ? sync_1.ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY
645
- : sync_1.ControlMessage.SYNC_ENGINE_STORAGE_SUBSCRIBED;
646
- if (type === readyType) {
647
- _this.initResolve();
648
- }
649
- core_1.Hub.dispatch('datastore', {
650
- event: type,
651
- data: data,
652
- });
653
- },
654
- error: function (err) {
655
- logger.warn('Sync error', err);
656
- _this.initReject();
657
- },
658
- });
659
- return [3 /*break*/, 8];
660
- case 7:
661
- logger.warn("Data won't be synchronized. No GraphQL endpoint configured. Did you forget `Amplify.configure(awsconfig)`?", {
662
- config: this.amplifyConfig,
640
+ return tslib_1.__generator(this, function (_a) {
641
+ return [2 /*return*/, this.runningProcesses
642
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
643
+ var aws_appsync_graphqlEndpoint, _a, fullSyncIntervalInMilliseconds;
644
+ var _this = this;
645
+ return tslib_1.__generator(this, function (_b) {
646
+ switch (_b.label) {
647
+ case 0:
648
+ this.state = DataStoreState.Starting;
649
+ if (!(this.initialized === undefined)) return [3 /*break*/, 1];
650
+ logger.debug('Starting DataStore');
651
+ this.initialized = new Promise(function (res, rej) {
652
+ _this.initResolve = res;
653
+ _this.initReject = rej;
654
+ });
655
+ return [3 /*break*/, 3];
656
+ case 1: return [4 /*yield*/, this.initialized];
657
+ case 2:
658
+ _b.sent();
659
+ return [2 /*return*/];
660
+ case 3:
661
+ this.storage = new storage_1.ExclusiveStorage(schema, namespaceResolver, getModelConstructorByModelName, modelInstanceCreator, this.storageAdapter, this.sessionId);
662
+ return [4 /*yield*/, this.storage.init()];
663
+ case 4:
664
+ _b.sent();
665
+ checkSchemaInitialized();
666
+ return [4 /*yield*/, checkSchemaVersion(this.storage, schema.version)];
667
+ case 5:
668
+ _b.sent();
669
+ aws_appsync_graphqlEndpoint = this.amplifyConfig.aws_appsync_graphqlEndpoint;
670
+ if (!aws_appsync_graphqlEndpoint) return [3 /*break*/, 7];
671
+ logger.debug('GraphQL endpoint available', aws_appsync_graphqlEndpoint);
672
+ _a = this;
673
+ return [4 /*yield*/, this.processSyncExpressions()];
674
+ case 6:
675
+ _a.syncPredicates = _b.sent();
676
+ this.sync = new sync_1.SyncEngine(schema, namespaceResolver, exports.syncClasses, userClasses, this.storage, modelInstanceCreator, this.conflictHandler, this.errorHandler, this.syncPredicates, this.amplifyConfig, this.authModeStrategy, this.amplifyContext, this.connectivityMonitor);
677
+ fullSyncIntervalInMilliseconds = this.fullSyncInterval * 1000 * 60;
678
+ syncSubscription = this.sync
679
+ .start({ fullSyncInterval: fullSyncIntervalInMilliseconds })
680
+ .subscribe({
681
+ next: function (_a) {
682
+ var type = _a.type, data = _a.data;
683
+ // In Node, we need to wait for queries to be synced to prevent returning empty arrays.
684
+ // In the Browser, we can begin returning data once subscriptions are in place.
685
+ var readyType = isNode
686
+ ? sync_1.ControlMessage.SYNC_ENGINE_SYNC_QUERIES_READY
687
+ : sync_1.ControlMessage.SYNC_ENGINE_STORAGE_SUBSCRIBED;
688
+ if (type === readyType) {
689
+ _this.initResolve();
690
+ }
691
+ core_1.Hub.dispatch('datastore', {
692
+ event: type,
693
+ data: data,
694
+ });
695
+ },
696
+ error: function (err) {
697
+ logger.warn('Sync error', err);
698
+ _this.initReject();
699
+ },
700
+ });
701
+ return [3 /*break*/, 8];
702
+ case 7:
703
+ logger.warn("Data won't be synchronized. No GraphQL endpoint configured. Did you forget `Amplify.configure(awsconfig)`?", {
704
+ config: this.amplifyConfig,
705
+ });
706
+ this.initResolve();
707
+ _b.label = 8;
708
+ case 8: return [4 /*yield*/, this.initialized];
709
+ case 9:
710
+ _b.sent();
711
+ this.state = DataStoreState.Running;
712
+ return [2 /*return*/];
713
+ }
663
714
  });
664
- this.initResolve();
665
- _b.label = 8;
666
- case 8: return [4 /*yield*/, this.initialized];
667
- case 9:
668
- _b.sent();
669
- return [2 /*return*/];
670
- }
715
+ }); }, 'datastore start')
716
+ .catch(this.handleAddProcError('DataStore.start()'))];
671
717
  });
672
718
  }); };
673
- this.query = function (modelConstructor, idOrCriteria, paginationProducer) { return __awaiter(_this, void 0, void 0, function () {
674
- var msg, modelDefinition, predicate, pagination, result;
675
- return __generator(this, function (_a) {
676
- switch (_a.label) {
677
- case 0: return [4 /*yield*/, this.start()];
678
- case 1:
679
- _a.sent();
680
- //#region Input validation
681
- if (!isValidModelConstructor(modelConstructor)) {
682
- msg = 'Constructor is not for a valid model';
683
- logger.error(msg, { modelConstructor: modelConstructor });
684
- throw new Error(msg);
685
- }
686
- if (typeof idOrCriteria === 'string') {
687
- if (paginationProducer !== undefined) {
688
- logger.warn('Pagination is ignored when querying by id');
689
- }
690
- }
691
- modelDefinition = getModelDefinition(modelConstructor);
692
- if (isQueryOne(idOrCriteria)) {
693
- predicate = predicates_1.ModelPredicateCreator.createForId(modelDefinition, idOrCriteria);
694
- }
695
- else {
696
- if (predicates_1.isPredicatesAll(idOrCriteria)) {
697
- // Predicates.ALL means "all records", so no predicate (undefined)
698
- predicate = undefined;
699
- }
700
- else {
701
- predicate = predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition, idOrCriteria);
719
+ this.query = function (modelConstructor, identifierOrCriteria, paginationProducer) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
720
+ var _this = this;
721
+ return tslib_1.__generator(this, function (_a) {
722
+ return [2 /*return*/, this.runningProcesses
723
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
724
+ var msg, modelDefinition, keyFields, predicate, msg, pagination, result, returnOne;
725
+ return tslib_1.__generator(this, function (_a) {
726
+ switch (_a.label) {
727
+ case 0: return [4 /*yield*/, this.start()];
728
+ case 1:
729
+ _a.sent();
730
+ //#region Input validation
731
+ if (!isValidModelConstructor(modelConstructor)) {
732
+ msg = 'Constructor is not for a valid model';
733
+ logger.error(msg, { modelConstructor: modelConstructor });
734
+ throw new Error(msg);
735
+ }
736
+ if (typeof identifierOrCriteria === 'string') {
737
+ if (paginationProducer !== undefined) {
738
+ logger.warn('Pagination is ignored when querying by id');
739
+ }
740
+ }
741
+ modelDefinition = getModelDefinition(modelConstructor);
742
+ keyFields = util_1.extractPrimaryKeyFieldNames(modelDefinition);
743
+ if (isQueryOne(identifierOrCriteria)) {
744
+ if (keyFields.length > 1) {
745
+ msg = util_1.errorMessages.queryByPkWithCompositeKeyPresent;
746
+ logger.error(msg, { keyFields: keyFields });
747
+ throw new Error(msg);
748
+ }
749
+ predicate = predicates_1.ModelPredicateCreator.createForSingleField(modelDefinition, keyFields[0], identifierOrCriteria);
750
+ }
751
+ else {
752
+ // Object is being queried using object literal syntax
753
+ if (types_1.isIdentifierObject(identifierOrCriteria, modelDefinition)) {
754
+ predicate = predicates_1.ModelPredicateCreator.createForPk(modelDefinition, identifierOrCriteria);
755
+ }
756
+ else if (predicates_1.isPredicatesAll(identifierOrCriteria)) {
757
+ // Predicates.ALL means "all records", so no predicate (undefined)
758
+ predicate = undefined;
759
+ }
760
+ else {
761
+ predicate = predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition, identifierOrCriteria);
762
+ }
763
+ }
764
+ pagination = this.processPagination(modelDefinition, paginationProducer);
765
+ //#endregion
766
+ logger.debug('params ready', {
767
+ modelConstructor: modelConstructor,
768
+ predicate: predicates_1.ModelPredicateCreator.getPredicates(predicate, false),
769
+ pagination: tslib_1.__assign(tslib_1.__assign({}, pagination), { sort: predicates_1.ModelSortPredicateCreator.getPredicates(pagination && pagination.sort, false) }),
770
+ });
771
+ return [4 /*yield*/, this.storage.query(modelConstructor, predicate, pagination)];
772
+ case 2:
773
+ result = _a.sent();
774
+ returnOne = isQueryOne(identifierOrCriteria) ||
775
+ types_1.isIdentifierObject(identifierOrCriteria, modelDefinition);
776
+ return [2 /*return*/, returnOne ? result[0] : result];
702
777
  }
703
- }
704
- pagination = this.processPagination(modelDefinition, paginationProducer);
705
- //#endregion
706
- logger.debug('params ready', {
707
- modelConstructor: modelConstructor,
708
- predicate: predicates_1.ModelPredicateCreator.getPredicates(predicate, false),
709
- pagination: __assign(__assign({}, pagination), { sort: predicates_1.ModelSortPredicateCreator.getPredicates(pagination && pagination.sort, false) }),
710
778
  });
711
- return [4 /*yield*/, this.storage.query(modelConstructor, predicate, pagination)];
712
- case 2:
713
- result = _a.sent();
714
- return [2 /*return*/, isQueryOne(idOrCriteria) ? result[0] : result];
715
- }
779
+ }); }, 'datastore query')
780
+ .catch(this.handleAddProcError('DataStore.query()'))];
716
781
  });
717
782
  }); };
718
- this.save = function (model, condition) { return __awaiter(_this, void 0, void 0, function () {
719
- var patchesTuple, modelConstructor, msg, modelDefinition, producedCondition, _a, savedModel;
783
+ this.save = function (model, condition) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
720
784
  var _this = this;
721
- return __generator(this, function (_b) {
722
- switch (_b.label) {
723
- case 0: return [4 /*yield*/, this.start()];
724
- case 1:
725
- _b.sent();
726
- patchesTuple = modelPatchesMap.get(model);
727
- modelConstructor = model
728
- ? model.constructor
729
- : undefined;
730
- if (!isValidModelConstructor(modelConstructor)) {
731
- msg = 'Object is not an instance of a valid model';
732
- logger.error(msg, { model: model });
733
- throw new Error(msg);
734
- }
735
- modelDefinition = getModelDefinition(modelConstructor);
736
- producedCondition = predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition, condition);
737
- return [4 /*yield*/, this.storage.runExclusive(function (s) { return __awaiter(_this, void 0, void 0, function () {
738
- return __generator(this, function (_a) {
739
- switch (_a.label) {
740
- case 0: return [4 /*yield*/, s.save(model, producedCondition, undefined, patchesTuple)];
741
- case 1:
742
- _a.sent();
743
- return [2 /*return*/, s.query(modelConstructor, predicates_1.ModelPredicateCreator.createForId(modelDefinition, model.id))];
785
+ return tslib_1.__generator(this, function (_a) {
786
+ return [2 /*return*/, this.runningProcesses
787
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
788
+ var patchesTuple, modelConstructor, msg, modelDefinition, producedCondition, _a, savedModel;
789
+ var _this = this;
790
+ return tslib_1.__generator(this, function (_b) {
791
+ switch (_b.label) {
792
+ case 0: return [4 /*yield*/, this.start()];
793
+ case 1:
794
+ _b.sent();
795
+ patchesTuple = modelPatchesMap.get(model);
796
+ modelConstructor = model ? model.constructor : undefined;
797
+ if (!isValidModelConstructor(modelConstructor)) {
798
+ msg = 'Object is not an instance of a valid model';
799
+ logger.error(msg, { model: model });
800
+ throw new Error(msg);
744
801
  }
745
- });
746
- }); })];
747
- case 2:
748
- _a = __read.apply(void 0, [_b.sent(), 1]), savedModel = _a[0];
749
- return [2 /*return*/, savedModel];
750
- }
802
+ modelDefinition = getModelDefinition(modelConstructor);
803
+ producedCondition = predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition, condition);
804
+ return [4 /*yield*/, this.storage.runExclusive(function (s) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
805
+ return tslib_1.__generator(this, function (_a) {
806
+ switch (_a.label) {
807
+ case 0: return [4 /*yield*/, s.save(model, producedCondition, undefined, patchesTuple)];
808
+ case 1:
809
+ _a.sent();
810
+ return [2 /*return*/, s.query(modelConstructor, predicates_1.ModelPredicateCreator.createForPk(modelDefinition, model))];
811
+ }
812
+ });
813
+ }); })];
814
+ case 2:
815
+ _a = tslib_1.__read.apply(void 0, [_b.sent(), 1]), savedModel = _a[0];
816
+ return [2 /*return*/, savedModel];
817
+ }
818
+ });
819
+ }); }, 'datastore save')
820
+ .catch(this.handleAddProcError('DataStore.save()'))];
751
821
  });
752
822
  }); };
753
823
  this.setConflictHandler = function (config) {
@@ -776,75 +846,95 @@ var DataStore = /** @class */ (function () {
776
846
  }
777
847
  return _this.errorHandler || defaultErrorHandler;
778
848
  };
779
- this.delete = function (modelOrConstructor, idOrCriteria) { return __awaiter(_this, void 0, void 0, function () {
780
- var condition, msg, modelConstructor, msg, msg, _a, deleted, model, modelConstructor, msg, modelDefinition, idPredicate, msg, _b, _c, deleted;
781
- return __generator(this, function (_d) {
782
- switch (_d.label) {
783
- case 0: return [4 /*yield*/, this.start()];
784
- case 1:
785
- _d.sent();
786
- if (!modelOrConstructor) {
787
- msg = 'Model or Model Constructor required';
788
- logger.error(msg, { modelOrConstructor: modelOrConstructor });
789
- throw new Error(msg);
790
- }
791
- if (!isValidModelConstructor(modelOrConstructor)) return [3 /*break*/, 3];
792
- modelConstructor = modelOrConstructor;
793
- if (!idOrCriteria) {
794
- msg = 'Id to delete or criteria required. Do you want to delete all? Pass Predicates.ALL';
795
- logger.error(msg, { idOrCriteria: idOrCriteria });
796
- throw new Error(msg);
797
- }
798
- if (typeof idOrCriteria === 'string') {
799
- condition = predicates_1.ModelPredicateCreator.createForId(getModelDefinition(modelConstructor), idOrCriteria);
800
- }
801
- else {
802
- condition = predicates_1.ModelPredicateCreator.createFromExisting(getModelDefinition(modelConstructor),
803
- /**
804
- * idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
805
- * The symbol is used only for typing purposes. e.g. see Predicates.ALL
806
- */
807
- idOrCriteria);
808
- if (!condition || !predicates_1.ModelPredicateCreator.isValidPredicate(condition)) {
809
- msg = 'Criteria required. Do you want to delete all? Pass Predicates.ALL';
810
- logger.error(msg, { condition: condition });
811
- throw new Error(msg);
812
- }
813
- }
814
- return [4 /*yield*/, this.storage.delete(modelConstructor, condition)];
815
- case 2:
816
- _a = __read.apply(void 0, [_d.sent(), 1]), deleted = _a[0];
817
- return [2 /*return*/, deleted];
818
- case 3:
819
- model = modelOrConstructor;
820
- modelConstructor = Object.getPrototypeOf(model || {})
821
- .constructor;
822
- if (!isValidModelConstructor(modelConstructor)) {
823
- msg = 'Object is not an instance of a valid model';
824
- logger.error(msg, { model: model });
825
- throw new Error(msg);
826
- }
827
- modelDefinition = getModelDefinition(modelConstructor);
828
- idPredicate = predicates_1.ModelPredicateCreator.createForId(modelDefinition, model.id);
829
- if (idOrCriteria) {
830
- if (typeof idOrCriteria !== 'function') {
831
- msg = 'Invalid criteria';
832
- logger.error(msg, { idOrCriteria: idOrCriteria });
833
- throw new Error(msg);
849
+ this.delete = function (modelOrConstructor, identifierOrCriteria) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
850
+ var _this = this;
851
+ return tslib_1.__generator(this, function (_a) {
852
+ return [2 /*return*/, this.runningProcesses
853
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
854
+ var condition, msg, modelConstructor, msg, modelDefinition, keyFields, msg, msg, _a, deleted, model, modelConstructor, msg, modelDefinition, pkPredicate, msg, _b, _c, deleted;
855
+ return tslib_1.__generator(this, function (_d) {
856
+ switch (_d.label) {
857
+ case 0: return [4 /*yield*/, this.start()];
858
+ case 1:
859
+ _d.sent();
860
+ if (!modelOrConstructor) {
861
+ msg = 'Model or Model Constructor required';
862
+ logger.error(msg, { modelOrConstructor: modelOrConstructor });
863
+ throw new Error(msg);
864
+ }
865
+ if (!isValidModelConstructor(modelOrConstructor)) return [3 /*break*/, 3];
866
+ modelConstructor = modelOrConstructor;
867
+ if (!identifierOrCriteria) {
868
+ msg = 'Id to delete or criteria required. Do you want to delete all? Pass Predicates.ALL';
869
+ logger.error(msg, { identifierOrCriteria: identifierOrCriteria });
870
+ throw new Error(msg);
871
+ }
872
+ modelDefinition = getModelDefinition(modelConstructor);
873
+ if (typeof identifierOrCriteria === 'string') {
874
+ keyFields = util_1.extractPrimaryKeyFieldNames(modelDefinition);
875
+ if (keyFields.length > 1) {
876
+ msg = util_1.errorMessages.deleteByPkWithCompositeKeyPresent;
877
+ logger.error(msg, { keyFields: keyFields });
878
+ throw new Error(msg);
879
+ }
880
+ condition = predicates_1.ModelPredicateCreator.createForSingleField(getModelDefinition(modelConstructor), keyFields[0], identifierOrCriteria);
881
+ }
882
+ else {
883
+ if (types_1.isIdentifierObject(identifierOrCriteria, modelDefinition)) {
884
+ condition = predicates_1.ModelPredicateCreator.createForPk(modelDefinition, identifierOrCriteria);
885
+ }
886
+ else {
887
+ condition = predicates_1.ModelPredicateCreator.createFromExisting(modelDefinition,
888
+ /**
889
+ * idOrCriteria is always a ProducerModelPredicate<T>, never a symbol.
890
+ * The symbol is used only for typing purposes. e.g. see Predicates.ALL
891
+ */
892
+ identifierOrCriteria);
893
+ }
894
+ if (!condition ||
895
+ !predicates_1.ModelPredicateCreator.isValidPredicate(condition)) {
896
+ msg = 'Criteria required. Do you want to delete all? Pass Predicates.ALL';
897
+ logger.error(msg, { condition: condition });
898
+ throw new Error(msg);
899
+ }
900
+ }
901
+ return [4 /*yield*/, this.storage.delete(modelConstructor, condition)];
902
+ case 2:
903
+ _a = tslib_1.__read.apply(void 0, [_d.sent(), 1]), deleted = _a[0];
904
+ return [2 /*return*/, deleted];
905
+ case 3:
906
+ model = modelOrConstructor;
907
+ modelConstructor = Object.getPrototypeOf(model || {})
908
+ .constructor;
909
+ if (!isValidModelConstructor(modelConstructor)) {
910
+ msg = 'Object is not an instance of a valid model';
911
+ logger.error(msg, { model: model });
912
+ throw new Error(msg);
913
+ }
914
+ modelDefinition = getModelDefinition(modelConstructor);
915
+ pkPredicate = predicates_1.ModelPredicateCreator.createForPk(modelDefinition, model);
916
+ if (identifierOrCriteria) {
917
+ if (typeof identifierOrCriteria !== 'function') {
918
+ msg = 'Invalid criteria';
919
+ logger.error(msg, { identifierOrCriteria: identifierOrCriteria });
920
+ throw new Error(msg);
921
+ }
922
+ condition = identifierOrCriteria(pkPredicate);
923
+ }
924
+ else {
925
+ condition = pkPredicate;
926
+ }
927
+ return [4 /*yield*/, this.storage.delete(model, condition)];
928
+ case 4:
929
+ _b = tslib_1.__read.apply(void 0, [_d.sent(), 1]), _c = tslib_1.__read(_b[0], 1), deleted = _c[0];
930
+ return [2 /*return*/, deleted];
834
931
  }
835
- condition = idOrCriteria(idPredicate);
836
- }
837
- else {
838
- condition = idPredicate;
839
- }
840
- return [4 /*yield*/, this.storage.delete(model, condition)];
841
- case 4:
842
- _b = __read.apply(void 0, [_d.sent(), 1]), _c = __read(_b[0], 1), deleted = _c[0];
843
- return [2 /*return*/, deleted];
844
- }
932
+ });
933
+ }); }, 'datastore delete')
934
+ .catch(this.handleAddProcError('DataStore.delete()'))];
845
935
  });
846
936
  }); };
847
- this.observe = function (modelOrConstructor, idOrCriteria) {
937
+ this.observe = function (modelOrConstructor, identifierOrCriteria) {
848
938
  var predicate;
849
939
  var modelConstructor = modelOrConstructor && isValidModelConstructor(modelOrConstructor)
850
940
  ? modelOrConstructor
@@ -853,10 +943,10 @@ var DataStore = /** @class */ (function () {
853
943
  var model = modelOrConstructor;
854
944
  var modelConstructor_1 = model && Object.getPrototypeOf(model).constructor;
855
945
  if (isValidModelConstructor(modelConstructor_1)) {
856
- if (idOrCriteria) {
946
+ if (identifierOrCriteria) {
857
947
  logger.warn('idOrCriteria is ignored when using a model instance', {
858
948
  model: model,
859
- idOrCriteria: idOrCriteria,
949
+ identifierOrCriteria: identifierOrCriteria,
860
950
  });
861
951
  }
862
952
  return _this.observe(modelConstructor_1, model.id);
@@ -867,9 +957,17 @@ var DataStore = /** @class */ (function () {
867
957
  throw new Error(msg);
868
958
  }
869
959
  }
870
- if (idOrCriteria !== undefined && modelConstructor === undefined) {
960
+ // observe should not accept object literal syntax
961
+ if (identifierOrCriteria &&
962
+ modelConstructor &&
963
+ types_1.isIdentifierObject(identifierOrCriteria, getModelDefinition(modelConstructor))) {
964
+ var msg = util_1.errorMessages.observeWithObjectLiteral;
965
+ logger.error(msg, { objectLiteral: identifierOrCriteria });
966
+ throw new Error(msg);
967
+ }
968
+ if (identifierOrCriteria !== undefined && modelConstructor === undefined) {
871
969
  var msg = 'Cannot provide criteria without a modelConstructor';
872
- logger.error(msg, idOrCriteria);
970
+ logger.error(msg, identifierOrCriteria);
873
971
  throw new Error(msg);
874
972
  }
875
973
  if (modelConstructor && !isValidModelConstructor(modelConstructor)) {
@@ -877,19 +975,27 @@ var DataStore = /** @class */ (function () {
877
975
  logger.error(msg, { modelConstructor: modelConstructor });
878
976
  throw new Error(msg);
879
977
  }
880
- if (typeof idOrCriteria === 'string') {
881
- predicate = predicates_1.ModelPredicateCreator.createForId(getModelDefinition(modelConstructor), idOrCriteria);
978
+ if (typeof identifierOrCriteria === 'string') {
979
+ var modelDefinition = getModelDefinition(modelConstructor);
980
+ var _a = tslib_1.__read(util_1.extractPrimaryKeyFieldNames(modelDefinition), 1), keyField = _a[0];
981
+ predicate = predicates_1.ModelPredicateCreator.createForSingleField(getModelDefinition(modelConstructor), keyField, identifierOrCriteria);
882
982
  }
883
983
  else {
884
- predicate =
885
- modelConstructor &&
886
- predicates_1.ModelPredicateCreator.createFromExisting(getModelDefinition(modelConstructor), idOrCriteria);
984
+ if (predicates_1.isPredicatesAll(identifierOrCriteria)) {
985
+ predicate = undefined;
986
+ }
987
+ else {
988
+ predicate =
989
+ modelConstructor &&
990
+ predicates_1.ModelPredicateCreator.createFromExisting(getModelDefinition(modelConstructor), identifierOrCriteria);
991
+ }
887
992
  }
888
993
  return new zen_observable_ts_1.default(function (observer) {
889
994
  var handle;
890
- (function () { return __awaiter(_this, void 0, void 0, function () {
995
+ _this.runningProcesses
996
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
891
997
  var _this = this;
892
- return __generator(this, function (_a) {
998
+ return tslib_1.__generator(this, function (_a) {
893
999
  switch (_a.label) {
894
1000
  case 0: return [4 /*yield*/, this.start()];
895
1001
  case 1:
@@ -903,36 +1009,52 @@ var DataStore = /** @class */ (function () {
903
1009
  return namespaceResolver(model) === util_1.USER;
904
1010
  })
905
1011
  .subscribe({
906
- next: function (item) { return __awaiter(_this, void 0, void 0, function () {
907
- var message, freshElement;
908
- return __generator(this, function (_a) {
909
- switch (_a.label) {
910
- case 0:
911
- message = item;
912
- if (!(item.opType !== 'DELETE')) return [3 /*break*/, 2];
913
- return [4 /*yield*/, this.query(item.model, item.element.id)];
914
- case 1:
915
- freshElement = _a.sent();
916
- message = __assign(__assign({}, message), { element: freshElement });
917
- _a.label = 2;
918
- case 2:
919
- observer.next(message);
920
- return [2 /*return*/];
921
- }
922
- });
923
- }); },
1012
+ next: function (item) {
1013
+ return _this.runningProcesses.isOpen &&
1014
+ _this.runningProcesses.add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
1015
+ var message, modelDefinition, keyFields, primaryKeysAndValues, freshElement;
1016
+ return tslib_1.__generator(this, function (_a) {
1017
+ switch (_a.label) {
1018
+ case 0:
1019
+ message = item;
1020
+ if (!(item.opType !== 'DELETE')) return [3 /*break*/, 2];
1021
+ modelDefinition = getModelDefinition(item.model);
1022
+ keyFields = util_1.extractPrimaryKeyFieldNames(modelDefinition);
1023
+ primaryKeysAndValues = util_1.extractPrimaryKeysAndValues(item.element, keyFields);
1024
+ return [4 /*yield*/, this.query(item.model, primaryKeysAndValues)];
1025
+ case 1:
1026
+ freshElement = _a.sent();
1027
+ message = tslib_1.__assign(tslib_1.__assign({}, message), { element: freshElement });
1028
+ _a.label = 2;
1029
+ case 2:
1030
+ observer.next(message);
1031
+ return [2 /*return*/];
1032
+ }
1033
+ });
1034
+ }); }, 'datastore observe message handler');
1035
+ },
924
1036
  error: function (err) { return observer.error(err); },
925
1037
  complete: function () { return observer.complete(); },
926
1038
  });
927
1039
  return [2 /*return*/];
928
1040
  }
929
1041
  });
930
- }); })();
931
- return function () {
932
- if (handle) {
933
- handle.unsubscribe();
934
- }
935
- };
1042
+ }); }, 'datastore observe observable initialization')
1043
+ .catch(_this.handleAddProcError('DataStore.observe()'))
1044
+ .catch(function (error) {
1045
+ observer.error(error);
1046
+ });
1047
+ // better than no cleaner, but if the subscriber is handling the
1048
+ // complete() message async and not registering with the context,
1049
+ // this will still be problematic.
1050
+ return _this.runningProcesses.addCleaner(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
1051
+ return tslib_1.__generator(this, function (_a) {
1052
+ if (handle) {
1053
+ handle.unsubscribe();
1054
+ }
1055
+ return [2 /*return*/];
1056
+ });
1057
+ }); }, 'DataStore.observe() cleanup');
936
1058
  });
937
1059
  };
938
1060
  this.observeQuery = function (model, criteria, options) {
@@ -966,8 +1088,9 @@ var DataStore = /** @class */ (function () {
966
1088
  var sort = (options || {}).sort;
967
1089
  var sortOptions = sort ? { sort: sort } : undefined;
968
1090
  var modelDefinition = getModelDefinition(model);
1091
+ var keyFields = util_1.extractPrimaryKeyFieldNames(modelDefinition);
969
1092
  if (isQueryOne(criteria)) {
970
- predicate = predicates_1.ModelPredicateCreator.createForId(modelDefinition, criteria);
1093
+ predicate = predicates_1.ModelPredicateCreator.createForSingleField(modelDefinition, keyFields[0], criteria);
971
1094
  }
972
1095
  else {
973
1096
  if (predicates_1.isPredicatesAll(criteria)) {
@@ -980,10 +1103,11 @@ var DataStore = /** @class */ (function () {
980
1103
  }
981
1104
  var _a = predicates_1.ModelPredicateCreator.getPredicates(predicate, false) || {}, predicates = _a.predicates, predicateGroupType = _a.type;
982
1105
  var hasPredicate = !!predicates;
983
- (function () { return __awaiter(_this, void 0, void 0, function () {
1106
+ _this.runningProcesses
1107
+ .add(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
984
1108
  var err_1;
985
1109
  var _this = this;
986
- return __generator(this, function (_a) {
1110
+ return tslib_1.__generator(this, function (_a) {
987
1111
  switch (_a.label) {
988
1112
  case 0:
989
1113
  _a.trys.push([0, 2, , 3]);
@@ -991,7 +1115,9 @@ var DataStore = /** @class */ (function () {
991
1115
  case 1:
992
1116
  // first, query and return any locally-available records
993
1117
  (_a.sent()).forEach(function (item) {
994
- return items.set(item.id, item);
1118
+ var itemModelDefinition = getModelDefinition(model);
1119
+ var idOrPk = utils_1.getIdentifierValue(itemModelDefinition, item);
1120
+ items.set(idOrPk, item);
995
1121
  });
996
1122
  // Observe the model and send a stream of updates (debounced).
997
1123
  // We need to post-filter results instead of passing criteria through
@@ -1000,15 +1126,17 @@ var DataStore = /** @class */ (function () {
1000
1126
  handle = this.observe(model).subscribe(function (_a) {
1001
1127
  var element = _a.element, model = _a.model, opType = _a.opType;
1002
1128
  var _b, _c;
1129
+ var itemModelDefinition = getModelDefinition(model);
1130
+ var idOrPk = utils_1.getIdentifierValue(itemModelDefinition, element);
1003
1131
  if (hasPredicate &&
1004
1132
  !util_1.validatePredicate(element, predicateGroupType, predicates)) {
1005
1133
  if (opType === 'UPDATE' &&
1006
- (items.has(element.id) || itemsChanged.has(element.id))) {
1134
+ (items.has(idOrPk) || itemsChanged.has(idOrPk))) {
1007
1135
  // tracking as a "deleted item" will include the item in
1008
1136
  // page limit calculations and ensure it is removed from the
1009
1137
  // final items collection, regardless of which collection(s)
1010
1138
  // it is currently in. (I mean, it could be in both, right!?)
1011
- deletedItemIds.push(element.id);
1139
+ deletedItemIds.push(idOrPk);
1012
1140
  }
1013
1141
  else {
1014
1142
  // ignore updates for irrelevant/filtered items.
@@ -1020,13 +1148,14 @@ var DataStore = /** @class */ (function () {
1020
1148
  // in the `mergePage` method within src/sync/merger.ts. The final state of a model instance
1021
1149
  // depends on the LATEST record (for a given id).
1022
1150
  if (opType === 'DELETE') {
1023
- deletedItemIds.push(element.id);
1151
+ deletedItemIds.push(idOrPk);
1024
1152
  }
1025
1153
  else {
1026
- itemsChanged.set(element.id, element);
1154
+ itemsChanged.set(idOrPk, element);
1027
1155
  }
1028
1156
  var isSynced = (_c = (_b = _this.sync) === null || _b === void 0 ? void 0 : _b.getModelSyncedStatus(model)) !== null && _c !== void 0 ? _c : false;
1029
- var limit = itemsChanged.size - deletedItemIds.length >= _this.syncPageSize;
1157
+ var limit = itemsChanged.size - deletedItemIds.length >=
1158
+ _this.syncPageSize;
1030
1159
  if (limit || isSynced) {
1031
1160
  limitTimerRace.resolve();
1032
1161
  }
@@ -1043,7 +1172,11 @@ var DataStore = /** @class */ (function () {
1043
1172
  case 3: return [2 /*return*/];
1044
1173
  }
1045
1174
  });
1046
- }); })();
1175
+ }); }, 'datastore observequery startup')
1176
+ .catch(_this.handleAddProcError('DataStore.observeQuery()'))
1177
+ .catch(function (error) {
1178
+ observer.error(error);
1179
+ });
1047
1180
  /**
1048
1181
  * Combines the `items`, `itemsChanged`, and `deletedItemIds` collections into
1049
1182
  * a snapshot in the form of `{ items: T[], isSynced: boolean}`.
@@ -1053,14 +1186,18 @@ var DataStore = /** @class */ (function () {
1053
1186
  var generateSnapshot = function () {
1054
1187
  var _a, _b;
1055
1188
  var isSynced = (_b = (_a = _this.sync) === null || _a === void 0 ? void 0 : _a.getModelSyncedStatus(model)) !== null && _b !== void 0 ? _b : false;
1056
- var itemsArray = __spread(Array.from(items.values()), Array.from(itemsChanged.values()));
1189
+ var itemsArray = tslib_1.__spread(Array.from(items.values()), Array.from(itemsChanged.values()));
1057
1190
  if (options === null || options === void 0 ? void 0 : options.sort) {
1058
1191
  sortItems(itemsArray);
1059
1192
  }
1060
1193
  items.clear();
1061
- itemsArray.forEach(function (item) { return items.set(item.id, item); });
1194
+ itemsArray.forEach(function (item) {
1195
+ var itemModelDefinition = getModelDefinition(model);
1196
+ var idOrPk = utils_1.getIdentifierValue(itemModelDefinition, item);
1197
+ items.set(idOrPk, item);
1198
+ });
1062
1199
  // remove deleted items from the final result set
1063
- deletedItemIds.forEach(function (id) { return items.delete(id); });
1200
+ deletedItemIds.forEach(function (idOrPk) { return items.delete(idOrPk); });
1064
1201
  return {
1065
1202
  items: Array.from(items.values()),
1066
1203
  isSynced: isSynced,
@@ -1075,7 +1212,8 @@ var DataStore = /** @class */ (function () {
1075
1212
  * @param snapshot The generated items data to emit.
1076
1213
  */
1077
1214
  var emitSnapshot = function (snapshot) {
1078
- // send the generated snapshot to the primary subscription
1215
+ // send the generated snapshot to the primary subscription.
1216
+ // NOTE: This observer's handler *could* be async ...
1079
1217
  observer.next(snapshot);
1080
1218
  // reset the changed items sets
1081
1219
  itemsChanged.clear();
@@ -1111,15 +1249,18 @@ var DataStore = /** @class */ (function () {
1111
1249
  if (event === sync_1.ControlMessage.SYNC_ENGINE_MODEL_SYNCED &&
1112
1250
  ((_b = data === null || data === void 0 ? void 0 : data.model) === null || _b === void 0 ? void 0 : _b.name) === model.name) {
1113
1251
  generateAndEmitSnapshot();
1114
- core_1.Hub.remove('api', hubCallback);
1252
+ core_1.Hub.remove('datastore', hubCallback);
1115
1253
  }
1116
1254
  };
1117
1255
  core_1.Hub.listen('datastore', hubCallback);
1118
- return function () {
1119
- if (handle) {
1120
- handle.unsubscribe();
1121
- }
1122
- };
1256
+ return _this.runningProcesses.addCleaner(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
1257
+ return tslib_1.__generator(this, function (_a) {
1258
+ if (handle) {
1259
+ handle.unsubscribe();
1260
+ }
1261
+ return [2 /*return*/];
1262
+ });
1263
+ }); }, 'datastore observequery cleaner');
1123
1264
  });
1124
1265
  };
1125
1266
  this.configure = function (config) {
@@ -1127,8 +1268,8 @@ var DataStore = /** @class */ (function () {
1127
1268
  _this.amplifyContext.Auth = _this.Auth;
1128
1269
  _this.amplifyContext.API = _this.API;
1129
1270
  _this.amplifyContext.Cache = _this.Cache;
1130
- var configDataStore = config.DataStore, configAuthModeStrategyType = config.authModeStrategyType, configConflictHandler = config.conflictHandler, configErrorHandler = config.errorHandler, configMaxRecordsToSync = config.maxRecordsToSync, configSyncPageSize = config.syncPageSize, configFullSyncInterval = config.fullSyncInterval, configSyncExpressions = config.syncExpressions, configAuthProviders = config.authProviders, configStorageAdapter = config.storageAdapter, configFromAmplify = __rest(config, ["DataStore", "authModeStrategyType", "conflictHandler", "errorHandler", "maxRecordsToSync", "syncPageSize", "fullSyncInterval", "syncExpressions", "authProviders", "storageAdapter"]);
1131
- _this.amplifyConfig = __assign(__assign({}, configFromAmplify), _this.amplifyConfig);
1271
+ var configDataStore = config.DataStore, configAuthModeStrategyType = config.authModeStrategyType, configConflictHandler = config.conflictHandler, configErrorHandler = config.errorHandler, configMaxRecordsToSync = config.maxRecordsToSync, configSyncPageSize = config.syncPageSize, configFullSyncInterval = config.fullSyncInterval, configSyncExpressions = config.syncExpressions, configAuthProviders = config.authProviders, configStorageAdapter = config.storageAdapter, configFromAmplify = tslib_1.__rest(config, ["DataStore", "authModeStrategyType", "conflictHandler", "errorHandler", "maxRecordsToSync", "syncPageSize", "fullSyncInterval", "syncExpressions", "authProviders", "storageAdapter"]);
1272
+ _this.amplifyConfig = tslib_1.__assign(tslib_1.__assign({}, configFromAmplify), _this.amplifyConfig);
1132
1273
  _this.conflictHandler = _this.setConflictHandler(config);
1133
1274
  _this.errorHandler = _this.setErrorHandler(config);
1134
1275
  var authModeStrategyType = (configDataStore && configDataStore.authModeStrategyType) ||
@@ -1178,66 +1319,132 @@ var DataStore = /** @class */ (function () {
1178
1319
  undefined;
1179
1320
  _this.sessionId = _this.retrieveSessionId();
1180
1321
  };
1181
- this.clear = function clear() {
1182
- return __awaiter(this, void 0, void 0, function () {
1183
- return __generator(this, function (_a) {
1184
- switch (_a.label) {
1185
- case 0:
1186
- checkSchemaInitialized();
1187
- if (!(this.storage === undefined)) return [3 /*break*/, 2];
1188
- // connect to storage so that it can be cleared without fully starting DataStore
1189
- this.storage = new storage_1.ExclusiveStorage(schema, namespaceResolver, getModelConstructorByModelName, modelInstanceCreator, this.storageAdapter, this.sessionId);
1190
- return [4 /*yield*/, this.storage.init()];
1191
- case 1:
1192
- _a.sent();
1193
- _a.label = 2;
1194
- case 2:
1195
- if (syncSubscription && !syncSubscription.closed) {
1196
- syncSubscription.unsubscribe();
1197
- }
1198
- return [4 /*yield*/, this.storage.clear()];
1199
- case 3:
1200
- _a.sent();
1201
- if (this.sync) {
1202
- this.sync.unsubscribeConnectivity();
1203
- }
1204
- this.initialized = undefined; // Should re-initialize when start() is called.
1205
- this.storage = undefined;
1206
- this.sync = undefined;
1207
- this.syncPredicates = new WeakMap();
1208
- return [2 /*return*/];
1209
- }
1210
- });
1211
- });
1212
- };
1213
- this.stop = function stop() {
1214
- return __awaiter(this, void 0, void 0, function () {
1215
- return __generator(this, function (_a) {
1216
- switch (_a.label) {
1217
- case 0:
1218
- if (!(this.initialized !== undefined)) return [3 /*break*/, 2];
1219
- return [4 /*yield*/, this.start()];
1220
- case 1:
1221
- _a.sent();
1222
- _a.label = 2;
1223
- case 2:
1224
- if (syncSubscription && !syncSubscription.closed) {
1225
- syncSubscription.unsubscribe();
1226
- }
1227
- if (this.sync) {
1228
- this.sync.unsubscribeConnectivity();
1229
- }
1230
- this.initialized = undefined; // Should re-initialize when start() is called.
1231
- this.sync = undefined;
1232
- return [2 /*return*/];
1233
- }
1234
- });
1235
- });
1236
- };
1237
1322
  }
1238
1323
  DataStore.prototype.getModuleName = function () {
1239
1324
  return 'DataStore';
1240
1325
  };
1326
+ /**
1327
+ * Builds a function to capture `BackgroundManagerNotOpenError`'s to produce friendlier,
1328
+ * more instructive errors for customers.
1329
+ *
1330
+ * @param operation The name of the operation (usually a Datastore method) the customer
1331
+ * tried to call.
1332
+ */
1333
+ DataStore.prototype.handleAddProcError = function (operation) {
1334
+ var _this = this;
1335
+ /**
1336
+ * If the tested error is a `BackgroundManagerNotOpenError`, it will be captured
1337
+ * and replaced with a friendlier message that instructs the App Developer.
1338
+ *
1339
+ * @param err An error to test.
1340
+ */
1341
+ var handler = function (err) {
1342
+ if (err.message.startsWith('BackgroundManagerNotOpenError')) {
1343
+ throw new Error([
1344
+ "DataStoreStateError: Tried to execute `" + operation + "` while DataStore was \"" + _this.state + "\".",
1345
+ "This can only be done while DataStore is \"Started\" or \"Stopped\". To remedy:",
1346
+ 'Ensure all calls to `stop()` and `clear()` have completed first.',
1347
+ 'If this is not possible, retry the operation until it succeeds.',
1348
+ ].join('\n'));
1349
+ }
1350
+ else {
1351
+ throw err;
1352
+ }
1353
+ };
1354
+ return handler;
1355
+ };
1356
+ /**
1357
+ * Clears all data from storage and removes all data, schema info, other
1358
+ * initialization details, and then stops DataStore.
1359
+ *
1360
+ * That said, reinitialization is required after clearing. This can be done
1361
+ * by explicitiliy calling `start()` or any method that implicitly starts
1362
+ * DataStore, such as `query()`, `save()`, or `delete()`.
1363
+ */
1364
+ DataStore.prototype.clear = function () {
1365
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
1366
+ return tslib_1.__generator(this, function (_a) {
1367
+ switch (_a.label) {
1368
+ case 0:
1369
+ checkSchemaInitialized();
1370
+ this.state = DataStoreState.Clearing;
1371
+ return [4 /*yield*/, this.runningProcesses.close()];
1372
+ case 1:
1373
+ _a.sent();
1374
+ if (!(this.storage === undefined)) return [3 /*break*/, 3];
1375
+ // connect to storage so that it can be cleared without fully starting DataStore
1376
+ this.storage = new storage_1.ExclusiveStorage(schema, namespaceResolver, getModelConstructorByModelName, modelInstanceCreator, this.storageAdapter, this.sessionId);
1377
+ return [4 /*yield*/, this.storage.init()];
1378
+ case 2:
1379
+ _a.sent();
1380
+ _a.label = 3;
1381
+ case 3:
1382
+ if (syncSubscription && !syncSubscription.closed) {
1383
+ syncSubscription.unsubscribe();
1384
+ }
1385
+ if (!this.sync) return [3 /*break*/, 5];
1386
+ return [4 /*yield*/, this.sync.stop()];
1387
+ case 4:
1388
+ _a.sent();
1389
+ _a.label = 5;
1390
+ case 5: return [4 /*yield*/, this.storage.clear()];
1391
+ case 6:
1392
+ _a.sent();
1393
+ this.initialized = undefined; // Should re-initialize when start() is called.
1394
+ this.storage = undefined;
1395
+ this.sync = undefined;
1396
+ this.syncPredicates = new WeakMap();
1397
+ return [4 /*yield*/, this.runningProcesses.open()];
1398
+ case 7:
1399
+ _a.sent();
1400
+ this.state = DataStoreState.NotRunning;
1401
+ return [2 /*return*/];
1402
+ }
1403
+ });
1404
+ });
1405
+ };
1406
+ /**
1407
+ * Stops all DataStore sync activities.
1408
+ *
1409
+ * TODO: "Waits for graceful termination of
1410
+ * running queries and terminates subscriptions."
1411
+ */
1412
+ DataStore.prototype.stop = function () {
1413
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
1414
+ return tslib_1.__generator(this, function (_a) {
1415
+ switch (_a.label) {
1416
+ case 0:
1417
+ this.state = DataStoreState.Stopping;
1418
+ return [4 /*yield*/, this.runningProcesses.close()];
1419
+ case 1:
1420
+ _a.sent();
1421
+ if (syncSubscription && !syncSubscription.closed) {
1422
+ syncSubscription.unsubscribe();
1423
+ }
1424
+ if (!this.sync) return [3 /*break*/, 3];
1425
+ return [4 /*yield*/, this.sync.stop()];
1426
+ case 2:
1427
+ _a.sent();
1428
+ _a.label = 3;
1429
+ case 3:
1430
+ this.initialized = undefined; // Should re-initialize when start() is called.
1431
+ this.sync = undefined;
1432
+ return [4 /*yield*/, this.runningProcesses.open()];
1433
+ case 4:
1434
+ _a.sent();
1435
+ this.state = DataStoreState.NotRunning;
1436
+ return [2 /*return*/];
1437
+ }
1438
+ });
1439
+ });
1440
+ };
1441
+ /**
1442
+ * Validates given pagination input from a query and creates a pagination
1443
+ * argument for use against the storage layer.
1444
+ *
1445
+ * @param modelDefinition
1446
+ * @param paginationProducer
1447
+ */
1241
1448
  DataStore.prototype.processPagination = function (modelDefinition, paginationProducer) {
1242
1449
  var sortPredicate;
1243
1450
  var _a = paginationProducer || {}, limit = _a.limit, page = _a.page, sort = _a.sort;
@@ -1272,19 +1479,23 @@ var DataStore = /** @class */ (function () {
1272
1479
  sort: sortPredicate,
1273
1480
  };
1274
1481
  };
1482
+ /**
1483
+ * Examines the configured `syncExpressions` and produces a WeakMap of
1484
+ * SchemaModel -> predicate to use during sync.
1485
+ */
1275
1486
  DataStore.prototype.processSyncExpressions = function () {
1276
- return __awaiter(this, void 0, void 0, function () {
1487
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
1277
1488
  var syncPredicates;
1278
1489
  var _this = this;
1279
- return __generator(this, function (_a) {
1490
+ return tslib_1.__generator(this, function (_a) {
1280
1491
  switch (_a.label) {
1281
1492
  case 0:
1282
1493
  if (!this.syncExpressions || !this.syncExpressions.length) {
1283
1494
  return [2 /*return*/, new WeakMap()];
1284
1495
  }
1285
- return [4 /*yield*/, Promise.all(this.syncExpressions.map(function (syncExpression) { return __awaiter(_this, void 0, void 0, function () {
1496
+ return [4 /*yield*/, Promise.all(this.syncExpressions.map(function (syncExpression) { return tslib_1.__awaiter(_this, void 0, void 0, function () {
1286
1497
  var _a, modelConstructor, conditionProducer, modelDefinition, condition, predicate;
1287
- return __generator(this, function (_b) {
1498
+ return tslib_1.__generator(this, function (_b) {
1288
1499
  switch (_b.label) {
1289
1500
  case 0: return [4 /*yield*/, syncExpression];
1290
1501
  case 1:
@@ -1318,9 +1529,9 @@ var DataStore = /** @class */ (function () {
1318
1529
  }
1319
1530
  };
1320
1531
  DataStore.prototype.unwrapPromise = function (conditionProducer) {
1321
- return __awaiter(this, void 0, void 0, function () {
1532
+ return tslib_1.__awaiter(this, void 0, void 0, function () {
1322
1533
  var condition, error_1;
1323
- return __generator(this, function (_a) {
1534
+ return tslib_1.__generator(this, function (_a) {
1324
1535
  switch (_a.label) {
1325
1536
  case 0:
1326
1537
  _a.trys.push([0, 2, , 3]);
@@ -1341,7 +1552,7 @@ var DataStore = /** @class */ (function () {
1341
1552
  };
1342
1553
  DataStore.prototype.weakMapFromEntries = function (entries) {
1343
1554
  return entries.reduce(function (map, _a) {
1344
- var _b = __read(_a, 2), modelDefinition = _b[0], predicate = _b[1];
1555
+ var _b = tslib_1.__read(_a, 2), modelDefinition = _b[0], predicate = _b[1];
1345
1556
  if (map.has(modelDefinition)) {
1346
1557
  var name_2 = modelDefinition.name;
1347
1558
  logger.warn("You can only utilize one Sync Expression per model.\n Subsequent sync expressions for the " + name_2 + " model will be ignored.");
@@ -1353,20 +1564,22 @@ var DataStore = /** @class */ (function () {
1353
1564
  return map;
1354
1565
  }, new WeakMap());
1355
1566
  };
1356
- // database separation for Amplify Console. Not a public API
1567
+ /**
1568
+ * A session ID to allow CMS to open databases against multiple apps.
1569
+ * This session ID is only expected be set by AWS Amplify Studio.
1570
+ */
1357
1571
  DataStore.prototype.retrieveSessionId = function () {
1358
1572
  try {
1359
1573
  var sessionId = sessionStorage.getItem('datastoreSessionId');
1360
1574
  if (sessionId) {
1361
1575
  var aws_appsync_graphqlEndpoint = this.amplifyConfig.aws_appsync_graphqlEndpoint;
1362
1576
  var appSyncUrl = aws_appsync_graphqlEndpoint.split('/')[2];
1363
- var _a = __read(appSyncUrl.split('.'), 1), appSyncId = _a[0];
1577
+ var _a = tslib_1.__read(appSyncUrl.split('.'), 1), appSyncId = _a[0];
1364
1578
  return sessionId + "-" + appSyncId;
1365
1579
  }
1366
1580
  }
1367
- catch (_b) {
1368
- return undefined;
1369
- }
1581
+ catch (_b) { }
1582
+ return undefined;
1370
1583
  };
1371
1584
  return DataStore;
1372
1585
  }());