Skip to content

Commit

Permalink
Merge branch 'master' into goose/dux-1281-tomaybe-instance-for-derive…
Browse files Browse the repository at this point in the history
…esqueletorecord
  • Loading branch information
parsonsmatt authored Oct 16, 2023
2 parents dcc9a64 + bd33498 commit 85b9d5e
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 12 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/haskell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ jobs:
--health-retries=3
strategy:
matrix:
cabal: ["3.6"]
ghc: ["8.6.5", "8.8.4", "8.10.4", "9.0.2", "9.2.2"]
cabal: ["3.8.1.0"]
ghc: ["8.6.5", "8.8.4", "8.10.4", "9.0.2", "9.2.2", "9.4.5", "9.6.2"]
env:
CONFIG: "--enable-tests --enable-benchmarks "
steps:
- uses: actions/checkout@v2
- uses: haskell/actions/setup@v1
- uses: haskell/actions/setup@v2
id: setup-haskell-cabal
with:
ghc-version: ${{ matrix.ghc }}
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ Advantages:
- `ON` clause is attached directly to the relevant join, so you never need to
worry about how they're ordered, nor will you ever run into bugs where the
`on` clause is on the wrong `JOIN`
- The `ON` clause lambda will all the available tables in it. This forbids
- The `ON` clause lambda will exclusively have all the available tables in it. This forbids
runtime errors where an `ON` clause refers to a table that isn't in scope yet.
- You can join on a table twice, and the aliases work out fine with the `ON`
clause.
Expand Down
19 changes: 19 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,25 @@
- `ToMaybe` instances are now derived for records so you can now left
join them in queries

3.5.10.3
========
- @ttuegel
- [#377](https://github.com/bitemyapp/esqueleto/pull/377)
- Fix Postgres syntax for `noWait`

3.5.10.2
========
- @parsonsmatt
- [#376](https://github.com/bitemyapp/esqueleto/pull/376)
- When using Postgres 15, `LIMIT`, and the `locking` functions, you
could accidentally construct SQL code like:

> ... LIMIT 1FOR UPDATE ...

This parsed on Postgres <15, but the new Postgres parser is more
strict, and fails to parse. This PR introduces newlines between each
query chunk, which fixes the issue.

3.5.10.1
========
- @9999years
Expand Down
18 changes: 14 additions & 4 deletions src/Database/Esqueleto/Internal/Internal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2963,6 +2963,15 @@ toRawSql mode (conn, firstIdentState) query =
flip S.runState firstIdentState $
W.runWriterT $
unQ query
deleteRepeatedNewlines txt =
let
(preNewlines, rest) = TL.break (== '\n') txt
(_, rest') = TL.break (/= '\n') rest
in
if TL.null rest'
then preNewlines <> "\n"
else preNewlines <> "\n" <> deleteRepeatedNewlines rest'

SideData distinctClause
fromClauses
setClauses
Expand All @@ -2978,7 +2987,7 @@ toRawSql mode (conn, firstIdentState) query =
-- that no name clashes will occur on subqueries that may
-- appear on the expressions below.
info = (projectBackend conn, finalIdentState)
in mconcat
in (\(x, t) -> (TLB.fromLazyText $ deleteRepeatedNewlines $ TL.strip $ TLB.toLazyText x, t)) $ mconcat $ intersperse ("\n", [])
[ makeCte info cteClause
, makeInsertInto info mode ret
, makeSelect info mode distinctClause ret
Expand All @@ -2992,6 +3001,7 @@ toRawSql mode (conn, firstIdentState) query =
, makeLocking info lockingClause
]


-- | Renders a 'SqlQuery' into a 'Text' value along with the list of
-- 'PersistValue's that would be supplied to the database for @?@ placeholders.
--
Expand Down Expand Up @@ -3213,11 +3223,11 @@ makeOrderBy :: IdentInfo -> [OrderByClause] -> (TLB.Builder, [PersistValue])
makeOrderBy _ [] = mempty
makeOrderBy info is =
let (tlb, vals) = makeOrderByNoNewline info is
in ("\n" <> tlb, vals)
in (tlb, vals)

makeLimit :: IdentInfo -> LimitClause -> (TLB.Builder, [PersistValue])
makeLimit (conn, _) (Limit ml mo) =
let limitRaw = getConnLimitOffset (v ml, v mo) "\n" conn
let limitRaw = getConnLimitOffset (v ml, v mo) "" conn
v :: Maybe Int64 -> Int
v = maybe 0 fromIntegral
in (TLB.fromText limitRaw, mempty)
Expand Down Expand Up @@ -3247,7 +3257,7 @@ makeLocking info (PostgresLockingClauses clauses) =
makeLockingStrength PostgresForShare = plain "FOR SHARE"

makeLockingBehavior :: OnLockedBehavior -> (TLB.Builder, [PersistValue])
makeLockingBehavior NoWait = plain "NO WAIT"
makeLockingBehavior NoWait = plain "NOWAIT"
makeLockingBehavior SkipLocked = plain "SKIP LOCKED"
makeLockingBehavior Wait = plain ""

Expand Down
2 changes: 1 addition & 1 deletion src/Database/Esqueleto/PostgreSQL.hs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ values exprs = Ex.From $ do
, params
)

-- | `NO WAIT` syntax for postgres locking
-- | `NOWAIT` syntax for postgres locking
-- error will be thrown if locked rows are attempted to be selected
--
-- @since 3.5.9.0
Expand Down
8 changes: 5 additions & 3 deletions test/Common/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1652,9 +1652,11 @@ testLocking = do
[complex, with1, with2, with3] <-
return $
map (toText conn) [complexQuery, queryWithClause1, queryWithClause2, queryWithClause3]
let expected = complex <> "\n" <> syntax
asserting $
(with1, with2, with3) `shouldBe` (expected, expected, expected)
let expected = complex <> syntax <> "\n"
asserting $ do
with1 `shouldBe` expected
with2 `shouldBe` expected
with3 `shouldBe` expected
itDb "looks sane for ForUpdate" $ sanityCheck ForUpdate "FOR UPDATE"
itDb "looks sane for ForUpdateSkipLocked" $ sanityCheck ForUpdateSkipLocked "FOR UPDATE SKIP LOCKED"
itDb "looks sane for ForShare" $ sanityCheck ForShare "FOR SHARE"
Expand Down
9 changes: 9 additions & 0 deletions test/PostgreSQL/Test.hs
Original file line number Diff line number Diff line change
Expand Up @@ -1423,6 +1423,15 @@ testPostgresqlLocking = do
asserting sideThreadAsserts
asserting $ length nonLockedRowsAfterUpdate `shouldBe` 3

describe "noWait" $ do
itDb "doesn't crash" $ do
select $ do
t <- Experimental.from $ table @Person
EP.forUpdateOf t EP.noWait
pure t

asserting noExceptions

-- Since lateral queries arent supported in Sqlite or older versions of mysql
-- the test is in the Postgres module
testLateralQuery :: SpecDb
Expand Down

0 comments on commit 85b9d5e

Please sign in to comment.