bitemyapp / bitemyapp/esqueleto

a monad for sqlexpr

Open
#264 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Haskell
Stars
399
Forks
107
Avg merge
1d 17h
Merged PRs (30d)
1

Description

thinking that it'd be nice to have a monad for SqlExpr to make it a bit easier and clearer how to write code with it

```haskell
newtype SqlExprM a = SqlExprM (ReaderT NeedsParens (ReaderT IdentInfo (Writer (TLB.Builder, [PersistValue])) a)

unSqlExprM :: SqlExprM () -> NeedsParens -> IdentInfo -> (TLB.Builder, [PersistValue])
unSqlExprM (SqlExprM expr) np ident =
execWrtier $ runReaderT (runReaderT expr np) ident

instance (a ~ ()) => IsString (SqlExprM a) where
fromString str = tell (fromString str, [])

param :: (PersistField a) => a -> SqlExprM ()
param a = tell ("?", [toPersistValue a])
```

This makes it much easier to write raw SQL expressions. Taking the example from [the Finally Tagless blog post](https://www.foxhound.systems/blog/final-tagless/), we could write:

```haskell
bool :: Bool -> SqlExpr Bool
bool b = param b

int :: Int -> SqlExpr Int
int i = param i

paren :: SqlExpr a -> SqlExpr a
paren = local (\_ -> True)

leq :: SqlExpr Int -> SqlExpr Int -> SqlExpr Bool
leq e1 e2 = do
paren e1
" <= "
paren e2

and_ :: SqlExpr Bool -> SqlExpr Bool -> SqlExpr Bool
and_ e1 e2 = do
paren e1
" AND "
paren e2

binop :: Builder -> SqlExpr a -> SqlExpr b -> SqlExpr c
binop op e1 e2 = do
paren e1
" "
tell (op, [])
" "
paren e2

or_ :: SqlExpr Bool -> SqlExpr Bool -> SqlExpr Bool
or_ = binop "OR"

op :: Builder -> SqlExpr a -> SqlExpr b
op x a =
tell (x, [])
" "
a

not_ :: SqlExpr Bool -> SqlExpr Bool
not_ = op "NOT"

where_ :: SqlExpr Bool -> (Builder, [PersistValue])
where_ e =
unSqlExprM e False
```

Needs some work to get the types to check but overall may be a nice UX improvement

Contributor guide

No contributing guide indexed for this repository

Research direction

No files or tests are named. Start by reviewing the existing SqlExpr implementation and the proposed SqlExprM design in this issue, then determine the required type corrections and API shape; done means the monad provides the intended raw-SQL expression UX and the examples type-check.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.