diff --git a/packages/core-types/src/schema/fields.ts b/packages/core-types/src/schema/fields.ts index e0c7281f625..964803760cb 100644 --- a/packages/core-types/src/schema/fields.ts +++ b/packages/core-types/src/schema/fields.ts @@ -67,13 +67,15 @@ export type GenericField = { export type AliasField = { kind: 'alias'; name: string; + type: null; // should always be null /** * The field def for which this is an alias. * * @typedoc */ - options: GenericField + options: + | GenericField | ObjectField | SchemaObjectField | ArrayField diff --git a/packages/schema-record/src/record.ts b/packages/schema-record/src/record.ts index 5491578874b..dca9461faad 100644 --- a/packages/schema-record/src/record.ts +++ b/packages/schema-record/src/record.ts @@ -189,9 +189,6 @@ export class SchemaRecord { // for its own usage. // _, @, $, * - const propArray = isEmbedded ? embeddedPath!.slice() : []; - propArray.push(prop as string); - const maybeField = prop === identityField?.name ? identityField : fields.get(prop as string); if (!maybeField) { if (IgnoredGlobalFields.has(prop as string)) { @@ -213,11 +210,15 @@ export class SchemaRecord { } const field = maybeField.kind === 'alias' ? maybeField.options : maybeField; - assert( `Alias fields cannot alias '@id' '@local' '@hash' or 'derived' fields`, maybeField.kind !== 'alias' || !['@id', '@local', '@hash', 'derived'].includes(maybeField.options.kind) ); + const propArray = isEmbedded ? embeddedPath!.slice() : []; + // we use the field.name instead of prop here because we want to use the cache-path not + // the record path. + propArray.push(field.name as string); + // propArray.push(prop as string); switch (field.kind) { case '@id': @@ -313,14 +314,21 @@ export class SchemaRecord { throw new Error(`Cannot set ${String(prop)} on ${identifier.type} because the record is not editable`); } - const propArray = isEmbedded ? embeddedPath!.slice() : []; - propArray.push(prop as string); - - const field = prop === identityField?.name ? identityField : fields.get(prop as string); - if (!field) { + const maybeField = prop === identityField?.name ? identityField : fields.get(prop as string); + if (!maybeField) { const type = isEmbedded ? embeddedType! : identifier.type; throw new Error(`There is no field named ${String(prop)} on ${type}`); } + const field = maybeField.kind === 'alias' ? maybeField.options : maybeField; + assert( + `Alias fields cannot alias '@id' '@local' '@hash' or 'derived' fields`, + maybeField.kind !== 'alias' || !['@id', '@local', '@hash', 'derived'].includes(maybeField.options.kind) + ); + const propArray = isEmbedded ? embeddedPath!.slice() : []; + // we use the field.name instead of prop here because we want to use the cache-path not + // the record path. + propArray.push(field.name as string); + // propArray.push(prop as string); switch (field.kind) { case '@id': { diff --git a/tests/warp-drive__schema-record/tests/reads/alias-test.ts b/tests/warp-drive__schema-record/tests/reads/alias-test.ts index c3cee78f756..15397d4ceef 100644 --- a/tests/warp-drive__schema-record/tests/reads/alias-test.ts +++ b/tests/warp-drive__schema-record/tests/reads/alias-test.ts @@ -16,6 +16,7 @@ interface User { $type: 'user'; rawNetWorth: string; netWorth: number; + [Type]: 'user'; } module('Reads | Alias fields', function (hooks) { @@ -58,10 +59,11 @@ module('Reads | Alias fields', function (hooks) { { kind: 'alias', name: 'netWorth', - type: 'float', + type: null, options: { name: 'rawNetWorth', kind: 'field', + type: 'float', options: { precision: 2 }, }, }, @@ -70,22 +72,22 @@ module('Reads | Alias fields', function (hooks) { ); const record = store.createRecord('user', { - rawNetWorth: '1_000_000.009', + rawNetWorth: '1000000.009', }); const identifier = recordIdentifierFor(record); const resource = store.cache.peek(identifier)!; - assert.strictEqual(record.rawNetWorth, '1_000_000.009', 'netWorth is accessible'); - assert.strictEqual(record.netWorth, 1_000_000.01, 'netWorth is accessible'); + assert.strictEqual(record.rawNetWorth, '1000000.009', 'netWorth is accessible in raw form'); + assert.strictEqual(record.netWorth, 1_000_000.009, 'netWorth is accessible in numeric form'); assert.strictEqual( store.cache.getAttr(identifier, 'rawNetWorth'), - '1000000.01', + '1000000.009', 'cache value for netWorth is correct' ); assert.strictEqual(store.cache.getAttr(identifier, 'netWorth'), undefined, 'not caching the alias field'); assert.strictEqual( resource.attributes?.rawNetWorth, - '1000000.01', + '1000000.009', 'resource cache value for rawNetWorth is correct' ); assert.strictEqual(resource.attributes?.netWorth, undefined, 'resource cache value for netWorth is correct'); @@ -96,8 +98,8 @@ module('Reads | Alias fields', function (hooks) { const identifier2 = recordIdentifierFor(record2); const resource2 = store.cache.peek(identifier2)!; - assert.strictEqual(record2.rawNetWorth, '1_000_000.009', 'netWorth is accessible'); - assert.strictEqual(record2.netWorth, 1_000_000.01, 'netWorth is accessible'); + assert.strictEqual(record2.rawNetWorth, '1000000.01', 'netWorth is accessible in raw form'); + assert.strictEqual(record2.netWorth, 1_000_000.01, 'netWorth is accessible in numeric form'); assert.strictEqual( store.cache.getAttr(identifier2, 'rawNetWorth'), '1000000.01',