feat: allow instances of serialize + deserialize outside this lib

This commit is contained in:
orion 2024-04-05 20:06:23 -05:00
parent 07c2f5dd84
commit 5fcf8c4549
Signed by: orion
GPG Key ID: 6D4165AE4C928719
5 changed files with 66 additions and 85 deletions

View File

@ -1,5 +1,5 @@
import {readFile, writeFile} from 'fs/promises'
import {execSync} from 'child_process'
import { readFile, writeFile } from 'fs/promises'
import { execSync } from 'child_process'
let ver = process.argv[2]
if (!ver) {
@ -19,7 +19,10 @@ const spagonew = spago.replace(/version: .+/, `version: '${ver}'`)
await writeFile('./spago.yaml', spagonew)
const readme = await readFile('./README.md', 'utf8')
const readmenew = readme.replace(/packages\/purescript-postgresql\/.+?\//g, `/packages/purescript-postgresql/${ver}/`)
const readmenew = readme.replace(
/packages\/purescript-postgresql\/.+?\//g,
`/packages/purescript-postgresql/${ver}/`,
)
await writeFile('./README.md', readmenew)
execSync(`git add spago.yaml package.json README.md`)

View File

@ -5,35 +5,23 @@ import Prelude
import Control.Alt ((<|>))
import Control.Monad.Error.Class (liftMaybe)
import Data.Array.NonEmpty.Internal (NonEmptyArray)
import Data.Either (hush)
import Data.Foldable (intercalate)
import Data.Generic.Rep (class Generic)
import Data.Generic.Rep as G
import Data.Maybe (Maybe(..), fromJust)
import Data.Maybe (Maybe(..))
import Data.Newtype as Newtype
import Data.Postgres (RepT, deserialize, serialize)
import Data.Postgres.Custom (class CustomRep, quoted, typeName)
import Data.Postgres (class Rep, RepT, deserialize, serialize)
import Data.Postgres.Custom (quoted)
import Data.Postgres.Query (Query, emptyQuery)
import Data.Postgres.Raw (Raw)
import Data.String as String
import Data.String.Regex (Regex)
import Data.String.Regex as Regex
import Data.String.Regex.Flags as Regex.Flags
import Data.Symbol (class IsSymbol)
import Foreign (ForeignError(..))
import Partial.Unsafe (unsafePartial)
import Type.Prelude (Proxy(..), reflectSymbol)
upperRe :: Regex
upperRe = unsafePartial fromJust $ hush $ Regex.regex "[A-Z]" Regex.Flags.global
typeName :: forall @a ty. CustomEnum a ty => String
typeName = reflectSymbol (Proxy @ty)
leadingUnderRe :: Regex
leadingUnderRe = unsafePartial fromJust $ hush $ Regex.regex "^_" Regex.Flags.noFlags
pascalToSnake :: String -> String
pascalToSnake = String.toLower <<< Regex.replace leadingUnderRe "" <<< Regex.replace upperRe "_$1"
class CustomRep a ty <= CustomEnum a ty | a -> ty where
class (IsSymbol ty, Rep a) <= CustomEnum a ty | a -> ty where
enumVariants :: NonEmptyArray a
parseEnum :: String -> Maybe a
printEnum :: a -> String

View File

@ -3,27 +3,28 @@ module Data.Postgres.Custom where
import Prelude
import Control.Monad.Except (ExceptT)
import Data.Either (hush)
import Data.List.NonEmpty (NonEmptyList)
import Data.Maybe (Maybe)
import Data.Maybe (Maybe, fromJust)
import Data.Postgres.Raw (Raw)
import Data.String as String
import Data.String.Regex (Regex)
import Data.String.Regex as Regex
import Data.String.Regex.Flags as Regex.Flags
import Effect (Effect)
import Foreign (ForeignError)
import Partial.Unsafe (unsafePartial)
import Type.Data.Symbol (reflectSymbol)
import Type.Prelude (class IsSymbol, Proxy(..))
class (IsSymbol ty) <= CustomSerialize a ty | a -> ty where
customPrintExpr :: a -> Maybe String
customSerialize :: a -> ExceptT (NonEmptyList ForeignError) Effect Raw
class (IsSymbol ty) <= CustomDeserialize a ty | a -> ty where
customDeserialize :: Raw -> ExceptT (NonEmptyList ForeignError) Effect a
class (IsSymbol ty, CustomSerialize a ty, CustomDeserialize a ty) <= CustomRep a ty | a -> ty
instance (IsSymbol ty, CustomSerialize a ty, CustomDeserialize a ty) => CustomRep a ty
quoted :: String -> String
quoted s = "'" <> s <> "'"
typeName :: forall @a ty. CustomRep a ty => String
typeName = reflectSymbol (Proxy @ty)
upperRe :: Regex
upperRe = unsafePartial fromJust $ hush $ Regex.regex "[A-Z]" Regex.Flags.global
leadingUnderRe :: Regex
leadingUnderRe = unsafePartial fromJust $ hush $ Regex.regex "^_" Regex.Flags.noFlags
pascalToSnake :: String -> String
pascalToSnake = String.toLower <<< Regex.replace leadingUnderRe "" <<< Regex.replace upperRe "_$1"

View File

@ -12,7 +12,6 @@ import Data.DateTime (DateTime)
import Data.List.NonEmpty (NonEmptyList)
import Data.Maybe (Maybe(..))
import Data.Newtype (class Newtype, unwrap, wrap)
import Data.Postgres.Custom (class CustomDeserialize, class CustomSerialize, customDeserialize, customSerialize)
import Data.Postgres.Range (Range, __rangeFromRecord, __rangeRawFromRaw, __rangeRawFromRecord, __rangeRawToRecord, __rangeToRecord)
import Data.Postgres.Raw (Null(..), Raw, jsNull)
import Data.Postgres.Raw (unsafeFromForeign, asForeign) as Raw
@ -73,87 +72,84 @@ instance Serialize Raw where
serialize = pure
-- | `NULL`
else instance Serialize Unit where
instance Serialize Unit where
serialize _ = serialize Null
-- | `NULL`
else instance Serialize Null where
instance Serialize Null where
serialize _ = unsafeSerializeCoerce jsNull
-- | `json`, `jsonb`
else instance WriteForeign a => Serialize (JSON a) where
instance WriteForeign a => Serialize (JSON a) where
serialize = serialize <<< writeJSON <<< unwrap
-- | `bytea`
else instance Serialize Buffer where
instance Serialize Buffer where
serialize = unsafeSerializeCoerce
-- | `int2`, `int4`
else instance Serialize Int where
instance Serialize Int where
serialize = unsafeSerializeCoerce
-- | `int8`
else instance Serialize BigInt where
instance Serialize BigInt where
serialize = serialize <<< BigInt.toString
-- | `bool`
else instance Serialize Boolean where
instance Serialize Boolean where
serialize = unsafeSerializeCoerce
-- | `text`, `inet`, `tsquery`, `tsvector`, `uuid`, `xml`, `cidr`, `time`, `timetz`
else instance Serialize String where
instance Serialize String where
serialize = unsafeSerializeCoerce
-- | `float4`, `float8`
else instance Serialize Number where
instance Serialize Number where
serialize = unsafeSerializeCoerce
-- | `timestamp`, `timestamptz`
else instance Serialize DateTime where
instance Serialize DateTime where
serialize = serialize <<< unwrap <<< DateTime.ISO.fromDateTime
-- | `Just` -> `a`, `Nothing` -> `NULL`
else instance Serialize a => Serialize (Maybe a) where
instance Serialize a => Serialize (Maybe a) where
serialize (Just a) = serialize a
serialize Nothing = unsafeSerializeCoerce jsNull
-- | postgres `array`
else instance Serialize a => Serialize (Array a) where
instance Serialize a => Serialize (Array a) where
serialize = unsafeSerializeCoerce <=< traverse serialize
else instance (Ord a, Rep a) => Serialize (Range a) where
instance (Ord a, Rep a) => Serialize (Range a) where
serialize =
map (Raw.unsafeFromForeign <<< unsafeToForeign <<< __rangeRawFromRecord <<< __rangeToRecord)
<<< traverse serialize
else instance (CustomSerialize a ty) => Serialize a where
serialize = customSerialize
instance Deserialize Raw where
deserialize = pure
-- | `NULL` (always succeeds)
else instance Deserialize Unit where
instance Deserialize Unit where
deserialize _ = pure unit
-- | `NULL` (fails if non-null)
else instance Deserialize Null where
instance Deserialize Null where
deserialize = map (const Null) <<< F.readNullOrUndefined <<< Raw.asForeign
-- | `json`, `jsonb`
else instance ReadForeign a => Deserialize (JSON a) where
instance ReadForeign a => Deserialize (JSON a) where
deserialize = map wrap <<< (hoist (pure <<< unwrap) <<< readJSON') <=< deserialize @String
-- | `bytea`
else instance Deserialize Buffer where
instance Deserialize Buffer where
deserialize = (F.unsafeReadTagged "Buffer") <<< Raw.asForeign
-- | `int2`, `int4`
else instance Deserialize Int where
instance Deserialize Int where
deserialize = F.readInt <<< Raw.asForeign
-- | `int8`
else instance Deserialize BigInt where
instance Deserialize BigInt where
deserialize =
let
invalid s = pure $ ForeignError $ "Invalid bigint: " <> s
@ -162,30 +158,30 @@ else instance Deserialize BigInt where
fromString <=< deserialize @String
-- | `bool`
else instance Deserialize Boolean where
instance Deserialize Boolean where
deserialize = F.readBoolean <<< Raw.asForeign
-- | `text`, `inet`, `tsquery`, `tsvector`, `uuid`, `xml`, `cidr`, `time`, `timetz`
else instance Deserialize String where
instance Deserialize String where
deserialize = F.readString <<< Raw.asForeign
-- | `float4`, `float8`
else instance Deserialize Number where
instance Deserialize Number where
deserialize = F.readNumber <<< Raw.asForeign
-- | `timestamp`, `timestamptz`
else instance Deserialize DateTime where
instance Deserialize DateTime where
deserialize raw = do
s :: String <- deserialize raw
let invalid = pure $ ForeignError $ "Not a valid ISO8601 string: `" <> s <> "`"
liftMaybe invalid $ DateTime.ISO.toDateTime $ wrap s
-- | postgres `array`
else instance Deserialize a => Deserialize (Array a) where
instance Deserialize a => Deserialize (Array a) where
deserialize = traverse (deserialize <<< Raw.unsafeFromForeign) <=< F.readArray <<< Raw.asForeign
-- | non-NULL -> `Just`, NULL -> `Nothing`
else instance Deserialize a => Deserialize (Maybe a) where
instance Deserialize a => Deserialize (Maybe a) where
deserialize raw =
let
nothing = const Nothing <$> deserialize @Null raw
@ -193,8 +189,5 @@ else instance Deserialize a => Deserialize (Maybe a) where
in
just <|> nothing
else instance (Ord a, Rep a) => Deserialize (Range a) where
instance (Ord a, Rep a) => Deserialize (Range a) where
deserialize = traverse deserialize <=< map (__rangeFromRecord <<< __rangeRawToRecord) <<< lift <<< __rangeRawFromRaw
else instance (CustomDeserialize a ty) => Deserialize a where
deserialize = customDeserialize

View File

@ -9,8 +9,7 @@ import Data.DateTime (DateTime(..))
import Data.Generic.Rep (class Generic)
import Data.Maybe (Maybe(..))
import Data.Newtype (unwrap)
import Data.Postgres (deserialize, serialize, smash)
import Data.Postgres.Custom (class CustomDeserialize, class CustomSerialize, customDeserialize)
import Data.Postgres (class Deserialize, class Serialize, deserialize, serialize, smash)
import Data.Postgres.Custom.Enum (class CustomEnum, create, enumDeserialize, enumPrintExpr, enumSerialize, genericEnumVariants, genericParseEnum, genericPrintEnum, parseEnum, printEnum)
import Data.Show.Generic (genericShow)
import Effect.Class (liftEffect)
@ -25,12 +24,11 @@ derive instance Eq Enum1
instance Show Enum1 where
show = genericShow
instance CustomSerialize Enum1 "enum_1" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum1 where
serialize a = enumSerialize a
instance CustomDeserialize Enum1 "enum_1" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum1 where
deserialize a = enumDeserialize a
instance CustomEnum Enum1 "enum_1" where
printEnum = genericPrintEnum
@ -44,12 +42,11 @@ derive instance Eq Enum2
instance Show Enum2 where
show = genericShow
instance CustomSerialize Enum2 "enum_2" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum2 where
serialize a = enumSerialize a
instance CustomDeserialize Enum2 "enum_2" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum2 where
deserialize a = enumDeserialize a
instance CustomEnum Enum2 "enum_2" where
printEnum a = genericPrintEnum a
@ -63,12 +60,11 @@ derive instance Eq Enum5
instance Show Enum5 where
show = genericShow
instance CustomSerialize Enum5 "enum_5" where
customPrintExpr a = enumPrintExpr a
customSerialize a = enumSerialize a
instance Serialize Enum5 where
serialize a = enumSerialize a
instance CustomDeserialize Enum5 "enum_5" where
customDeserialize a = enumDeserialize a
instance Deserialize Enum5 where
deserialize a = enumDeserialize a
instance CustomEnum Enum5 "enum_5" where
printEnum a = genericPrintEnum a