@ember-data/model 4.10.0-alpha.2 → 4.10.0-alpha.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/addon/{-private/diff-array.ts → -private.js} +41 -13
- package/addon/-private.js.map +1 -0
- package/addon/has-many-357b6265.js +6277 -0
- package/addon/has-many-357b6265.js.map +1 -0
- package/addon/index.js +1 -0
- package/addon/index.js.map +1 -0
- package/addon-main.js +90 -0
- package/package.json +43 -15
- package/addon/-private/attr.js +0 -162
- package/addon/-private/belongs-to.js +0 -268
- package/addon/-private/debug/assert-polymorphic-type.js +0 -71
- package/addon/-private/deprecated-promise-proxy.ts +0 -76
- package/addon/-private/errors.ts +0 -425
- package/addon/-private/has-many.js +0 -280
- package/addon/-private/index.ts +0 -14
- package/addon/-private/legacy-data-fetch.js +0 -395
- package/addon/-private/legacy-data-utils.ts +0 -92
- package/addon/-private/legacy-relationships-support.ts +0 -774
- package/addon/-private/many-array.ts +0 -401
- package/addon/-private/model-for-mixin.ts +0 -38
- package/addon/-private/model.js +0 -2516
- package/addon/-private/notify-changes.ts +0 -72
- package/addon/-private/promise-belongs-to.ts +0 -73
- package/addon/-private/promise-many-array.ts +0 -425
- package/addon/-private/promise-proxy-base.js +0 -4
- package/addon/-private/record-state.ts +0 -468
- package/addon/-private/references/belongs-to.ts +0 -624
- package/addon/-private/references/has-many.ts +0 -669
- package/addon/-private/relationship-meta.ts +0 -98
- package/addon/-private/util.ts +0 -31
- package/addon/index.ts +0 -39
- package/blueprints/model/HELP.md +0 -26
- package/blueprints/model/files/__root__/__path__/__name__.js +0 -5
- package/blueprints/model/index.js +0 -158
- package/blueprints/model/native-files/__root__/__path__/__name__.js +0 -5
- package/blueprints/model-test/index.js +0 -33
- package/blueprints/model-test/mocha-files/__root__/__path__/__test__.js +0 -18
- package/blueprints/model-test/mocha-rfc-232-files/__root__/__path__/__test__.js +0 -15
- package/blueprints/model-test/qunit-files/__root__/__path__/__test__.js +0 -14
- package/index.js +0 -47
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
@module @ember-data/store
|
|
3
|
-
*/
|
|
4
|
-
import { assert, deprecate } from '@ember/debug';
|
|
5
|
-
|
|
6
|
-
import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
|
|
7
|
-
import type Store from '@ember-data/store';
|
|
8
|
-
import { IDENTIFIER_ARRAY_TAG, MUTATE, RecordArray, recordIdentifierFor, SOURCE } from '@ember-data/store/-private';
|
|
9
|
-
import type ShimModelClass from '@ember-data/store/-private/legacy-model-support/shim-model-class';
|
|
10
|
-
import { IdentifierArrayCreateOptions } from '@ember-data/store/-private/record-arrays/identifier-array';
|
|
11
|
-
import type { CreateRecordProperties } from '@ember-data/store/-private/store-service';
|
|
12
|
-
import type { Links, PaginationLinks } from '@ember-data/types/q/ember-data-json-api';
|
|
13
|
-
import type { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
14
|
-
import type { RecordData } from '@ember-data/types/q/record-data';
|
|
15
|
-
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
16
|
-
import type { FindOptions } from '@ember-data/types/q/store';
|
|
17
|
-
import type { Dict } from '@ember-data/types/q/utils';
|
|
18
|
-
|
|
19
|
-
import { LegacySupport } from './legacy-relationships-support';
|
|
20
|
-
|
|
21
|
-
export interface ManyArrayCreateArgs {
|
|
22
|
-
identifiers: StableRecordIdentifier[];
|
|
23
|
-
type: string;
|
|
24
|
-
store: Store;
|
|
25
|
-
allowMutation: boolean;
|
|
26
|
-
manager: LegacySupport;
|
|
27
|
-
|
|
28
|
-
identifier: StableRecordIdentifier;
|
|
29
|
-
recordData: RecordData;
|
|
30
|
-
meta: Dict<unknown> | null;
|
|
31
|
-
links: Links | PaginationLinks | null;
|
|
32
|
-
key: string;
|
|
33
|
-
isPolymorphic: boolean;
|
|
34
|
-
isAsync: boolean;
|
|
35
|
-
_inverseIsAsync: boolean;
|
|
36
|
-
isLoaded: boolean;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
A `ManyArray` is a `MutableArray` that represents the contents of a has-many
|
|
40
|
-
relationship.
|
|
41
|
-
|
|
42
|
-
The `ManyArray` is instantiated lazily the first time the relationship is
|
|
43
|
-
requested.
|
|
44
|
-
|
|
45
|
-
This class is not intended to be directly instantiated by consuming applications.
|
|
46
|
-
|
|
47
|
-
### Inverses
|
|
48
|
-
|
|
49
|
-
Often, the relationships in Ember Data applications will have
|
|
50
|
-
an inverse. For example, imagine the following models are
|
|
51
|
-
defined:
|
|
52
|
-
|
|
53
|
-
```app/models/post.js
|
|
54
|
-
import Model, { hasMany } from '@ember-data/model';
|
|
55
|
-
|
|
56
|
-
export default class PostModel extends Model {
|
|
57
|
-
@hasMany('comment') comments;
|
|
58
|
-
}
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
```app/models/comment.js
|
|
62
|
-
import Model, { belongsTo } from '@ember-data/model';
|
|
63
|
-
|
|
64
|
-
export default class CommentModel extends Model {
|
|
65
|
-
@belongsTo('post') post;
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
If you created a new instance of `Post` and added
|
|
70
|
-
a `Comment` record to its `comments` has-many
|
|
71
|
-
relationship, you would expect the comment's `post`
|
|
72
|
-
property to be set to the post that contained
|
|
73
|
-
the has-many.
|
|
74
|
-
|
|
75
|
-
We call the record to which a relationship belongs-to the
|
|
76
|
-
relationship's _owner_.
|
|
77
|
-
|
|
78
|
-
@class ManyArray
|
|
79
|
-
@public
|
|
80
|
-
*/
|
|
81
|
-
export default class RelatedCollection extends RecordArray {
|
|
82
|
-
declare isAsync: boolean;
|
|
83
|
-
/**
|
|
84
|
-
The loading state of this array
|
|
85
|
-
|
|
86
|
-
@property {Boolean} isLoaded
|
|
87
|
-
@public
|
|
88
|
-
*/
|
|
89
|
-
|
|
90
|
-
declare isLoaded: boolean;
|
|
91
|
-
/**
|
|
92
|
-
`true` if the relationship is polymorphic, `false` otherwise.
|
|
93
|
-
|
|
94
|
-
@property {Boolean} isPolymorphic
|
|
95
|
-
@private
|
|
96
|
-
*/
|
|
97
|
-
declare isPolymorphic: boolean;
|
|
98
|
-
declare _inverseIsAsync: boolean;
|
|
99
|
-
/**
|
|
100
|
-
Metadata associated with the request for async hasMany relationships.
|
|
101
|
-
|
|
102
|
-
Example
|
|
103
|
-
|
|
104
|
-
Given that the server returns the following JSON payload when fetching a
|
|
105
|
-
hasMany relationship:
|
|
106
|
-
|
|
107
|
-
```js
|
|
108
|
-
{
|
|
109
|
-
"comments": [{
|
|
110
|
-
"id": 1,
|
|
111
|
-
"comment": "This is the first comment",
|
|
112
|
-
}, {
|
|
113
|
-
// ...
|
|
114
|
-
}],
|
|
115
|
-
|
|
116
|
-
"meta": {
|
|
117
|
-
"page": 1,
|
|
118
|
-
"total": 5
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
You can then access the meta data via the `meta` property:
|
|
124
|
-
|
|
125
|
-
```js
|
|
126
|
-
let comments = await post.comments;
|
|
127
|
-
let meta = comments.meta;
|
|
128
|
-
|
|
129
|
-
// meta.page => 1
|
|
130
|
-
// meta.total => 5
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
@property {Object | null} meta
|
|
134
|
-
@public
|
|
135
|
-
*/
|
|
136
|
-
declare meta: Dict<unknown> | null;
|
|
137
|
-
/**
|
|
138
|
-
* Retrieve the links for this relationship
|
|
139
|
-
*
|
|
140
|
-
@property {Object | null} links
|
|
141
|
-
@public
|
|
142
|
-
*/
|
|
143
|
-
declare links: Links | PaginationLinks | null;
|
|
144
|
-
declare identifier: StableRecordIdentifier;
|
|
145
|
-
declare recordData: RecordData;
|
|
146
|
-
// @ts-expect-error
|
|
147
|
-
declare _manager: LegacySupport;
|
|
148
|
-
declare store: Store;
|
|
149
|
-
declare key: string;
|
|
150
|
-
declare type: ShimModelClass;
|
|
151
|
-
|
|
152
|
-
constructor(options: ManyArrayCreateArgs) {
|
|
153
|
-
super(options as unknown as IdentifierArrayCreateOptions);
|
|
154
|
-
this.isLoaded = options.isLoaded || false;
|
|
155
|
-
this.isAsync = options.isAsync || false;
|
|
156
|
-
this.isPolymorphic = options.isPolymorphic || false;
|
|
157
|
-
this.identifier = options.identifier;
|
|
158
|
-
this.key = options.key;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
[MUTATE](prop: string, args: unknown[], result?: unknown) {
|
|
162
|
-
switch (prop) {
|
|
163
|
-
case 'length 0': {
|
|
164
|
-
this._manager.updateCache({
|
|
165
|
-
op: 'replaceRelatedRecords',
|
|
166
|
-
record: this.identifier,
|
|
167
|
-
field: this.key,
|
|
168
|
-
value: [],
|
|
169
|
-
});
|
|
170
|
-
break;
|
|
171
|
-
}
|
|
172
|
-
case 'replace cell': {
|
|
173
|
-
const [index, prior, value] = args as [number, StableRecordIdentifier, StableRecordIdentifier];
|
|
174
|
-
this._manager.updateCache({
|
|
175
|
-
op: 'replaceRelatedRecord',
|
|
176
|
-
record: this.identifier,
|
|
177
|
-
field: this.key,
|
|
178
|
-
value,
|
|
179
|
-
prior,
|
|
180
|
-
index,
|
|
181
|
-
});
|
|
182
|
-
break;
|
|
183
|
-
}
|
|
184
|
-
case 'push':
|
|
185
|
-
this._manager.updateCache({
|
|
186
|
-
op: 'addToRelatedRecords',
|
|
187
|
-
record: this.identifier,
|
|
188
|
-
field: this.key,
|
|
189
|
-
value: extractIdentifiersFromRecords(args as RecordInstance[]),
|
|
190
|
-
});
|
|
191
|
-
break;
|
|
192
|
-
case 'pop':
|
|
193
|
-
if (result) {
|
|
194
|
-
this._manager.updateCache({
|
|
195
|
-
op: 'removeFromRelatedRecords',
|
|
196
|
-
record: this.identifier,
|
|
197
|
-
field: this.key,
|
|
198
|
-
value: recordIdentifierFor(result as RecordInstance),
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
break;
|
|
202
|
-
|
|
203
|
-
case 'unshift':
|
|
204
|
-
this._manager.updateCache({
|
|
205
|
-
op: 'addToRelatedRecords',
|
|
206
|
-
record: this.identifier,
|
|
207
|
-
field: this.key,
|
|
208
|
-
value: extractIdentifiersFromRecords(args as RecordInstance[]),
|
|
209
|
-
index: 0,
|
|
210
|
-
});
|
|
211
|
-
break;
|
|
212
|
-
|
|
213
|
-
case 'shift':
|
|
214
|
-
if (result) {
|
|
215
|
-
this._manager.updateCache({
|
|
216
|
-
op: 'removeFromRelatedRecords',
|
|
217
|
-
record: this.identifier,
|
|
218
|
-
field: this.key,
|
|
219
|
-
value: recordIdentifierFor(result as RecordInstance),
|
|
220
|
-
index: 0,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
break;
|
|
224
|
-
|
|
225
|
-
case 'sort':
|
|
226
|
-
this._manager.updateCache({
|
|
227
|
-
op: 'sortRelatedRecords',
|
|
228
|
-
record: this.identifier,
|
|
229
|
-
field: this.key,
|
|
230
|
-
value: (result as RecordInstance[]).map(recordIdentifierFor),
|
|
231
|
-
});
|
|
232
|
-
break;
|
|
233
|
-
|
|
234
|
-
case 'splice': {
|
|
235
|
-
const [start, removeCount, ...adds] = args as [number, number, RecordInstance];
|
|
236
|
-
// detect a full replace
|
|
237
|
-
if (removeCount > 0 && adds.length === this[SOURCE].length) {
|
|
238
|
-
this._manager.updateCache({
|
|
239
|
-
op: 'replaceRelatedRecords',
|
|
240
|
-
record: this.identifier,
|
|
241
|
-
field: this.key,
|
|
242
|
-
value: extractIdentifiersFromRecords(adds),
|
|
243
|
-
});
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
if (removeCount > 0) {
|
|
247
|
-
this._manager.updateCache({
|
|
248
|
-
op: 'removeFromRelatedRecords',
|
|
249
|
-
record: this.identifier,
|
|
250
|
-
field: this.key,
|
|
251
|
-
value: (result as RecordInstance[]).map(recordIdentifierFor),
|
|
252
|
-
index: start,
|
|
253
|
-
});
|
|
254
|
-
}
|
|
255
|
-
if (adds?.length) {
|
|
256
|
-
this._manager.updateCache({
|
|
257
|
-
op: 'addToRelatedRecords',
|
|
258
|
-
record: this.identifier,
|
|
259
|
-
field: this.key,
|
|
260
|
-
value: extractIdentifiersFromRecords(adds),
|
|
261
|
-
index: start,
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
default:
|
|
268
|
-
assert(`unable to convert ${prop} into a transaction that updates the cache state for this record array`);
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
notify() {
|
|
273
|
-
const tag = this[IDENTIFIER_ARRAY_TAG];
|
|
274
|
-
tag.ref = null;
|
|
275
|
-
tag.shouldReset = true;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
/**
|
|
279
|
-
Reloads all of the records in the manyArray. If the manyArray
|
|
280
|
-
holds a relationship that was originally fetched using a links url
|
|
281
|
-
Ember Data will revisit the original links url to repopulate the
|
|
282
|
-
relationship.
|
|
283
|
-
|
|
284
|
-
If the manyArray holds the result of a `store.query()` reload will
|
|
285
|
-
re-run the original query.
|
|
286
|
-
|
|
287
|
-
Example
|
|
288
|
-
|
|
289
|
-
```javascript
|
|
290
|
-
let user = store.peekRecord('user', '1')
|
|
291
|
-
await login(user);
|
|
292
|
-
|
|
293
|
-
let permissions = await user.permissions;
|
|
294
|
-
await permissions.reload();
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
@method reload
|
|
298
|
-
@public
|
|
299
|
-
*/
|
|
300
|
-
reload(options?: FindOptions) {
|
|
301
|
-
// TODO this is odd, we don't ask the store for anything else like this?
|
|
302
|
-
return this._manager.reloadHasMany(this.key, options);
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
Saves all of the records in the `ManyArray`.
|
|
307
|
-
|
|
308
|
-
Example
|
|
309
|
-
|
|
310
|
-
```javascript
|
|
311
|
-
let inbox = await store.findRecord('inbox', '1');
|
|
312
|
-
let messages = await inbox.messages;
|
|
313
|
-
messages.forEach((message) => {
|
|
314
|
-
message.isRead = true;
|
|
315
|
-
});
|
|
316
|
-
messages.save();
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
@method save
|
|
320
|
-
@public
|
|
321
|
-
@return {PromiseArray} promise
|
|
322
|
-
*/
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
Create a child record within the owner
|
|
326
|
-
|
|
327
|
-
@method createRecord
|
|
328
|
-
@public
|
|
329
|
-
@param {Object} hash
|
|
330
|
-
@return {Model} record
|
|
331
|
-
*/
|
|
332
|
-
createRecord(hash: CreateRecordProperties): RecordInstance {
|
|
333
|
-
const { store } = this;
|
|
334
|
-
|
|
335
|
-
const record = store.createRecord(this.modelName, hash);
|
|
336
|
-
this.push(record);
|
|
337
|
-
|
|
338
|
-
return record;
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
RelatedCollection.prototype.isAsync = false;
|
|
342
|
-
RelatedCollection.prototype.isPolymorphic = false;
|
|
343
|
-
RelatedCollection.prototype.identifier = null as unknown as StableRecordIdentifier;
|
|
344
|
-
RelatedCollection.prototype.recordData = null as unknown as RecordData;
|
|
345
|
-
RelatedCollection.prototype._inverseIsAsync = false;
|
|
346
|
-
RelatedCollection.prototype.key = '';
|
|
347
|
-
RelatedCollection.prototype.DEPRECATED_CLASS_NAME = 'ManyArray';
|
|
348
|
-
|
|
349
|
-
type PromiseProxyRecord = { then(): void; content: RecordInstance | null | undefined };
|
|
350
|
-
|
|
351
|
-
function assertRecordPassedToHasMany(record: RecordInstance | PromiseProxyRecord) {
|
|
352
|
-
assert(
|
|
353
|
-
`All elements of a hasMany relationship must be instances of Model, you passed $${typeof record}`,
|
|
354
|
-
(function () {
|
|
355
|
-
try {
|
|
356
|
-
recordIdentifierFor(record);
|
|
357
|
-
return true;
|
|
358
|
-
} catch {
|
|
359
|
-
return false;
|
|
360
|
-
}
|
|
361
|
-
})()
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function extractIdentifiersFromRecords(records: RecordInstance[]): StableRecordIdentifier[] {
|
|
366
|
-
return records.map(extractIdentifierFromRecord);
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function extractIdentifierFromRecord(recordOrPromiseRecord: PromiseProxyRecord | RecordInstance) {
|
|
370
|
-
if (DEPRECATE_PROMISE_PROXIES) {
|
|
371
|
-
if (isPromiseRecord(recordOrPromiseRecord)) {
|
|
372
|
-
let content = recordOrPromiseRecord.content;
|
|
373
|
-
assert(
|
|
374
|
-
'You passed in a promise that did not originate from an EmberData relationship. You can only pass promises that come from a belongsTo relationship.',
|
|
375
|
-
content !== undefined && content !== null
|
|
376
|
-
);
|
|
377
|
-
deprecate(
|
|
378
|
-
`You passed in a PromiseProxy to a Relationship API that now expects a resolved value. await the value before setting it.`,
|
|
379
|
-
false,
|
|
380
|
-
{
|
|
381
|
-
id: 'ember-data:deprecate-promise-proxies',
|
|
382
|
-
until: '5.0',
|
|
383
|
-
since: {
|
|
384
|
-
enabled: '4.7',
|
|
385
|
-
available: '4.7',
|
|
386
|
-
},
|
|
387
|
-
for: 'ember-data',
|
|
388
|
-
}
|
|
389
|
-
);
|
|
390
|
-
assertRecordPassedToHasMany(content);
|
|
391
|
-
return recordIdentifierFor(content);
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
assertRecordPassedToHasMany(recordOrPromiseRecord);
|
|
396
|
-
return recordIdentifierFor(recordOrPromiseRecord);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
function isPromiseRecord(record: PromiseProxyRecord | RecordInstance): record is PromiseProxyRecord {
|
|
400
|
-
return !!record.then;
|
|
401
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { getOwner } from '@ember/application';
|
|
2
|
-
|
|
3
|
-
import type Store from '@ember-data/store';
|
|
4
|
-
|
|
5
|
-
import Model from './model';
|
|
6
|
-
|
|
7
|
-
/*
|
|
8
|
-
In case someone defined a relationship to a mixin, for example:
|
|
9
|
-
```
|
|
10
|
-
import Model, { belongsTo, hasMany } from '@ember-data/model';
|
|
11
|
-
import Mixin from '@ember/object/mixin';
|
|
12
|
-
|
|
13
|
-
class CommentModel extends Model {
|
|
14
|
-
@belongsTo('commentable', { polymorphic: true }) owner;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
let Commentable = Mixin.create({
|
|
18
|
-
@hasMany('comment') comments;
|
|
19
|
-
});
|
|
20
|
-
```
|
|
21
|
-
we want to look up a Commentable class which has all the necessary
|
|
22
|
-
relationship meta data. Thus, we look up the mixin and create a mock
|
|
23
|
-
Model, so we can access the relationship CPs of the mixin (`comments`)
|
|
24
|
-
in this case
|
|
25
|
-
*/
|
|
26
|
-
export default function modelForMixin(store: Store, normalizedModelName: string): Model | null {
|
|
27
|
-
let owner: any = getOwner(store);
|
|
28
|
-
let MaybeMixin = owner.factoryFor(`mixin:${normalizedModelName}`);
|
|
29
|
-
let mixin = MaybeMixin && MaybeMixin.class;
|
|
30
|
-
if (mixin) {
|
|
31
|
-
let ModelForMixin = Model.extend(mixin);
|
|
32
|
-
ModelForMixin.__isMixin = true;
|
|
33
|
-
ModelForMixin.__mixin = mixin;
|
|
34
|
-
//Cache the class as a model
|
|
35
|
-
owner.register('model:' + normalizedModelName, ModelForMixin);
|
|
36
|
-
}
|
|
37
|
-
return owner.factoryFor(`model:${normalizedModelName}`);
|
|
38
|
-
}
|