0

Can js-data create relations on nested objects? Here is an example:

GET /card/2

{
  "id": 2,
  "name": "foo",
  "action": {     // <-- nested object
    "typeId": 1,  // foreign key to actionType.id
    "param0": 20
  }
}

GET /action-types

[{
  "id": 1,
  "name": "Jump",
  "paramsMeta": [{
     "name": "Distance",
     "max": 30
  }]
}, {
  "id": 2,
  "name": "Damage",
  "paramsMeta": [{
    "name": "amount",
    "min": 0
  }, {
    "name": "isRelative",
    "type": "Boolean"
  }]
}]

resources.js:

DS.defineResource({
  name: 'card',
  relations: {
    hasOne: {
      actionType: {
        localField: 'action.type',
        localKey: 'action.typeId'
      }
    }
  }
});

DS.defineResource(
  name: 'actionType',
  endpoint: 'action-types'
);

What I need is to initialize property card.action.type. But in current example property card['action.type'] is initialized and that's not what I want. To be more specific, current card Object after js-data processing is:

> console.log(DS.get('card', 2));
>
{
  id: 2,
  name: 'foo',
  'action.type': { id: 1, name: 'Jump', ... } // <-- reference to actionType
  action: {
    typeId: 1, param0: 20
  }
}

But I need the structure to be like this:

> console.log(DS.get('card', 2));
>
{
  id: 2,
  name: 'foo',
  action: {
    typeId: 1,
    type: { id: 1, name: 'Jump', ... }, // <-- reference to actionType
    param0: 20
  }
}

js-data version: 2.9.0

Vlad-HC
  • 4,359
  • 2
  • 20
  • 25
  • Based on the JSON you posted, "localField" should be set to "action", not "action.type". To help you further, can you explain what "typeId" is? Is it a primary key for actions, or a foreign key to some other entity? You also need to post your resource definition for "actionType", as you've only shown one side of the relation. – jdobry May 25 '16 at 18:06
  • Sure. I've updated the question. Now it has more details. – Vlad-HC May 25 '16 at 18:26

1 Answers1

0

Problem

You need to switch from a hasOne to a belongsTo relation, e.g.:

belongsTo: {
  'action-type': {
    localField: 'action.type',
    localKey: 'action.typeId'
  }
}

Here are two plunkers that try to do what you want:

js-data v2: http://plnkr.co/edit/nbZtaXZ8AZwh9ITiG1kO?p=preview (relations on nested path, doesn't work quite right)

js-data v3: http://plnkr.co/edit/Tyxsab0icCs8nn68fkta?p=preview (relations on nested path, doesn't work quite right)

Unfortunately, JSData can't create ES5 getters for a nested path like action.type, so the links simply don't work quite as expected. (Well is does make a getter, but it ends up being a property named action.type, not what you want).

Workaround

One workaround would be to define an intermediate "action" resource, and have the following relationships:

  • card belongsTo action
  • action hasOne card
  • action belongsTo actionType
  • actionType hasMany action

The only caveat is the card.action now needs to have a primary key. The easiest thing would be to simply make card.action.id equal to card.id.

Here are two plunkers that demonstrate this workaround:

js-data v2: http://plnkr.co/edit/cUDyP0Zmk39zP30sTVpL?p=preview (relations on nested path, solved using intermediate resource)

js-data v3: http://plnkr.co/edit/J8yNL9zIp5h9RJL9XM9w?p=preview (relations on nested path, solved using intermediate resource)

jdobry
  • 1,041
  • 6
  • 17
  • Thank you for a detailed answer. It seems that adding primary key is not an options because of backend restrictions and because of that the fact that some cards have more than one action (for example, card can also have `triggerAction` field or `additionalAction` field). Currently I'm trying to link `actionType` relation by hand - waiting for DS.find() promise to be resolved and than linking `actionType` object by `card.action = DS.get('actionType', action.typeId);` – Vlad-HC May 31 '16 at 04:20