selda 0.3.3.1 → 0.3.4.0
raw patch · 4 files changed
+88/−2 lines, 4 files
Files
- ChangeLog.md +5/−0
- selda.cabal +2/−1
- src/Database/Selda/Nullable.hs +80/−0
- src/Database/Selda/Selectors.hs +1/−1
ChangeLog.md view
@@ -1,6 +1,11 @@ # Revision history for Selda +## 0.3.4.0 -- 2018-09-29++* Added convenience functions for working with nullable columns.++ ## 0.3.3.1 -- 2018-09-04 * DISTINCT should now always return distinct results.
selda.cabal view
@@ -1,5 +1,5 @@ name: selda-version: 0.3.3.1+version: 0.3.4.0 synopsis: Multi-backend, high-level EDSL for interacting with SQL databases. description: This package provides an EDSL for writing portable, type-safe, high-level database code. Its feature set includes querying and modifying databases,@@ -47,6 +47,7 @@ Database.Selda Database.Selda.Backend Database.Selda.Migrations+ Database.Selda.Nullable Database.Selda.SqlType Database.Selda.Unsafe Database.Selda.Validation
+ src/Database/Selda/Nullable.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE TypeFamilies, TypeOperators, ConstraintKinds, FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+-- | Convenience facilities for working with nullable columns.+module Database.Selda.Nullable+ ( NonNull, (:?~)+ , nonNull, restrict', (?!)+ , (?==), (?/=), (?>), (?<), (?>=), (?<=), (?+), (?-), (?*), (?/)+ ) where+import Database.Selda+import Database.Selda.Unsafe (cast)+import Database.Selda.Selectors+import Database.Selda.Column+import Unsafe.Coerce++-- | Two SQL types which are identical modulo nullability.+type a :?~ b =+ ( NonNull a ~ NonNull b+ , SqlType (NonNull a)+ , SqlType (NonNull b)+ )++type family NonNull a where+ NonNull (Maybe a) = a+ NonNull a = a++-- | Unconditionally convert a nullable value into a non-nullable one,+-- using the standard SQL null-coalescing behavior.+fromNullable :: SqlType (NonNull a) => Col s a -> Col s (NonNull a)+fromNullable = cast++(?==), (?/=) :: (a :?~ b, SqlType a) => Col s a -> Col s b -> Col s (Maybe Bool)++(?>), (?<), (?>=), (?<=) :: (a :?~ b, SqlOrd (NonNull a))+ => Col s a -> Col s b -> Col s (Maybe Bool)++(?+), (?-), (?*) :: (a :?~ b, Num (NonNull a))+ => Col s a -> Col s b -> Col s (Maybe (NonNull a))++(?/) :: (a :?~ b, Fractional (Col s (NonNull a)))+ => Col s a -> Col s b -> Col s (Maybe (NonNull a))++a ?== b = cast $ fromNullable a .== fromNullable b+a ?/= b = cast $ fromNullable a ./= fromNullable b+a ?> b = cast $ fromNullable a .> fromNullable b+a ?< b = cast $ fromNullable a .< fromNullable b+a ?>= b = cast $ fromNullable a .>= fromNullable b+a ?<= b = cast $ fromNullable a .<= fromNullable b+a ?+ b = cast $ fromNullable a + fromNullable b+a ?- b = cast $ fromNullable a - fromNullable b+a ?* b = cast $ fromNullable a * fromNullable b+a ?/ b = cast $ fromNullable a / fromNullable b+infixl 4 ?==+infixl 4 ?/=+infixl 4 ?>+infixl 4 ?<+infixl 4 ?>=+infixl 4 ?<=+infixl 6 ?++infixl 6 ?-+infixl 7 ?*+infixl 7 ?/++-- | Selector indexing, overloaded to work on nullable as well as non-nullable+-- rows.+(?!) :: forall s t a. SqlType a+ => Row s t -> Selector (NonNull t) a -> Col s (Coalesce (Maybe a))+(Many xs) ?! i = case xs !! (selectorIndex i) of Untyped x -> One (unsafeCoerce x)+infixl 9 ?!++-- | Converts a nullable column into a non-nullable one, yielding the empty+-- result set if the column is null.+nonNull :: SqlType a => Col s (Maybe a) -> Query s (Col s a)+nonNull x = do+ restrict (not_ $ isNull x)+ return (cast x)++-- | Restrict a query using a nullable expression.+-- Equivalent to @restrict . ifNull false@.+restrict' :: Col s (Maybe Bool) -> Query s ()+restrict' = restrict . cast
src/Database/Selda/Selectors.hs view
@@ -32,7 +32,7 @@ -- If a nullable column is extracted from a nullable row, the resulting -- nested @Maybe@s will be squashed into a single level of nesting. (?) :: SqlType a => Row s (Maybe t) -> Selector t a -> Col s (Coalesce (Maybe a))-Many xs ? Selector i = case xs !! i of Untyped x -> One (unsafeCoerce x)+(Many xs) ? (Selector i) = case xs !! i of Untyped x -> One (unsafeCoerce x) infixl 9 ? upd :: Row s a -> Assignment s a -> Row s a