8000 Allow compound keys · Issue #116 · js-data/js-data · GitHub
[go: up one dir, main page]

Skip to content
Allow compound keys #116
Closed
Closed
@WillsB3

Description

@WillsB3

Apologies in advance for the length of this issue…

We’re trying to get an implementation working where one of our resources uses a compound primary key.

We have a parent model (lets call it Collection) which has a relation to a child model (lets call it Document). Documents represent resources that come from an external site. We use the Document ID from the external site in our URLs so users can correlate the resource on our site with the resource on the external site.

When viewing one of the child models in our system in the context of one of these “collections” the user facing URL looks like this: /collection/:collection_id/document/:document_id.

We can’t use only the document_id as the primary key for Documents because a single document may exit in multiple “collections”, so to uniquely identify a “document” instance from within our system you need to know both collection_id and document_id. Thus the API endpoint to fetch details for a specific Document instance is /api/collection/:collection_id/document/:document_id.

It sounds strange but there are reasons why documents exist in the context of collections. For example users can override certain data on a specific Document, but this edited data is only relevant for the Document instance within the users Collection, so users which have another copy of the same original Document (remember, Documents originate from an external site) in another collection don’t see this overridden/edited data.

If it helps I can try and set up a Plunkr with this scenario (of collections and documents) to show the resource definitions we have, but essentially we have a belongsTo relation in our Document resource definition that looks like this:

DS.defineResource({
    name: 'document',

    relations: {
        belongsTo: {
            collection: {
                parent: true,
                localField: 'collection',
                localKey: 'collection_id'
            }
        }
    }   
});

We currently have nothing special (in fact very little at all) in our Collection resource definition:

DS.defineResource({
    name: 'collection'
});

(We haven’t added the reverse hasMany relation here yet as we may not need it).

Our difficulty comes in trying to fetch a Document from the server using .find(). We don’t have a single field on the Document model that can be used to uniquely identify a given instance of Document within a collection. However given that the document view exists within a Collection (user facing URL /collection/:collection_id/document/:document_id) we know both the collection_id and document_id, so to fetch the Document instance we need to perform a GET to /api/collection/:collection_id/document/:document_id/. This is the key part of the issue.

As far as I can tell, there is no way to inform js-data that the only way to be able to fetch a Document is by combining the document_id with the collection_id. js-data is obviously aware of the relation between Document and Collection, and if document_id itself were unique js-data would be able to handle the call to /api/collection/:collection_id/document/:document_id/ because of the parent: true declaration in the resource config, but currently js-data doesn’t know that both the collection_id and document_id comprise the compound primary key.

Is there some way that js-data could be configured so that it can understand this sort of compound key? Perhaps something like this would be possible:

DS.defineResource({
    name: 'document',
    compoundKey: {
        parts: {
            collection: 'id',
            self: 'id'
        }
    }

    relations: {
        belongsTo: {
            collection: {
                parent: true,
                localField: 'collection',
                localKey: 'collection_id'
            }
        }
    }
});

In this example the parts object lists the relations and the field on the relation that is used as part of the compound key. self is a special case key which refers to the current resource type (it could just as easily be document: 'id')

Maybe something even simpler is possible:

DS.defineResource({
    name: 'document',
    relations: {
        belongsTo: {
            collection: {
                parent: true,
                compoundKey: true,
                localField: 'collection',
                localKey: 'collection_id'
            }
        }
    }
});

In this case perhaps the compoundKey setting could be checked if parent: true is set. If both parent: true and compoundKey: true are set, then js-data would know that in order to work with Document resources it needs to use both the Document id and id of the relation that has the parent: true setting.

Both of these are just quick suggestions, no doubt they’d need more thought/refinement.

We had tried setting the id attribute of our Document model to a computed property which used the collection_id and document_id combined with a separator, something like this:

DS.defineResource({
    name: 'document',

    relations: {
        belongsTo: {
            collection: {
                parent: true,
                localField: 'collection',
                localKey: 'collection_id'
            }
        }
    },

    computed: {
        c_id: ['collection_id', 'document_id', function (collectionId, documentId) {
                    return collectionId + ':' + documentId;
                }]
    }

});

But of course when trying to fetch or save a Document resource the requests look something like this for a document with id A12345 in a Collection with id 12: /api/collection/12/document/12:A12345 which is obviously incorrect.

What do you think? Do you think it will be possible for js-data to be able to handle this kind of relationship?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0