Skip to content

Provide helper methods on entity.Key for Kind, parent, name, and ID #574

Description

@jgeewax

(In reference to https://github.com/GoogleCloudPlatform/gcloud-node/blob/412598cad200198caaac5dbe83700fd1665b2102/lib/datastore/entity.js#L54)

It'd be really nice if we had some helper methods on the Key class, so that you could do the following...

var gcloud = require('gcloud');
var dataset = gcloud.datastore.dataset({...});

Auto-generated ID example:

entity = {
  key: dataset.key('Person').
  data: {name: 'Jim'}
};

dataset.save(entity, function(err, entity) {
  var key = entity.key;
  console.log('kind is', key.kind); // 'Person'
  console.log('id is', key.id);  // 1234567 (auto-generated ID in this case)
  console.log('name is', key.name); // undefined or null
  console.log('parent is', key.parent); // undefined or null
});

Specific name and parent example

entity = {
  key: dataset.key(['Person', 'mom', 'Person', 'jim']).
  data: {name: 'Jim'}
};

dataset.save(entity, function(err, entity) {
  var key = entity.key;
  console.log('kind is', key.kind); // 'Person'
  console.log('id is', key.id);  // undefined or null
  console.log('name is', key.name); // 'jim'
  console.log('parent is', key.parent); // {key object}
  console.log('parent kind is', key.parent.kind); // 'Person'
  console.log('parent id is', key.parent.id); // undefined or null
  console.log('parent name is', key.parent.name); // 'mom'
  console.log('parent parent is', key.parent.parent); // undefined or null
});

Is this a reasonable request?

Activity

  1. added this to the Datastore Future milestone on May 9, 2015
  2. ryanseys commented on May 11, 2015

    @ryanseys
    Contributor

    Yeah this seems nice. I like this. Would this functionality mimic existing similar functionality from another gcloud library (python? ruby?) that we could take a look at? Or can we just run with this idea on our own?

  3. jgeewax commented on May 11, 2015

    @jgeewax
    ContributorAuthor

    I think the Python methods are modeled after ext.db and ext.db which is the closest we'll get to "being official" (see http://googlecloudplatform.github.io/gcloud-python/latest/datastore-keys.html and https://github.com/GoogleCloudPlatform/gcloud-python/blob/master/gcloud/datastore/key.py)

  4. stephenplusplus commented on Nov 23, 2015

    @stephenplusplus
    Contributor

    I'll put this in queue for after #897 merges.

  5. stephenplusplus commented on Dec 1, 2015

    @stephenplusplus
    Contributor

    Here's what I've got. Look okay @jgeewax?

    Your example

    new Key({ path: ['Person', 'mom', 'Person', 'jim'] })
    // returns:
    Key {
      namespace: undefined,
      path: [ 'Person', 'mom', 'Person', 'jim' ],
      name: 'jim',
      kind: 'Person',
      parent:
       Key {
         namespace: undefined,
         path: [ 'Person', 'mom' ],
         name: 'mom',
         kind: 'Person' } }

    Example with extra level of hierarchy and numeric ID

    new Key({ path: ['Person', 'mom', 'Person', 'jim', 'SmallPerson', 1] })
    // returns:
    Key {
      namespace: undefined,
      path: [ 'Person', 'mom', 'Person', 'jim', 'SmallPerson', 1 ],
      id: 1,
      kind: 'SmallPerson',
      parent:
       Key {
         namespace: undefined,
         path: [ 'Person', 'mom', 'Person', 'jim' ],
         name: 'jim',
         kind: 'Person',
         parent:
          Key {
            namespace: undefined,
            path: [Object],
            name: 'mom',
            kind: 'Person' } } }
  6. jgeewax commented on Dec 1, 2015

    @jgeewax
    ContributorAuthor

    I don't spot anything crazy, but just to be sure -- this is a method that derives the results at eval time, right? Or is it duplicate information being stored?

  7. stephenplusplus commented on Dec 1, 2015

    @stephenplusplus
    Contributor

    At the time of instantiation, the parts of a key are split apart to create named properties for the given path array. So all of these things are stored in memory with the object. This is how all of our custom type constructors work.

    The duplicate information, do you mean the path? I kept that around since I thought it would be unfair for the user to lose a reference to their original input.

  8. jgeewax commented on Dec 1, 2015

    @jgeewax
    ContributorAuthor
  9. stephenplusplus commented on Dec 1, 2015

    @stephenplusplus
    Contributor

    Gotcha. What types of changes should we support? We can prevent a parent from being overwritten for example, or just a kind, an ID, etc. Or, we allow everything.

    We would have to compute the path when it's asked for or update it when one of its parts changes... probably easier to compute the path on request.

    Here's a working constructor that allows anything to be changed and path will follow:

    function Key(options) {
      this.namespace = options.namespace;
    
      if (options.path.length % 2 === 0) {
        var identifier = options.path.pop();
    
        if (is.number(identifier)) {
          this.id = identifier;
        } else if (is.string(identifier)) {
          this.name = identifier;
        }
      }
    
      this.kind = options.path.pop();
    
      if (options.path.length > 0) {
        this.parent = new Key(options);
      }
    
      // `path` is computed on demand to consider any changes that may have been
      // made to the key.
      Object.defineProperty(this, 'path', {
        enumerable: true,
        get: function () {
          return arrify(this.parent && this.parent.path)
            .concat([this.kind, this.name || this.id]);
        }
      });
    }
    
    var key = new Key({ path: ['Person', 'mom', 'Person', 'jim'] });
    console.log(key.path);
    // [ 'Person', 'mom', 'Person', 'jim' ]
    
    key.parent.name = 'sam';
    console.log(key.path);
    // [ 'Person', 'sam', 'Person', 'jim' ]
    
    console.log(key.parent.path);
    // [ 'Person', 'sam' ]

    The one case I can think of that isn't covered is if a user had an ID but now assigns a name. But then I'm back to how mutable we should allow a Key path to be?

  10. jgeewax commented on Dec 1, 2015

    @jgeewax
    ContributorAuthor

    Yep - the on-demand eval SGTM. Basically anything that is derived would ideally be on-demand evaluated... right? which would include ID / name, ie:

    var key = new Key({ path: ['Person', 'mom', 'Person', 'jim'] });
    console.log(key.path);
    // [ 'Person', 'mom', 'Person', 'jim' ]
    
    key.parent.name = null;
    key.parent.id = 1
    console.log(key.path);
    // [ 'Person', 1, 'Person', 'jim' ]
    
    console.log(key.parent.path);
    // [ 'Person', 1 ]
  11. stephenplusplus commented on Dec 1, 2015

    @stephenplusplus
    Contributor

    Yeah that works fine. PR incoming!

  12. 27 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

api: datastoreIssues related to the Datastore API.

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions