hasql-postgresql-types 0.1.0.1 → 0.2
raw patch · 5 files changed
+255/−52 lines, 5 filesdep +hasql-mappingdep +postgresql-typesdep ~hasqlPVP ok
version bump matches the API change (PVP)
Dependencies added: hasql-mapping, postgresql-types
Dependency ranges changed: hasql
API changes (from Hackage documentation)
- Hasql.PostgresqlTypes: decoder :: IsScalar a => Value a
- Hasql.PostgresqlTypes: encoder :: IsScalar a => Value a
+ Hasql.PostgresqlTypes: instance (GHC.Internal.TypeNats.KnownNat precision, GHC.Internal.TypeNats.KnownNat scale) => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Numeric.Numeric precision scale)
+ Hasql.PostgresqlTypes: instance GHC.Internal.TypeNats.KnownNat len => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Bit.Bit len)
+ Hasql.PostgresqlTypes: instance GHC.Internal.TypeNats.KnownNat len => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Bpchar.Bpchar len)
+ Hasql.PostgresqlTypes: instance GHC.Internal.TypeNats.KnownNat maxLen => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Varbit.Varbit maxLen)
+ Hasql.PostgresqlTypes: instance GHC.Internal.TypeNats.KnownNat maxLen => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Varchar.Varchar maxLen)
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Bool.Bool
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Box.Box
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Bytea.Bytea
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Char.Char
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Cidr.Cidr
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Circle.Circle
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Date.Date
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Float4.Float4
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Float8.Float8
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Hstore.Hstore
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Inet.Inet
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Int2.Int2
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Int4.Int4
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Int8.Int8
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Interval.Interval
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Json.Json
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Jsonb.Jsonb
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Line.Line
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Lseg.Lseg
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Macaddr.Macaddr
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Macaddr8.Macaddr8
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Money.Money
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Oid.Oid
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Path.Path
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Point.Point
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Polygon.Polygon
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Text.Text
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Time.Time
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Timestamp.Timestamp
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Timestamptz.Timestamptz
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Timetz.Timetz
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Tsvector.Tsvector
+ Hasql.PostgresqlTypes: instance Hasql.Mapping.IsScalar.IsScalar PostgresqlTypes.Uuid.Uuid
+ Hasql.PostgresqlTypes: instance PostgresqlTypes.Algebra.IsMultirangeElement element => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Multirange.Multirange element)
+ Hasql.PostgresqlTypes: instance PostgresqlTypes.Algebra.IsRangeElement element => Hasql.Mapping.IsScalar.IsScalar (PostgresqlTypes.Range.Range element)
Files
- CHANGELOG.md +17/−0
- README.md +4/−3
- hasql-postgresql-types.cabal +8/−2
- src/library/Hasql/PostgresqlTypes.hs +170/−47
- src/library/Hasql/PostgresqlTypes/Core.hs +56/−0
+ CHANGELOG.md view
@@ -0,0 +1,17 @@+# Changelog++## 0.2++*Breaking changes*++- Removed the `encoder` and `decoder` functions from `Hasql.PostgresqlTypes`. Codec access is now done via the `IsScalar` typeclass from the new [`hasql-mapping`](https://hackage.haskell.org/package/hasql-mapping) dependency. Import `Hasql.PostgresqlTypes ()` to bring the instances into scope, then use `Hasql.Mapping.IsScalar.encoder` and `Hasql.Mapping.IsScalar.decoder` (or the re-exports from `Hasql.Mapping`).+- Bumped `hasql` lower bound from `1.10.1` to `1.10.3`.++*New features*++- Added `IsScalar` instances for all PostgreSQL types defined in [`postgresql-types`](https://hackage.haskell.org/package/postgresql-types), including `Tsvector`.+- Added new dependencies: [`hasql-mapping`](https://hackage.haskell.org/package/hasql-mapping) and [`postgresql-types`](https://hackage.haskell.org/package/postgresql-types).++## 0.1.0.1++Initial release.
README.md view
@@ -13,16 +13,17 @@ ## Usage ```haskell-import Hasql.PostgresqlTypes (encoder, decoder)+import Hasql.PostgresqlTypes () -- for the instances import qualified PostgresqlTypes as Pt import qualified Hasql.Statement as Statement import qualified Hasql.Encoders as Encoders import qualified Hasql.Decoders as Decoders+import qualified Hasql.Mapping.IsScalar as IsScalar myStatement :: Statement.Statement Pt.Timestamptz [Pt.Timestamptz] myStatement = Statement.preparable sql enc dec where sql = "SELECT $1::timestamptz"- enc = Encoders.param (Encoders.nonNullable encoder)- dec = Decoders.rowList (Decoders.column (Decoders.nonNullable decoder))+ enc = Encoders.param (Encoders.nonNullable IsScalar.encoder)+ dec = Decoders.rowList (Decoders.column (Decoders.nonNullable IsScalar.decoder)) ```
hasql-postgresql-types.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: hasql-postgresql-types-version: 0.1.0.1+version: 0.2 category: PostgreSQL, Codecs, Hasql synopsis: Integration of "hasql" with "postgresql-types" description:@@ -19,6 +19,7 @@ license: MIT license-file: LICENSE extra-doc-files:+ CHANGELOG.md LICENSE README.md @@ -96,9 +97,14 @@ exposed-modules: Hasql.PostgresqlTypes + other-modules:+ Hasql.PostgresqlTypes.Core+ build-depends: base >=4.11 && <5,- hasql ^>=1.10.1,+ hasql ^>=1.10.3,+ hasql-mapping ^>=0.1,+ postgresql-types ^>=0.1, postgresql-types-algebra ^>=0.1, ptr-peeker ^>=0.1.0.1, ptr-poker ^>=0.1.3,
src/library/Hasql/PostgresqlTypes.hs view
@@ -1,68 +1,191 @@+{-# OPTIONS_GHC -Wno-orphans #-}+ -- | -- This module provides a bridge between the types defined in the ["postgresql-types"](https://hackage.haskell.org/package/postgresql-types) and the ["hasql"](https://hackage.haskell.org/package/hasql) library, -- offering automatic encoder and decoder generation for types that implement the 'IsScalar' constraint. -- -- == Usage Example ----- > import Hasql.PostgresqlTypes (encoder, decoder)+-- > import Hasql.PostgresqlTypes () -- > import qualified PostgresqlTypes as Pt -- > import qualified Hasql.Statement as Statement -- > import qualified Hasql.Encoders as Encoders -- > import qualified Hasql.Decoders as Decoders+-- > import qualified Hasql.Mapping.IsScalar as IsScalar -- > -- > myStatement :: Statement.Statement Pt.Timestamptz [Pt.Timestamptz] -- > myStatement = Statement.preparable sql enc dec -- > where -- > sql = "SELECT $1::timestamptz"--- > enc = Encoders.param (Encoders.nonNullable encoder)--- > dec = Decoders.rowList (Decoders.column (Decoders.nonNullable decoder))+-- > enc = Encoders.param (Encoders.nonNullable IsScalar.encoder)+-- > dec = Decoders.rowList (Decoders.column (Decoders.nonNullable IsScalar.decoder)) -- -- The 'encoder' and 'decoder' functions work with any type having an 'IsScalar' instance, -- automatically handling binary encoding/decoding and OID resolution.-module Hasql.PostgresqlTypes- ( encoder,- decoder,- )-where+module Hasql.PostgresqlTypes () where -import Data.String (fromString)-import Data.Tagged (untag)-import qualified Hasql.Decoders as Decoders-import qualified Hasql.Encoders as Encoders-import PostgresqlTypes.Algebra (IsScalar (..))-import qualified PtrPeeker-import qualified PtrPoker.Write as Write-import qualified TextBuilder-import Prelude+import GHC.TypeLits (KnownNat)+import qualified Hasql.Mapping.IsScalar as IsScalar+import qualified Hasql.PostgresqlTypes.Core as Core+import PostgresqlTypes+import PostgresqlTypes.Algebra --- | Hasql value encoder for a PostgreSQL standard type.------ Generates a Hasql value encoder for any type implementing 'IsScalar'.--- The encoder handles type resolution, and binary encoding automatically.-encoder :: forall a. (IsScalar a) => Encoders.Value a-encoder =- Encoders.custom- Nothing- (untag (typeName @a))- ((,) <$> untag (baseOid @a) <*> untag (arrayOid @a))- []- (\_ value -> Write.toByteString (binaryEncoder value))- (TextBuilder.toText . textualEncoder)+instance (KnownNat len) => IsScalar.IsScalar (Bit len) where+ encoder = Core.encoder+ decoder = Core.decoder --- | Hasql value decoder for a PostgreSQL standard type.------ Generates a Hasql value decoder for any type implementing 'IsScalar'.--- The decoder handles type resolution, and binary decoding with proper error handling.-decoder :: forall a. (IsScalar a) => Decoders.Value a-decoder =- Decoders.custom- Nothing- (untag (typeName @a))- ((,) <$> untag (baseOid @a) <*> untag (arrayOid @a))- []- ( \_ bytes ->- case PtrPeeker.runVariableOnByteString binaryDecoder bytes of- Left bytesUnconsumed -> Left ("Binary decoder did not consume all input bytes, unconsumed bytes: " <> fromString (show bytesUnconsumed))- Right (Left err) -> Left (fromString (show err))- Right (Right value) -> Right value- )+instance IsScalar.IsScalar Bool where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Box where+ encoder = Core.encoder+ decoder = Core.decoder++instance (KnownNat len) => IsScalar.IsScalar (Bpchar len) where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Bytea where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Char where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Cidr where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Circle where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Date where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Float4 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Float8 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Hstore where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Inet where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Int2 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Int4 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Int8 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Interval where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Json where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Jsonb where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Line where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Lseg where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Macaddr where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Macaddr8 where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Money where+ encoder = Core.encoder+ decoder = Core.decoder++instance (IsMultirangeElement element) => IsScalar.IsScalar (Multirange element) where+ encoder = Core.encoder+ decoder = Core.decoder++instance (KnownNat precision, KnownNat scale) => IsScalar.IsScalar (Numeric precision scale) where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Oid where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Path where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Point where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Polygon where+ encoder = Core.encoder+ decoder = Core.decoder++instance (IsRangeElement element) => IsScalar.IsScalar (Range element) where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Text where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Time where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Timestamp where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Timestamptz where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Timetz where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Uuid where+ encoder = Core.encoder+ decoder = Core.decoder++instance (KnownNat maxLen) => IsScalar.IsScalar (Varbit maxLen) where+ encoder = Core.encoder+ decoder = Core.decoder++instance (KnownNat maxLen) => IsScalar.IsScalar (Varchar maxLen) where+ encoder = Core.encoder+ decoder = Core.decoder++instance IsScalar.IsScalar Tsvector where+ encoder = Core.encoder+ decoder = Core.decoder
+ src/library/Hasql/PostgresqlTypes/Core.hs view
@@ -0,0 +1,56 @@+-- |+-- Internal implementation of the hasql encoder and decoder for types+-- that implement the 'IsScalar' constraint from+-- ["postgresql-types-algebra"](https://hackage.haskell.org/package/postgresql-types-algebra).+-- These are used by the 'IsScalar.IsScalar' instances defined in+-- "Hasql.PostgresqlTypes".+--+-- The 'encoder' and 'decoder' functions work with any type having an 'IsScalar' instance,+-- automatically handling binary encoding/decoding and OID resolution.+module Hasql.PostgresqlTypes.Core+ ( encoder,+ decoder,+ )+where++import Data.String (fromString)+import Data.Tagged (untag)+import qualified Hasql.Decoders as Decoders+import qualified Hasql.Encoders as Encoders+import PostgresqlTypes.Algebra (IsScalar (..))+import qualified PtrPeeker+import qualified PtrPoker.Write as Write+import qualified TextBuilder+import Prelude++-- | Hasql value encoder for a PostgreSQL standard type.+--+-- Generates a Hasql value encoder for any type implementing 'IsScalar'.+-- The encoder handles type resolution, and binary encoding automatically.+encoder :: forall a. (IsScalar a) => Encoders.Value a+encoder =+ Encoders.custom+ Nothing+ (untag (typeName @a))+ ((,) <$> untag (baseOid @a) <*> untag (arrayOid @a))+ []+ (\_ value -> Write.toByteString (binaryEncoder value))+ (TextBuilder.toText . textualEncoder)++-- | Hasql value decoder for a PostgreSQL standard type.+--+-- Generates a Hasql value decoder for any type implementing 'IsScalar'.+-- The decoder handles type resolution, and binary decoding with proper error handling.+decoder :: forall a. (IsScalar a) => Decoders.Value a+decoder =+ Decoders.custom+ Nothing+ (untag (typeName @a))+ ((,) <$> untag (baseOid @a) <*> untag (arrayOid @a))+ []+ ( \_ bytes ->+ case PtrPeeker.runVariableOnByteString binaryDecoder bytes of+ Left bytesUnconsumed -> Left ("Binary decoder did not consume all input bytes, unconsumed bytes: " <> fromString (show bytesUnconsumed))+ Right (Left err) -> Left (fromString (show err))+ Right (Right value) -> Right value+ )