@ember-data/model 4.8.0-alpha.4 → 4.8.0-beta.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.
- package/addon/-private/belongs-to.js +4 -4
- package/addon/-private/deprecated-promise-proxy.ts +54 -0
- package/addon/-private/has-many.js +7 -5
- package/addon/-private/legacy-relationships-support.ts +182 -118
- package/addon/-private/many-array.ts +211 -249
- package/addon/-private/model.js +147 -73
- package/addon/-private/promise-belongs-to.ts +1 -1
- package/addon/-private/promise-many-array.ts +35 -13
- package/addon/-private/promise-proxy-base.js +4 -0
- package/addon/-private/record-state.ts +1 -1
- package/addon/-private/references/belongs-to.ts +35 -13
- package/addon/-private/references/has-many.ts +40 -17
- package/addon/-private/relationship-meta.ts +3 -1
- package/index.js +2 -0
- package/package.json +6 -6
package/addon/-private/model.js
CHANGED
|
@@ -7,8 +7,6 @@ import EmberError from '@ember/error';
|
|
|
7
7
|
import EmberObject from '@ember/object';
|
|
8
8
|
import { dependentKeyCompat } from '@ember/object/compat';
|
|
9
9
|
import { run } from '@ember/runloop';
|
|
10
|
-
import { inject as service } from '@ember/service';
|
|
11
|
-
import { isNone } from '@ember/utils';
|
|
12
10
|
import { DEBUG } from '@glimmer/env';
|
|
13
11
|
import { tracked } from '@glimmer/tracking';
|
|
14
12
|
import Ember from 'ember';
|
|
@@ -19,12 +17,14 @@ import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
|
|
|
19
17
|
import {
|
|
20
18
|
DEPRECATE_EARLY_STATIC,
|
|
21
19
|
DEPRECATE_MODEL_REOPEN,
|
|
20
|
+
DEPRECATE_NON_EXPLICIT_POLYMORPHISM,
|
|
22
21
|
DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
|
|
23
22
|
DEPRECATE_SAVE_PROMISE_ACCESS,
|
|
24
23
|
} from '@ember-data/private-build-infra/deprecations';
|
|
25
24
|
import { recordIdentifierFor, storeFor } from '@ember-data/store';
|
|
26
|
-
import { coerceId,
|
|
25
|
+
import { coerceId, recordDataFor } from '@ember-data/store/-private';
|
|
27
26
|
|
|
27
|
+
import { deprecatedPromiseObject } from './deprecated-promise-proxy';
|
|
28
28
|
import Errors from './errors';
|
|
29
29
|
import { LegacySupport } from './legacy-relationships-support';
|
|
30
30
|
import notifyChanges from './notify-changes';
|
|
@@ -32,18 +32,21 @@ import RecordState, { peekTag, tagged } from './record-state';
|
|
|
32
32
|
import { relationshipFromMeta } from './relationship-meta';
|
|
33
33
|
|
|
34
34
|
const { changeProperties } = Ember;
|
|
35
|
-
export const LEGACY_SUPPORT = new
|
|
36
|
-
|
|
35
|
+
export const LEGACY_SUPPORT = new Map();
|
|
36
|
+
|
|
37
|
+
export function lookupLegacySupport(record) {
|
|
37
38
|
const identifier = recordIdentifierFor(record);
|
|
38
39
|
let support = LEGACY_SUPPORT.get(identifier);
|
|
39
40
|
|
|
40
41
|
if (!support) {
|
|
41
42
|
support = new LegacySupport(record);
|
|
42
43
|
LEGACY_SUPPORT.set(identifier, support);
|
|
44
|
+
LEGACY_SUPPORT.set(record, support);
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
return support;
|
|
46
|
-
}
|
|
48
|
+
}
|
|
49
|
+
|
|
47
50
|
function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
|
|
48
51
|
let possibleRelationships = relationshipsSoFar || [];
|
|
49
52
|
|
|
@@ -55,7 +58,7 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
|
|
|
55
58
|
let relationshipsForType = relationshipMap.get(type.modelName);
|
|
56
59
|
let relationships = Array.isArray(relationshipsForType)
|
|
57
60
|
? relationshipsForType.filter((relationship) => {
|
|
58
|
-
let optionsForRelationship =
|
|
61
|
+
let optionsForRelationship = relationship.options;
|
|
59
62
|
|
|
60
63
|
if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) {
|
|
61
64
|
return true;
|
|
@@ -119,7 +122,6 @@ function computeOnce(target, key, desc) {
|
|
|
119
122
|
@extends Ember.EmberObject
|
|
120
123
|
*/
|
|
121
124
|
class Model extends EmberObject {
|
|
122
|
-
@service store;
|
|
123
125
|
___private_notifications;
|
|
124
126
|
|
|
125
127
|
init(options = {}) {
|
|
@@ -130,29 +132,29 @@ class Model extends EmberObject {
|
|
|
130
132
|
}
|
|
131
133
|
const createProps = options._createProps;
|
|
132
134
|
const _secretInit = options._secretInit;
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
options._createProps = null;
|
|
136
|
+
options._secretInit = null;
|
|
137
|
+
|
|
138
|
+
let store = (this.store = _secretInit.store);
|
|
135
139
|
super.init(options);
|
|
136
140
|
|
|
137
|
-
_secretInit
|
|
141
|
+
let identity = _secretInit.identifier;
|
|
142
|
+
_secretInit.cb(this, _secretInit.recordData, identity, _secretInit.store);
|
|
143
|
+
|
|
138
144
|
this.___recordState = DEBUG ? new RecordState(this) : null;
|
|
139
145
|
|
|
140
146
|
this.setProperties(createProps);
|
|
141
147
|
|
|
142
|
-
let store = storeFor(this);
|
|
143
148
|
let notifications = store._notificationManager;
|
|
144
|
-
let identity = recordIdentifierFor(this);
|
|
145
|
-
|
|
146
149
|
this.___private_notifications = notifications.subscribe(identity, (identifier, type, key) => {
|
|
147
150
|
notifyChanges(identifier, type, key, this, store);
|
|
148
151
|
});
|
|
149
152
|
}
|
|
150
153
|
|
|
151
154
|
destroy() {
|
|
152
|
-
|
|
155
|
+
const identifier = recordIdentifierFor(this);
|
|
153
156
|
this.___recordState?.destroy();
|
|
154
157
|
const store = storeFor(this);
|
|
155
|
-
const identifier = recordIdentifierFor(this);
|
|
156
158
|
store._notificationManager.unsubscribe(this.___private_notifications);
|
|
157
159
|
// Legacy behavior is to notify the relationships on destroy
|
|
158
160
|
// such that they "clear". It's uncertain this behavior would
|
|
@@ -160,7 +162,16 @@ class Model extends EmberObject {
|
|
|
160
162
|
// to simply not notify, for this reason the store does not itself
|
|
161
163
|
// notify individual changes once the delete has been signaled,
|
|
162
164
|
// this decision is left to model instances.
|
|
163
|
-
|
|
165
|
+
|
|
166
|
+
this.eachRelationship((key, meta) => {
|
|
167
|
+
if (meta.kind === 'belongsTo') {
|
|
168
|
+
this.notifyPropertyChange(key);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
LEGACY_SUPPORT.get(this)?.destroy();
|
|
172
|
+
LEGACY_SUPPORT.delete(this);
|
|
173
|
+
LEGACY_SUPPORT.delete(identifier);
|
|
174
|
+
|
|
164
175
|
super.destroy();
|
|
165
176
|
}
|
|
166
177
|
|
|
@@ -493,9 +504,8 @@ class Model extends EmberObject {
|
|
|
493
504
|
}
|
|
494
505
|
}
|
|
495
506
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
return this.id;
|
|
507
|
+
toString() {
|
|
508
|
+
return `<model::${this.constructor.modelName}:${this.id}>`;
|
|
499
509
|
}
|
|
500
510
|
|
|
501
511
|
/**
|
|
@@ -838,12 +848,15 @@ class Model extends EmberObject {
|
|
|
838
848
|
rollbackAttributes() {
|
|
839
849
|
const { currentState } = this;
|
|
840
850
|
const { isNew } = currentState;
|
|
841
|
-
|
|
842
|
-
this.
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
851
|
+
|
|
852
|
+
storeFor(this)._join(() => {
|
|
853
|
+
recordDataFor(this).rollbackAttrs(recordIdentifierFor(this));
|
|
854
|
+
this.errors.clear();
|
|
855
|
+
currentState.cleanErrorRequests();
|
|
856
|
+
if (isNew) {
|
|
857
|
+
this.unloadRecord();
|
|
858
|
+
}
|
|
859
|
+
});
|
|
847
860
|
}
|
|
848
861
|
|
|
849
862
|
/**
|
|
@@ -1037,7 +1050,7 @@ class Model extends EmberObject {
|
|
|
1037
1050
|
@return {BelongsToReference} reference for this relationship
|
|
1038
1051
|
*/
|
|
1039
1052
|
belongsTo(name) {
|
|
1040
|
-
return
|
|
1053
|
+
return lookupLegacySupport(this).referenceFor('belongsTo', name);
|
|
1041
1054
|
}
|
|
1042
1055
|
|
|
1043
1056
|
/**
|
|
@@ -1100,7 +1113,7 @@ class Model extends EmberObject {
|
|
|
1100
1113
|
@return {HasManyReference} reference for this relationship
|
|
1101
1114
|
*/
|
|
1102
1115
|
hasMany(name) {
|
|
1103
|
-
return
|
|
1116
|
+
return lookupLegacySupport(this).referenceFor('hasMany', name);
|
|
1104
1117
|
}
|
|
1105
1118
|
|
|
1106
1119
|
/**
|
|
@@ -1142,7 +1155,7 @@ class Model extends EmberObject {
|
|
|
1142
1155
|
record.eachRelationship(function(name, descriptor) {
|
|
1143
1156
|
if (descriptor.kind === 'hasMany') {
|
|
1144
1157
|
let serializedHasManyName = name.toUpperCase() + '_IDS';
|
|
1145
|
-
json[serializedHasManyName] = record.get(name).
|
|
1158
|
+
json[serializedHasManyName] = record.get(name).map(r => r.id);
|
|
1146
1159
|
}
|
|
1147
1160
|
});
|
|
1148
1161
|
|
|
@@ -1381,42 +1394,46 @@ class Model extends EmberObject {
|
|
|
1381
1394
|
this.modelName
|
|
1382
1395
|
);
|
|
1383
1396
|
}
|
|
1384
|
-
let inverseType = this.typeForRelationship(name, store);
|
|
1385
|
-
if (!inverseType) {
|
|
1386
|
-
return null;
|
|
1387
|
-
}
|
|
1388
1397
|
|
|
1389
|
-
|
|
1398
|
+
const relationship = this.relationshipsByName.get(name);
|
|
1399
|
+
const { options } = relationship;
|
|
1400
|
+
const isPolymorphic = options.polymorphic;
|
|
1401
|
+
|
|
1390
1402
|
//If inverse is manually specified to be null, like `comments: hasMany('message', { inverse: null })`
|
|
1391
|
-
|
|
1392
|
-
|
|
1403
|
+
const isExplicitInverseNull = options.inverse === null;
|
|
1404
|
+
const isAbstractType =
|
|
1405
|
+
!isExplicitInverseNull && isPolymorphic && !store.getSchemaDefinitionService().doesTypeExist(relationship.type);
|
|
1406
|
+
|
|
1407
|
+
if (isExplicitInverseNull || isAbstractType) {
|
|
1408
|
+
assert(
|
|
1409
|
+
`No schema for the abstract type '${relationship.type}' for the polymorphic relationship '${name}' on '${this.modelName}' was provided by the SchemaDefinitionService.`,
|
|
1410
|
+
!isPolymorphic || isExplicitInverseNull
|
|
1411
|
+
);
|
|
1393
1412
|
return null;
|
|
1394
1413
|
}
|
|
1395
1414
|
|
|
1396
|
-
let
|
|
1415
|
+
let fieldOnInverse, inverseKind, inverseRelationship, inverseOptions;
|
|
1416
|
+
let inverseSchema = this.typeForRelationship(name, store);
|
|
1397
1417
|
|
|
1418
|
+
// if the type does not exist and we are not polymorphic
|
|
1398
1419
|
//If inverse is specified manually, return the inverse
|
|
1399
|
-
if (options.inverse) {
|
|
1400
|
-
|
|
1401
|
-
|
|
1420
|
+
if (options.inverse !== undefined) {
|
|
1421
|
+
fieldOnInverse = options.inverse;
|
|
1422
|
+
inverseRelationship = inverseSchema && inverseSchema.relationshipsByName.get(fieldOnInverse);
|
|
1402
1423
|
|
|
1403
1424
|
assert(
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
"' on the '" +
|
|
1407
|
-
inverseType.modelName +
|
|
1408
|
-
"' model. This is most likely due to a missing attribute on your model definition.",
|
|
1409
|
-
!isNone(inverse)
|
|
1425
|
+
`We found no field named '${fieldOnInverse}' on the schema for '${inverseSchema.modelName}' to be the inverse of the '${name}' relationship on '${this.modelName}'. This is most likely due to a missing field on your model definition.`,
|
|
1426
|
+
inverseRelationship
|
|
1410
1427
|
);
|
|
1411
1428
|
|
|
1412
1429
|
// TODO probably just return the whole inverse here
|
|
1413
|
-
inverseKind =
|
|
1414
|
-
inverseOptions =
|
|
1430
|
+
inverseKind = inverseRelationship.kind;
|
|
1431
|
+
inverseOptions = inverseRelationship.options;
|
|
1415
1432
|
} else {
|
|
1416
1433
|
//No inverse was specified manually, we need to use a heuristic to guess one
|
|
1417
|
-
if (
|
|
1434
|
+
if (relationship.type === relationship.parentModelName) {
|
|
1418
1435
|
warn(
|
|
1419
|
-
`Detected a reflexive relationship
|
|
1436
|
+
`Detected a reflexive relationship named '${name}' on the schema for '${relationship.type}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`,
|
|
1420
1437
|
false,
|
|
1421
1438
|
{
|
|
1422
1439
|
id: 'ds.model.reflexive-relationship-without-inverse',
|
|
@@ -1424,30 +1441,33 @@ class Model extends EmberObject {
|
|
|
1424
1441
|
);
|
|
1425
1442
|
}
|
|
1426
1443
|
|
|
1427
|
-
let possibleRelationships = findPossibleInverses(this,
|
|
1444
|
+
let possibleRelationships = findPossibleInverses(this, inverseSchema, name);
|
|
1428
1445
|
|
|
1429
1446
|
if (possibleRelationships.length === 0) {
|
|
1430
1447
|
return null;
|
|
1431
1448
|
}
|
|
1432
1449
|
|
|
1433
|
-
|
|
1434
|
-
let
|
|
1435
|
-
|
|
1436
|
-
|
|
1450
|
+
if (DEBUG) {
|
|
1451
|
+
let filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
|
|
1452
|
+
let optionsForRelationship = possibleRelationship.options;
|
|
1453
|
+
return name === optionsForRelationship.inverse;
|
|
1454
|
+
});
|
|
1437
1455
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1456
|
+
assert(
|
|
1457
|
+
"You defined the '" +
|
|
1458
|
+
name +
|
|
1459
|
+
"' relationship on " +
|
|
1460
|
+
this +
|
|
1461
|
+
', but you defined the inverse relationships of type ' +
|
|
1462
|
+
inverseSchema.toString() +
|
|
1463
|
+
' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
|
|
1464
|
+
filteredRelationships.length < 2
|
|
1465
|
+
);
|
|
1466
|
+
}
|
|
1448
1467
|
|
|
1449
|
-
|
|
1450
|
-
|
|
1468
|
+
let explicitRelationship = possibleRelationships.find((relationship) => relationship.options.inverse === name);
|
|
1469
|
+
if (explicitRelationship) {
|
|
1470
|
+
possibleRelationships = [explicitRelationship];
|
|
1451
1471
|
}
|
|
1452
1472
|
|
|
1453
1473
|
assert(
|
|
@@ -1458,24 +1478,78 @@ class Model extends EmberObject {
|
|
|
1458
1478
|
', but multiple possible inverse relationships of type ' +
|
|
1459
1479
|
this +
|
|
1460
1480
|
' were found on ' +
|
|
1461
|
-
|
|
1481
|
+
inverseSchema +
|
|
1462
1482
|
'. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
|
|
1463
1483
|
possibleRelationships.length === 1
|
|
1464
1484
|
);
|
|
1465
1485
|
|
|
1466
|
-
|
|
1486
|
+
fieldOnInverse = possibleRelationships[0].name;
|
|
1467
1487
|
inverseKind = possibleRelationships[0].kind;
|
|
1468
1488
|
inverseOptions = possibleRelationships[0].options;
|
|
1469
1489
|
}
|
|
1470
1490
|
|
|
1491
|
+
// ensure inverse is properly configured
|
|
1492
|
+
if (DEBUG && isPolymorphic) {
|
|
1493
|
+
if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
|
|
1494
|
+
if (!inverseOptions.as) {
|
|
1495
|
+
deprecate(
|
|
1496
|
+
`Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
|
|
1497
|
+
false,
|
|
1498
|
+
{
|
|
1499
|
+
id: 'ember-data:non-explicit-relationships',
|
|
1500
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
1501
|
+
until: '5.0',
|
|
1502
|
+
for: 'ember-data',
|
|
1503
|
+
}
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
} else {
|
|
1507
|
+
assert(
|
|
1508
|
+
`Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${fieldOnInverse}' on type '${inverseSchema.modelName}' is misconfigured.`,
|
|
1509
|
+
inverseOptions.as
|
|
1510
|
+
);
|
|
1511
|
+
assert(
|
|
1512
|
+
`options.as should match the expected type of the polymorphic relationship. Expected field '${fieldOnInverse}' on type '${inverseSchema.modelName}' to specify '${relationship.type}' but found '${inverseOptions.as}'`,
|
|
1513
|
+
!!inverseOptions.as && relationship.type === inverseOptions.as
|
|
1514
|
+
);
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1518
|
+
// ensure we are properly configured
|
|
1519
|
+
if (DEBUG && inverseOptions.polymorphic) {
|
|
1520
|
+
if (DEPRECATE_NON_EXPLICIT_POLYMORPHISM) {
|
|
1521
|
+
if (!options.as) {
|
|
1522
|
+
deprecate(
|
|
1523
|
+
`Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${this.modelName}' is misconfigured.`,
|
|
1524
|
+
false,
|
|
1525
|
+
{
|
|
1526
|
+
id: 'ember-data:non-explicit-relationships',
|
|
1527
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
1528
|
+
until: '5.0',
|
|
1529
|
+
for: 'ember-data',
|
|
1530
|
+
}
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
} else {
|
|
1534
|
+
assert(
|
|
1535
|
+
`Relationships that satisfy polymorphic relationships MUST define which abstract-type they are satisfying using 'as'. The field '${name}' on type '${this.modelName}' is misconfigured.`,
|
|
1536
|
+
options.as
|
|
1537
|
+
);
|
|
1538
|
+
assert(
|
|
1539
|
+
`options.as should match the expected type of the polymorphic relationship. Expected field '${name}' on type '${this.modelName}' to specify '${inverseRelationship.type}' but found '${options.as}'`,
|
|
1540
|
+
!!options.as && inverseRelationship.type === options.as
|
|
1541
|
+
);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1471
1545
|
assert(
|
|
1472
|
-
`The ${
|
|
1473
|
-
|
|
1546
|
+
`The ${inverseSchema.modelName}:${fieldOnInverse} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`,
|
|
1547
|
+
inverseOptions.inverse !== null
|
|
1474
1548
|
);
|
|
1475
1549
|
|
|
1476
1550
|
return {
|
|
1477
|
-
type:
|
|
1478
|
-
name:
|
|
1551
|
+
type: inverseSchema,
|
|
1552
|
+
name: fieldOnInverse,
|
|
1479
1553
|
kind: inverseKind,
|
|
1480
1554
|
options: inverseOptions,
|
|
1481
1555
|
};
|
|
@@ -4,11 +4,11 @@ import type PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
|
|
|
4
4
|
import type ObjectProxy from '@ember/object/proxy';
|
|
5
5
|
|
|
6
6
|
import type Store from '@ember-data/store';
|
|
7
|
-
import { PromiseObject } from '@ember-data/store/-private';
|
|
8
7
|
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
9
8
|
import type { Dict } from '@ember-data/types/q/utils';
|
|
10
9
|
|
|
11
10
|
import { LegacySupport } from './legacy-relationships-support';
|
|
11
|
+
import { PromiseObject } from './promise-proxy-base';
|
|
12
12
|
|
|
13
13
|
export interface BelongsToProxyMeta {
|
|
14
14
|
key: string;
|
|
@@ -2,18 +2,23 @@ import ArrayMixin, { NativeArray } from '@ember/array';
|
|
|
2
2
|
import type ArrayProxy from '@ember/array/proxy';
|
|
3
3
|
import { assert, deprecate } from '@ember/debug';
|
|
4
4
|
import { dependentKeyCompat } from '@ember/object/compat';
|
|
5
|
+
import { DEBUG } from '@glimmer/env';
|
|
5
6
|
import { tracked } from '@glimmer/tracking';
|
|
6
7
|
import Ember from 'ember';
|
|
7
8
|
|
|
8
9
|
import { resolve } from 'rsvp';
|
|
9
10
|
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
import {
|
|
12
|
+
DEPRECATE_A_USAGE,
|
|
13
|
+
DEPRECATE_COMPUTED_CHAINS,
|
|
14
|
+
DEPRECATE_PROMISE_MANY_ARRAY_BEHAVIORS,
|
|
15
|
+
} from '@ember-data/private-build-infra/deprecations';
|
|
13
16
|
import { StableRecordIdentifier } from '@ember-data/types/q/identifier';
|
|
14
17
|
import type { RecordInstance } from '@ember-data/types/q/record-instance';
|
|
15
18
|
import { FindOptions } from '@ember-data/types/q/store';
|
|
16
19
|
|
|
20
|
+
import type ManyArray from './many-array';
|
|
21
|
+
|
|
17
22
|
export interface HasManyProxyCreateArgs {
|
|
18
23
|
promise: Promise<ManyArray>;
|
|
19
24
|
content?: ManyArray;
|
|
@@ -53,13 +58,27 @@ export default class PromiseManyArray {
|
|
|
53
58
|
this.isDestroyed = false;
|
|
54
59
|
this.isDestroying = false;
|
|
55
60
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
if (DEPRECATE_A_USAGE) {
|
|
62
|
+
const meta = Ember.meta(this);
|
|
63
|
+
meta.hasMixin = (mixin: Object) => {
|
|
64
|
+
deprecate(`Do not use A() on an EmberData PromiseManyArray`, false, {
|
|
65
|
+
id: 'ember-data:no-a-with-array-like',
|
|
66
|
+
until: '5.0',
|
|
67
|
+
since: { enabled: '4.8', available: '4.8' },
|
|
68
|
+
for: 'ember-data',
|
|
69
|
+
});
|
|
70
|
+
// @ts-expect-error ArrayMixin is more than a type
|
|
71
|
+
if (mixin === NativeArray || mixin === ArrayMixin) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
};
|
|
76
|
+
} else if (DEBUG) {
|
|
77
|
+
const meta = Ember.meta(this);
|
|
78
|
+
meta.hasMixin = (mixin: Object) => {
|
|
79
|
+
assert(`Do not use A() on an EmberData PromiseManyArray`);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
63
82
|
}
|
|
64
83
|
|
|
65
84
|
//---- Methods/Properties on ArrayProxy that we will keep as our API
|
|
@@ -75,7 +94,9 @@ export default class PromiseManyArray {
|
|
|
75
94
|
get length(): number {
|
|
76
95
|
// shouldn't be needed, but ends up being needed
|
|
77
96
|
// for computed chains even in 4.x
|
|
78
|
-
|
|
97
|
+
if (DEPRECATE_COMPUTED_CHAINS) {
|
|
98
|
+
this['[]'];
|
|
99
|
+
}
|
|
79
100
|
return this.content ? this.content.length : 0;
|
|
80
101
|
}
|
|
81
102
|
|
|
@@ -85,7 +106,9 @@ export default class PromiseManyArray {
|
|
|
85
106
|
// to recompute. We entangle the '[]' tag from
|
|
86
107
|
@dependentKeyCompat
|
|
87
108
|
get '[]'() {
|
|
88
|
-
|
|
109
|
+
if (DEPRECATE_COMPUTED_CHAINS) {
|
|
110
|
+
return this.content?.length && this.content;
|
|
111
|
+
}
|
|
89
112
|
}
|
|
90
113
|
|
|
91
114
|
/**
|
|
@@ -99,7 +122,6 @@ export default class PromiseManyArray {
|
|
|
99
122
|
* @private
|
|
100
123
|
*/
|
|
101
124
|
forEach(cb) {
|
|
102
|
-
this['[]']; // needed for < 3.23 support e.g. 3.20 lts
|
|
103
125
|
if (this.content && this.length) {
|
|
104
126
|
this.content.forEach(cb);
|
|
105
127
|
}
|
|
@@ -105,7 +105,7 @@ export function tagged(_target, key, desc) {
|
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
Historically EmberData managed a state machine
|
|
108
|
-
for each record, the
|
|
108
|
+
for each record, the localState for which
|
|
109
109
|
was reflected onto Model.
|
|
110
110
|
|
|
111
111
|
This implements the flags and stateName for backwards compat
|
|
@@ -1,15 +1,17 @@
|
|
|
1
|
+
import { deprecate } from '@ember/debug';
|
|
1
2
|
import { dependentKeyCompat } from '@ember/object/compat';
|
|
2
3
|
import { cached, tracked } from '@glimmer/tracking';
|
|
3
4
|
|
|
4
5
|
import type { Object as JSONObject, Value as JSONValue } from 'json-typescript';
|
|
5
6
|
import { resolve } from 'rsvp';
|
|
6
7
|
|
|
7
|
-
import
|
|
8
|
+
import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
|
|
9
|
+
import type { Graph } from '@ember-data/record-data/-private/graph/graph';
|
|
10
|
+
import type BelongsToRelationship from '@ember-data/record-data/-private/relationships/state/belongs-to';
|
|
8
11
|
import type Store from '@ember-data/store';
|
|
9
12
|
import { assertPolymorphicType } from '@ember-data/store/-debug';
|
|
10
13
|
import { recordIdentifierFor } from '@ember-data/store/-private';
|
|
11
14
|
import type { NotificationType } from '@ember-data/store/-private/managers/record-notification-manager';
|
|
12
|
-
import type { DebugWeakCache } from '@ember-data/store/-private/utils/weak-cache';
|
|
13
15
|
import type {
|
|
14
16
|
LinkObject,
|
|
15
17
|
Links,
|
|
@@ -54,6 +56,7 @@ export default class BelongsToReference {
|
|
|
54
56
|
declare type: string;
|
|
55
57
|
___identifier: StableRecordIdentifier;
|
|
56
58
|
declare store: Store;
|
|
59
|
+
declare graph: Graph;
|
|
57
60
|
|
|
58
61
|
// unsubscribe tokens given to us by the notification manager
|
|
59
62
|
___token!: object;
|
|
@@ -63,10 +66,12 @@ export default class BelongsToReference {
|
|
|
63
66
|
|
|
64
67
|
constructor(
|
|
65
68
|
store: Store,
|
|
69
|
+
graph: Graph,
|
|
66
70
|
parentIdentifier: StableRecordIdentifier,
|
|
67
71
|
belongsToRelationship: BelongsToRelationship,
|
|
68
72
|
key: string
|
|
69
73
|
) {
|
|
74
|
+
this.graph = graph;
|
|
70
75
|
this.key = key;
|
|
71
76
|
this.belongsToRelationship = belongsToRelationship;
|
|
72
77
|
this.type = belongsToRelationship.definition.type;
|
|
@@ -382,8 +387,25 @@ export default class BelongsToReference {
|
|
|
382
387
|
@return {Promise<record>} A promise that resolves with the new value in this belongs-to relationship.
|
|
383
388
|
*/
|
|
384
389
|
async push(data: SingleResourceDocument | Promise<SingleResourceDocument>): Promise<RecordInstance> {
|
|
385
|
-
|
|
386
|
-
|
|
390
|
+
let jsonApiDoc: SingleResourceDocument = data as SingleResourceDocument;
|
|
391
|
+
if (DEPRECATE_PROMISE_PROXIES && (data as { then: unknown }).then) {
|
|
392
|
+
jsonApiDoc = await resolve(data);
|
|
393
|
+
if (jsonApiDoc !== data) {
|
|
394
|
+
deprecate(
|
|
395
|
+
`You passed in a Promise to a Reference API that now expects a resolved value. await the value before setting it.`,
|
|
396
|
+
false,
|
|
397
|
+
{
|
|
398
|
+
id: 'ember-data:deprecate-promise-proxies',
|
|
399
|
+
until: '5.0',
|
|
400
|
+
since: {
|
|
401
|
+
enabled: '4.8',
|
|
402
|
+
available: '4.8',
|
|
403
|
+
},
|
|
404
|
+
for: 'ember-data',
|
|
405
|
+
}
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
387
409
|
let record = this.store.push(jsonApiDoc);
|
|
388
410
|
|
|
389
411
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
@@ -394,9 +416,9 @@ export default class BelongsToReference {
|
|
|
394
416
|
this.store
|
|
395
417
|
);
|
|
396
418
|
|
|
397
|
-
const {
|
|
398
|
-
this.store.
|
|
399
|
-
graph.push({
|
|
419
|
+
const { identifier } = this.belongsToRelationship;
|
|
420
|
+
this.store._join(() => {
|
|
421
|
+
this.graph.push({
|
|
400
422
|
op: 'replaceRelatedRecord',
|
|
401
423
|
record: identifier,
|
|
402
424
|
field: this.key,
|
|
@@ -525,9 +547,9 @@ export default class BelongsToReference {
|
|
|
525
547
|
@return {Promise} a promise that resolves with the record in this belongs-to relationship.
|
|
526
548
|
*/
|
|
527
549
|
load(options?: Dict<unknown>) {
|
|
528
|
-
const support: LegacySupport = (
|
|
529
|
-
|
|
530
|
-
)
|
|
550
|
+
const support: LegacySupport = (LEGACY_SUPPORT as Map<StableRecordIdentifier, LegacySupport>).get(
|
|
551
|
+
this.___identifier
|
|
552
|
+
)!;
|
|
531
553
|
return support.getBelongsTo(this.key, options);
|
|
532
554
|
}
|
|
533
555
|
|
|
@@ -582,9 +604,9 @@ export default class BelongsToReference {
|
|
|
582
604
|
@return {Promise} a promise that resolves with the record in this belongs-to relationship after the reload has completed.
|
|
583
605
|
*/
|
|
584
606
|
reload(options?: Dict<unknown>) {
|
|
585
|
-
const support: LegacySupport = (
|
|
586
|
-
|
|
587
|
-
)
|
|
607
|
+
const support: LegacySupport = (LEGACY_SUPPORT as Map<StableRecordIdentifier, LegacySupport>).get(
|
|
608
|
+
this.___identifier
|
|
609
|
+
)!;
|
|
588
610
|
return support.reloadBelongsTo(this.key, options).then(() => this.value());
|
|
589
611
|
}
|
|
590
612
|
}
|