thinky icon indicating copy to clipboard operation
thinky copied to clipboard

Proposal: syntactic sugar for "virtual" primary key field

Open marshall007 opened this issue 10 years ago • 2 comments

Since virtual fields cannot be persisted to the db, I've been using the following workaround for generated primary key fields:

var Patch = thinky.createModel('patches', {
  id: type.array().schema(type.string()),
  sha: type.string(),
  file_id: type.string()
});

Patch.docAddListener('saving', function(patch) {
  // set primary key before saving
  return patch.id = [patch.sha, patch.file_id];
});

This has been a pretty common use-case in the projects I've used thinky with and it would be nice if this functionality were exposed in a nicer way. Either:

  1. When the primary key field is defined in the schema as a virtual, persist it anyway.
  2. Expose a way to persist any virtual field.
    • ex. type.virtual().default(...).persist(true)
  3. Expose a new API specifically for primary key generation.
    • ex. Model.pk('id', function (doc) { ... })

marshall007 avatar Apr 17 '15 23:04 marshall007

I'm sick-ish so my brain may not properly work, but I thought a bit about it.

I'm a bit reluctant about saving virtual fields for a few reasons:

  • It's simpler if you consider that you can never save virtual fields
  • Virtual fields are basically sugar for you to directly pass the document to a template (by generating fields like full_name.

About your use case for primary key, there is one more thing to consider. I think you should never change the primary key of your document. Currently if you do:

var doc = new Model(...);
doc.save().then(function(result) {
    doc.id = "anotherValueForId";
    return doc.save();
}).then(function(result) {
    // ....
})

Here we just save two documents. The document is not really updated, but more copied. If you want to generate a primary key based on the other fields, you should use a normal type and default. I believe in your case @marshall007, this should work for you too:

var Patch = thinky.createModel('patches', {
  id: type.array().schema(type.string()).default(function(patch) {
    return [this.sha, this.file_id];
  }),
  sha: type.string(),
  file_id: type.string()
});

If a document is not saved and you're saving it, it will generate the primary key based on sha and file_id.

If you really need to copy the document with a new primary key, I think we should add a new method like clone.

Let me know if that works for you @marshall007.

neumino avatar Apr 18 '15 18:04 neumino

@neumino never thought about doing it that way, thanks! In my case, the values in those other fields never change so I don't have to worry about the update scenario. I just like to keep a copy of those fields in the document so that in queries I can reference them by name rather than as the nth element of the primary key.

marshall007 avatar Apr 20 '15 21:04 marshall007