Bookshelf.js - unexpected transactional behavior

I have been looking at this for days, and so far I cannot come to a rational explanation. So, quick background: I use bookshelfjs and I want to use transactions to perform 3 inserts and after saving add additional links. To make things work the way I want them, I used Bluebird Promise.

router.get('/transaction', function(req, res){

    bookshelf.transaction(function(t){

        return Promise.all([
            //this block is part of transaction!
            new Participant({name: 'Transaction John'}).save(null, {transacting: t}),
            new Participant({name: 'Transaction Doe'}).save(null, {transacting: t}),
            new Town({town_number: 1000, town_title: 'LA'}).save(null, {transacting: t})
        ]).spread(function(p1, p2, t1){

            return Promise.all([ 
                /*
                    this block, however, is not. second address save fails, because I use "p4.get('id')" which does not exists
                    the first address is saved, the second is not; but since I use transactions, nothing should be saved!
                */
                new Address({
                        house_number: 3,
                        street_name: 'Transaction street name',
                        town_id: t1.get('id'),
                        participant_id: p1.get('id')        
                    }).save(null, {transacting: t}),    

                new Address({
                        house_number: 3,
                        street_name: 'Transaction street name 2',
                        town_id: t1.get('id'),
                        participant_id: p4.get('id')        
                    }).save(null, {transacting: t})
            ]);
        });

    }).then(function(){
        res.json('success');        
    }).catch(function(error){
        console.log('error');
        res.json(error);
    });

});

Here are the requests for the above code:

{ __cid: '__cid1', sql: 'begin transaction;' }
{ __cid: '__cid1',
  method: 'insert',
  options: undefined,
  bindings: [ 'Transaction John' ],
  sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
  method: 'insert',
  options: undefined,
  bindings: [ 'Transaction Doe' ],
  sql: 'insert into "participants" ("name") values (?)' }
{ __cid: '__cid1',
  method: 'insert',
  options: undefined,
  bindings: [ 1000, 'LA' ],
  sql: 'insert into "towns" ("town_number", "town_title") values (?, ?)' }
[ReferenceError: p4 is not defined]
{ __cid: '__cid1', sql: 'rollback;' }
{ __cid: '__cid1',
  method: 'insert',
  options: undefined,
  bindings: [ 3, 1, 'Transaction street name', 1 ],
  sql: 'insert into "addresses" ("house_number", "participant_id", "street_name"
, "town_id") values (?, ?, ?, ?)' }

As you can see from the above code, a rollback occurs that corresponds to the above code, but after the rollback there is an additional insert. This is NOT what is supposed to happen.

Why does Promise.all work in the first part of the code, and in the second it looks like it's not? Is there a mistake, or am I not understanding something correctly?

Thank you for your responses!

+4
1

Bookshelf.js:

. all

, Bookshelf.js , : https://github.com/tgriesser/knex/pull/786

+4

All Articles