| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
Database.DuckDB.Simple.Generic
Description
This module provides the glue needed to reuse the existing ToField/FromField
machinery with algebraic data types via GHC generics. The supported mapping is
currently intentionally conservative:
- Product types (records or tuples) whose fields already satisfy
DuckValueare encoded as STRUCT values. Record fields retain their selector name; positional products fall back tofield1,field2, … - Sum types (:+:) become UNION values. Each constructor becomes a union
member; payloads are encoded as structs (or
NULLfor nullary constructors).
Recursive types are supported as long as every payload is itself encodable
through DuckValue. Note that sum types must have constructor fields that are
structural products (i.e. we do not yet expose mixed union/record nesting for
non-record constructors).
Typical usage looks like:
data User = User { userId :: Int64, userName :: Text }
deriving stock (Generic)
instance DuckValue User
toField (genericToFieldValue user) -- Struct {"userId" := ..., ...}For sum types:
data Shape = Circle Double | Rectangle Double Double | Origin deriving stock (Generic) instance DuckValue Shape
Constructors are turned into a union with members Circle{radius},
Rectangle{width,height}, and Origin (null payload).
You can also lean on DerivingVia using the exported ViaDuckDB newtype:
data User = User { userId :: Int64, userName :: Text }
deriving stock (Generic)
deriving (DuckDBColumnType, ToField, FromField) via (ViaDuckDB User)The derived instances automatically encodedecode via STRUCTUNION representations.
Extending this module
The rest of this file is organised so that each building block is reusable:
DuckValuecovers leaf-level conversions between Haskell values, DuckDBFieldValues, and logical type metadata.GToFieldand friends walk the generic representation to assemble structs or unions and carry around the logical type information we later need when binding parameters.ViaDuckDBwires everything together for deriving via.
When adding new features, mimic the structure used here (and document new classes the way the existing ones are documented) so other backends can take inspiration from this implementation.
Synopsis
- class DuckValue a where
- duckToField :: a -> FieldValue
- duckFromField :: FieldValue -> Either String a
- duckLogicalType :: Proxy a -> LogicalTypeRep
- class GToField (f :: Type -> Type)
- class GFromField (f :: Type -> Type)
- genericToFieldValue :: (Generic a, GToField (Rep a)) => a -> FieldValue
- genericFromFieldValue :: (Generic a, GFromField (Rep a)) => FieldValue -> Either String a
- genericLogicalType :: (Generic a, GToField (Rep a)) => Proxy a -> LogicalTypeRep
- genericToStructValue :: (Generic a, GToField (Rep a)) => a -> Maybe (StructValue FieldValue)
- genericToUnionValue :: (Generic a, GToField (Rep a)) => a -> Maybe (UnionValue FieldValue)
- newtype ViaDuckDB a = ViaDuckDB {
- getViaDuckDB :: a
Field-level primitives
class DuckValue a where Source #
Types that can appear inside generated structs/unions.
A DuckValue instance must provide:
- encoding to
FieldValue - logical type metadata (
duckLogicalType) - decoding from
FieldValue
The primitive instances below are the canonical source for how scalar types
should be represented; both the generic implementation and the manual
ToField/FromField instances rely on them.
Minimal complete definition
Methods
duckToField :: a -> FieldValue Source #
duckFromField :: FieldValue -> Either String a Source #
default duckFromField :: (FromField a, Show a) => FieldValue -> Either String a Source #
duckLogicalType :: Proxy a -> LogicalTypeRep Source #
Instances
class GToField (f :: Type -> Type) Source #
Generic encoding to the intermediate Encoded representation. Every
instance must also supply the corresponding logical type description.
Minimal complete definition
gToField, gLogicalType
Instances
| GToField' (IsSum f) f => GToField f Source # | |
Defined in Database.DuckDB.Simple.Generic | |
class GFromField (f :: Type -> Type) Source #
Generic decoding entry point mirroring GToField. This is used both by
genericFromFieldValue and the Generically deriving helper.
Minimal complete definition
gFromField
Instances
| GFromField' (IsSum f) f => GFromField f Source # | |
Defined in Database.DuckDB.Simple.Generic Methods gFromField :: FieldValue -> Either String (f p) | |
Generic encoding/decoding for ADTs
genericToFieldValue :: (Generic a, GToField (Rep a)) => a -> FieldValue Source #
Convert a Haskell value (using its generic representation) into a DuckDB FieldValue.
genericFromFieldValue :: (Generic a, GFromField (Rep a)) => FieldValue -> Either String a Source #
Decode a DuckDB FieldValue back into a Haskell value using its generic representation.
genericLogicalType :: (Generic a, GToField (Rep a)) => Proxy a -> LogicalTypeRep Source #
Extract the logical DuckDB type corresponding to a Haskell value.
genericToStructValue :: (Generic a, GToField (Rep a)) => a -> Maybe (StructValue FieldValue) Source #
Convenience helpers that project out structured values directly.
genericToUnionValue :: (Generic a, GToField (Rep a)) => a -> Maybe (UnionValue FieldValue) Source #
Extract a UNION-shaped generic encoding directly when one is produced.
DerivingVia helper
Wrapper for deriving-via so that instance ToField (ViaDuckDB a) picks up
the generic encoding provided by this module.
Constructors
| ViaDuckDB | |
Fields
| |
Instances
| (Generic a, GFromField (Rep a), Typeable a) => FromField (ViaDuckDB a) Source # | Deriving-via |
Defined in Database.DuckDB.Simple.Generic Methods fromField :: FieldParser (ViaDuckDB a) Source # | |
| (Generic a, GToField (Rep a)) => DuckDBColumnType (ViaDuckDB a) Source # | The deriving-via version of |
Defined in Database.DuckDB.Simple.Generic | |
| (Generic a, GToField (Rep a)) => ToField (ViaDuckDB a) Source # | Deriving-via |
Defined in Database.DuckDB.Simple.Generic Methods toField :: ViaDuckDB a -> FieldBinding Source # | |