3

I know the title is a mouthful but I honestly couldn't come up with a better one for my specific case (open to suggestions). So basically I jotted down on this JSFiddle (a simplified version of) the issue I am facing. I am using AngularJS's $q.all method to collect an array of promises dependent on query results:

db.transaction(function(tx) {
    $q.all(fn(tx)).then(function(a) {
        console.log("Result:", a);
    });
});

where fn is a function that returns an array of promises.
In the above case, everything works as expected and the result (the array of sql query results which resolve the promises) is console.logged correctly.
However, if I wrap $q.all in the then method of another deferred object, as so:

db.transaction(function(tx) {
    fn2(tx).then(function(tx) {
        $q.all(fn(tx)).then(function(a) {
            console.log("Result:", a);
        });
    });
});

I get the error: Error: Failed to execute 'executeSql' on 'SQLTransaction': SQL execution is disallowed.
(fn2 is a function that merely returns a promise which resolves to the tx object itself).
Have I stumbled upon a common pitfall? I searched about but haven't come up with anything. Cheers.

Andrea Aloi
  • 971
  • 1
  • 17
  • 37

1 Answers1

6

That's because the transaction is already getting closed when fn2 is resolved.

If you don't use a transaction (or even the same one) in both fn2 and fn it should work:

db.transaction(function(tx) {
    fn2(tx).then(function(tx) {
        // new tranaction as the old one is closed
        db.transaction(function(tx) {
            $q.all(fn(tx)).then(function(a) {
                console.log("Result:", a);
            });
        });
    });
}); 

See this fiddle.

eladcon
  • 5,815
  • 1
  • 16
  • 19
  • Thank you. I see, but I don't understand the reason why the transaction should close when `fn2` is resolved. Besides, I mentioned this was a simplified example, but in my actual scenario `fn2` executes queries inside transaction `tx`; if I issue a new "nested" transaction as per your example and the sql executions in it for some reason fail, will the already-closed, old transaction rollback or has that already been committed? This is my main concern. – Andrea Aloi May 20 '15 at 08:49
  • I guess my best option is to replace `$q.all(fn(tx))` with `$q.all(fn(tx, fn2))` and modify `fn` so it accepts a transaction and a function (or possibly any number thereof) and prepends `fn2`'s promise to the `promiseArray` used by `$q.all`, so there is no chaining and the process basically reverts to the first, working example. – Andrea Aloi May 20 '15 at 09:00
  • that's just how WebSQL works. it's closing the transaction once it gets back to the event loop.. yeah i guess your solution should work that way – eladcon May 20 '15 at 09:05
  • It does: http://jsfiddle.net/axedre/k7sr39kg/1/. I will go with my solution since the queries both inside `fn2` and inside `fn` must be executed in the **same** transaction, so that if any fails the whole transaction does, too. Thanks for your help! – Andrea Aloi May 20 '15 at 09:14