bitemyapp / bitemyapp/esqueleto

Case analyzing enumerable types

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

Description

Hello. Does it make any sense to have a function like this in the library:

```haskell
-- |
-- Given ...
-- - an SQL expression that produces a value of some enum
-- - and a function that maps the enum to SQL expressions
-- ... produces an SQL expression that @CASE@-s on the enum value and gives the appropriate result
enumCase ::
forall e a.
(Enum e, Bounded e, PersistField e, PersistField a) =>
SqlExpr (Value e) ->
(e -> SqlExpr (Value a)) ->
SqlExpr (Value a)
enumCase choiceExpr f = case_ (caseEntry <$> [minBound ..]) (unsafeSqlValue "NULL")
where
caseEntry :: e -> (SqlExpr (Value Bool), SqlExpr (Value a))
caseEntry e = (val e ==. choiceExpr, f e)
```

This allows us to use arguably more natural Haskell case analysis to dispatch on an SQL expression representing an enumerable type, instead of constructing a syntax tree using `case_`, `when_`, `then_`, `else_` etc. For example instead of:

```haskell
case_
[ when_
(account ^. SomeEnumField ==. val SomeEnumValue)
then_
foo
, when_
(account ^. SomeEnumField ==. val SomeOtherValue)
then_
bar
]
(else_ baz)
```

we can have:

```haskell
enumCase (account ^. SomeEnumField) $ \case
SomeEnumValue -> foo
SomeOtherValue -> bar
_ -> baz
```

Note that I'm assuming the SQL type is no larger than the Haskell type that represents it: if this is sometimes not the case, it is safer to accept a default value instead of using `unsafeSqlValue "NULL"`:

```haskell
-- |
-- Given ...
-- - an SQL expression that produces a value of some enum
-- - a default SQL expression
-- - and a function that maps the enum to SQL expressions
-- ... produces an SQL expression that @CASE@-s on the enum value and gives the appropriate result
enumCase ::
forall e a.
(Enum e, Bounded e, PersistField e, PersistField a) =>
SqlExpr (Value e) ->
SqlExpr (Value e) ->
(e -> SqlExpr (Value a)) ->
SqlExpr (Value a)
enumCase choiceExpr defaultExpr f = case_ (caseEntry <$> [minBound ..]) defaultExpr
where
caseEntry :: e -> (SqlExpr (Value Bool), SqlExpr (Value a))
caseEntry e = (val e ==. choiceExpr, f e)
```

Contributor guide

No contributing guide indexed for this repository

Research direction

Review the existing case_, when_, then_, and else_ combinators alongside the two proposed enumCase signatures. Resolve whether enumCase should use an implicit NULL fallback or require a default expression, then confirm the chosen API against the library's current conventions and coverage needs.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell, sql
Domain
databases
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.