@airtable/blocks 1.9.0-experimental-5565d56-20211029 → 1.10.1

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 (61) hide show
  1. package/CHANGELOG.md +15 -4
  2. package/dist/cjs/error_utils.js +0 -17
  3. package/dist/cjs/models/grouped_record_query_result.js +14 -5
  4. package/dist/cjs/models/linked_records_query_result.js +27 -75
  5. package/dist/cjs/models/mutations.js +162 -18
  6. package/dist/cjs/models/record.js +56 -309
  7. package/dist/cjs/models/record_query_result.js +1 -4
  8. package/dist/cjs/models/record_store.js +765 -554
  9. package/dist/cjs/models/table.js +7 -7
  10. package/dist/cjs/models/table_or_view_query_result.js +414 -480
  11. package/dist/cjs/models/view.js +1 -1
  12. package/dist/cjs/models/view_data_store.js +295 -243
  13. package/dist/cjs/private_utils.js +0 -40
  14. package/dist/cjs/sdk.js +2 -12
  15. package/dist/cjs/testing/abstract_mock_airtable_interface.js +10 -55
  16. package/dist/cjs/ui/use_records.js +1 -5
  17. package/dist/cjs/watchable.js +1 -15
  18. package/dist/types/src/models/grouped_record_query_result.d.ts +3 -3
  19. package/dist/types/src/models/grouped_record_query_result.d.ts.map +1 -1
  20. package/dist/types/src/models/linked_records_query_result.d.ts.map +1 -1
  21. package/dist/types/src/models/mutations.d.ts.map +1 -1
  22. package/dist/types/src/models/record.d.ts +4 -13
  23. package/dist/types/src/models/record.d.ts.map +1 -1
  24. package/dist/types/src/models/record_query_result.d.ts +2 -3
  25. package/dist/types/src/models/record_query_result.d.ts.map +1 -1
  26. package/dist/types/src/models/record_store.d.ts.map +1 -1
  27. package/dist/types/src/models/table.d.ts +1 -1
  28. package/dist/types/src/models/table_or_view_query_result.d.ts +5 -3
  29. package/dist/types/src/models/table_or_view_query_result.d.ts.map +1 -1
  30. package/dist/types/src/models/view.d.ts +1 -1
  31. package/dist/types/src/models/view_data_store.d.ts +1 -0
  32. package/dist/types/src/models/view_data_store.d.ts.map +1 -1
  33. package/dist/types/src/models/view_metadata_query_result.d.ts +1 -1
  34. package/dist/types/src/models/view_metadata_query_result.d.ts.map +1 -1
  35. package/dist/types/src/private_utils.d.ts +3 -26
  36. package/dist/types/src/private_utils.d.ts.map +1 -1
  37. package/dist/types/src/sdk.d.ts.map +1 -1
  38. package/dist/types/src/testing/abstract_mock_airtable_interface.d.ts +11 -11
  39. package/dist/types/src/testing/abstract_mock_airtable_interface.d.ts.map +1 -1
  40. package/dist/types/src/types/airtable_interface.d.ts +19 -43
  41. package/dist/types/src/types/airtable_interface.d.ts.map +1 -1
  42. package/dist/types/src/types/table.d.ts +2 -0
  43. package/dist/types/src/types/table.d.ts.map +1 -1
  44. package/dist/types/src/types/view.d.ts +8 -3
  45. package/dist/types/src/types/view.d.ts.map +1 -1
  46. package/dist/types/src/watchable.d.ts.map +1 -1
  47. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts +5 -7
  48. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts.map +1 -1
  49. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface.d.ts +11 -18
  50. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface.d.ts.map +1 -1
  51. package/dist/types/test/test_helpers.d.ts +0 -2
  52. package/dist/types/test/test_helpers.d.ts.map +1 -1
  53. package/package.json +2 -3
  54. package/dist/cjs/models/query_manager.js +0 -327
  55. package/dist/cjs/types/block_query_spec.js +0 -85
  56. package/dist/types/src/models/query_manager.d.ts +0 -2
  57. package/dist/types/src/models/query_manager.d.ts.map +0 -1
  58. package/dist/types/src/types/block_query_spec.d.ts +0 -139
  59. package/dist/types/src/types/block_query_spec.d.ts.map +0 -1
  60. package/dist/types/test/airtable_interface_mocks/mock_base_data_stores.d.ts +0 -51
  61. package/dist/types/test/airtable_interface_mocks/mock_base_data_stores.d.ts.map +0 -1
@@ -2,7 +2,13 @@
2
2
 
3
3
  var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
4
 
5
- require("core-js/modules/es.array.find");
5
+ require("core-js/modules/es.symbol");
6
+
7
+ require("core-js/modules/es.symbol.description");
8
+
9
+ require("core-js/modules/es.array.filter");
10
+
11
+ require("core-js/modules/es.array.iterator");
6
12
 
7
13
  require("core-js/modules/es.array.map");
8
14
 
@@ -10,17 +16,17 @@ require("core-js/modules/es.array.slice");
10
16
 
11
17
  require("core-js/modules/es.object.to-string");
12
18
 
13
- require("core-js/modules/es.object.values");
14
-
15
19
  require("core-js/modules/es.promise");
16
20
 
17
- require("core-js/modules/web.dom-collections.for-each");
21
+ require("core-js/modules/web.dom-collections.iterator");
18
22
 
19
23
  Object.defineProperty(exports, "__esModule", {
20
24
  value: true
21
25
  });
22
26
  exports.default = exports.WatchableViewDataStoreKeys = void 0;
23
27
 
28
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
29
+
24
30
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
25
31
 
26
32
  require("regenerator-runtime/runtime");
@@ -29,9 +35,11 @@ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/cl
29
35
 
30
36
  var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
31
37
 
38
+ var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
39
+
32
40
  var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
33
41
 
34
- var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
42
+ var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get"));
35
43
 
36
44
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
37
45
 
@@ -43,12 +51,11 @@ var _private_utils = require("../private_utils");
43
51
 
44
52
  var _error_utils = require("../error_utils");
45
53
 
46
- var _block_query_spec = require("../types/block_query_spec");
47
-
48
54
  var _abstract_model_with_async_data = _interopRequireDefault(require("./abstract_model_with_async_data"));
49
55
 
50
56
  var WatchableViewDataStoreKeys = Object.freeze({
51
57
  visibleRecords: 'visibleRecords',
58
+ visibleRecordIds: 'visibleRecordIds',
52
59
  groups: 'groups',
53
60
  groupLevels: 'groupLevels',
54
61
  recordColors: 'recordColors',
@@ -59,11 +66,9 @@ var WatchableViewDataStoreKeys = Object.freeze({
59
66
 
60
67
  exports.WatchableViewDataStoreKeys = WatchableViewDataStoreKeys;
61
68
 
62
- // ViewDataStore manages loadable data for a specific view. That means the set of visible records,
69
+ // ViewDataStore contains loadable data for a specific view. That means the set of visible records,
63
70
  // and field order/visibility information. View itself only contains core schema information. The
64
- // data here doesn't belong in View as it's record data or conditionally loaded and therefore
65
- // loaded via queries (and therefore managed by publicAirtableInterface)
66
- // TODO: (#proj-blocks-sdk-record-limits) Remove AbstractModelWithAsyncData
71
+ // data here doesn't belong in View as it's record data or conditionally loaded.
67
72
 
68
73
  /** @internal */
69
74
  var ViewDataStore =
@@ -75,6 +80,11 @@ function (_AbstractModelWithAsy) {
75
80
  value: function _isWatchableKey(key) {
76
81
  return (0, _private_utils.isEnumValue)(WatchableViewDataStoreKeys, key);
77
82
  }
83
+ }, {
84
+ key: "_shouldLoadDataForKey",
85
+ value: function _shouldLoadDataForKey(key) {
86
+ return true;
87
+ }
78
88
  }]);
79
89
 
80
90
  function ViewDataStore(sdk, parentRecordStore, viewId) {
@@ -84,38 +94,16 @@ function (_AbstractModelWithAsy) {
84
94
  _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(ViewDataStore).call(this, sdk, "".concat(viewId, "-ViewDataStore")));
85
95
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "viewId", void 0);
86
96
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "parentRecordStore", void 0);
87
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_publicViewStore", void 0);
88
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_queryManager", void 0);
89
- (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_queryIdFromReferenceCountedLoadData", null);
97
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_mostRecentTableLoadPromise", void 0);
98
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_airtableInterface", void 0);
90
99
  _this.parentRecordStore = parentRecordStore;
91
- _this._queryManager = sdk._queryManager;
100
+ _this._airtableInterface = sdk.__airtableInterface;
101
+ _this._mostRecentTableLoadPromise = null;
92
102
  _this.viewId = viewId;
93
-
94
- var publicViewStore = _this.parentRecordStore._airtableInterface.getViewMetadataStoreIfExists(_this.parentRecordStore.tableId, viewId);
95
-
96
- (0, _error_utils.invariant)(publicViewStore, 'PublicViewStore must exist for all valid viewIds');
97
- _this._publicViewStore = publicViewStore;
98
103
  return _this;
99
104
  }
100
105
 
101
106
  (0, _createClass2.default)(ViewDataStore, [{
102
- key: "_assertExistsAndLoaded",
103
-
104
- /**
105
- * @internal
106
- */
107
- value: function _assertExistsAndLoaded() {
108
- // Access data in order to throw if the data has been deleted / isn't loaded
109
- var data = this._dataOrNullIfDeleted; // Currently it is not possible for the ViewDataStore to spawn an error on deletion
110
- // because the parent TableOrViewQueryResult or ViewMetadataQueryResult throw their own
111
- // errors when the view is deleted.
112
- // istanbul ignore if
113
-
114
- if (data === null) {
115
- throw this._spawnErrorForDeletion();
116
- }
117
- }
118
- }, {
119
107
  key: "_onChangeIsDataLoaded",
120
108
  value: function _onChangeIsDataLoaded() {// noop
121
109
  }
@@ -123,58 +111,212 @@ function (_AbstractModelWithAsy) {
123
111
  key: "__onDataDeletion",
124
112
  value: function __onDataDeletion() {
125
113
  this._forceUnload();
126
-
127
- this._queryManager.forceUnloadWatchesOnWatchableModel(this);
114
+ }
115
+ }, {
116
+ key: "loadDataAsync",
117
+ value: function loadDataAsync() {
118
+ var tableLoadPromise;
119
+ return _regenerator.default.async(function loadDataAsync$(_context) {
120
+ while (1) {
121
+ switch (_context.prev = _context.next) {
122
+ case 0:
123
+ // Override this method to also load table data.
124
+ // NOTE: it's important that we call loadDataAsync on the table here and not in
125
+ // _loadDataAsync since we want the retain counts for the view and table to increase/decrease
126
+ // in lock-step. If we load table data in _loadDataAsync, the table's retain
127
+ // count only increments some of the time, which leads to unexpected behavior.
128
+ tableLoadPromise = this.parentRecordStore.loadRecordMetadataAsync();
129
+ this._mostRecentTableLoadPromise = tableLoadPromise;
130
+ _context.next = 4;
131
+ return _regenerator.default.awrap((0, _get2.default)((0, _getPrototypeOf2.default)(ViewDataStore.prototype), "loadDataAsync", this).call(this));
132
+
133
+ case 4:
134
+ case "end":
135
+ return _context.stop();
136
+ }
137
+ }
138
+ }, null, this);
128
139
  }
129
140
  }, {
130
141
  key: "_loadDataAsync",
131
142
  value: function _loadDataAsync() {
132
- var changedKeysOnLoad;
133
- return _regenerator.default.async(function _loadDataAsync$(_context) {
143
+ var tableLoadPromise, _ref, _ref2, viewData, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, record;
144
+
145
+ return _regenerator.default.async(function _loadDataAsync$(_context2) {
134
146
  while (1) {
135
- switch (_context.prev = _context.next) {
147
+ switch (_context2.prev = _context2.next) {
136
148
  case 0:
137
- // TODO: (#proj-blocks-sdk-record-limits) Do we want to remove this reference counting semantic?
138
- // We can assume that each query is identical, but it might be helpful to have all queries be
139
- // registered across the bridge so that we can track utilization.
140
- (0, _error_utils.invariant)(this._queryIdFromReferenceCountedLoadData === null, 'Can not reissue an identical view data store query');
141
- _context.next = 3;
142
- return _regenerator.default.awrap(this._queryManager.fetchAndSubscribeToQueryAsync({
143
- sourceType: _block_query_spec.BlockQuerySourceType.VIEW,
144
- sourceTableId: this.parentRecordStore.tableId,
145
- sourceViewId: this.viewId,
146
- viewMetadataSelection: {
147
- shouldIncludeVisibleRecordIds: true,
148
- shouldIncludeFieldOrder: true,
149
- shouldIncludeGroups: true,
150
- shouldIncludeGroupingLevels: true,
151
- shouldIncludeColorsForRecordId: true
149
+ // We need to be sure that the table data is loaded *before* we return
150
+ // from this method.
151
+ (0, _error_utils.invariant)(this._mostRecentTableLoadPromise, 'No table load promise');
152
+ tableLoadPromise = this._mostRecentTableLoadPromise;
153
+ _context2.next = 4;
154
+ return _regenerator.default.awrap(Promise.all([this._airtableInterface.fetchAndSubscribeToViewDataAsync(this.parentRecordStore.tableId, this.viewId), tableLoadPromise]));
155
+
156
+ case 4:
157
+ _ref = _context2.sent;
158
+ _ref2 = (0, _slicedToArray2.default)(_ref, 1);
159
+ viewData = _ref2[0];
160
+ this._data.visibleRecordIds = viewData.visibleRecordIds;
161
+ this._data.fieldOrder = viewData.fieldOrder;
162
+ this._data.groups = viewData.groups;
163
+ this._data.groupLevels = viewData.groupLevels;
164
+ this._data.colorsByRecordId = viewData.colorsByRecordId;
165
+
166
+ if (!this._data.colorsByRecordId) {
167
+ _context2.next = 32;
168
+ break;
169
+ }
170
+
171
+ _iteratorNormalCompletion = true;
172
+ _didIteratorError = false;
173
+ _iteratorError = undefined;
174
+ _context2.prev = 16;
175
+
176
+ for (_iterator = this.visibleRecords[Symbol.iterator](); !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
177
+ record = _step.value;
178
+
179
+ if ((0, _private_utils.has)(this._data.colorsByRecordId, record.id)) {
180
+ record.__triggerOnChangeForRecordColorInViewId(this.viewId);
152
181
  }
153
- }));
182
+ }
154
183
 
155
- case 3:
156
- this._queryIdFromReferenceCountedLoadData = _context.sent;
157
- changedKeysOnLoad = Object.values(WatchableViewDataStoreKeys);
184
+ _context2.next = 24;
185
+ break;
158
186
 
159
- this._queryManager.onLoadKeys(this, changedKeysOnLoad);
187
+ case 20:
188
+ _context2.prev = 20;
189
+ _context2.t0 = _context2["catch"](16);
190
+ _didIteratorError = true;
191
+ _iteratorError = _context2.t0;
160
192
 
161
- return _context.abrupt("return", []);
193
+ case 24:
194
+ _context2.prev = 24;
195
+ _context2.prev = 25;
162
196
 
163
- case 7:
197
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
198
+ _iterator.return();
199
+ }
200
+
201
+ case 27:
202
+ _context2.prev = 27;
203
+
204
+ if (!_didIteratorError) {
205
+ _context2.next = 30;
206
+ break;
207
+ }
208
+
209
+ throw _iteratorError;
210
+
211
+ case 30:
212
+ return _context2.finish(27);
213
+
214
+ case 31:
215
+ return _context2.finish(24);
216
+
217
+ case 32:
218
+ return _context2.abrupt("return", [WatchableViewDataStoreKeys.visibleRecords, WatchableViewDataStoreKeys.visibleRecordIds, WatchableViewDataStoreKeys.allFieldIds, WatchableViewDataStoreKeys.groups, WatchableViewDataStoreKeys.groupLevels, WatchableViewDataStoreKeys.visibleFieldIds, WatchableViewDataStoreKeys.recordColors]);
219
+
220
+ case 33:
164
221
  case "end":
165
- return _context.stop();
222
+ return _context2.stop();
166
223
  }
167
224
  }
168
- }, null, this);
225
+ }, null, this, [[16, 20, 24, 32], [25,, 27, 31]]);
226
+ }
227
+ }, {
228
+ key: "unloadData",
229
+ value: function unloadData() {
230
+ // Override this method to also unload the table's data.
231
+ // NOTE: it's important that we do this here, since we want the view and table's
232
+ // retain counts to increment/decrement in lock-step. If we unload the table's
233
+ // data in _unloadData, it leads to unexpected behavior.
234
+ (0, _get2.default)((0, _getPrototypeOf2.default)(ViewDataStore.prototype), "unloadData", this).call(this);
235
+ this.parentRecordStore.unloadRecordMetadata();
169
236
  }
170
237
  }, {
171
238
  key: "_unloadData",
172
239
  value: function _unloadData() {
173
- (0, _error_utils.invariant)(this._queryIdFromReferenceCountedLoadData, 'Can not unsubscribe from a view store that is not subscribed');
240
+ this._mostRecentTableLoadPromise = null;
241
+
242
+ this._airtableInterface.unsubscribeFromViewData(this.parentRecordStore.tableId, this.viewId);
243
+
244
+ if (!this.isDeleted) {
245
+ this._data.visibleRecordIds = undefined;
246
+ this._data.groups = undefined;
247
+ this._data.colorsByRecordId = undefined;
248
+ }
249
+ }
250
+ }, {
251
+ key: "__generateChangesForParentTableAddMultipleRecords",
252
+ value: function __generateChangesForParentTableAddMultipleRecords(recordIds) {
253
+ var newVisibleRecordIds = [...this.visibleRecordIds, ...recordIds];
254
+ return [{
255
+ path: ['tablesById', this.parentRecordStore.tableId, 'viewsById', this.viewId, 'visibleRecordIds'],
256
+ value: newVisibleRecordIds
257
+ }];
258
+ }
259
+ }, {
260
+ key: "__generateChangesForParentTableDeleteMultipleRecords",
261
+ value: function __generateChangesForParentTableDeleteMultipleRecords(recordIds) {
262
+ var recordIdsToDeleteSet = {};
263
+ var _iteratorNormalCompletion2 = true;
264
+ var _didIteratorError2 = false;
265
+ var _iteratorError2 = undefined;
266
+
267
+ try {
268
+ for (var _iterator2 = recordIds[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
269
+ var recordId = _step2.value;
270
+ recordIdsToDeleteSet[recordId] = true;
271
+ }
272
+ } catch (err) {
273
+ _didIteratorError2 = true;
274
+ _iteratorError2 = err;
275
+ } finally {
276
+ try {
277
+ if (!_iteratorNormalCompletion2 && _iterator2.return != null) {
278
+ _iterator2.return();
279
+ }
280
+ } finally {
281
+ if (_didIteratorError2) {
282
+ throw _iteratorError2;
283
+ }
284
+ }
285
+ }
286
+
287
+ var newVisibleRecordIds = this.visibleRecordIds.filter(recordId => !recordIdsToDeleteSet[recordId]);
288
+ var changePayload = [{
289
+ path: ['tablesById', this.parentRecordStore.tableId, 'viewsById', this.viewId, 'visibleRecordIds'],
290
+ value: newVisibleRecordIds
291
+ }];
292
+
293
+ if (this._data.groups) {
294
+ var newGroups = this.__recursivelyRemoveRecordsFromGroupsInPlace((0, _private_utils.cloneDeep)(this._data.groups), recordIdsToDeleteSet);
295
+
296
+ changePayload.push({
297
+ path: ['tablesById', this.parentRecordStore.tableId, 'viewsById', this.viewId, 'groups'],
298
+ value: newGroups
299
+ });
300
+ }
301
+
302
+ return changePayload;
303
+ }
304
+ }, {
305
+ key: "__recursivelyRemoveRecordsFromGroupsInPlace",
306
+ value: function __recursivelyRemoveRecordsFromGroupsInPlace(groups, recordIdsToDeleteSet) {
307
+ if (!groups || groups.length === 0) {
308
+ return groups;
309
+ }
174
310
 
175
- this._queryManager.unsubscribeFromQueryId(this._queryIdFromReferenceCountedLoadData);
311
+ return groups.map(group => {
312
+ if (group.visibleRecordIds) {
313
+ group.visibleRecordIds = group.visibleRecordIds.filter(id => !recordIdsToDeleteSet[id]);
314
+ }
315
+
316
+ this.__recursivelyRemoveRecordsFromGroupsInPlace(group.groups, recordIdsToDeleteSet);
176
317
 
177
- this._queryIdFromReferenceCountedLoadData = null;
318
+ return group;
319
+ });
178
320
  }
179
321
  /**
180
322
  * The record IDs that are not filtered out of this view.
@@ -192,187 +334,107 @@ function (_AbstractModelWithAsy) {
192
334
  * @param recordOrRecordId the record/record id to get the color for
193
335
  */
194
336
  value: function getRecordColor(record) {
195
- (0, _error_utils.invariant)(this.isDataLoaded, 'View data is not loaded');
196
-
197
- this._assertExistsAndLoaded();
198
-
199
- return this._publicViewStore.getColorForRecordId(record.id);
200
- }
201
- }, {
202
- key: "_findBlockSubscriptionChangedMatchingSubscriptionChangeTypeForViewIfExists",
203
- value: function _findBlockSubscriptionChangedMatchingSubscriptionChangeTypeForViewIfExists(changes, changeTypeToMatch) {
204
- var _changes$find;
337
+ var _ref3, _this$_data$colorsByR;
205
338
 
206
- return (_changes$find = changes.find(change => change.type === changeTypeToMatch && change.tableId === this.parentRecordStore.tableId && change.viewId === this.viewId)) !== null && _changes$find !== void 0 ? _changes$find : null;
339
+ (0, _error_utils.invariant)(this.isDataLoaded, 'View data is not loaded');
340
+ return (_ref3 = (_this$_data$colorsByR = this._data.colorsByRecordId) === null || _this$_data$colorsByR === void 0 ? void 0 : _this$_data$colorsByR[record.id]) !== null && _ref3 !== void 0 ? _ref3 : null;
207
341
  }
208
342
  }, {
209
- key: "_constructBlockQuerySpecForWatchableKey",
210
- value: function _constructBlockQuerySpecForWatchableKey(key, callbackForRegistration, context) {
211
- var querySpecOptions = {};
212
-
213
- var wrappedCallbackForQueryChange = () => {
214
- callbackForRegistration.call(context, this, key);
215
- };
216
-
217
- switch (key) {
218
- case WatchableViewDataStoreKeys.visibleRecords:
219
- querySpecOptions.shouldIncludeVisibleRecordIds = true;
220
- break;
221
-
222
- case WatchableViewDataStoreKeys.groups:
223
- {
224
- querySpecOptions.shouldIncludeGroups = true;
225
- break;
226
- }
227
-
228
- case WatchableViewDataStoreKeys.groupLevels:
229
- {
230
- querySpecOptions.shouldIncludeGroupingLevels = true;
231
- break;
232
- }
233
-
234
- case WatchableViewDataStoreKeys.recordColors:
235
- {
236
- querySpecOptions.shouldIncludeColorsForRecordId = true;
343
+ key: "triggerOnChangeForDirtyPaths",
344
+ value: function triggerOnChangeForDirtyPaths(dirtyPaths) {
345
+ if (dirtyPaths.visibleRecordIds) {
346
+ this._onChange(WatchableViewDataStoreKeys.visibleRecords);
237
347
 
238
- wrappedCallbackForQueryChange = changes => {
239
- var recordColorsChange = this._findBlockSubscriptionChangedMatchingSubscriptionChangeTypeForViewIfExists(changes, _block_query_spec.BlockQuerySubscriptionChangeType.CHANGED_COLORS_BY_RECORD_ID_FOR_VIEW);
348
+ this._onChange(WatchableViewDataStoreKeys.visibleRecordIds);
349
+ }
240
350
 
241
- var recordIdsOrNull = null;
351
+ if (dirtyPaths.fieldOrder) {
352
+ this._onChange(WatchableViewDataStoreKeys.allFieldIds); // TODO(kasra): only trigger visibleFields if the *visible* field ids changed.
242
353
 
243
- if (recordColorsChange) {
244
- (0, _error_utils.invariant)(recordColorsChange.type === _block_query_spec.BlockQuerySubscriptionChangeType.CHANGED_COLORS_BY_RECORD_ID_FOR_VIEW, 'Invalid record colors change event');
245
- recordIdsOrNull = recordColorsChange.recordIds;
246
- } // We also always call this, even if no recordColors changed to closely mirror
247
- // the old version of the SDK (https://github.com/Hyperbase/blocks-sdk/blob/8e3ac1a37be9c9850e64085975b102a483116080/packages/sdk/src/models/view_data_store.ts#L319-L361)
248
- // In the future, this should not be the case (don't call callback if nothing changed)
249
354
 
355
+ this._onChange(WatchableViewDataStoreKeys.visibleFieldIds);
356
+ } // Technically it's possible for groupLevels changing to cause a groups
357
+ // change since we derive group information from the groupLevels (fieldId)
250
358
 
251
- callbackForRegistration.call(context, this, key, recordIdsOrNull);
252
- };
253
359
 
254
- break;
255
- }
360
+ if (dirtyPaths.groups || dirtyPaths.groupLevels) {
361
+ this._onChange(WatchableViewDataStoreKeys.groups);
362
+ }
256
363
 
257
- case WatchableViewDataStoreKeys.allFieldIds:
258
- {
259
- querySpecOptions.shouldIncludeFieldOrder = true;
260
- break;
261
- }
364
+ if (dirtyPaths.groupLevels) {
365
+ this._onChange(WatchableViewDataStoreKeys.groupLevels);
366
+ }
262
367
 
263
- case WatchableViewDataStoreKeys.visibleFieldIds:
264
- {
265
- // TODO: This will trigger even if fieldIds which aren't visible in the view change.
266
- // This is NOT a regression, a fix would be to add an intermediate callback
267
- // which swallows changes if the visible fieldOrder does not change.
268
- querySpecOptions.shouldIncludeFieldOrder = true;
269
- break;
368
+ if (dirtyPaths.colorsByRecordId) {
369
+ var changedRecordIds = dirtyPaths.colorsByRecordId._isDirty ? null : Object.keys(dirtyPaths.colorsByRecordId);
370
+
371
+ if (changedRecordIds) {
372
+ // Checking isRecordMetadataLoaded fixes a timing issue:
373
+ // When a new table loads in liveapp, we'll receive the record
374
+ // colors before getting the response to our loadData call.
375
+ // This is a temporary fix: we need a more general solution to
376
+ // avoid processing events associated with subscriptions whose
377
+ // data we haven't received yet.
378
+ if (this.parentRecordStore.isRecordMetadataLoaded) {
379
+ var _iteratorNormalCompletion3 = true;
380
+ var _didIteratorError3 = false;
381
+ var _iteratorError3 = undefined;
382
+
383
+ try {
384
+ for (var _iterator3 = changedRecordIds[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
385
+ var recordId = _step3.value;
386
+ var record = this.parentRecordStore.getRecordByIdIfExists(recordId); // Similar to above, we could be receiving the change notification
387
+ // for a record color before receiving the new record itself.
388
+
389
+ if (record) {
390
+ record.__triggerOnChangeForRecordColorInViewId(this.viewId);
391
+ }
392
+ }
393
+ } catch (err) {
394
+ _didIteratorError3 = true;
395
+ _iteratorError3 = err;
396
+ } finally {
397
+ try {
398
+ if (!_iteratorNormalCompletion3 && _iterator3.return != null) {
399
+ _iterator3.return();
400
+ }
401
+ } finally {
402
+ if (_didIteratorError3) {
403
+ throw _iteratorError3;
404
+ }
405
+ }
406
+ }
270
407
  }
271
- // TypeScript ensures that key is of type never so we don't need to test this via istanbul
272
- // istanbul ignore next
408
+ }
273
409
 
274
- default:
275
- throw (0, _error_utils.spawnExhaustiveSwitchError)(key);
410
+ this._onChange(WatchableViewDataStoreKeys.recordColors, changedRecordIds);
276
411
  }
277
-
278
- return {
279
- querySpecToSubscribeWith: {
280
- sourceType: _block_query_spec.BlockQuerySourceType.VIEW,
281
- sourceTableId: this.parentRecordStore.tableId,
282
- sourceViewId: this.viewId,
283
- viewMetadataSelection: querySpecOptions
284
- },
285
- wrappedCallbackForQueryChange
286
- };
287
- }
288
- /**
289
- * Watching a key that needs to load data asynchronously will automatically
290
- * cause the data to be fetched. Once the data is available, the callback
291
- * will be called.
292
- *
293
- * @inheritdoc
294
- */
295
-
296
- }, {
297
- key: "watch",
298
- value: function watch(keys, callbackForWatchKey, context) {
299
- this._assertNotForceUnloaded();
300
-
301
- var validKeys = this._getWatchableValidKeysOrThrow(keys, 'view watch');
302
-
303
- validKeys.forEach(validKey => {
304
- var _this$_constructBlock = this._constructBlockQuerySpecForWatchableKey(validKey, callbackForWatchKey, context),
305
- querySpecToSubscribeWith = _this$_constructBlock.querySpecToSubscribeWith,
306
- wrappedCallbackForQueryChange = _this$_constructBlock.wrappedCallbackForQueryChange;
307
-
308
- this._queryManager.watchWithQuerySpec(querySpecToSubscribeWith, this, validKey, wrappedCallbackForQueryChange, callbackForWatchKey, context);
309
- });
310
- return validKeys;
311
- }
312
- /**
313
- * Unwatching a key that needs to load data asynchronously will automatically
314
- * cause the data to be released. Once the data is available, the callback
315
- * will be called.
316
- *
317
- * @inheritdoc
318
- */
319
-
320
- }, {
321
- key: "unwatch",
322
- value: function unwatch(keys, callbackForRegistration, context) {
323
- // We have already unsubscribed from all watches (because query-based watches force data to be loaded)
324
- // so no watches are subscribed
325
- if (this._isForceUnloaded) {
326
- return [];
327
- } // We warn instead of throw here because we used to warn instead of throw and don't
328
- // want to make a breaking change.
329
-
330
-
331
- var validKeys = this._getWatchableValidKeysOrThrow(keys, 'view unwatch', true);
332
-
333
- validKeys.forEach(key => this._queryManager.unwatchFromQueryKey(key, callbackForRegistration, context));
334
- return validKeys;
335
- }
336
- }, {
337
- key: "triggerOnChangeForDirtyPaths",
338
- value: function triggerOnChangeForDirtyPaths(dirtyPaths) {// This is only triggered for changes to values in the type ViewData, which is
339
- // populated and kept up to date by watching base schema (aka the view's id, name, type).
340
- // None of these are watchable, so we don't need to call this._onChange() for them.
341
- // In the future we may want to make the view's name watchable, which is the only property
342
- // here that we'd expect to change. In this case, it would be handled here.
343
412
  }
344
413
  }, {
345
414
  key: "_dataOrNullIfDeleted",
346
415
  get: function get() {
347
- var _ref;
416
+ var _ref4;
348
417
 
349
418
  var tableData = this._baseData.tablesById[this.parentRecordStore.tableId];
350
- return (_ref = tableData === null || tableData === void 0 ? void 0 : tableData.viewsById[this.viewId]) !== null && _ref !== void 0 ? _ref : null;
419
+ return (_ref4 = tableData === null || tableData === void 0 ? void 0 : tableData.viewsById[this.viewId]) !== null && _ref4 !== void 0 ? _ref4 : null;
351
420
  }
352
421
  }, {
353
422
  key: "isDataLoaded",
354
423
  get: function get() {
355
- return this._isDataLoaded;
356
- }
357
- }, {
358
- key: "isRecordDataLoadedForView",
359
- get: function get() {
360
- // We _currently_ only issue queries that also load cell data in the view which
361
- // is synchronously returned with all other view data, so we can collapse this
362
- // to if the viewData has loaded.
363
- // TODO: (#proj-blocks-sdk-record-limits) Actually track if all cell data is loaded
364
- // based on issued queries from ViewDataStore
365
- return this.isDataLoaded;
424
+ return this._isDataLoaded && this.parentRecordStore.isRecordMetadataLoaded;
366
425
  }
367
426
  }, {
368
427
  key: "visibleRecordIds",
369
428
  get: function get() {
370
- this._assertExistsAndLoaded(); // Freezing the visibleRecordIds happens on the other side of the bridge
371
-
429
+ var visibleRecordIds = this._data.visibleRecordIds;
430
+ (0, _error_utils.invariant)(visibleRecordIds, 'View data is not loaded'); // Freeze visibleRecordIds so users can't mutate it.
431
+ // If it changes from liveapp, we get an entire new array which will
432
+ // replace this one, so it's okay to freeze it.
372
433
 
373
- var visibleRecordIds = this._publicViewStore.getVisibleRecordIds();
434
+ if (!Object.isFrozen(visibleRecordIds)) {
435
+ Object.freeze(visibleRecordIds);
436
+ }
374
437
 
375
- (0, _error_utils.invariant)(visibleRecordIds, 'View data is not loaded');
376
438
  return visibleRecordIds;
377
439
  }
378
440
  /**
@@ -384,12 +446,8 @@ function (_AbstractModelWithAsy) {
384
446
  }, {
385
447
  key: "visibleRecords",
386
448
  get: function get() {
387
- (0, _error_utils.invariant)(this.isRecordDataLoadedForView, 'Table data is not loaded for this view');
388
-
389
- this._assertExistsAndLoaded();
390
-
391
- var visibleRecordIds = this._publicViewStore.getVisibleRecordIds();
392
-
449
+ (0, _error_utils.invariant)(this.parentRecordStore.isRecordMetadataLoaded, 'Table data is not loaded');
450
+ var visibleRecordIds = this._data.visibleRecordIds;
393
451
  (0, _error_utils.invariant)(visibleRecordIds, 'View data is not loaded');
394
452
  return visibleRecordIds.map(recordId => {
395
453
  var record = this.parentRecordStore.getRecordByIdIfExists(recordId);
@@ -408,9 +466,9 @@ function (_AbstractModelWithAsy) {
408
466
  }, {
409
467
  key: "groups",
410
468
  get: function get() {
411
- this._assertExistsAndLoaded();
412
-
413
- return this._publicViewStore.getGroups();
469
+ (0, _error_utils.invariant)(this.parentRecordStore.isRecordMetadataLoaded, 'Table data is not loaded');
470
+ var groups = this._data.groups;
471
+ return groups !== null && groups !== void 0 ? groups : null;
414
472
  }
415
473
  /**
416
474
  * Gets the group config for this view, can be watched to know when groupLevels
@@ -420,29 +478,23 @@ function (_AbstractModelWithAsy) {
420
478
  }, {
421
479
  key: "groupLevels",
422
480
  get: function get() {
423
- this._assertExistsAndLoaded();
424
-
425
- return this._publicViewStore.getGroupLevels();
481
+ (0, _error_utils.invariant)(this.parentRecordStore.isRecordMetadataLoaded, 'Table data is not loaded');
482
+ var groupLevels = this._data.groupLevels;
483
+ return groupLevels !== null && groupLevels !== void 0 ? groupLevels : null;
426
484
  }
427
485
  }, {
428
486
  key: "allFieldIds",
429
487
  get: function get() {
430
- this._assertExistsAndLoaded(); // TODO: (#proj-blocks-sdk-record-limits) Future sdk version shouldn't deep
431
- // copy this, and it should be legal to return the frozen object directly
432
-
433
-
434
- return (0, _private_utils.cloneDeep)(this._publicViewStore.getFieldOrder().fieldIds);
488
+ var fieldOrder = this._data.fieldOrder;
489
+ (0, _error_utils.invariant)(fieldOrder, 'View data is not loaded');
490
+ return fieldOrder.fieldIds;
435
491
  }
436
492
  }, {
437
493
  key: "visibleFieldIds",
438
494
  get: function get() {
439
- this._assertExistsAndLoaded();
440
-
441
- var fieldOrder = this._publicViewStore.getFieldOrder();
442
-
495
+ var fieldOrder = this._data.fieldOrder;
443
496
  (0, _error_utils.invariant)(fieldOrder, 'View data is not loaded');
444
- var fieldIds = fieldOrder.fieldIds; // Slice returns a mutable copy even though visibleFieldCount is readonly
445
-
497
+ var fieldIds = fieldOrder.fieldIds;
446
498
  return fieldIds.slice(0, fieldOrder.visibleFieldCount);
447
499
  }
448
500
  }]);