{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Database.Persist.Postgresql.JSON
( (@>.)
, (<@.)
, (?.)
, (?|.)
, (?&.)
, Value()
) where
import Data.Aeson (FromJSON, ToJSON, Value, encode, eitherDecodeStrict)
import qualified Data.ByteString.Lazy as BSL
import Data.Proxy (Proxy)
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding as TE (encodeUtf8)
import Database.Persist (EntityField, Filter(..), PersistValue(..), PersistField(..), PersistFilter(..))
import Database.Persist.Sql (PersistFieldSql(..), SqlType(..))
import Database.Persist.Types (FilterValue(..))
infix 4 @>., <@., ?., ?|., ?&.
(@>.) :: EntityField record Value -> Value -> Filter record
@>. :: EntityField record Value -> Value -> Filter record
(@>.) EntityField record Value
field Value
val = EntityField record Value
-> FilterValue Value -> PersistFilter -> Filter record
forall record typ.
PersistField typ =>
EntityField record typ
-> FilterValue typ -> PersistFilter -> Filter record
Filter EntityField record Value
field (Value -> FilterValue Value
forall typ. typ -> FilterValue typ
FilterValue Value
val) (PersistFilter -> Filter record) -> PersistFilter -> Filter record
forall a b. (a -> b) -> a -> b
$ Text -> PersistFilter
BackendSpecificFilter Text
" @> "
(<@.) :: EntityField record Value -> Value -> Filter record
<@. :: EntityField record Value -> Value -> Filter record
(<@.) EntityField record Value
field Value
val = EntityField record Value
-> FilterValue Value -> PersistFilter -> Filter record
forall record typ.
PersistField typ =>
EntityField record typ
-> FilterValue typ -> PersistFilter -> Filter record
Filter EntityField record Value
field (Value -> FilterValue Value
forall typ. typ -> FilterValue typ
FilterValue Value
val) (PersistFilter -> Filter record) -> PersistFilter -> Filter record
forall a b. (a -> b) -> a -> b
$ Text -> PersistFilter
BackendSpecificFilter Text
" <@ "
(?.) :: EntityField record Value -> Text -> Filter record
?. :: EntityField record Value -> Text -> Filter record
(?.) = Text -> EntityField record Value -> Text -> Filter record
forall a record.
PersistField a =>
Text -> EntityField record Value -> a -> Filter record
jsonFilter Text
" ?? "
(?|.) :: EntityField record Value -> [Text] -> Filter record
?|. :: EntityField record Value -> [Text] -> Filter record
(?|.) EntityField record Value
field = Text
-> EntityField record Value -> PostgresArray Text -> Filter record
forall a record.
PersistField a =>
Text -> EntityField record Value -> a -> Filter record
jsonFilter Text
" ??| " EntityField record Value
field (PostgresArray Text -> Filter record)
-> ([Text] -> PostgresArray Text) -> [Text] -> Filter record
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> PostgresArray Text
forall a. [a] -> PostgresArray a
PostgresArray
(?&.) :: EntityField record Value -> [Text] -> Filter record
?&. :: EntityField record Value -> [Text] -> Filter record
(?&.) EntityField record Value
field = Text
-> EntityField record Value -> PostgresArray Text -> Filter record
forall a record.
PersistField a =>
Text -> EntityField record Value -> a -> Filter record
jsonFilter Text
" ??& " EntityField record Value
field (PostgresArray Text -> Filter record)
-> ([Text] -> PostgresArray Text) -> [Text] -> Filter record
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> PostgresArray Text
forall a. [a] -> PostgresArray a
PostgresArray
jsonFilter :: PersistField a => Text -> EntityField record Value -> a -> Filter record
jsonFilter :: Text -> EntityField record Value -> a -> Filter record
jsonFilter Text
op EntityField record Value
field a
a = EntityField record Value
-> FilterValue Value -> PersistFilter -> Filter record
forall record typ.
PersistField typ =>
EntityField record typ
-> FilterValue typ -> PersistFilter -> Filter record
Filter EntityField record Value
field (a -> FilterValue Value
forall a typ. PersistField a => a -> FilterValue typ
UnsafeValue a
a) (PersistFilter -> Filter record) -> PersistFilter -> Filter record
forall a b. (a -> b) -> a -> b
$ Text -> PersistFilter
BackendSpecificFilter Text
op
instance PersistField Value where
toPersistValue :: Value -> PersistValue
toPersistValue = Value -> PersistValue
forall a. ToJSON a => a -> PersistValue
toPersistValueJsonB
fromPersistValue :: PersistValue -> Either Text Value
fromPersistValue = PersistValue -> Either Text Value
forall a. FromJSON a => PersistValue -> Either Text a
fromPersistValueJsonB
instance PersistFieldSql Value where
sqlType :: Proxy Value -> SqlType
sqlType = Proxy Value -> SqlType
forall a. (ToJSON a, FromJSON a) => Proxy a -> SqlType
sqlTypeJsonB
toPersistValueJsonB :: ToJSON a => a -> PersistValue
toPersistValueJsonB :: a -> PersistValue
toPersistValueJsonB = ByteString -> PersistValue
PersistLiteralEscaped (ByteString -> PersistValue)
-> (a -> ByteString) -> a -> PersistValue
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
BSL.toStrict (ByteString -> ByteString) -> (a -> ByteString) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ByteString
forall a. ToJSON a => a -> ByteString
encode
fromPersistValueJsonB :: FromJSON a => PersistValue -> Either Text a
fromPersistValueJsonB :: PersistValue -> Either Text a
fromPersistValueJsonB (PersistText Text
t) =
case ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecodeStrict (ByteString -> Either String a) -> ByteString -> Either String a
forall a b. (a -> b) -> a -> b
$ Text -> ByteString
TE.encodeUtf8 Text
t of
Left String
str -> Text -> Either Text a
forall a b. a -> Either a b
Left (Text -> Either Text a) -> Text -> Either Text a
forall a b. (a -> b) -> a -> b
$ Text -> Text -> Text -> Text
forall a. Show a => Text -> a -> Text -> Text
fromPersistValueParseError Text
"FromJSON" Text
t (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
str
Right a
v -> a -> Either Text a
forall a b. b -> Either a b
Right a
v
fromPersistValueJsonB (PersistByteString ByteString
bs) =
case ByteString -> Either String a
forall a. FromJSON a => ByteString -> Either String a
eitherDecodeStrict ByteString
bs of
Left String
str -> Text -> Either Text a
forall a b. a -> Either a b
Left (Text -> Either Text a) -> Text -> Either Text a
forall a b. (a -> b) -> a -> b
$ Text -> ByteString -> Text -> Text
forall a. Show a => Text -> a -> Text -> Text
fromPersistValueParseError Text
"FromJSON" ByteString
bs (Text -> Text) -> Text -> Text
forall a b. (a -> b) -> a -> b
$ String -> Text
T.pack String
str
Right a
v -> a -> Either Text a
forall a b. b -> Either a b
Right a
v
fromPersistValueJsonB PersistValue
x = Text -> Either Text a
forall a b. a -> Either a b
Left (Text -> Either Text a) -> Text -> Either Text a
forall a b. (a -> b) -> a -> b
$ Text -> Text -> PersistValue -> Text
fromPersistValueError Text
"FromJSON" Text
"string or bytea" PersistValue
x
sqlTypeJsonB :: (ToJSON a, FromJSON a) => Proxy a -> SqlType
sqlTypeJsonB :: Proxy a -> SqlType
sqlTypeJsonB Proxy a
_ = Text -> SqlType
SqlOther Text
"JSONB"
fromPersistValueError :: Text
-> Text
-> PersistValue
-> Text
fromPersistValueError :: Text -> Text -> PersistValue -> Text
fromPersistValueError Text
haskellType Text
databaseType PersistValue
received = [Text] -> Text
T.concat
[ Text
"Failed to parse Haskell type `"
, Text
haskellType
, Text
"`; expected "
, Text
databaseType
, Text
" from database, but received: "
, String -> Text
T.pack (PersistValue -> String
forall a. Show a => a -> String
show PersistValue
received)
, Text
". Potential solution: Check that your database schema matches your Persistent model definitions."
]
fromPersistValueParseError :: (Show a)
=> Text
-> a
-> Text
-> Text
fromPersistValueParseError :: Text -> a -> Text -> Text
fromPersistValueParseError Text
haskellType a
received Text
err = [Text] -> Text
T.concat
[ Text
"Failed to parse Haskell type `"
, Text
haskellType
, Text
"`, but received "
, String -> Text
T.pack (a -> String
forall a. Show a => a -> String
show a
received)
, Text
" | with error: "
, Text
err
]
newtype PostgresArray a = PostgresArray [a]
instance PersistField a => PersistField (PostgresArray a) where
toPersistValue :: PostgresArray a -> PersistValue
toPersistValue (PostgresArray [a]
ts) = [PersistValue] -> PersistValue
PersistArray ([PersistValue] -> PersistValue) -> [PersistValue] -> PersistValue
forall a b. (a -> b) -> a -> b
$ a -> PersistValue
forall a. PersistField a => a -> PersistValue
toPersistValue (a -> PersistValue) -> [a] -> [PersistValue]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [a]
ts
fromPersistValue :: PersistValue -> Either Text (PostgresArray a)
fromPersistValue (PersistArray [PersistValue]
as) = [a] -> PostgresArray a
forall a. [a] -> PostgresArray a
PostgresArray ([a] -> PostgresArray a)
-> Either Text [a] -> Either Text (PostgresArray a)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (PersistValue -> Either Text a)
-> [PersistValue] -> Either Text [a]
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse PersistValue -> Either Text a
forall a. PersistField a => PersistValue -> Either Text a
fromPersistValue [PersistValue]
as
fromPersistValue PersistValue
wat = Text -> Either Text (PostgresArray a)
forall a b. a -> Either a b
Left (Text -> Either Text (PostgresArray a))
-> Text -> Either Text (PostgresArray a)
forall a b. (a -> b) -> a -> b
$ Text -> Text -> PersistValue -> Text
fromPersistValueError Text
"PostgresArray" Text
"array" PersistValue
wat