I'm sure I am missing something but I find the Bookshelf API to be relentlessly confusing for me. Here's what I am trying to do:
- I have a model called
Radio
with an application-assigned string primary key namedserial
and, for the purpose of this example, two fields namedexample1
andexample2
. I have specified the custom ID withidAttribute: 'serial'
in the model definition. - I'm trying to perform an upsert with Bookshelf (not with Knex directly, in my actual application that query becomes rather complex).
- I've got the insert case working but can't seem to get the update case working.
- For simplicity I'm not caring about transactions or atomicity right now. I am satisfied to get a simple select → insert/update to work.
And specifically in this example:
- On insert set
example1
andexample2
. - On update set
example1
and leaveexample2
unchanged.
So I've got something like this in the Bookshelf model, as a class (i.e. "static") method ("info" has fields "serial", "example1", and "example2"):
insertOrUpdate: function (info) {
return new Radio({'serial':info.serial}).fetch().then(function (model) {
if (model) {
model.set('example1', info.example1);
return model.save({}, {
method: 'update',
patch: true
})
} else {
return new Radio({
serial: info.serial,
example1: info.example1,
example2: info.example2
}).save({}, {
method: 'insert'
})
}
}).then(function (model) {
console.log("SUCCESS");
}).catch(function (err) {
console.log("ERROR", err);
});
}
Example call:
Radio.insertOrUpdate({
serial: ...,
example1: ...,
example2: ...
})
The problem I'm running into here is that while the "insert" case works, the "update" case fails with:
ERROR { Error: ER_PARSE_ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'where `serial` = '123223'' at line 1
Which is obvious with Knex debugging turned on, where the generated query is missing the set
clause:
update `radios` set where `serial` = ?
Now, I'm focused on the Bookshelf docs for fetch
and save
, and I'm wondering if I'm headed in the wrong direction.
I know I'm using the API wrong but I can't figure it out. A couple of weird things I noticed / had to do just to get it into its semi-working state:
I don't understand the first parameter of
save
. It would make sense to me if save was a static method ofModel
, but it isn't. It's an instance method and you can already pass attributes to theModel
constructor (e.g. what wouldnew X(a:1).save({a:2})
mean...?), and you can already set attributes withset
prior to the save. So I can't make sense of this. I had to pass{}
as a placeholder to let me specify the options.There is this
forge
thing but I'm not sure what its purpose is since you can already pass attributes to theModel
constructor (unless the authors found some benefit toX.forge({a:1})
vs.new X({a:1})
...?).I found that I had to explicitly specify the method to save because of an apparent Bookshelf quirk: Bookshelf bases its choice of method on
isNew()
, butisNew()
is alwaystrue
when you pass the id to the model constructor, which you have to do in the application-assigned ID case. Therefore for application-assigned IDs Bookshelf will always do an "insert" since it always thinks the model "is new". So you have to force the method to "update"... this just adds to my Bookshelf confusion.
Anyways, how do I do this properly? How do I make this insert and update work?
More importantly, where is this documented? In good faith I assume that it is documented clearly somewhere and I just can't see the forest for the trees right now, so I'd actually appreciate some direction to follow in the docs even more than a direct answer, because I do need to figure this out. I've been spending a lot of time on Bookshelf instead of actual development, so much that I almost wish I would have just stuck to direct SQL queries from the start.