neumino / thinky

JavaScript ORM for RethinkDB
http://justonepixel.com/thinky/
Other
1.12k stars 128 forks source link

What is the best way to manage "relational" defaults? #607

Open yussinsharp opened 7 years ago

yussinsharp commented 7 years ago

Question

Say I wanted to have a default for a model (ModelA) that was the id of another model (ModelB). The schemas look like this:

const ModelA = thinky.createModel('ModelA', {
  id: type.string().uuid(4),
  name: type.string(),
  modelBId: type.string().uuid(4),
});

const ModelB = thinky.createModel('ModelB', {
  id: type.string().uuid(4),
  title: type.string().default('Untitled'),
});

When I create a new modelA, I want it to automatically create a new modelB with some default attributes and add the id of that newly created modelB to the modelBId attribute of modelA. So it would work like this:

ModelA.save({ name: 'Test' })
  .then((m) => {
    console.log(m.modelBId); // ID of newly created modelB
  })
  .catch(err => console.log(err));

Is this possible? I know that .default() can accept a function but that function assumes a synchronous process because it has to next support like the pre and post event hooks do.

gjuchault commented 7 years ago

I guess you can indeed use pre('save') which can be used to set default values if you want:

ModelA.pre('save', function(next) {
  this.modelB = this.modelB || new ModelB();
});
yussinsharp commented 7 years ago

That would not work as I need the id of the default-created ModelB. This would assume that I store modelB nested in the document. However it is stored separately and referenced with the id and a hasOne relationship.

gjuchault commented 7 years ago

You could still do something like that :

Assuming you have express app. You can use lots of things global, some memory store, etc.

const defaultModelB = new ModelB(...)
app.locals.defaultModelB = defaultModelB
ModelA.pre('save', (next) => {
  this.modelB = this.modelB || app.locals.defaultModelB;
})

Note: you need either the id if you want to store this.ModelB_id or the object if you ant to go with this.modelB

yussinsharp commented 7 years ago

The id would be undefined. Ids are not created until they are saved in the DB.

const defaultModelB = new ModelB(...);
console.log(defaultModelB.id); // undefined
gjuchault commented 7 years ago

You can use a middleware like that :

app.use((req, res, next) => {
  if (!defaultModelB.isSaved()) {
    defaultModelB.save().then(() => next())
  }

  next()
})
yussinsharp commented 7 years ago

Okay, but that's not what I am looking for. To be specific, I want to handle this all with only the Model. Including Express middlewares is not a solution for me.

gjuchault commented 7 years ago

I think even in Eloquent there are no default relationships