Skip to content

Experimental API to support implicit transactions

Compare
Choose a tag to compare
@mdwheele mdwheele released this 26 Oct 15:39
· 2 commits to master since this release

YORM now has basic support for transactions!

I've made this release under an "Experimental" flag because I'm not entirely thrilled with the API right now. With that said, we'll likely always support this more verbose / chatty API because why not. Take a look at how a basic transaction works:

const { transaction } = require('yorm')

/**
 * Use `transaction` to start a transaction. Pass in each Model 
 * class you want to be available to participate in the transaction. 
 * 
 * The last argument is always a callback that receives Model classes
 * (in the order you provided them) that have been bound to the 
 * transaction. In this way, the Model classes are able to participate
 * in the transaction within the scope of the provided callback.
 */
await transaction(User, Post, async (User, Post) => {
  // User inside the closure is not the same as User outside
  // the closure. The inside User has the Knex transaction bound.
  const user = await User.create()
  await Post.create({ user_id: user.id, title: 'Created if the User is successfully created.' })

  // Any exception / error thrown inside the closure will rollback. Otherwise, 
  // the transaction is implicitly committed.
})

I don't really like that we have to pass in each participating Model class, but maybe it'll grow on me. There is something to be said for being explicit and honestly, it's not bad until you start seeing 5-6 collaborators in the same transaction. Truth be told, I think that I would consider it a smell if I did have 6+ models mutating within a single transaction so maybe it's for the best that this pain becomes visual.

Anywho, this is what we were shooting for, but didn't arrive at:

import { transaction } from 'yorm.js'

transaction(async () => {
  const user = await User.create()
  await Post.create({ user_id: user.id, title: 'Created if the User is successfully created.' })
})
import { beginTransaction, commit, rollback } from 'yorm.js'

beginTransaction()

try {
  const user = await User.create()
  await Post.create({ user_id: user.id, title: 'Created if the User is successfully created.' })
  commit()
} catch (error) {
  rollback()
}

We'll keep working on it, but in the meantime give it a whirl!