@ember-data/store 4.5.0-beta.0 → 4.5.0

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 (64) hide show
  1. package/addon/-private/{system/backburner.js → backburner.js} +0 -0
  2. package/addon/-private/{system/coerce-id.ts → coerce-id.ts} +0 -0
  3. package/addon/-private/{system/store/common.js → common.js} +0 -0
  4. package/addon/-private/{system/core-store.ts → core-store.ts} +467 -1253
  5. package/addon/-private/{system/errors-utils.js → errors-utils.js} +7 -6
  6. package/addon/-private/{system/fetch-manager.ts → fetch-manager.ts} +72 -42
  7. package/addon/-private/finders.js +107 -0
  8. package/addon/-private/identifer-debug-consts.ts +3 -0
  9. package/addon/-private/{identifiers/cache.ts → identifier-cache.ts} +26 -14
  10. package/addon/-private/{system/identity-map.ts → identity-map.ts} +2 -1
  11. package/addon/-private/index.ts +17 -17
  12. package/addon/-private/instance-cache.ts +387 -0
  13. package/addon/-private/{system/store/internal-model-factory.ts → internal-model-factory.ts} +25 -19
  14. package/addon/-private/{system/internal-model-map.ts → internal-model-map.ts} +9 -5
  15. package/addon/-private/model/internal-model.ts +602 -0
  16. package/addon/-private/{system/references/record.ts → model/record-reference.ts} +23 -36
  17. package/addon/-private/{system/model → model}/shim-model-class.ts +19 -14
  18. package/addon/-private/{system/normalize-model-name.ts → normalize-model-name.ts} +0 -0
  19. package/addon/-private/{system/promise-proxies.ts → promise-proxies.ts} +12 -5
  20. package/addon/-private/{system/promise-proxy-base.js → promise-proxy-base.js} +0 -0
  21. package/addon/-private/{system/record-array-manager.ts → record-array-manager.ts} +19 -18
  22. package/addon/-private/{system/record-arrays → record-arrays}/adapter-populated-record-array.ts +11 -10
  23. package/addon/-private/{system/record-arrays → record-arrays}/record-array.ts +37 -19
  24. package/addon/-private/record-data-for.ts +39 -0
  25. package/addon/-private/{system/store/record-data-store-wrapper.ts → record-data-store-wrapper.ts} +21 -26
  26. package/addon/-private/{system/record-notification-manager.ts → record-notification-manager.ts} +8 -3
  27. package/addon/-private/{system/request-cache.ts → request-cache.ts} +5 -6
  28. package/addon/-private/{system/schema-definition-service.ts → schema-definition-service.ts} +30 -14
  29. package/addon/-private/{system/store/serializer-response.ts → serializer-response.ts} +7 -6
  30. package/addon/-private/{system/snapshot-record-array.ts → snapshot-record-array.ts} +27 -8
  31. package/addon/-private/{system/snapshot.ts → snapshot.ts} +54 -39
  32. package/addon/-private/utils/construct-resource.ts +7 -3
  33. package/addon/-private/utils/promise-record.ts +9 -18
  34. package/addon/-private/{system/weak-cache.ts → weak-cache.ts} +2 -2
  35. package/addon/index.ts +1 -0
  36. package/package.json +21 -20
  37. package/addon/-private/identifiers/is-stable-identifier.ts +0 -18
  38. package/addon/-private/identifiers/utils/uuid-v4.ts +0 -80
  39. package/addon/-private/system/ds-model-store.ts +0 -136
  40. package/addon/-private/system/model/internal-model.ts +0 -1303
  41. package/addon/-private/system/model/states.js +0 -736
  42. package/addon/-private/system/record-arrays.ts +0 -8
  43. package/addon/-private/system/record-data-for.ts +0 -54
  44. package/addon/-private/system/references/belongs-to.ts +0 -406
  45. package/addon/-private/system/references/has-many.ts +0 -487
  46. package/addon/-private/system/references/reference.ts +0 -205
  47. package/addon/-private/system/references.js +0 -9
  48. package/addon/-private/system/store/finders.js +0 -412
  49. package/addon/-private/ts-interfaces/ds-model.ts +0 -50
  50. package/addon/-private/ts-interfaces/ember-data-json-api.ts +0 -145
  51. package/addon/-private/ts-interfaces/fetch-manager.ts +0 -44
  52. package/addon/-private/ts-interfaces/identifier.ts +0 -246
  53. package/addon/-private/ts-interfaces/minimum-adapter-interface.ts +0 -584
  54. package/addon/-private/ts-interfaces/minimum-serializer-interface.ts +0 -257
  55. package/addon/-private/ts-interfaces/promise-proxies.ts +0 -3
  56. package/addon/-private/ts-interfaces/record-data-json-api.ts +0 -29
  57. package/addon/-private/ts-interfaces/record-data-record-wrapper.ts +0 -46
  58. package/addon/-private/ts-interfaces/record-data-schemas.ts +0 -45
  59. package/addon/-private/ts-interfaces/record-data-store-wrapper.ts +0 -56
  60. package/addon/-private/ts-interfaces/record-data.ts +0 -72
  61. package/addon/-private/ts-interfaces/record-instance.ts +0 -18
  62. package/addon/-private/ts-interfaces/schema-definition-service.ts +0 -12
  63. package/addon/-private/ts-interfaces/store.ts +0 -10
  64. package/addon/-private/ts-interfaces/utils.ts +0 -6
@@ -1,736 +0,0 @@
1
- /**
2
- @module @ember-data/store
3
- */
4
- import { assert } from '@ember/debug';
5
-
6
- /*
7
- This file encapsulates the various states that a record can transition
8
- through during its lifecycle.
9
- */
10
- /**
11
- ### State
12
-
13
- Each record has a `currentState` property that explicitly tracks what
14
- state a record is in at any given time. For instance, if a record is
15
- newly created and has not yet been sent to the adapter to be saved,
16
- it would be in the `root.loaded.created.uncommitted` state. If a
17
- record has had local modifications made to it that are in the
18
- process of being saved, the record would be in the
19
- `root.loaded.updated.inFlight` state. (This state path will be
20
- explained in more detail below.)
21
-
22
- Events are sent by the record or its store to the record's
23
- `currentState` property. How the state reacts to these events is
24
- dependent on which state it is in. In some states, certain events
25
- will be invalid and will cause an exception to be raised.
26
-
27
- States are hierarchical and every state is a sub-state of the
28
- `RootState`. For example, a record can be in the
29
- `root.deleted.uncommitted` state then transitions into the
30
- `root.deleted.inFlight` state. If a child state does not implement
31
- an event handler, the state manager will attempt to invoke the event
32
- on all parent states until the root state is reached. The state
33
- hierarchy of a record is described in terms of a path string. You
34
- can determine a record's current state by getting the state's
35
- `stateName` property:
36
-
37
- ```javascript
38
- record.get('currentState.stateName');
39
- //=> "root.created.uncommitted"
40
- ```
41
-
42
- The hierarchy of valid states that ship with ember data looks like
43
- this:
44
-
45
- ```text
46
- * root
47
- * deleted
48
- * saved
49
- * uncommitted
50
- * inFlight
51
- * empty
52
- * loaded
53
- * created
54
- * uncommitted
55
- * inFlight
56
- * saved
57
- * updated
58
- * uncommitted
59
- * inFlight
60
- * loading
61
- ```
62
-
63
- The `Model` states are themselves stateless. What that means is
64
- that, the hierarchical states that each of *those* points to is a
65
- shared data structure. For performance reasons, instead of each
66
- record getting its own copy of the hierarchy of states, each record
67
- points to this global, immutable shared instance. How does a state
68
- know which record it should be acting on? We pass the record
69
- instance into the state's event handlers as the first argument.
70
-
71
- The record passed as the first parameter is where you should stash
72
- state about the record if needed; you should never store data on the state
73
- object itself.
74
-
75
- ### Events and Flags
76
-
77
- A state may implement zero or more events and flags.
78
-
79
- #### Events
80
-
81
- Events are named functions that are invoked when sent to a record. The
82
- record will first look for a method with the given name on the
83
- current state. If no method is found, it will search the current
84
- state's parent, and then its grandparent, and so on until reaching
85
- the top of the hierarchy. If the root is reached without an event
86
- handler being found, an exception will be raised. This can be very
87
- helpful when debugging new features.
88
-
89
- Here's an example implementation of a state with a `myEvent` event handler:
90
-
91
- ```javascript
92
- aState: State.create({
93
- myEvent: function(manager, param) {
94
- console.log("Received myEvent with", param);
95
- }
96
- })
97
- ```
98
-
99
- To trigger this event:
100
-
101
- ```javascript
102
- record.send('myEvent', 'foo');
103
- //=> "Received myEvent with foo"
104
- ```
105
-
106
- Note that an optional parameter can be sent to a record's `send()` method,
107
- which will be passed as the second parameter to the event handler.
108
-
109
- Events should transition to a different state if appropriate. This can be
110
- done by calling the record's `transitionTo()` method with a path to the
111
- desired state. The state manager will attempt to resolve the state path
112
- relative to the current state. If no state is found at that path, it will
113
- attempt to resolve it relative to the current state's parent, and then its
114
- parent, and so on until the root is reached. For example, imagine a hierarchy
115
- like this:
116
-
117
- * created
118
- * uncommitted <-- currentState
119
- * inFlight
120
- * updated
121
- * inFlight
122
-
123
- If we are currently in the `uncommitted` state, calling
124
- `transitionTo('inFlight')` would transition to the `created.inFlight` state,
125
- while calling `transitionTo('updated.inFlight')` would transition to
126
- the `updated.inFlight` state.
127
-
128
- Remember that *only events* should ever cause a state transition. You should
129
- never call `transitionTo()` from outside a state's event handler. If you are
130
- tempted to do so, create a new event and send that to the state manager.
131
-
132
- #### Flags
133
-
134
- Flags are Boolean values that can be used to introspect a record's current
135
- state in a more user-friendly way than examining its state path. For example,
136
- instead of doing this:
137
-
138
- ```javascript
139
- var statePath = record.get('stateManager.currentPath');
140
- if (statePath === 'created.inFlight') {
141
- doSomething();
142
- }
143
- ```
144
-
145
- You can say:
146
-
147
- ```javascript
148
- if (record.get('isNew') && record.get('isSaving')) {
149
- doSomething();
150
- }
151
- ```
152
-
153
- If your state does not set a value for a given flag, the value will
154
- be inherited from its parent (or the first place in the state hierarchy
155
- where it is defined).
156
-
157
- The current set of flags are defined below. If you want to add a new flag,
158
- in addition to the area below, you will also need to declare it in the
159
- `Model` class.
160
-
161
-
162
- * [isEmpty](Model/properties/isEmpty?anchor=isEmpty)
163
- * [isLoading](Model/properties/isLoading?anchor=isLoading)
164
- * [isLoaded](Model/properties/isLoaded?anchor=isLoaded)
165
- * [hasDirtyAttributes](Model/properties/hasDirtyAttributes?anchor=hasDirtyAttributes)
166
- * [isSaving](Model/properties/isSaving?anchor=isSaving)
167
- * [isDeleted](Model/properties/isDeleted?anchor=isDeleted)
168
- * [isNew](Model/properties/isNew?anchor=isNew)
169
- * [isValid](Model/properties/isValid?anchor=isValid)
170
-
171
- @class RootState
172
- @internal
173
- */
174
-
175
- function didSetProperty(internalModel, context) {
176
- if (context.isDirty) {
177
- internalModel.send('becomeDirty');
178
- } else {
179
- internalModel.send('propertyWasReset');
180
- }
181
- }
182
-
183
- // Implementation notes:
184
- //
185
- // Each state has a boolean value for all of the following flags:
186
- //
187
- // * isLoaded: The record has a populated `data` property. When a
188
- // record is loaded via `store.find`, `isLoaded` is false
189
- // until the adapter sets it. When a record is created locally,
190
- // its `isLoaded` property is always true.
191
- // * isDirty: The record has local changes that have not yet been
192
- // saved by the adapter. This includes records that have been
193
- // created (but not yet saved) or deleted.
194
- // * isSaving: The record has been committed, but
195
- // the adapter has not yet acknowledged that the changes have
196
- // been persisted to the backend.
197
- // * isDeleted: The record was marked for deletion. When `isDeleted`
198
- // is true and `isDirty` is true, the record is deleted locally
199
- // but the deletion was not yet persisted. When `isSaving` is
200
- // true, the change is in-flight. When both `isDirty` and
201
- // `isSaving` are false, the change has persisted.
202
- // * isNew: The record was created on the client and the adapter
203
- // did not yet report that it was successfully saved.
204
- // * isValid: The adapter did not report any server-side validation
205
- // failures.
206
-
207
- // The dirty state is a abstract state whose functionality is
208
- // shared between the `created` and `updated` states.
209
- //
210
- // The deleted state shares the `isDirty` flag with the
211
- // subclasses of `DirtyState`, but with a very different
212
- // implementation.
213
- //
214
- // Dirty states have three child states:
215
- //
216
- // `uncommitted`: the store has not yet handed off the record
217
- // to be saved.
218
- // `inFlight`: the store has handed off the record to be saved,
219
- // but the adapter has not yet acknowledged success.
220
- // `invalid`: the record has invalid information and cannot be
221
- // sent to the adapter yet.
222
- const DirtyState = {
223
- initialState: 'uncommitted',
224
-
225
- // FLAGS
226
- isDirty: true,
227
-
228
- // SUBSTATES
229
-
230
- // When a record first becomes dirty, it is `uncommitted`.
231
- // This means that there are local pending changes, but they
232
- // have not yet begun to be saved, and are not invalid.
233
- uncommitted: {
234
- // EVENTS
235
- didSetProperty,
236
-
237
- //TODO(Igor) reloading now triggers a
238
- //loadingData event, though it seems fine?
239
- loadingData() {},
240
-
241
- propertyWasReset(internalModel, name) {
242
- if (!internalModel.hasChangedAttributes()) {
243
- internalModel.send('rolledBack');
244
- }
245
- },
246
-
247
- pushedData(internalModel) {
248
- if (!internalModel.hasChangedAttributes()) {
249
- internalModel.transitionTo('loaded.saved');
250
- }
251
- },
252
-
253
- becomeDirty() {},
254
-
255
- willCommit(internalModel) {
256
- internalModel.transitionTo('inFlight');
257
- },
258
-
259
- reloadRecord(internalModel, { resolve, options }) {
260
- resolve(internalModel.store._reloadRecord(internalModel, options));
261
- },
262
-
263
- rolledBack(internalModel) {
264
- internalModel.transitionTo('loaded.saved');
265
- },
266
-
267
- becameInvalid(internalModel) {
268
- internalModel.transitionTo('invalid');
269
- },
270
-
271
- rollback(internalModel) {
272
- internalModel.rollbackAttributes();
273
- },
274
- },
275
-
276
- // Once a record has been handed off to the adapter to be
277
- // saved, it is in the 'in flight' state. Changes to the
278
- // record cannot be made during this window.
279
- inFlight: {
280
- // FLAGS
281
- isSaving: true,
282
-
283
- // EVENTS
284
- didSetProperty,
285
- becomeDirty() {},
286
- pushedData() {},
287
-
288
- unloadRecord: assertAgainstUnloadRecord,
289
-
290
- // TODO: More robust semantics around save-while-in-flight
291
- willCommit() {},
292
-
293
- didCommit(internalModel) {
294
- internalModel.transitionTo('saved');
295
- internalModel.send('invokeLifecycleCallbacks', this.dirtyType);
296
- },
297
-
298
- rolledBack() {},
299
-
300
- becameInvalid(internalModel) {
301
- internalModel.transitionTo('invalid');
302
- internalModel.send('invokeLifecycleCallbacks');
303
- },
304
-
305
- becameError(internalModel) {
306
- internalModel.transitionTo('uncommitted');
307
- },
308
- },
309
-
310
- // A record is in the `invalid` if the adapter has indicated
311
- // the the record failed server-side invalidations.
312
- invalid: {
313
- // FLAGS
314
- isValid: false,
315
-
316
- // EVENTS
317
- deleteRecord(internalModel) {
318
- internalModel.transitionTo('deleted.uncommitted');
319
- },
320
-
321
- didSetProperty(internalModel, context) {
322
- internalModel.getRecord().errors._remove(context.name);
323
-
324
- didSetProperty(internalModel, context);
325
-
326
- if (!internalModel.hasErrors()) {
327
- this.becameValid(internalModel);
328
- }
329
- },
330
-
331
- becameInvalid() {},
332
- becomeDirty() {},
333
- pushedData() {},
334
-
335
- willCommit(internalModel) {
336
- clearErrorMessages(internalModel);
337
- internalModel.transitionTo('inFlight');
338
- },
339
-
340
- rolledBack(internalModel) {
341
- clearErrorMessages(internalModel);
342
- internalModel.transitionTo('loaded.saved');
343
- },
344
-
345
- becameValid(internalModel) {
346
- internalModel.transitionTo('uncommitted');
347
- },
348
-
349
- invokeLifecycleCallbacks() {},
350
- },
351
- };
352
-
353
- // The created and updated states are created outside the state
354
- // chart so we can reopen their substates and add mixins as
355
- // necessary.
356
-
357
- function deepClone(object) {
358
- const clone = {};
359
- let value;
360
-
361
- for (let prop in object) {
362
- value = object[prop];
363
- if (value && typeof value === 'object') {
364
- clone[prop] = deepClone(value);
365
- } else {
366
- clone[prop] = value;
367
- }
368
- }
369
-
370
- return clone;
371
- }
372
-
373
- function mixin(original, hash) {
374
- for (let prop in hash) {
375
- original[prop] = hash[prop];
376
- }
377
-
378
- return original;
379
- }
380
-
381
- function dirtyState(options) {
382
- var newState = deepClone(DirtyState);
383
- return mixin(newState, options);
384
- }
385
-
386
- const createdState = dirtyState({
387
- dirtyType: 'created',
388
- // FLAGS
389
- isNew: true,
390
-
391
- setup(internalModel) {
392
- internalModel.store.recordArrayManager.recordDidChange(internalModel.identifier);
393
- },
394
- });
395
-
396
- createdState.invalid.rolledBack = function (internalModel) {
397
- internalModel.transitionTo('deleted.saved');
398
- };
399
-
400
- createdState.uncommitted.rolledBack = function (internalModel) {
401
- internalModel.transitionTo('deleted.saved');
402
- };
403
-
404
- const updatedState = dirtyState({
405
- dirtyType: 'updated',
406
- });
407
-
408
- function createdStateDeleteRecord(internalModel) {
409
- internalModel.transitionTo('deleted.saved');
410
- internalModel.send('invokeLifecycleCallbacks');
411
- }
412
-
413
- createdState.uncommitted.deleteRecord = createdStateDeleteRecord;
414
-
415
- createdState.invalid.deleteRecord = createdStateDeleteRecord;
416
-
417
- createdState.uncommitted.rollback = function (internalModel) {
418
- DirtyState.uncommitted.rollback.apply(this, arguments);
419
- internalModel.transitionTo('deleted.saved');
420
- };
421
-
422
- createdState.uncommitted.pushedData = function (internalModel) {
423
- // TODO @runspired consider where to do this once we kill off state machine
424
- internalModel.store._notificationManager.notify(internalModel.identifier, 'identity');
425
- internalModel.transitionTo('loaded.updated.uncommitted');
426
- };
427
-
428
- createdState.uncommitted.propertyWasReset = function () {};
429
-
430
- function assertAgainstUnloadRecord(internalModel) {
431
- assert('You can only unload a record which is not inFlight. `' + internalModel + '`', false);
432
- }
433
-
434
- updatedState.invalid.becameValid = function (internalModel) {
435
- // we're eagerly transition into the loaded.saved state, even though we could
436
- // be still dirty; but the setup hook of the loaded.saved state checks for
437
- // dirty attributes and transitions into the corresponding dirty state
438
- internalModel.transitionTo('loaded.saved');
439
- };
440
-
441
- updatedState.inFlight.unloadRecord = assertAgainstUnloadRecord;
442
-
443
- updatedState.uncommitted.deleteRecord = function (internalModel) {
444
- internalModel.transitionTo('deleted.uncommitted');
445
- };
446
-
447
- updatedState.invalid.rolledBack = function (internalModel) {
448
- clearErrorMessages(internalModel);
449
- internalModel.transitionTo('loaded.saved');
450
- };
451
-
452
- const RootState = {
453
- // FLAGS
454
- isEmpty: false,
455
- isLoading: false,
456
- isLoaded: false,
457
- isDirty: false,
458
- isSaving: false,
459
- isDeleted: false,
460
- isNew: false,
461
- isValid: true,
462
-
463
- // DEFAULT EVENTS
464
-
465
- // Trying to roll back if you're not in the dirty state
466
- // doesn't change your state. For example, if you're in the
467
- // in-flight state, rolling back the record doesn't move
468
- // you out of the in-flight state.
469
- rolledBack() {},
470
- unloadRecord(internalModel) {},
471
-
472
- propertyWasReset() {},
473
-
474
- // SUBSTATES
475
-
476
- // A record begins its lifecycle in the `empty` state.
477
- // If its data will come from the adapter, it will
478
- // transition into the `loading` state. Otherwise, if
479
- // the record is being created on the client, it will
480
- // transition into the `created` state.
481
- empty: {
482
- isEmpty: true,
483
-
484
- // EVENTS
485
- loadingData(internalModel, promise) {
486
- internalModel.transitionTo('loading');
487
- },
488
-
489
- loadedData(internalModel) {
490
- internalModel.transitionTo('loaded.created.uncommitted');
491
- },
492
-
493
- pushedData(internalModel) {
494
- internalModel.transitionTo('loaded.saved');
495
- },
496
-
497
- // Record is already in an empty state, triggering transition to empty here
498
- // produce an error.
499
- notFound() {},
500
- },
501
-
502
- // A record enters this state when the store asks
503
- // the adapter for its data. It remains in this state
504
- // until the adapter provides the requested data.
505
- //
506
- // Usually, this process is asynchronous, using an
507
- // XHR to retrieve the data.
508
- loading: {
509
- // FLAGS
510
- isLoading: true,
511
-
512
- exit(internalModel) {
513
- internalModel._promiseProxy = null;
514
- },
515
-
516
- loadingData() {},
517
-
518
- // EVENTS
519
- pushedData(internalModel) {
520
- internalModel.transitionTo('loaded.saved');
521
- //TODO this seems out of place here
522
- internalModel.didCleanError();
523
- },
524
-
525
- becameError() {},
526
-
527
- notFound(internalModel) {
528
- internalModel.transitionTo('empty');
529
- },
530
- },
531
-
532
- // A record enters this state when its data is populated.
533
- // Most of a record's lifecycle is spent inside substates
534
- // of the `loaded` state.
535
- loaded: {
536
- initialState: 'saved',
537
-
538
- // FLAGS
539
- isLoaded: true,
540
-
541
- //TODO(Igor) Reloading now triggers a loadingData event,
542
- //but it should be ok?
543
- loadingData() {},
544
-
545
- // SUBSTATES
546
-
547
- // If there are no local changes to a record, it remains
548
- // in the `saved` state.
549
- saved: {
550
- setup(internalModel) {
551
- if (internalModel.hasChangedAttributes()) {
552
- internalModel.adapterDidDirty();
553
- }
554
- },
555
-
556
- // EVENTS
557
- didSetProperty,
558
-
559
- pushedData() {},
560
-
561
- becomeDirty(internalModel) {
562
- internalModel.transitionTo('updated.uncommitted');
563
- },
564
-
565
- willCommit(internalModel) {
566
- internalModel.transitionTo('updated.inFlight');
567
- },
568
-
569
- reloadRecord() {},
570
-
571
- deleteRecord(internalModel) {
572
- internalModel.transitionTo('deleted.uncommitted');
573
- },
574
-
575
- unloadRecord(internalModel) {},
576
-
577
- didCommit() {},
578
-
579
- // loaded.saved.notFound would be triggered by a failed
580
- // `reload()` on an unchanged record
581
- notFound() {},
582
- },
583
-
584
- // A record is in this state after it has been locally
585
- // created but before the adapter has indicated that
586
- // it has been saved.
587
- created: createdState,
588
-
589
- // A record is in this state if it has already been
590
- // saved to the server, but there are new local changes
591
- // that have not yet been saved.
592
- updated: updatedState,
593
- },
594
-
595
- // A record is in this state if it was deleted from the store.
596
- deleted: {
597
- initialState: 'uncommitted',
598
- dirtyType: 'deleted',
599
-
600
- // FLAGS
601
- isDeleted: true,
602
- isLoaded: true,
603
- isDirty: true,
604
-
605
- // TRANSITIONS
606
- setup(internalModel) {
607
- internalModel.store.recordArrayManager.recordDidChange(internalModel.identifier);
608
- },
609
-
610
- // SUBSTATES
611
-
612
- // When a record is deleted, it enters the `start`
613
- // state. It will exit this state when the record
614
- // starts to commit.
615
- uncommitted: {
616
- // EVENTS
617
-
618
- willCommit(internalModel) {
619
- internalModel.transitionTo('inFlight');
620
- },
621
-
622
- rollback(internalModel) {
623
- internalModel.rollbackAttributes();
624
- },
625
-
626
- pushedData() {},
627
- becomeDirty() {},
628
- deleteRecord() {},
629
-
630
- rolledBack(internalModel) {
631
- internalModel.transitionTo('loaded.saved');
632
- },
633
- },
634
-
635
- // After a record starts committing, but
636
- // before the adapter indicates that the deletion
637
- // has saved to the server, a record is in the
638
- // `inFlight` substate of `deleted`.
639
- inFlight: {
640
- // FLAGS
641
- isSaving: true,
642
-
643
- // EVENTS
644
-
645
- unloadRecord: assertAgainstUnloadRecord,
646
-
647
- // TODO: More robust semantics around save-while-in-flight
648
- willCommit() {},
649
- didCommit(internalModel) {
650
- internalModel.transitionTo('saved');
651
-
652
- internalModel.send('invokeLifecycleCallbacks');
653
- },
654
-
655
- becameError(internalModel) {
656
- internalModel.transitionTo('uncommitted');
657
- },
658
-
659
- becameInvalid(internalModel) {
660
- internalModel.transitionTo('invalid');
661
- },
662
- },
663
-
664
- // Once the adapter indicates that the deletion has
665
- // been saved, the record enters the `saved` substate
666
- // of `deleted`.
667
- saved: {
668
- // FLAGS
669
- isDirty: false,
670
-
671
- setup(internalModel) {
672
- internalModel.removeFromInverseRelationships();
673
- },
674
-
675
- invokeLifecycleCallbacks() {},
676
-
677
- willCommit() {},
678
- didCommit() {},
679
- pushedData() {},
680
- },
681
-
682
- invalid: {
683
- isValid: false,
684
-
685
- didSetProperty(internalModel, context) {
686
- internalModel.getRecord().errors._remove(context.name);
687
-
688
- didSetProperty(internalModel, context);
689
-
690
- if (!internalModel.hasErrors()) {
691
- this.becameValid(internalModel);
692
- }
693
- },
694
-
695
- becameInvalid() {},
696
- becomeDirty() {},
697
- deleteRecord() {},
698
- willCommit() {},
699
-
700
- rolledBack(internalModel) {
701
- clearErrorMessages(internalModel);
702
- internalModel.transitionTo('loaded.saved');
703
- },
704
-
705
- becameValid(internalModel) {
706
- internalModel.transitionTo('uncommitted');
707
- },
708
- },
709
- },
710
-
711
- invokeLifecycleCallbacks() {},
712
- };
713
-
714
- function wireState(object, parent, name) {
715
- // TODO: Use Object.create and copy instead
716
- object = mixin(parent ? Object.create(parent) : {}, object);
717
- object.parentState = parent;
718
- object.stateName = name;
719
-
720
- for (let prop in object) {
721
- if (!Object.prototype.hasOwnProperty.call(object, prop) || prop === 'parentState' || prop === 'stateName') {
722
- continue;
723
- }
724
- if (typeof object[prop] === 'object') {
725
- object[prop] = wireState(object[prop], object, name + '.' + prop);
726
- }
727
- }
728
-
729
- return object;
730
- }
731
-
732
- function clearErrorMessages(internalModel) {
733
- internalModel.getRecord().errors._clear();
734
- }
735
-
736
- export default wireState(RootState, null, 'root');