@ember-data/model 4.8.0-alpha.6 → 4.9.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -150,10 +150,11 @@ export class LegacySupport {
150
150
  }
151
151
 
152
152
  let promise = this._findBelongsTo(key, resource, relationship, options);
153
+ const isLoaded = relatedIdentifier && store._instanceCache.recordIsLoaded(relatedIdentifier);
153
154
 
154
155
  return this._updatePromiseProxyFor('belongsTo', key, {
155
156
  promise,
156
- content: relatedIdentifier ? store._instanceCache.getRecord(relatedIdentifier) : null,
157
+ content: isLoaded ? store._instanceCache.getRecord(relatedIdentifier!) : null,
157
158
  _belongsToState,
158
159
  });
159
160
  } else {
@@ -210,38 +211,40 @@ export class LegacySupport {
210
211
  }
211
212
 
212
213
  getManyArray(key: string, definition?: UpgradedMeta): RelatedCollection {
213
- assert('hasMany only works with the @ember-data/record-data package', HAS_RECORD_DATA_PACKAGE);
214
- let manyArray: RelatedCollection | undefined = this._manyArrayCache[key];
215
- if (!definition) {
216
- const graphFor = (
217
- importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
218
- ).graphFor;
219
- definition = graphFor(this.store).get(this.identifier, key).definition;
220
- }
214
+ if (HAS_RECORD_DATA_PACKAGE) {
215
+ let manyArray: RelatedCollection | undefined = this._manyArrayCache[key];
216
+ if (!definition) {
217
+ const graphFor = (
218
+ importSync('@ember-data/record-data/-private') as typeof import('@ember-data/record-data/-private')
219
+ ).graphFor;
220
+ definition = graphFor(this.store).get(this.identifier, key).definition;
221
+ }
221
222
 
222
- if (!manyArray) {
223
- const [identifiers, doc] = this._getCurrentState(this.identifier, key);
224
-
225
- manyArray = new RelatedCollection({
226
- store: this.store,
227
- type: definition.type,
228
- identifier: this.identifier,
229
- recordData: this.recordData,
230
- identifiers,
231
- key,
232
- meta: doc.meta || null,
233
- links: doc.links || null,
234
- isPolymorphic: definition.isPolymorphic,
235
- isAsync: definition.isAsync,
236
- _inverseIsAsync: definition.inverseIsAsync,
237
- manager: this,
238
- isLoaded: !definition.isAsync,
239
- allowMutation: true,
240
- });
241
- this._manyArrayCache[key] = manyArray;
242
- }
223
+ if (!manyArray) {
224
+ const [identifiers, doc] = this._getCurrentState(this.identifier, key);
225
+
226
+ manyArray = new RelatedCollection({
227
+ store: this.store,
228
+ type: definition.type,
229
+ identifier: this.identifier,
230
+ recordData: this.recordData,
231
+ identifiers,
232
+ key,
233
+ meta: doc.meta || null,
234
+ links: doc.links || null,
235
+ isPolymorphic: definition.isPolymorphic,
236
+ isAsync: definition.isAsync,
237
+ _inverseIsAsync: definition.inverseIsAsync,
238
+ manager: this,
239
+ isLoaded: !definition.isAsync,
240
+ allowMutation: true,
241
+ });
242
+ this._manyArrayCache[key] = manyArray;
243
+ }
243
244
 
244
- return manyArray;
245
+ return manyArray;
246
+ }
247
+ assert('hasMany only works with the @ember-data/record-data package');
245
248
  }
246
249
 
247
250
  fetchAsyncHasMany(
@@ -7,7 +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 { isNone } from '@ember/utils';
11
10
  import { DEBUG } from '@glimmer/env';
12
11
  import { tracked } from '@glimmer/tracking';
13
12
  import Ember from 'ember';
@@ -18,6 +17,7 @@ import { HAS_DEBUG_PACKAGE } from '@ember-data/private-build-infra';
18
17
  import {
19
18
  DEPRECATE_EARLY_STATIC,
20
19
  DEPRECATE_MODEL_REOPEN,
20
+ DEPRECATE_NON_EXPLICIT_POLYMORPHISM,
21
21
  DEPRECATE_RELATIONSHIPS_WITHOUT_INVERSE,
22
22
  DEPRECATE_SAVE_PROMISE_ACCESS,
23
23
  } from '@ember-data/private-build-infra/deprecations';
@@ -58,7 +58,7 @@ function findPossibleInverses(type, inverseType, name, relationshipsSoFar) {
58
58
  let relationshipsForType = relationshipMap.get(type.modelName);
59
59
  let relationships = Array.isArray(relationshipsForType)
60
60
  ? relationshipsForType.filter((relationship) => {
61
- let optionsForRelationship = inverseType.metaForProperty(relationship.name).options;
61
+ let optionsForRelationship = relationship.options;
62
62
 
63
63
  if (!optionsForRelationship.inverse && optionsForRelationship.inverse !== null) {
64
64
  return true;
@@ -1394,42 +1394,46 @@ class Model extends EmberObject {
1394
1394
  this.modelName
1395
1395
  );
1396
1396
  }
1397
- let inverseType = this.typeForRelationship(name, store);
1398
- if (!inverseType) {
1399
- return null;
1400
- }
1401
1397
 
1402
- let propertyMeta = this.metaForProperty(name);
1398
+ const relationship = this.relationshipsByName.get(name);
1399
+ const { options } = relationship;
1400
+ const isPolymorphic = options.polymorphic;
1401
+
1403
1402
  //If inverse is manually specified to be null, like `comments: hasMany('message', { inverse: null })`
1404
- let options = propertyMeta.options;
1405
- if (options.inverse === null) {
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
+ );
1406
1412
  return null;
1407
1413
  }
1408
1414
 
1409
- let inverseName, inverseKind, inverse, inverseOptions;
1415
+ let fieldOnInverse, inverseKind, inverseRelationship, inverseOptions;
1416
+ let inverseSchema = this.typeForRelationship(name, store);
1410
1417
 
1418
+ // if the type does not exist and we are not polymorphic
1411
1419
  //If inverse is specified manually, return the inverse
1412
- if (options.inverse) {
1413
- inverseName = options.inverse;
1414
- inverse = inverseType.relationshipsByName.get(inverseName);
1420
+ if (options.inverse !== undefined) {
1421
+ fieldOnInverse = options.inverse;
1422
+ inverseRelationship = inverseSchema && inverseSchema.relationshipsByName.get(fieldOnInverse);
1415
1423
 
1416
1424
  assert(
1417
- "We found no inverse relationships by the name of '" +
1418
- inverseName +
1419
- "' on the '" +
1420
- inverseType.modelName +
1421
- "' model. This is most likely due to a missing attribute on your model definition.",
1422
- !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
1423
1427
  );
1424
1428
 
1425
1429
  // TODO probably just return the whole inverse here
1426
- inverseKind = inverse.kind;
1427
- inverseOptions = inverse.options;
1430
+ inverseKind = inverseRelationship.kind;
1431
+ inverseOptions = inverseRelationship.options;
1428
1432
  } else {
1429
1433
  //No inverse was specified manually, we need to use a heuristic to guess one
1430
- if (propertyMeta.type === propertyMeta.parentModelName) {
1434
+ if (relationship.type === relationship.parentModelName) {
1431
1435
  warn(
1432
- `Detected a reflexive relationship by the name of '${name}' without an inverse option. Look at https://guides.emberjs.com/current/models/relationships/#toc_reflexive-relations for how to explicitly specify inverses.`,
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.`,
1433
1437
  false,
1434
1438
  {
1435
1439
  id: 'ds.model.reflexive-relationship-without-inverse',
@@ -1437,30 +1441,33 @@ class Model extends EmberObject {
1437
1441
  );
1438
1442
  }
1439
1443
 
1440
- let possibleRelationships = findPossibleInverses(this, inverseType, name);
1444
+ let possibleRelationships = findPossibleInverses(this, inverseSchema, name);
1441
1445
 
1442
1446
  if (possibleRelationships.length === 0) {
1443
1447
  return null;
1444
1448
  }
1445
1449
 
1446
- let filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
1447
- let optionsForRelationship = inverseType.metaForProperty(possibleRelationship.name).options;
1448
- return name === optionsForRelationship.inverse;
1449
- });
1450
+ if (DEBUG) {
1451
+ let filteredRelationships = possibleRelationships.filter((possibleRelationship) => {
1452
+ let optionsForRelationship = possibleRelationship.options;
1453
+ return name === optionsForRelationship.inverse;
1454
+ });
1450
1455
 
1451
- assert(
1452
- "You defined the '" +
1453
- name +
1454
- "' relationship on " +
1455
- this +
1456
- ', but you defined the inverse relationships of type ' +
1457
- inverseType.toString() +
1458
- ' multiple times. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
1459
- filteredRelationships.length < 2
1460
- );
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
+ }
1461
1467
 
1462
- if (filteredRelationships.length === 1) {
1463
- possibleRelationships = filteredRelationships;
1468
+ let explicitRelationship = possibleRelationships.find((relationship) => relationship.options.inverse === name);
1469
+ if (explicitRelationship) {
1470
+ possibleRelationships = [explicitRelationship];
1464
1471
  }
1465
1472
 
1466
1473
  assert(
@@ -1471,24 +1478,78 @@ class Model extends EmberObject {
1471
1478
  ', but multiple possible inverse relationships of type ' +
1472
1479
  this +
1473
1480
  ' were found on ' +
1474
- inverseType +
1481
+ inverseSchema +
1475
1482
  '. Look at https://guides.emberjs.com/current/models/relationships/#toc_explicit-inverses for how to explicitly specify inverses',
1476
1483
  possibleRelationships.length === 1
1477
1484
  );
1478
1485
 
1479
- inverseName = possibleRelationships[0].name;
1486
+ fieldOnInverse = possibleRelationships[0].name;
1480
1487
  inverseKind = possibleRelationships[0].kind;
1481
1488
  inverseOptions = possibleRelationships[0].options;
1482
1489
  }
1483
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
+
1484
1545
  assert(
1485
- `The ${inverseType.modelName}:${inverseName} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`,
1486
- !inverseOptions || inverseOptions.inverse !== null
1546
+ `The ${inverseSchema.modelName}:${fieldOnInverse} relationship declares 'inverse: null', but it was resolved as the inverse for ${this.modelName}:${name}.`,
1547
+ inverseOptions.inverse !== null
1487
1548
  );
1488
1549
 
1489
1550
  return {
1490
- type: inverseType,
1491
- name: inverseName,
1551
+ type: inverseSchema,
1552
+ name: fieldOnInverse,
1492
1553
  kind: inverseKind,
1493
1554
  options: inverseOptions,
1494
1555
  };
@@ -6,7 +6,7 @@ import type { Object as JSONObject, Value as JSONValue } from 'json-typescript';
6
6
  import { resolve } from 'rsvp';
7
7
 
8
8
  import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
9
- import type { Graph } from '@ember-data/record-data/-private/graph';
9
+ import type { Graph } from '@ember-data/record-data/-private/graph/graph';
10
10
  import type BelongsToRelationship from '@ember-data/record-data/-private/relationships/state/belongs-to';
11
11
  import type Store from '@ember-data/store';
12
12
  import { assertPolymorphicType } from '@ember-data/store/-debug';
@@ -9,7 +9,7 @@ import { resolve } from 'rsvp';
9
9
  import { ManyArray } from 'ember-data/-private';
10
10
 
11
11
  import { DEPRECATE_PROMISE_PROXIES } from '@ember-data/private-build-infra/deprecations';
12
- import type { Graph } from '@ember-data/record-data/-private/graph';
12
+ import type { Graph } from '@ember-data/record-data/-private/graph/graph';
13
13
  import type ManyRelationship from '@ember-data/record-data/-private/relationships/state/has-many';
14
14
  import type Store from '@ember-data/store';
15
15
  import { recordIdentifierFor } from '@ember-data/store';
@@ -75,7 +75,9 @@ class RelationshipDefinition implements RelationshipSchema {
75
75
 
76
76
  if (shouldFindInverse(this.meta)) {
77
77
  inverse = modelClass.inverseFor(this.key, store);
78
- } else if (DEBUG) {
78
+ }
79
+ // TODO make this error again for the non-polymorphic case
80
+ if (DEBUG && !this.options.polymorphic) {
79
81
  modelClass.typeForRelationship(this.key, store);
80
82
  }
81
83
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ember-data/model",
3
- "version": "4.8.0-alpha.6",
3
+ "version": "4.9.0-alpha.1",
4
4
  "description": "A presentation layer for apps built with @ember-data/store",
5
5
  "keywords": [
6
6
  "ember-addon"
@@ -22,9 +22,9 @@
22
22
  "test:node": "mocha"
23
23
  },
24
24
  "dependencies": {
25
- "@ember-data/canary-features": "4.8.0-alpha.6",
26
- "@ember-data/private-build-infra": "4.8.0-alpha.6",
27
- "@ember-data/store": "4.8.0-alpha.6",
25
+ "@ember-data/canary-features": "4.9.0-alpha.1",
26
+ "@ember-data/private-build-infra": "4.9.0-alpha.1",
27
+ "@ember-data/store": "4.9.0-alpha.1",
28
28
  "@ember/edition-utils": "^1.2.0",
29
29
  "@ember/string": "^3.0.0",
30
30
  "@embroider/macros": "^1.8.3",
@@ -38,7 +38,7 @@
38
38
  "inflection": "~1.13.2"
39
39
  },
40
40
  "devDependencies": {
41
- "@ember-data/unpublished-test-infra": "4.8.0-alpha.6",
41
+ "@ember-data/unpublished-test-infra": "4.9.0-alpha.1",
42
42
  "@ember/optional-features": "^2.0.0",
43
43
  "@ember/test-helpers": "~2.7.0",
44
44
  "broccoli-asset-rev": "^3.0.0",