We are planning on building a Node.js service. Here's our evaluation of the current ORM landscape:
Last updated: May 2 2016
- Objection.js
- http://vincit.github.io/objection.js/#introduction
- Bad: API is Promise based and bulky. This means people can forget to have an error handler due to not being error first
- Good: Uses JSON schema for validation; this means content should be relatively reusable between server/browser
- Good: Has nice syntax for relationships
- Good: Built on knex.js which seems to be canonical SQL driver
- Neutral: Recommends using Knex.js' migration tool for migrations
- Good: Well maintained
- http://isitmaintained.com/project/Vincit/objection.js
- Resolution time: 1 day, Open issues: 13%
- http://isitmaintained.com/project/Vincit/objection.js
- Sails
- https://github.com/balderdashy/sails
- Not looking for an opinionated MVC, skipping for now
- Waterline, ORM from Sails
- https://github.com/balderdashy/waterline
- Bad: Response time takes a while
- But might be well supported since Sails?
- http://isitmaintained.com/project/balderdashy/waterline
- Resolution time: 10 days, Open issues: 2%
- sequelize
- https://github.com/sequelize/sequelize
- Good: Syntax is clean and straightforward
- Good: Seems to have everything we need (e.g. relationships, validation)
- TODO: There might be callback support via
nodeify - Good: Well maintained
- http://isitmaintained.com/project/sequelize/sequelize
- Resolution time: 1 day, Open issues: 12%
- http://isitmaintained.com/project/sequelize/sequelize
- Bookshelf.js
- http://bookshelfjs.org/
- Good: Feels very Backbone.js-esque (e.g.
get/set, virtual properties (similar tobackbone-relationship)) - Good: Supports callbacks
- Good: Authored by knex.js author
- Bad: Maintenance isn't great
- http://isitmaintained.com/project/tgriesser/bookshelf
- Resolution time: 6 days, Open issues: 28%
- http://isitmaintained.com/project/tgriesser/bookshelf
- orm2
- https://github.com/dresende/node-orm2
- Used it previously, had a terrible experience
Our likely choice is sequelize (possibly with callback bindings via bluebird-nodeify)
First goofy thing: 'orders' is the name of the SQL table. Why am i littering everywhere in my code with the names of tables? Isn't the ORM supposed to abstract away such details? Even worse, what if I have to change the table in the database? Not unheard of, pretty common as applications tend to age actually. Maybe I'm refactoring and moving schemas. Having implementation details of the database bleed into my code everywhere is a huge problem for me.
Second goofy thing: the awkward DSL of using something like '[why,is,this,an,array,in,a,string]' to eagerly fetch over these entities? Again, incredibly hard to work with in a long-term setting. Having tokenizable, refactorable pieces in a way that is convenient is a big deal. I could use something like
[${Why.tableName},${Is.tableName},...], but this is already becoming far more cumbersome than sequelize.