Skip to content

Commit

Permalink
chore: stub out linksMode work
Browse files Browse the repository at this point in the history
  • Loading branch information
runspired authored and gitKrystan committed Nov 12, 2024
1 parent 80bf8a5 commit 68544a2
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 0 deletions.
68 changes: 68 additions & 0 deletions packages/core-types/src/schema/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -729,6 +729,40 @@ export type LegacyBelongsToField = {
*/
polymorphic?: boolean;

/**
* Whether this field should ever make use of the legacy support infra
* from @ember-data/model and the LegacyNetworkMiddleware for adapters and serializers.
*
* When true, none of the legacy support will be utilized. Sync relationships
* will be expected to already have all their data. When reloading a sync relationship
* you would be expected to have a `related link` available from a prior relationship
* payload e.g.
*
* ```ts
* {
* data: {
* type: 'user',
* id: '2',
* attributes: { name: 'Chris' },
* relationships: {
* bestFriend: {
* links: { related: "/users/1/bestFriend" },
* data: { type: 'user', id: '1' },
* }
* }
* },
* included: [
* { type: 'user', id: '1', attributes: { name: 'Krystan' } }
* ]
* }
* ```
*
* Async relationships will be loaded via their link if needed.
*
* @typedoc
*/
linksMode?: true;

/**
* When omitted, the cache data for this field will
* clear local state of all changes except for the
Expand Down Expand Up @@ -819,6 +853,40 @@ export type LegacyHasManyField = {
*/
polymorphic?: boolean;

/**
* Whether this field should ever make use of the legacy support infra
* from @ember-data/model and the LegacyNetworkMiddleware for adapters and serializers.
*
* When true, none of the legacy support will be utilized. Sync relationships
* will be expected to already have all their data. When reloading a sync relationship
* you would be expected to have a `related link` available from a prior relationship
* payload e.g.
*
* ```ts
* {
* data: {
* type: 'user',
* id: '2',
* attributes: { name: 'Chris' },
* relationships: {
* bestFriends: {
* links: { related: "/users/1/bestFriends" },
* data: [ { type: 'user', id: '1' } ],
* }
* }
* },
* included: [
* { type: 'user', id: '1', attributes: { name: 'Krystan' } }
* ]
* }
* ```
*
* Async relationships will be loaded via their link if needed.
*
* @typedoc
*/
linksMode?: true;

/**
* When omitted, the cache data for this field will
* clear local state of all changes except for the
Expand Down
1 change: 1 addition & 0 deletions packages/model/src/-private/belongs-to.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export type RelationshipOptions<T, Async extends boolean> = {
inverse: null | (IsUnknown<T> extends true ? string : keyof NoNull<T> & string);
polymorphic?: boolean;
as?: string;
linksMode?: true;
resetOnRemoteUpdate?: boolean;
};

Expand Down
2 changes: 2 additions & 0 deletions packages/model/src/-private/references/belongs-to.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,8 @@ export default class BelongsToReference<
@param {Object} options the options to pass in.
@return {Promise} a promise that resolves with the record in this belongs-to relationship.
*/
// load and reload on the references will need to understand linksmode and make a `findBelongsTo`
// or `findHasMany` operation request with the link instead of getBelongsto/reloadBelongsTo etc
async load(options?: Record<string, unknown>): Promise<Related | null> {
const support: LegacySupport = (LEGACY_SUPPORT as Map<StableRecordIdentifier, LegacySupport>).get(
this.___identifier
Expand Down
12 changes: 12 additions & 0 deletions packages/schema-record/src/record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ export class SchemaRecord {
entangleSignal(signals, receiver, field.name);
return computeAttribute(cache, identifier, prop as string);
case 'resource':
// we will do something very similar to this for belongsTo in links mode
assert(
`SchemaRecord.${field.name} is not available in legacy mode because it has type '${field.kind}'`,
!target[Legacy]
Expand Down Expand Up @@ -310,14 +311,25 @@ export class SchemaRecord {
Mode[Editable]
);
case 'belongsTo':
if (field.options.linksMode) {
// do non-legacy approach else do the below
// unlike computeResource, we will just return the record value
// in the async case, we should probably just return a promise resolving to the record value
// we can error for the async case initially in favor of shipping sync case quickly
}
if (!HAS_MODEL_PACKAGE) {
assert(
`Cannot use belongsTo fields in your schema unless @ember-data/model is installed to provide legacy model support. ${field.name} should likely be migrated to be a resource field.`
);
}
// change here would be to detect the new "links-only" mode
// likely we should do this via an option on the schema
// if in that mode, you are no longer required to use legacy
// if in that mode, even if legacy, we no longer go through getLegacySupport
assert(`Expected to have a getLegacySupport function`, getLegacySupport);
assert(`Can only use belongsTo fields when the resource is in legacy mode`, Mode[Legacy]);
entangleSignal(signals, receiver, field.name);

return getLegacySupport(receiver as unknown as MinimalLegacyRecord).getBelongsTo(field.name);
case 'hasMany':
if (!HAS_MODEL_PACKAGE) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// before doing any of the things for legacy, write and fix tests for non-legacy links-only mode
// - those tests will be in a new file under tests/reads/belongs-to-test.ts in this test app
//
// the main thing to do for legacy:
// we should add tests to this file for a record in legacy-mode but with links-only mode on relationships
//
// a second thing to do for legacy:
// we should also add tests to the main test suite to confirm that instances of @ember-data/model in links-only
// mode fetch their async relationship data via the link via requestmanager without requiring the legacy support
// infrastructure.
import { module, test } from 'qunit';

import { setupTest } from 'ember-qunit';
Expand Down
83 changes: 83 additions & 0 deletions tests/warp-drive__schema-record/tests/reads/belongs-to-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { TestContext } from '@ember/test-helpers';

import { module, test } from 'qunit';

import { setupTest } from 'ember-qunit';

import type Store from '@ember-data/store';
import type { Type } from '@warp-drive/core-types/symbols';
import { registerDerivations, withDefaults } from '@warp-drive/schema-record/schema';

type User = {
id: string | null;
$type: 'user';
name: string;
bestFriend: User | null;
[Type]: 'user';
};

module('Reads | belongsTo in linksMode', function (hooks) {
setupTest(hooks);

test('we can use sync belongsTo in linksMode', function (this: TestContext, assert) {
const store = this.owner.lookup('service:store') as Store;
const { schema } = store;

registerDerivations(schema);

schema.registerResource(
withDefaults({
type: 'user',
fields: [
{
name: 'name',
kind: 'field',
},
{
name: 'bestFriend',
type: 'user',
kind: 'belongsTo',
options: { inverse: 'bestFriend', async: false, linksMode: true },
},
],
})
);

const record = store.push<User>({
data: {
type: 'user',
id: '1',
attributes: {
name: 'Chris',
},
relationships: {
bestFriend: {
data: { type: 'user', id: '2' },
},
},
},
included: [
{
type: 'user',
id: '2',
attributes: {
name: 'Rey',
},
relationships: {
bestFriend: {
data: { type: 'user', id: '1' },
},
},
},
],
});

assert.strictEqual(record.id, '1', 'id is accessible');
assert.strictEqual(record.$type, 'user', '$type is accessible');
assert.strictEqual(record.name, 'Chris', 'name is accessible');
assert.strictEqual(record.bestFriend?.id, '2', 'bestFriend.id is accessible');
assert.strictEqual(record.bestFriend?.$type, 'user', 'bestFriend.user is accessible');
assert.strictEqual(record.bestFriend?.name, 'Rey', 'bestFriend.name is accessible');
assert.strictEqual(record.bestFriend?.bestFriend?.id, record.id, 'bestFriend is reciprocal');
});
});

0 comments on commit 68544a2

Please sign in to comment.