Skip to content

Commit befe116

Browse files
runspiredgitKrystan
authored andcommitted
chore: remove restriction on new field kinds being used with legacy mode (#9769)
* chore: remove restriction on new field kinds being used with legacy mode * chore: cleanup types * fix * fix test * fix docs
1 parent 8e16d34 commit befe116

File tree

28 files changed

+720
-138
lines changed

28 files changed

+720
-138
lines changed

packages/core-types/src/schema/fields.ts

+559-43
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { resourceSchema } from './fields';
2+
3+
// @ts-expect-error attribute field should result in an invalid schema
4+
// unless marked legacy
5+
resourceSchema({
6+
type: 'user',
7+
identity: { name: 'id', kind: '@id' },
8+
fields: [
9+
{
10+
name: 'name',
11+
kind: 'attribute',
12+
},
13+
],
14+
});
15+
resourceSchema({
16+
legacy: true,
17+
type: 'user',
18+
identity: { name: 'id', kind: '@id' },
19+
fields: [
20+
{
21+
name: 'name',
22+
kind: 'attribute',
23+
},
24+
],
25+
});
26+
27+
// @ts-expect-error relationship field should result in an invalid schema
28+
// unless marked legacy or linksMode
29+
resourceSchema({
30+
type: 'user',
31+
identity: { name: 'id', kind: '@id' },
32+
fields: [
33+
{
34+
name: 'friends',
35+
kind: 'hasMany',
36+
type: 'user',
37+
options: { async: false, inverse: null },
38+
},
39+
],
40+
});
41+
resourceSchema({
42+
legacy: true,
43+
type: 'user',
44+
identity: { name: 'id', kind: '@id' },
45+
fields: [
46+
{
47+
name: 'friends',
48+
kind: 'hasMany',
49+
type: 'user',
50+
options: { async: false, inverse: null },
51+
},
52+
],
53+
});
54+
resourceSchema({
55+
type: 'user',
56+
identity: { name: 'id', kind: '@id' },
57+
fields: [
58+
{
59+
name: 'friends',
60+
kind: 'hasMany',
61+
type: 'user',
62+
options: {
63+
async: false,
64+
inverse: null,
65+
linksMode: true,
66+
resetOnRemoteUpdate: false,
67+
},
68+
},
69+
],
70+
});

packages/json-api/src/-private/cache.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import type {
3131
CollectionField,
3232
FieldSchema,
3333
LegacyHasManyField,
34-
LegacyRelationshipSchema,
34+
LegacyRelationshipField,
3535
ResourceField,
3636
} from '@warp-drive/core-types/schema/fields';
3737
import type {
@@ -505,6 +505,9 @@ export default class JSONAPICache implements Cache {
505505
const store = this._capabilities._store;
506506
const attrs = this._capabilities.schema.fields(identifier);
507507
attrs.forEach((attr, key) => {
508+
if (attr.kind === 'alias') {
509+
return;
510+
}
508511
if (key in attributes && attributes[key] !== undefined) {
509512
return;
510513
}
@@ -1817,6 +1820,8 @@ function getDefaultValue(
18171820
identifier: StableRecordIdentifier,
18181821
store: Store
18191822
): Value | undefined {
1823+
assert(`AliasFields should not be directly accessed from the cache`, schema?.kind !== 'alias');
1824+
18201825
const options = schema?.options;
18211826

18221827
if (!schema || (!options && !schema.type)) {
@@ -1989,7 +1994,7 @@ function setupRelationships(
19891994
}
19901995
}
19911996

1992-
function isRelationship(field: FieldSchema): field is LegacyRelationshipSchema | CollectionField | ResourceField {
1997+
function isRelationship(field: FieldSchema): field is LegacyRelationshipField | CollectionField | ResourceField {
19931998
const { kind } = field;
19941999
return kind === 'hasMany' || kind === 'belongsTo' || kind === 'resource' || kind === 'collection';
19952000
}

packages/legacy-compat/src/legacy-network-handler/legacy-data-fetch.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import { DEBUG } from '@warp-drive/build-config/env';
77
import { assert } from '@warp-drive/build-config/macros';
88
import type { StableRecordIdentifier } from '@warp-drive/core-types';
99
import type { StableExistingRecordIdentifier } from '@warp-drive/core-types/identifier';
10-
import type { LegacyRelationshipSchema as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
10+
import type {
11+
LegacyRelationshipField as RelationshipSchema,
12+
LegacyRelationshipSchema as RelationshipSchema,
13+
} from '@warp-drive/core-types/schema/fields';
1114
import type { ExistingResourceObject, JsonApiDocument } from '@warp-drive/core-types/spec/json-api-raw';
1215

1316
import { upgradeStore } from '../-private';

packages/legacy-compat/src/legacy-network-handler/legacy-network-handler.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { DEBUG, TESTING } from '@warp-drive/build-config/env';
1010
import { assert } from '@warp-drive/build-config/macros';
1111
import type { StableExistingRecordIdentifier, StableRecordIdentifier } from '@warp-drive/core-types/identifier';
1212
import type { ImmutableRequestInfo } from '@warp-drive/core-types/request';
13-
import type { LegacyRelationshipSchema as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
13+
import type { LegacyRelationshipField as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
1414
import type { SingleResourceDataDocument } from '@warp-drive/core-types/spec/document';
1515
import type { ApiError } from '@warp-drive/core-types/spec/error';
1616
import type {

packages/legacy-compat/src/legacy-network-handler/minimum-adapter-interface.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import type Store from '@ember-data/store';
55
import type { CollectionRecordArray } from '@ember-data/store/-private';
66
import type { ModelSchema } from '@ember-data/store/types';
7-
import type { LegacyRelationshipSchema as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
7+
import type { LegacyRelationshipField as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
88

99
import type { Snapshot } from './snapshot';
1010
import type { SnapshotRecordArray } from './snapshot-record-array';

packages/legacy-compat/src/legacy-network-handler/snapshot.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import type { ChangedAttributesHash } from '@warp-drive/core-types/cache';
1616
import type { CollectionRelationship } from '@warp-drive/core-types/cache/relationship';
1717
import type { Value } from '@warp-drive/core-types/json/raw';
1818
import type { TypedRecordInstance, TypeFromInstance } from '@warp-drive/core-types/record';
19-
import type { LegacyAttributeField, LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields';
19+
import type { LegacyAttributeField, LegacyRelationshipField } from '@warp-drive/core-types/schema/fields';
2020

2121
import { upgradeStore } from '../-private';
2222
import type { SerializerOptions } from './minimum-serializer-interface';
@@ -532,7 +532,7 @@ export class Snapshot<R = unknown> {
532532
@param {Object} [binding] the value to which the callback's `this` should be bound
533533
@public
534534
*/
535-
eachRelationship(callback: (key: string, meta: LegacyRelationshipSchema) => void, binding?: unknown): void {
535+
eachRelationship(callback: (key: string, meta: LegacyRelationshipField) => void, binding?: unknown): void {
536536
const fields = this._store.schema.fields(this.identifier);
537537
fields.forEach((field, key) => {
538538
if (field.kind === 'belongsTo' || field.kind === 'hasMany') {

packages/model/src/-private/debug/assert-polymorphic-type.ts

+11
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ if (DEBUG) {
116116
assert(assertionMessage, isPolymorphic);
117117
}
118118
}
119+
120+
if (meta) {
121+
assert(
122+
`Expected the schema for the field ${parentDefinition.inverseKey} on ${addedIdentifier.type} to be for a legacy relationship`,
123+
meta.kind === 'belongsTo' || meta.kind === 'hasMany'
124+
);
125+
assert(
126+
`The schema for the relationship '${parentDefinition.inverseKey}' on '${addedIdentifier.type}' type does not implement '${parentDefinition.type}' and thus cannot be assigned to the '${parentDefinition.key}' relationship in '${parentIdentifier.type}'. The definition should specify 'as: "${parentDefinition.type}"' in options.`,
127+
meta?.options?.as === parentDefinition.type
128+
);
129+
}
119130
}
120131
};
121132
}

packages/model/src/-private/model.ts

+18-22
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { DEBUG } from '@warp-drive/build-config/env';
2222
import { assert } from '@warp-drive/build-config/macros';
2323
import type { StableRecordIdentifier } from '@warp-drive/core-types';
2424
import type { Cache, ChangedAttributesHash } from '@warp-drive/core-types/cache';
25-
import type { LegacyAttributeField, LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields';
25+
import type { LegacyAttributeField, LegacyRelationshipField } from '@warp-drive/core-types/schema/fields';
2626
import { RecordStore } from '@warp-drive/core-types/symbols';
2727

2828
import { Errors } from './errors';
@@ -1060,17 +1060,13 @@ class Model extends EmberObject implements MinimalLegacyRecord {
10601060
@param {any} binding the value to which the callback's `this` should be bound
10611061
*/
10621062
eachRelationship<T>(
1063-
callback: (
1064-
this: NoInfer<T> | undefined,
1065-
key: MaybeRelationshipFields<this>,
1066-
meta: LegacyRelationshipSchema
1067-
) => void,
1063+
callback: (this: NoInfer<T> | undefined, key: MaybeRelationshipFields<this>, meta: LegacyRelationshipField) => void,
10681064
binding?: T
10691065
): void {
10701066
(this.constructor as typeof Model).eachRelationship<T, this>(callback, binding);
10711067
}
10721068

1073-
relationshipFor(name: string): LegacyRelationshipSchema | undefined {
1069+
relationshipFor(name: string): LegacyRelationshipField | undefined {
10741070
return (this.constructor as typeof Model).relationshipsByName.get(name);
10751071
}
10761072

@@ -1199,7 +1195,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
11991195
}
12001196

12011197
@computeOnce
1202-
static get inverseMap(): Record<string, LegacyRelationshipSchema | null> {
1198+
static get inverseMap(): Record<string, LegacyRelationshipField | null> {
12031199
if (DEPRECATE_EARLY_STATIC) {
12041200
deprecate(
12051201
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1217,7 +1213,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
12171213
this.modelName
12181214
);
12191215
}
1220-
return Object.create(null) as Record<string, LegacyRelationshipSchema | null>;
1216+
return Object.create(null) as Record<string, LegacyRelationshipField | null>;
12211217
}
12221218

12231219
/**
@@ -1253,7 +1249,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
12531249
@param {Store} store
12541250
@return {Object} the inverse relationship, or null
12551251
*/
1256-
static inverseFor(name: string, store: Store): LegacyRelationshipSchema | null {
1252+
static inverseFor(name: string, store: Store): LegacyRelationshipField | null {
12571253
if (DEPRECATE_EARLY_STATIC) {
12581254
deprecate(
12591255
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1282,7 +1278,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
12821278
}
12831279

12841280
//Calculate the inverse, ignoring the cache
1285-
static _findInverseFor(name: string, store: Store): LegacyRelationshipSchema | null {
1281+
static _findInverseFor(name: string, store: Store): LegacyRelationshipField | null {
12861282
if (DEPRECATE_EARLY_STATIC) {
12871283
deprecate(
12881284
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1384,7 +1380,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
13841380
*/
13851381

13861382
@computeOnce
1387-
static get relationships(): Map<string, LegacyRelationshipSchema[]> {
1383+
static get relationships(): Map<string, LegacyRelationshipField[]> {
13881384
if (DEPRECATE_EARLY_STATIC) {
13891385
deprecate(
13901386
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1403,7 +1399,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
14031399
);
14041400
}
14051401

1406-
const map = new Map<string, LegacyRelationshipSchema[]>();
1402+
const map = new Map<string, LegacyRelationshipField[]>();
14071403
const relationshipsByName = this.relationshipsByName;
14081404

14091405
// Loop through each computed property on the class
@@ -1597,7 +1593,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
15971593
@readOnly
15981594
*/
15991595
@computeOnce
1600-
static get relationshipsByName(): Map<string, LegacyRelationshipSchema> {
1596+
static get relationshipsByName(): Map<string, LegacyRelationshipField> {
16011597
if (DEPRECATE_EARLY_STATIC) {
16021598
deprecate(
16031599
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1630,7 +1626,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
16301626
}
16311627

16321628
@computeOnce
1633-
static get relationshipsObject(): Record<string, LegacyRelationshipSchema> {
1629+
static get relationshipsObject(): Record<string, LegacyRelationshipField> {
16341630
if (DEPRECATE_EARLY_STATIC) {
16351631
deprecate(
16361632
`Accessing schema information on Models without looking up the model via the store is deprecated. Use store.modelFor (or better Snapshots or the store.getSchemaDefinitionService() apis) instead.`,
@@ -1649,7 +1645,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
16491645
);
16501646
}
16511647

1652-
const relationships = Object.create(null) as Record<string, LegacyRelationshipSchema>;
1648+
const relationships = Object.create(null) as Record<string, LegacyRelationshipField>;
16531649
const modelName = this.modelName;
16541650
this.eachComputedProperty((name: string, meta: unknown) => {
16551651
if (!isRelationshipSchema(meta)) {
@@ -1760,7 +1756,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
17601756
callback: (
17611757
this: T | undefined,
17621758
key: MaybeRelationshipFields<Schema>,
1763-
relationship: LegacyRelationshipSchema
1759+
relationship: LegacyRelationshipField
17641760
) => void,
17651761
binding?: T
17661762
): void {
@@ -1833,7 +1829,7 @@ class Model extends EmberObject implements MinimalLegacyRecord {
18331829
* @deprecated
18341830
*/
18351831
static determineRelationshipType(
1836-
knownSide: LegacyRelationshipSchema,
1832+
knownSide: LegacyRelationshipField,
18371833
store: Store
18381834
): 'oneToOne' | 'oneToMany' | 'manyToOne' | 'manyToMany' | 'oneToNone' | 'manyToNone' {
18391835
if (DEPRECATE_EARLY_STATIC) {
@@ -2302,7 +2298,7 @@ if (DEBUG) {
23022298

23032299
export { Model };
23042300

2305-
function isRelationshipSchema(meta: unknown): meta is LegacyRelationshipSchema {
2301+
function isRelationshipSchema(meta: unknown): meta is LegacyRelationshipField {
23062302
const hasKind = typeof meta === 'object' && meta !== null && 'kind' in meta && 'options' in meta;
23072303
return hasKind && (meta.kind === 'hasMany' || meta.kind === 'belongsTo');
23082304
}
@@ -2315,7 +2311,7 @@ function findPossibleInverses(
23152311
Klass: typeof Model,
23162312
inverseType: typeof Model,
23172313
name: string,
2318-
relationshipsSoFar?: LegacyRelationshipSchema[]
2314+
relationshipsSoFar?: LegacyRelationshipField[]
23192315
) {
23202316
const possibleRelationships = relationshipsSoFar || [];
23212317

@@ -2372,8 +2368,8 @@ function legacyFindInverseFor(Klass: typeof Model, name: string, store: Store) {
23722368

23732369
let fieldOnInverse: string | null | undefined;
23742370
let inverseKind: 'belongsTo' | 'hasMany';
2375-
let inverseRelationship: LegacyRelationshipSchema | undefined;
2376-
let inverseOptions: LegacyRelationshipSchema['options'] | undefined;
2371+
let inverseRelationship: LegacyRelationshipField | undefined;
2372+
let inverseOptions: LegacyRelationshipField['options'] | undefined;
23772373
const inverseSchema = Klass.typeForRelationship(name, store);
23782374
assert(`No model was found for '${relationship.type}'`, inverseSchema);
23792375

packages/model/src/-private/model.type-test.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { expectTypeOf } from 'expect-type';
33

44
import Store from '@ember-data/store';
55
import type { RelatedCollection as ManyArray } from '@ember-data/store/-private';
6-
import type { LegacyAttributeField, LegacyRelationshipSchema } from '@warp-drive/core-types/schema/fields';
6+
import type { LegacyAttributeField, LegacyRelationshipField } from '@warp-drive/core-types/schema/fields';
77
import { Type } from '@warp-drive/core-types/symbols';
88

99
import { attr } from './attr';
@@ -189,7 +189,7 @@ user.eachAttribute((key, meta) => {
189189
});
190190
user.eachRelationship((key, meta) => {
191191
expectTypeOf(key).toEqualTypeOf<'twin' | 'enemies' | 'friends'>();
192-
expectTypeOf(meta).toEqualTypeOf<LegacyRelationshipSchema>();
192+
expectTypeOf(meta).toEqualTypeOf<LegacyRelationshipField>();
193193
});
194194

195195
branded.eachAttribute((key, meta) => {
@@ -199,7 +199,7 @@ branded.eachAttribute((key, meta) => {
199199

200200
branded.eachRelationship((key, meta) => {
201201
expectTypeOf(key).toEqualTypeOf<'bestFriend' | 'twin' | 'enemies' | 'friends'>();
202-
expectTypeOf(meta).toEqualTypeOf<LegacyRelationshipSchema>();
202+
expectTypeOf(meta).toEqualTypeOf<LegacyRelationshipField>();
203203
});
204204

205205
// this ensures that `serialize` can be overridden

packages/model/src/-private/notify-changes.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type Store from '@ember-data/store';
44
import type { NotificationType } from '@ember-data/store';
55
import { assert } from '@warp-drive/build-config/macros';
66
import type { StableRecordIdentifier } from '@warp-drive/core-types';
7-
import type { LegacyRelationshipSchema as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
7+
import type { LegacyRelationshipField as RelationshipSchema } from '@warp-drive/core-types/schema/fields';
88

99
import { LEGACY_SUPPORT } from './legacy-relationships-support';
1010
import type { Model } from './model';

0 commit comments

Comments
 (0)