duckdb-simple
Safe HaskellNone
LanguageHaskell2010

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 DuckValue are encoded as STRUCT values. Record fields retain their selector name; positional products fall back to field1, field2, …
  • Sum types (:+:) become UNION values. Each constructor becomes a union member; payloads are encoded as structs (or NULL for 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:

  • DuckValue covers leaf-level conversions between Haskell values, DuckDB FieldValues, and logical type metadata.
  • GToField and friends walk the generic representation to assemble structs or unions and carry around the logical type information we later need when binding parameters.
  • ViaDuckDB wires 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

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

duckToField, duckLogicalType

Instances

Instances details
DuckValue ByteString Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue IntervalValue Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue TimeWithZone Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Int16 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Int32 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Int64 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Int8 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Word16 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Word32 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Word64 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Word8 Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Text Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Day Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue UTCTime Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue LocalTime Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue TimeOfDay Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue UUID Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Integer Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Natural Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue String Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Bool Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Double Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Float Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Int Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue Word Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue a => DuckValue (Maybe a) Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue a => DuckValue [a] Source #

List values encode as DuckDB LIST (variable-length).

Instance details

Defined in Database.DuckDB.Simple.Generic

(Ord k, DuckValue k, DuckValue v) => DuckValue (Map k v) Source #

Map values encode as DuckDB MAP.

Instance details

Defined in Database.DuckDB.Simple.Generic

DuckValue a => DuckValue (Array Int a) Source #

Array values encode as DuckDB ARRAY (fixed-length). Note: Arrays must have consistent bounds to work correctly with DuckDB.

Instance details

Defined in Database.DuckDB.Simple.Generic

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

Instances details
GToField' (IsSum f) f => GToField f Source # 
Instance details

Defined in Database.DuckDB.Simple.Generic

Methods

gToField :: f p -> Encoded

gLogicalType :: Proxy (f p) -> LogicalTypeRep

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

Instances details
GFromField' (IsSum f) f => GFromField f Source # 
Instance details

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

newtype ViaDuckDB a Source #

Wrapper for deriving-via so that instance ToField (ViaDuckDB a) picks up the generic encoding provided by this module.

Constructors

ViaDuckDB 

Fields

Instances

Instances details
(Generic a, GFromField (Rep a), Typeable a) => FromField (ViaDuckDB a) Source #

Deriving-via FromField instance. Errors are rewrapped using the existing returnError helper so callers receive a proper ResultError.

Instance details

Defined in Database.DuckDB.Simple.Generic

(Generic a, GToField (Rep a)) => DuckDBColumnType (ViaDuckDB a) Source #

The deriving-via version of DuckDBColumnType. We look at the generic logical type and map it back to a textual name. The textual names are only used for diagnostics (errors and column metadata).

Instance details

Defined in Database.DuckDB.Simple.Generic

(Generic a, GToField (Rep a)) => ToField (ViaDuckDB a) Source #

Deriving-via ToField instance. We reuse the helpers above to decide whether the top-level representation is a union, struct, or scalar and then delegate to the existing ToField instances for those composite types.

Instance details

Defined in Database.DuckDB.Simple.Generic