On Tue, Sep 17, 2019 at 08:21:52PM -0500, xxxxxx@ancell-ent.com wrote:
> > You can also rollback the innermost savepoint s2 without also
> > rolling back s1 or the surrounding "proper" transaction. So as far
> > as I'm concerned, these semantics are a perfect fit for a nested
> > "with-transaction" operator.
>
> So you'd do it like http://wiki.call-cc.org/eggref/5/postgresql
Right, that's one part of the API I like a lot.
> > (with-transaction CONN THUNK [isolation: LEVEL] [access: MODE])
>
> > Execute THUNK within a BEGIN TRANSACTION block, and return the value
> > of thunk.
>
> > The transaction is committed if thunk returns a true value. If an
> > exception occurs during thunk, or thunk returns #f, or the commit
> > fails, the transaction will be rolled back. If this rollback fails,
> > that is a critical error and you should likely abort.
>
> > Nested applications of with-transaction are supported -- only those
> > statements executed within THUNK are committed or rolled back by any
> > with-transaction call, as you would expect.
>
> Without looking at any code, what are the mechanics of rolling back an
> inner savepoint? Do you execute a bare statement (ugly) and then
> return non-#f from the inner with-transaction's thunk?
I don't understand what you mean by "do you execute a bare statement".
Usually you'll only want to roll back when an exception occurs. If you
want to explicitly roll back, you can just return #f from the thunk which
should be rolled back. e.g.,
(with-transaction db
(lambda ()
(query db "INSERT INTO foo (bar, qux) VALUES (1, 2)")
(with-transaction
(lambda ()
(query db "INSERT INTO foo (bar, qux) VALUES (3, 4)")
;; Oops, decide to roll this back
#f))
(query db "INSERT INTO foo (bar, qux) VALUES (5, 6)")))
When this returns, foo will contain the tuples 1,2 and 5,6.
> And I have to say that I really don't like the code style you get with
> naive use of this (with THUNK) paradigm, even before it gets nested.
> While making things very clear in one way, it's also very ugly, and it
> radically distinguishes the operations in the THUNKs compared to
> single ones which get by with auto-commit mode. (Requiring the
> wrapping those with a (with-fake-transaction THUNK) will fix the
> distinguishing issue while making *everything* ugly.)
What exactly do you find so ugly? In my experience, you don't tend to
have that many nested transactions. Usually, you have one big outer
transaction and that's it.
> A further argument is that if my above partly aesthetic claim is
> correct, the ugly ceremony required will to an extent discourage the
> use of transactions, which would be bad....
I don't see this is very different from with-input-from-port (which
I consider super-Schemely because it's in the standard), or in my
http-client library with-input-from-request. Maybe our personal
styles of how we write Scheme just differ?
> I suppose I want something that looks more like how you'd plainly
> write it out, but with with-transaction magic decorating it instead
> intermingling with BEGIN TRANSACTION etc. operations.
>
> Wouldn't fixing that calls for macro magic? How much can and should
> we require (fancy?) macros in an SRFI?
Let's please avoid macros unless absolutely necessary! Macros don't
compose, but procedures do.
Cheers,
Peter