yesodweb / yesodweb/persistent

Remove `connLimitOffset`

Open
#1,325 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Haskell
Stars
486
Forks
306
PR merge metrics
No merged PRs in 30d

Description

connLimitOffset is used in esqueleto, which has me investigating it.

These are the uses of the term in persistent repository:

λ ~/Projects/persistent/ master rg connLimitOffset
persistent-sqlite/Database/Persist/Sqlite.hs
291:            , connLimitOffset = decorateSQLWithLimitOffset "LIMIT -1"
482:                , connLimitOffset = decorateSQLWithLimitOffset "LIMIT -1"

persistent/ChangeLog.md
95:    * The `connLimitOffset` function used to have a `Bool` parameter. This

persistent-postgresql/Database/Persist/Postgresql.hs
407:        , connLimitOffset = decorateSQLWithLimitOffset "LIMIT ALL"
1778:                , connLimitOffset = undefined

persistent/Database/Persist/SqlBackend.hs
119:    func <- asks (SqlBackend.connLimitOffset . projectBackend)

persistent/Database/Persist/SqlBackend/Internal.hs
112:    , connLimitOffset :: (Int,Int) -> Text -> Text

persistent/Database/Persist/Sql/Orphan/PersistQuery.hs
119:        sql conn = connLimitOffset conn (limit,offset) $ mconcat
140:        sql conn = connLimitOffset conn (limit,offset) $ mconcat

persistent/Database/Persist/SqlBackend/Internal/MkSqlBackend.hs
71:    , connLimitOffset :: (Int,Int) -> Text -> Text

persistent-mysql/Database/Persist/MySQL.hs
155:                , connLimitOffset = decorateSQLWithLimitOffset "LIMIT 18446744073709551615"
1303:                , connLimitOffset = undefined

In other words, it is always assigned with the result of decorateSqlWithLimitOffset applied to that Text parameter.

λ ~/Projects/persistent/ master rg decorateSQLWithLimitOffset
persistent-sqlite/Database/Persist/Sqlite.hs
291:            , connLimitOffset = decorateSQLWithLimitOffset "LIMIT -1"
482:                , connLimitOffset = decorateSQLWithLimitOffset "LIMIT -1"

persistent-postgresql/Database/Persist/Postgresql.hs
407:        , connLimitOffset = decorateSQLWithLimitOffset "LIMIT ALL"

persistent/Database/Persist/Sql.hs
57:    , decorateSQLWithLimitOffset

persistent/Database/Persist/Sql/Orphan/PersistQuery.hs
14:    , decorateSQLWithLimitOffset
485:decorateSQLWithLimitOffset
490:decorateSQLWithLimitOffset nolimit (limit,offset) sql =

persistent-mysql/Database/Persist/MySQL.hs
155:                , connLimitOffset = decorateSQLWithLimitOffset "LIMIT 18446744073709551615"

That is implemented in Database.Persist.Sql.Orphan.PersistQuery here:

-- | Generates sql for limit and offset for postgres, sqlite and mysql.
decorateSQLWithLimitOffset
    :: Text
    -> (Int,Int)
    -> Text
    -> Text
decorateSQLWithLimitOffset nolimit (limit,offset) sql =
    let
        lim = case (limit, offset) of
                (0, 0) -> ""
                (0, _) -> T.cons ' ' nolimit
                (_, _) -> " LIMIT " <> T.pack (show limit)
        off = if offset == 0
                    then ""
                    else " OFFSET " <> T.pack (show offset)
    in mconcat
            [ sql
            , lim
            , off
            ]

noLimit is necessary because MySQL and Sqlite throw a syntax error if you have an OFFSET without a corresponding LIMIT clause.

Since the noLimit parameter is actually what varies, let's store that in the record instead of the function. Then, decorating with LIMIT/OFFSET can be done as a function implemented directly.

This simplifies esqueleto's use-case.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with connLimitOffset in persistent/Database/Persist/SqlBackend/Internal.hs and persistent/Database/Persist/SqlBackend/Internal/MkSqlBackend.hs, then trace its uses in Sql/Orphan/PersistQuery.hs. Review the SQLite, PostgreSQL, and MySQL backend definitions and decorateSQLWithLimitOffset. Done means the backend record stores the varying no-limit value while limit/offset SQL generation continues to work across these backends.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell, mysql, postgresql, sqlite
Domain
databases
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.