bitemyapp / esqueleto

New home of Esqueleto, please file issues so we can get things caught up!
BSD 3-Clause "New" or "Revised" License
370 stars 107 forks source link

Support more locking kind #339

Closed josephsumabat closed 1 year ago

josephsumabat commented 1 year ago

Context: Support FOR UPDATE Of tablename and FOR SHARE OF tablename syntax for Postgresql:

This allows a the FOR UPDATE SKIP LOCKED behaviour when you have a LEFT OUTER JOIN with a nullable side. Currently you will get the error:

FOR UPDATE cannot be applied to the nullable side of an outer join

The workaround currently using esqueleto is to do seperate queries and then join them manually if you want to select rows for an update while skipping locked rows (or to just do a raw query). I ran into this situation at work.

See: https://www.postgresql.org/docs/current/sql-select.html namely:

FOR { UPDATE | NO KEY UPDATE | SHARE | KEY SHARE } [ OF table_name [, ...] ] [ NOWAIT | SKIP LOCKED ] [...] ]

also documented in MySQL: https://dev.mysql.com/doc/refman/8.0/en/select.html

    [FOR {UPDATE | SHARE}
        [OF tbl_name [, tbl_name] ...]
        [NOWAIT | SKIP LOCKED]
      | LOCK IN SHARE MODE]
    [into_option]

Usage example would be

select $ do
    (p :& bp) <- from $ 
        table @Person
        `innerJoin` table @BlogPost
            `on` do
                \(p :& b) -> p ^. PersonId ==. b ^. BlogPostAuthorId
                EP.forUpdateOf (p :& b) EP.skipLocked
    return p

After submitting your PR:

josephsumabat commented 1 year ago

@parsonsmatt I've changed the monoid instance to concatenate postgres locking clauses (which results in a valid query) and prioritize general locking clauses over postgres ones.

josephsumabat commented 1 year ago

Past few commits were just updating documentation and version number