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

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 (98) hide show
  1. package/CHANGELOG.md +26 -2
  2. package/dist/cjs/error_utils.js +17 -0
  3. package/dist/cjs/models/base.js +16 -11
  4. package/dist/cjs/models/cursor.js +2 -0
  5. package/dist/cjs/models/field.js +157 -36
  6. package/dist/cjs/models/grouped_record_query_result.js +5 -14
  7. package/dist/cjs/models/linked_records_query_result.js +75 -27
  8. package/dist/cjs/models/mutation_constants.js +3 -1
  9. package/dist/cjs/models/mutations.js +70 -178
  10. package/dist/cjs/models/query_manager.js +327 -0
  11. package/dist/cjs/models/record.js +308 -55
  12. package/dist/cjs/models/record_query_result.js +4 -1
  13. package/dist/cjs/models/record_store.js +554 -765
  14. package/dist/cjs/models/table.js +22 -19
  15. package/dist/cjs/models/table_or_view_query_result.js +480 -414
  16. package/dist/cjs/models/view_data_store.js +243 -295
  17. package/dist/cjs/private_utils.js +50 -0
  18. package/dist/cjs/sdk.js +12 -2
  19. package/dist/cjs/testing/{mock_airtable_interface.js → abstract_mock_airtable_interface.js} +71 -22
  20. package/dist/cjs/types/block_query_spec.js +85 -0
  21. package/dist/cjs/types/field.js +1 -0
  22. package/dist/cjs/types/mutations.js +1 -0
  23. package/dist/cjs/ui/icon_config.js +6 -2
  24. package/dist/cjs/ui/use_global_config.js +1 -1
  25. package/dist/cjs/ui/use_records.js +5 -1
  26. package/dist/cjs/unstable_testing_utils.js +2 -2
  27. package/dist/cjs/watchable.js +123 -71
  28. package/dist/types/src/models/base.d.ts +10 -9
  29. package/dist/types/src/models/base.d.ts.map +1 -1
  30. package/dist/types/src/models/cursor.d.ts +2 -0
  31. package/dist/types/src/models/cursor.d.ts.map +1 -1
  32. package/dist/types/src/models/field.d.ts +71 -9
  33. package/dist/types/src/models/field.d.ts.map +1 -1
  34. package/dist/types/src/models/grouped_record_query_result.d.ts +3 -3
  35. package/dist/types/src/models/grouped_record_query_result.d.ts.map +1 -1
  36. package/dist/types/src/models/linked_records_query_result.d.ts.map +1 -1
  37. package/dist/types/src/models/mutation_constants.d.ts +1 -0
  38. package/dist/types/src/models/mutation_constants.d.ts.map +1 -1
  39. package/dist/types/src/models/mutations.d.ts.map +1 -1
  40. package/dist/types/src/models/query_manager.d.ts +2 -0
  41. package/dist/types/src/models/query_manager.d.ts.map +1 -0
  42. package/dist/types/src/models/record.d.ts +12 -3
  43. package/dist/types/src/models/record.d.ts.map +1 -1
  44. package/dist/types/src/models/record_query_result.d.ts +3 -2
  45. package/dist/types/src/models/record_query_result.d.ts.map +1 -1
  46. package/dist/types/src/models/record_store.d.ts.map +1 -1
  47. package/dist/types/src/models/table.d.ts +8 -10
  48. package/dist/types/src/models/table.d.ts.map +1 -1
  49. package/dist/types/src/models/table_or_view_query_result.d.ts +3 -5
  50. package/dist/types/src/models/table_or_view_query_result.d.ts.map +1 -1
  51. package/dist/types/src/models/view_data_store.d.ts +0 -1
  52. package/dist/types/src/models/view_data_store.d.ts.map +1 -1
  53. package/dist/types/src/models/view_metadata_query_result.d.ts +1 -1
  54. package/dist/types/src/models/view_metadata_query_result.d.ts.map +1 -1
  55. package/dist/types/src/private_utils.d.ts +30 -1
  56. package/dist/types/src/private_utils.d.ts.map +1 -1
  57. package/dist/types/src/sdk.d.ts.map +1 -1
  58. package/dist/types/src/testing/{mock_airtable_interface.d.ts → abstract_mock_airtable_interface.d.ts} +20 -15
  59. package/dist/types/src/testing/abstract_mock_airtable_interface.d.ts.map +1 -0
  60. package/dist/types/src/types/airtable_interface.d.ts +45 -21
  61. package/dist/types/src/types/airtable_interface.d.ts.map +1 -1
  62. package/dist/types/src/types/block_query_spec.d.ts +139 -0
  63. package/dist/types/src/types/block_query_spec.d.ts.map +1 -0
  64. package/dist/types/src/types/field.d.ts +167 -51
  65. package/dist/types/src/types/field.d.ts.map +1 -1
  66. package/dist/types/src/types/mutations.d.ts +46 -3
  67. package/dist/types/src/types/mutations.d.ts.map +1 -1
  68. package/dist/types/src/types/table.d.ts +0 -2
  69. package/dist/types/src/types/table.d.ts.map +1 -1
  70. package/dist/types/src/types/view.d.ts +3 -8
  71. package/dist/types/src/types/view.d.ts.map +1 -1
  72. package/dist/types/src/ui/icon_config.d.ts +7 -3
  73. package/dist/types/src/ui/icon_config.d.ts.map +1 -1
  74. package/dist/types/src/ui/link.d.ts +1 -1
  75. package/dist/types/src/ui/link.d.ts.map +1 -1
  76. package/dist/types/src/ui/use_global_config.d.ts +1 -1
  77. package/dist/types/src/unstable_testing_utils.d.ts +1 -1
  78. package/dist/types/src/unstable_testing_utils.d.ts.map +1 -1
  79. package/dist/types/src/watchable.d.ts.map +1 -1
  80. package/dist/types/stories/helpers/fake_cell_renderer.d.ts.map +1 -1
  81. package/dist/types/stories/helpers/field_type.d.ts.map +1 -1
  82. package/dist/types/stories/helpers/sync_source_options.d.ts +7 -0
  83. package/dist/types/stories/helpers/sync_source_options.d.ts.map +1 -0
  84. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts +121 -0
  85. package/dist/types/test/airtable_interface_mocks/fixture_data.d.ts.map +1 -0
  86. package/dist/types/test/airtable_interface_mocks/linked_records.d.ts +2 -2
  87. package/dist/types/test/airtable_interface_mocks/linked_records.d.ts.map +1 -1
  88. package/dist/types/test/airtable_interface_mocks/{mock_airtable_interface_internal.d.ts → mock_airtable_interface.d.ts} +26 -18
  89. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface.d.ts.map +1 -0
  90. package/dist/types/test/airtable_interface_mocks/mock_base_data_stores.d.ts +51 -0
  91. package/dist/types/test/airtable_interface_mocks/mock_base_data_stores.d.ts.map +1 -0
  92. package/dist/types/test/airtable_interface_mocks/project_tracker.d.ts +2 -2
  93. package/dist/types/test/airtable_interface_mocks/project_tracker.d.ts.map +1 -1
  94. package/dist/types/test/test_helpers.d.ts +2 -0
  95. package/dist/types/test/test_helpers.d.ts.map +1 -1
  96. package/package.json +2 -1
  97. package/dist/types/src/testing/mock_airtable_interface.d.ts.map +0 -1
  98. package/dist/types/test/airtable_interface_mocks/mock_airtable_interface_internal.d.ts.map +0 -1
package/CHANGELOG.md CHANGED
@@ -9,9 +9,33 @@ Not every commit needs to result in a change to this file (e.g. docs and chore c
9
9
  commit that affects the code in a way that consumers might care about should include edits to the
10
10
  'Unreleased' section though. Breaking changes should be prefixed with `**BREAKING:**`.
11
11
 
12
- ## [Unreleased](https://github.com/airtable/blocks/compare/@airtable/blocks@1.7.1...HEAD)
12
+ ## [Unreleased](https://github.com/airtable/blocks/compare/@airtable/blocks@1.9.0...HEAD)
13
13
 
14
- No changes.
14
+ <<<<<<< seankeenan-at-fixTypoAndFormattingFromOpenPR
15
+
16
+ - # Fix typo in cursor.ts documentation - thanks @m2creates!
17
+ - Add new `calendarDay` icon (and micro variant)
18
+ > > > > > > > main
19
+
20
+ ## [1.9.0](https://github.com/airtable/blocks/compare/@airtable/blocks@1.8.0...@airtable/blocks@1.9.0) - 2021-09-15
21
+
22
+ - Update documentation for `FieldType.CHECKBOX` cell read & write types to be more accurate.
23
+ - Fetching field types & configs is now cached, making it more performant.
24
+ - Field descriptions can now be edited and specified when creating a new field:
25
+ - Added `field.updateDescriptionAsync`.
26
+ - Added optional `description` argument to `table.createFieldAsync`.
27
+ - Added optional `description` property to `field` objects accepted by
28
+ `base.createTableAsync`.
29
+
30
+ ## [1.8.0](https://github.com/airtable/blocks/compare/@airtable/blocks@1.7.2...@airtable/blocks@1.8.0) - 2021-07-12
31
+
32
+ - Add `opts` argument to `Field.updateOptionsAsync` with `enableSelectFieldChoiceDeletion` opt.
33
+ - Add `prefersSingleRecordLink` to `field.options` for `MULTIPLE_RECORD_LINKS` type fields.
34
+ - Add new timeline icon (and micro variant).
35
+
36
+ ## [1.7.2](https://github.com/airtable/blocks/compare/@airtable/blocks@1.7.1...@airtable/blocks@1.7.2) - 2021-05-26
37
+
38
+ - Add `FieldType.EXTERNAL_SYNC_SOURCE`.
15
39
 
16
40
  ## [1.7.1](https://github.com/airtable/blocks/compare/@airtable/blocks@1.7.0...@airtable/blocks@1.7.1) - 2021-05-21
17
41
 
@@ -8,6 +8,7 @@ Object.defineProperty(exports, "__esModule", {
8
8
  exports.spawnError = spawnError;
9
9
  exports.invariant = invariant;
10
10
  exports.spawnUnknownSwitchCaseError = spawnUnknownSwitchCaseError;
11
+ exports.spawnExhaustiveSwitchError = spawnExhaustiveSwitchError;
11
12
  exports.spawnAbstractMethodError = spawnAbstractMethodError;
12
13
 
13
14
  // If errorOriginFn is specified, all frames above and including the call to errorOriginFn
@@ -79,6 +80,22 @@ function spawnUnknownSwitchCaseError(valueDescription, providedValue, key) {
79
80
  var providedValueKeyString = providedValueKey !== null && providedValueKey !== undefined ? providedValueKey : 'null';
80
81
  return spawnErrorWithOriginOmittedFromStackTrace('Unknown value %s for %s', [providedValueKeyString, valueDescription], spawnUnknownSwitchCaseError);
81
82
  }
83
+ /**
84
+ * Forces TypeScript to prove that calling this function is impossible at a
85
+ * type level by accepting `never`. In the unlikely case this function is
86
+ * called we infer a useful error message.
87
+ *
88
+ * @internal
89
+ */
90
+
91
+
92
+ function spawnExhaustiveSwitchError(impossibleValue) {
93
+ if (impossibleValue === null) {
94
+ return spawnErrorWithOriginOmittedFromStackTrace('Unexpected null in exhaustive switch', undefined, spawnExhaustiveSwitchError);
95
+ } else {
96
+ return spawnErrorWithOriginOmittedFromStackTrace("Unexpected %s in exhaustive switch", [typeof impossibleValue], spawnExhaustiveSwitchError);
97
+ }
98
+ }
82
99
  /**
83
100
  * @internal
84
101
  */
@@ -435,8 +435,6 @@ function (_AbstractModel) {
435
435
  return table;
436
436
  }
437
437
  /**
438
- * _Beta feature with unstable API. May have breaking changes before release._
439
- *
440
438
  * Checks whether the current user has permission to create a table.
441
439
  *
442
440
  * Accepts partial input, in the same format as {@link createTableAsync}.
@@ -473,14 +471,13 @@ function (_AbstractModel) {
473
471
  type: field.type
474
472
  }, field.options ? {
475
473
  options: field.options
476
- } : null) : undefined
474
+ } : null) : undefined,
475
+ description: field.description
477
476
  };
478
477
  })
479
478
  });
480
479
  }
481
480
  /**
482
- * _Beta feature with unstable API. May have breaking changes before release._
483
- *
484
481
  * An alias for `checkPermissionsForCreateTable(name, fields).hasPermission`.
485
482
  *
486
483
  * Checks whether the current user has permission to create a table.
@@ -506,12 +503,11 @@ function (_AbstractModel) {
506
503
  return this.checkPermissionsForCreateTable(name, fields).hasPermission;
507
504
  }
508
505
  /**
509
- * _Beta feature with unstable API. May have breaking changes before release._
510
- *
511
506
  * Creates a new table.
512
507
  *
513
508
  * Throws an error if the user does not have permission to create a table, if an invalid
514
- * table name is provided, or if invalid fields are provided (invalid name, type or options).
509
+ * table name is provided, or if invalid fields are provided (invalid name, type, options or
510
+ * description).
515
511
  *
516
512
  * Refer to {@link FieldType} for supported field types, the write format for field options, and
517
513
  * other specifics for certain field types.
@@ -528,7 +524,10 @@ function (_AbstractModel) {
528
524
  * table in your app.
529
525
  *
530
526
  * @param name name for the table. must be case-insensitive unique
531
- * @param fields array of fields to create in the table: see below for details.
527
+ * @param fields array of fields to create in the table: see below for an example. `name` and
528
+ * `type` must be specified for all fields, while `options` is only required for fields that
529
+ * have field options. `description` is optional and will be `''` if not specified or if
530
+ * specified as `null`.
532
531
  *
533
532
  * @example
534
533
  * ```js
@@ -536,7 +535,7 @@ function (_AbstractModel) {
536
535
  * const name = 'My new table';
537
536
  * const fields = [
538
537
  * // Name will be the primary field of the table.
539
- * {name: 'Name', type: FieldType.SINGLE_LINE_TEXT},
538
+ * {name: 'Name', type: FieldType.SINGLE_LINE_TEXT, description: 'This is the primary field'},
540
539
  * {name: 'Notes', type: FieldType.RICH_TEXT},
541
540
  * {name: 'Attachments', type: FieldType.MULTIPLE_ATTACHMENTS},
542
541
  * {name: 'Number', type: FieldType.NUMBER, options: {
@@ -572,13 +571,19 @@ function (_AbstractModel) {
572
571
  type: _mutations.MutationTypes.CREATE_SINGLE_TABLE,
573
572
  name,
574
573
  fields: fields.map(field => {
574
+ var _field$description;
575
+
575
576
  return {
576
577
  name: field.name,
577
578
  config: _objectSpread({
578
579
  type: field.type
579
580
  }, field.options ? {
580
581
  options: field.options
581
- } : null)
582
+ } : null),
583
+ // Coerce undefined to null so that only old SDKs pass "undefined" for description
584
+ // '' is permitted, as we already set empty descriptions to '' when editing descriptions
585
+ // from the UI
586
+ description: (_field$description = field.description) !== null && _field$description !== void 0 ? _field$description : null
582
587
  };
583
588
  })
584
589
  }));
@@ -89,6 +89,7 @@ var WatchableCursorKeys = Object.freeze({
89
89
  * return (
90
90
  * <div>
91
91
  * Active table: {cursor.activeTableId}
92
+ * <br />
92
93
  * Active view: {cursor.activeViewId}
93
94
  * </div>
94
95
  * );
@@ -109,6 +110,7 @@ var WatchableCursorKeys = Object.freeze({
109
110
  * return (
110
111
  * <div>
111
112
  * Selected records: {cursor.selectedRecordIds.join(', ')}
113
+ * <br />
112
114
  * Selected fields: {cursor.selectedFieldIds.join(', ')}
113
115
  * </div>
114
116
  * );
@@ -109,7 +109,9 @@ function (_AbstractModel) {
109
109
  (0, _classCallCheck2.default)(this, Field);
110
110
  _this = (0, _possibleConstructorReturn2.default)(this, (0, _getPrototypeOf2.default)(Field).call(this, sdk, fieldId));
111
111
  (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_parentTable", void 0);
112
+ (0, _defineProperty2.default)((0, _assertThisInitialized2.default)(_this), "_cachedFieldTypeConfigOrNull", void 0);
112
113
  _this._parentTable = parentTable;
114
+ _this._cachedFieldTypeConfigOrNull = null;
113
115
  return _this;
114
116
  }
115
117
  /**
@@ -118,16 +120,50 @@ function (_AbstractModel) {
118
120
 
119
121
 
120
122
  (0, _createClass2.default)(Field, [{
121
- key: "checkPermissionsForUpdateOptions",
123
+ key: "_getCachedConfigFromFieldTypeProvider",
124
+ // We use a cached response from FieldTypeProvider because getting the config can
125
+ // be an expensive operation. In particular when fieldConfigs are extremely large
126
+ // (eg: Select fields with lots of select options)
127
+ value: function _getCachedConfigFromFieldTypeProvider() {
128
+ if (this._cachedFieldTypeConfigOrNull !== null) {
129
+ return this._cachedFieldTypeConfigOrNull;
130
+ }
122
131
 
132
+ var airtableInterface = this._sdk.__airtableInterface;
133
+ var appInterface = this._sdk.__appInterface;
134
+ this._cachedFieldTypeConfigOrNull = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById());
135
+ return this._cachedFieldTypeConfigOrNull;
136
+ }
137
+ }, {
138
+ key: "_clearCachedConfig",
139
+ value: function _clearCachedConfig() {
140
+ this._cachedFieldTypeConfigOrNull = null;
141
+ }
123
142
  /**
124
- * _Beta feature with unstable API. May have breaking changes before release._
143
+ * The type and options of the field to make type narrowing `FieldOptions` easier.
125
144
  *
145
+ * @see {@link FieldConfig}
146
+ * @example
147
+ * const fieldConfig = field.config;
148
+ * if (fieldConfig.type === FieldType.SINGLE_SELECT) {
149
+ * return fieldConfig.options.choices;
150
+ * } else if (fieldConfig.type === FieldType.MULTIPLE_LOOKUP_VALUES && fieldConfig.options.isValid) {
151
+ * if (fieldConfig.options.result.type === FieldType.SINGLE_SELECT) {
152
+ * return fieldConfig.options.result.options.choices;
153
+ * }
154
+ * }
155
+ * return DEFAULT_CHOICES;
156
+ */
157
+
158
+ }, {
159
+ key: "checkPermissionsForUpdateOptions",
160
+
161
+ /**
126
162
  * Checks whether the current user has permission to perform the given options update.
127
163
  *
128
164
  * Accepts partial input, in the same format as {@link updateOptionsAsync}.
129
165
  *
130
- * Returns `{hasPermission: true}` if the current user can update the specified record,
166
+ * Returns `{hasPermission: true}` if the current user can update the specified field,
131
167
  * `{hasPermission: false, reasonDisplayString: string}` otherwise. `reasonDisplayString` may be
132
168
  * used to display an error message to the user.
133
169
  *
@@ -154,8 +190,6 @@ function (_AbstractModel) {
154
190
  });
155
191
  }
156
192
  /**
157
- * _Beta feature with unstable API. May have breaking changes before release._
158
- *
159
193
  * An alias for `checkPermissionsForUpdateOptions(options).hasPermission`.
160
194
  *
161
195
  * Checks whether the current user has permission to perform the options update.
@@ -180,8 +214,6 @@ function (_AbstractModel) {
180
214
  return this.checkPermissionsForUpdateOptions(options).hasPermission;
181
215
  }
182
216
  /**
183
- * _Beta feature with unstable API. May have breaking changes before release._
184
- *
185
217
  * Updates the options for this field.
186
218
  *
187
219
  * Throws an error if the user does not have permission to update the field, if invalid
@@ -195,7 +227,11 @@ function (_AbstractModel) {
195
227
  * **not** applied optimistically locally. You must `await` the returned promise before
196
228
  * relying on the change in your app.
197
229
  *
230
+ * Optionally, you can pass an `opts` object as the second argument. See {@link UpdateFieldOptionsOpts}
231
+ * for available options.
232
+ *
198
233
  * @param options new options for the field
234
+ * @param opts optional options to affect the behavior of the update
199
235
  *
200
236
  * @example
201
237
  * ```js
@@ -217,11 +253,14 @@ function (_AbstractModel) {
217
253
  }, {
218
254
  key: "updateOptionsAsync",
219
255
  value: function updateOptionsAsync(options) {
256
+ var opts,
257
+ _args = arguments;
220
258
  return _regenerator.default.async(function updateOptionsAsync$(_context) {
221
259
  while (1) {
222
260
  switch (_context.prev = _context.next) {
223
261
  case 0:
224
- _context.next = 2;
262
+ opts = _args.length > 1 && _args[1] !== undefined ? _args[1] : {};
263
+ _context.next = 3;
225
264
  return _regenerator.default.awrap(this._sdk.__mutations.applyMutationAsync({
226
265
  type: _mutations.MutationTypes.UPDATE_SINGLE_FIELD_CONFIG,
227
266
  tableId: this.parentTable.id,
@@ -229,16 +268,115 @@ function (_AbstractModel) {
229
268
  config: {
230
269
  type: this.type,
231
270
  options: options
232
- }
271
+ },
272
+ opts
233
273
  }));
234
274
 
235
- case 2:
275
+ case 3:
236
276
  case "end":
237
277
  return _context.stop();
238
278
  }
239
279
  }
240
280
  }, null, this);
241
281
  }
282
+ /**
283
+ * Checks whether the current user has permission to perform the given description update.
284
+ *
285
+ * Accepts partial input, in the same format as {@link updateDescriptionAsync}.
286
+ *
287
+ * Returns `{hasPermission: true}` if the current user can update the specified field,
288
+ * `{hasPermission: false, reasonDisplayString: string}` otherwise. `reasonDisplayString` may be
289
+ * used to display an error message to the user.
290
+ *
291
+ * @param description new description for the field
292
+ *
293
+ * @example
294
+ * ```js
295
+ * const updateFieldCheckResult = field.checkPermissionsForUpdateDescription();
296
+ *
297
+ * if (!updateFieldCheckResult.hasPermission) {
298
+ * alert(updateFieldCheckResult.reasonDisplayString);
299
+ * }
300
+ * ```
301
+ */
302
+
303
+ }, {
304
+ key: "checkPermissionsForUpdateDescription",
305
+ value: function checkPermissionsForUpdateDescription(description) {
306
+ return this._sdk.__mutations.checkPermissionsForMutation({
307
+ type: _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION,
308
+ tableId: this.parentTable.id,
309
+ id: this.id,
310
+ description
311
+ });
312
+ }
313
+ /**
314
+ * An alias for `checkPermissionsForUpdateDescription(options).hasPermission`.
315
+ *
316
+ * Checks whether the current user has permission to perform the description update.
317
+ *
318
+ * Accepts partial input, in the same format as {@link updateDescriptionAsync}.
319
+ *
320
+ * @param description new description for the field
321
+ *
322
+ * @example
323
+ * ```js
324
+ * const canUpdateField = field.hasPermissionToUpdateDescription();
325
+ *
326
+ * if (!canUpdateField) {
327
+ * alert('not allowed!');
328
+ * }
329
+ * ```
330
+ */
331
+
332
+ }, {
333
+ key: "hasPermissionToUpdateDescription",
334
+ value: function hasPermissionToUpdateDescription(description) {
335
+ return this.checkPermissionsForUpdateDescription(description).hasPermission;
336
+ }
337
+ /**
338
+ * Updates the description for this field.
339
+ *
340
+ * To remove an existing description, pass `''` as the new description.
341
+ * `null` is also accepted and will be coerced to `''` for consistency with field creation.
342
+ *
343
+ * Throws an error if the user does not have permission to update the field, or if an invalid
344
+ * description is provided.
345
+ *
346
+ * This action is asynchronous. Unlike updates to cell values, updates to field descriptions are
347
+ * **not** applied optimistically locally. You must `await` the returned promise before
348
+ * relying on the change in your app.
349
+ *
350
+ * @param description new description for the field
351
+ *
352
+ * @example
353
+ * ```js
354
+ * await myTextField.updateDescriptionAsync('This is a text field');
355
+ * ```
356
+ */
357
+
358
+ }, {
359
+ key: "updateDescriptionAsync",
360
+ value: function updateDescriptionAsync(description) {
361
+ return _regenerator.default.async(function updateDescriptionAsync$(_context2) {
362
+ while (1) {
363
+ switch (_context2.prev = _context2.next) {
364
+ case 0:
365
+ _context2.next = 2;
366
+ return _regenerator.default.awrap(this._sdk.__mutations.applyMutationAsync({
367
+ type: _mutations.MutationTypes.UPDATE_SINGLE_FIELD_DESCRIPTION,
368
+ tableId: this.parentTable.id,
369
+ id: this.id,
370
+ description
371
+ }));
372
+
373
+ case 2:
374
+ case "end":
375
+ return _context2.stop();
376
+ }
377
+ }
378
+ }, null, this);
379
+ }
242
380
  /**
243
381
  * `true` if this field is computed, `false` otherwise. A field is
244
382
  * "computed" if it's value is not set by user input (e.g. autoNumber, formula,
@@ -327,6 +465,9 @@ function (_AbstractModel) {
327
465
  }, {
328
466
  key: "__triggerOnChangeForDirtyPaths",
329
467
  value: function __triggerOnChangeForDirtyPaths(dirtyPaths) {
468
+ // Always clear the cached config when anything on the field data model changes
469
+ this._clearCachedConfig();
470
+
330
471
  if (dirtyPaths.name) {
331
472
  this._onChange(WatchableFieldKeys.name);
332
473
  }
@@ -400,11 +541,8 @@ function (_AbstractModel) {
400
541
  }, {
401
542
  key: "type",
402
543
  get: function get() {
403
- var airtableInterface = this._sdk.__airtableInterface;
404
- var appInterface = this._sdk.__appInterface;
405
-
406
- var _airtableInterface$fi = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById()),
407
- type = _airtableInterface$fi.type; // We intend to switch from "lookup" to "multipleLookupValues", but need to support both
544
+ var _this$_getCachedConfi = this._getCachedConfigFromFieldTypeProvider(),
545
+ type = _this$_getCachedConfi.type; // We intend to switch from "lookup" to "multipleLookupValues", but need to support both
408
546
  // until the transition is complete. See <https://airtable.quip.com/VxaMAmAfUscs> for more.
409
547
  // @ts-ignore
410
548
 
@@ -435,31 +573,14 @@ function (_AbstractModel) {
435
573
  }, {
436
574
  key: "options",
437
575
  get: function get() {
438
- var airtableInterface = this._sdk.__airtableInterface;
439
- var appInterface = this._sdk.__appInterface;
440
-
441
- var _airtableInterface$fi2 = airtableInterface.fieldTypeProvider.getConfig(appInterface, this._data, this.parentTable.__getFieldNamesById()),
442
- options = _airtableInterface$fi2.options; // TODO(emma): can we remove this cloneDeep?
576
+ var _this$_getCachedConfi2 = this._getCachedConfigFromFieldTypeProvider(),
577
+ options = _this$_getCachedConfi2.options; // TODO: In the next breaking release freeze (inside of the cache) and replace
578
+ // FieldOptions with readonly<FieldOptions>.
579
+ // Today this is required because we re-use the fieldTypeProvider.getConfig response.
443
580
 
444
581
 
445
582
  return options ? (0, _private_utils.cloneDeep)(options) : null;
446
583
  }
447
- /**
448
- * The type and options of the field to make type narrowing `FieldOptions` easier.
449
- *
450
- * @see {@link FieldConfig}
451
- * @example
452
- * const fieldConfig = field.config;
453
- * if (fieldConfig.type === FieldType.SINGLE_SELECT) {
454
- * return fieldConfig.options.choices;
455
- * } else if (fieldConfig.type === FieldType.MULTIPLE_LOOKUP_VALUES && fieldConfig.options.isValid) {
456
- * if (fieldConfig.options.result.type === FieldType.SINGLE_SELECT) {
457
- * return fieldConfig.options.result.options.choices;
458
- * }
459
- * }
460
- * return DEFAULT_CHOICES;
461
- */
462
-
463
584
  }, {
464
585
  key: "config",
465
586
  get: function get() {
@@ -245,19 +245,13 @@ function (_RecordQueryResult) {
245
245
  while (1) {
246
246
  switch (_context2.prev = _context2.next) {
247
247
  case 0:
248
- this._parentQueryResult.__groupedRecordQueryResultPool.registerObjectForReuseStrong(this); // Ensure we invalidate our memoized computed recordIds whenever a relevant hook changes
249
- // TODO: (SeanKeenan) At the moment this should never be relevant, because groups are recreated
250
- // anytime the groups change - but this is how it should work once groups persist AND
251
- // watching recordIds only changes if records in this group change.
252
- // In the meantime this does ensure that a deleted GroupedRecordQuery with stale recordIds
253
- // doesn't return the cached array.
248
+ // TODO: This entire class assumes it is torn down and re-created by the parent whenever
249
+ // a change to the group is made.
250
+ this._parentQueryResult.__groupedRecordQueryResultPool.registerObjectForReuseStrong(this);
254
251
 
255
-
256
- this.watch(['recordIds', 'groups', 'groupLevels'], this._invalidateComputedRecordIds, this);
257
- this.watch(['recordIds'], this._invalidateRecordIdsSet, this);
258
252
  return _context2.abrupt("return", this._getChangedKeysOnLoad());
259
253
 
260
- case 4:
254
+ case 2:
261
255
  case "end":
262
256
  return _context2.stop();
263
257
  }
@@ -269,10 +263,7 @@ function (_RecordQueryResult) {
269
263
  }, {
270
264
  key: "_unloadData",
271
265
  value: function _unloadData() {
272
- // Ensure we invalidate our memoized computed recordIds whenever a relevant hook changes
273
- this.unwatch(['recordIds', 'groups', 'groupLevels'], this._invalidateComputedRecordIds, this);
274
- this.unwatch(['recordIds'], this._invalidateRecordIdsSet, this); // Invalidate both of the caches, as this object can no longer be accessed
275
-
266
+ // Invalidate both of the caches, as this object can no longer be accessed
276
267
  this._invalidateComputedRecordIds();
277
268
 
278
269
  this._invalidateRecordIdsSet();