Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot get the Identifier of the record #9516

Closed
Jopie01 opened this issue Jul 22, 2024 · 10 comments
Closed

Cannot get the Identifier of the record #9516

Jopie01 opened this issue Jul 22, 2024 · 10 comments

Comments

@Jopie01
Copy link

Jopie01 commented Jul 22, 2024

I'm using the most recent alpha versions of Ember-Data / WarpDrive. I migrated everything to the newest Schema service and SchemaRecord. However the fields and relationships are the Legacy ones. Everything works nicely, data is fetched and displayed correctly.

Now I want to get the Identifier from the record, but I can't. I always get the error Uncaught Error: No field named identifier on ui.menu. Logging the record to the console, I see that everything is there. I get a Proxy with a Symbol(Identifier) which contains the needed data. I can get the identifier by calling the toString function which return everything as a string. But that's not what I want.

I'm surely missing something, but what? I just want the identifier of that record.

@runspired
Copy link
Contributor

you can call recordIdentifierFor(record) with the record instance to get it, or you can add it to the schema. identifier is not one of the properties exposed by using withDefaults, though easy to add, the field def would be:

  {
    type: '@identity',
    name: 'identifier',
    kind: 'derived',
    options: { key: '^' },
  },

This presumes you've registered the derivations made available by the schema-record package for use with defaults / identity etc.

import { registerDerivations } from '@warp-drive/schema-record/schema';

//...

registerDerivations(schema);

@Jopie01
Copy link
Author

Jopie01 commented Jul 25, 2024

Sorry for the delay. I added the field to my schema and called the registerDerivations and now I can call record.identifier and it will return the identifier.

I had some trouble with getting it to work because there is also a registerDerivation function without the s. And I'm extending the schema service to add my own fetch logic to it so I had to call registerDerivations(this) because I'm inside the schema service already.

@runspired
Copy link
Contributor

Awesome!

@Jopie01
Copy link
Author

Jopie01 commented Jul 26, 2024

After reading the source code a bit I was getting bold and also moved my id field to a derived one

{
  type: '@identity',
  name: 'id',
  kind: 'derived',
  options: { key: 'id' },
}

As it turns out you can add several keys to get the data. After moving the field everything still works.

@runspired
Copy link
Contributor

runspired commented Jul 26, 2024

@Jopie01 this is actually one of the things provided by withDefaults :D

see:

export const SchemaRecordFields: FieldSchema[] = [
{
type: '@constructor',
name: 'constructor',
kind: 'derived',
},
{
type: '@identity',
name: '$type',
kind: 'derived',
options: { key: 'type' },
},
];
function _constructor(record: SchemaRecord) {
let state = Support.get(record as WeakKey);
if (!state) {
state = {};
Support.set(record as WeakKey, state);
}
return (state._constructor = state._constructor || {
name: `SchemaRecord<${recordIdentifierFor(record).type}>`,
get modelName() {
throw new Error('Cannot access record.constructor.modelName on non-Legacy Schema Records.');
},
});
}
_constructor[Type] = '@constructor';
export function withDefaults(schema: WithPartial<ResourceSchema, 'identity'>): ResourceSchema {
schema.identity = schema.identity || { name: 'id', kind: '@id' };
schema.fields.push(...SchemaRecordFields);
return schema as ResourceSchema;
}

specifically, primaryKey is set by the special identity slot in the resource-schema, and the default is id, likely you can just remove your derived id field and everything will still work the same

@Jopie01
Copy link
Author

Jopie01 commented Jul 26, 2024

Hmm, I tried to remove the id field, but then I got the error that the field does not exist. I also had to add isDestroyed and isDestroying fields to make the schema-record happy.

I now start with setting up a new schema with the fields. Then I walk through my list of fields which I got from the backend and push them also to the fields list.

let newSchema = {
  type: <model>,
  legacy: true,
  traits: [],
  fields: [{
      type: null,
      name: 'isDestroyed',
      kind: 'attribute',
      options: {},
    }, {
      type: null,
      name: 'isDestroying',
      kind: 'attribute',
      options: {},
    }, {
      type: '@identity',
      name: 'id',
      kind: 'derived',
      options: { key: 'id' },
    }, {
      type: '@identity',
      name: 'identifier',
      kind: 'derived',
      options: { key: '^' },
    }]
}

/* 
 ....  walk through my list of fields and add them to the schema
*/

this.registerResource(newSchema);
registerDerivations(this);

@runspired
Copy link
Contributor

ah, you're using legacy mode. Try the withDefaults approach instead :)

@Jopie01
Copy link
Author

Jopie01 commented Jul 30, 2024

ah, you're using legacy mode.

That's correct, I have to wait until PR #9320 lands or ready to test. I suspect there won't be a very big difference between legacy and the new approach?

@runspired
Copy link
Contributor

yeah, you only need legacy mode when using hasMany/belongsTo/attribute. didn't see any hasMany/belongsTo in what you posted above though 😅

legacy also has a withDefaults fwiw:

export function withDefaults(schema: WithPartial<ResourceSchema, 'legacy' | 'identity'>): ResourceSchema {

import { withDefaults } from '@ember-data/model/migration-support';

@Jopie01
Copy link
Author

Jopie01 commented Jul 31, 2024

didn't see any hasMany/belongsTo in what you posted above though 😅

I added a comment which stated "walk through my list of fields and add them to the schema" .... 😛 and in that list of fields there are belongsTo and hasMany fields. That's why I added legacy: true to the schema.

legacy also has a withDefaults

I will keep it as is for now. It works perfectly well and I have to clean up my customization of the schema class some day nonetheless. At that moment I will look into the withDefaults

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

No branches or pull requests

2 participants