thinky icon indicating copy to clipboard operation
thinky copied to clipboard

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

Open yussinsharp opened this issue 8 years ago • 7 comments

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.

yussinsharp avatar Mar 01 '17 19:03 yussinsharp

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();
});

gjuchault avatar Mar 02 '17 23:03 gjuchault

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.

yussinsharp avatar Mar 21 '17 04:03 yussinsharp

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

gjuchault avatar Mar 21 '17 09:03 gjuchault

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

yussinsharp avatar Mar 21 '17 15:03 yussinsharp

You can use a middleware like that :

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

  next()
})

gjuchault avatar Mar 21 '17 15:03 gjuchault

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.

yussinsharp avatar Mar 21 '17 15:03 yussinsharp

I think even in Eloquent there are no default relationships

gjuchault avatar Mar 21 '17 17:03 gjuchault