polytropos-rel8
Copyright(c) 2026 The Polytropos Authors
LicenseEUPL-1.2 OR Apache-2.0
Maintainernadia.yvette.chambers@ik.me
Stabilityexperimental
Portabilitynon-portable (GHC extensions)
Safe HaskellNone
LanguageGHC2021

Polytropos.Rel8

Description

Integration of polytropos open rows with Oliver Charles' rel8 PostgreSQL framework.

Architectural Overview & Rationale

PolyRow provides rel8's Rel8able for the product row r: * Its column schema is a right-nested HProduct tree of HLabeled HIdentity columns built directly from the row's type-level field list. * The flat SmallArray payload of the underlying Rep is read and written slot by slot — one slot per column, in row order. * Conversion to and from rel8's columnar representation never materialises an intermediate tuple and is unbounded in arity, completely avoiding GHC's 62-column tuple limit.

When to Use This Module

  • When defining database schemas and type-safe SQL queries with rel8 where rows are modelled as open polytropos records.

Worked Example

Worked Example

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -fplugin=Polytropos.Plugin #-}

import Rel8
import Polytropos
import Polytropos.Rel8

type AccountRow = '["id" ':= Int64, "balance" ':= Double]
type AccountTable = PolyRow AccountRow

-- Lift a record to a Rel8 SQL expression row:
rec :: Record AccountRow
rec = REC { id = 42 :: Int64, balance = 1000.50 :: Double }

sqlExpr :: AccountTable Expr
sqlExpr = litRecord rec
Synopsis

A rel8 Table from an Open Row

newtype PolyRow (r :: Row) (context :: Type -> Type) Source #

A rel8 table row backed by an open polytropos product row r.

The newtype is polymorphic in the rel8 context functor context so that rel8 can use the same Rel8able at Result, Expr, Name, etc.

Constructors

PolyRow 

Fields

Instances

Instances details
Rel8ableRow r => Rel8able (PolyRow r) Source # 
Instance details

Defined in Polytropos.Rel8

Associated Types

type GColumns (PolyRow r) 
Instance details

Defined in Polytropos.Rel8

type GFromExprs (PolyRow r) 
Instance details

Defined in Polytropos.Rel8

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns (PolyRow r) context -> PolyRow r context #

gtoColumns :: forall (context :: Context). SContext context -> PolyRow r context -> GColumns (PolyRow r) context #

gfromResult :: GColumns (PolyRow r) Result -> GFromExprs (PolyRow r) #

gtoResult :: GFromExprs (PolyRow r) -> GColumns (PolyRow r) Result #

Eq (Record r) => Eq (PolyRow r Result) Source # 
Instance details

Defined in Polytropos.Rel8

Show (Record r) => Show (PolyRow r Result) Source # 
Instance details

Defined in Polytropos.Rel8

type GColumns (PolyRow r) Source # 
Instance details

Defined in Polytropos.Rel8

type GFromExprs (PolyRow r) Source # 
Instance details

Defined in Polytropos.Rel8

toRecord :: forall (r :: Row). PolyRow r Result -> Record r Source #

Convert a PolyRow r Result to a polytropos Record r.

fromRecord :: forall (r :: Row). Record r -> PolyRow r Result Source #

Wrap a polytropos Record r as a PolyRow r Result.

Schema & Rel8able Row Class

class HTable (GColumns t) => Rel8able (t :: Rel8able) #

This type class allows you to define custom Tables using higher-kinded data types. Higher-kinded data types are data types of the pattern:

data MyType f =
  MyType { field1 :: Column f T1 OR HK1 f
         , field2 :: Column f T2 OR HK2 f
         , ...
         , fieldN :: Column f Tn OR HKn f
         }

where Tn is any Haskell type, and HKn is any higher-kinded type.

That is, higher-kinded data are records where all fields in the record are all either of the type Column f T (for any T), or are themselves higher-kinded data:

Nested
data Nested f =
  Nested { nested1 :: MyType f
         , nested2 :: MyType f
         }

The Rel8able type class is used to give us a special mapping operation that lets us change the type parameter f.

Supplying Rel8able instances

This type class should be derived generically for all table types in your project. To do this, enable the DeriveAnyClass and DeriveGeneric language extensions:

{-# LANGUAGE DeriveAnyClass, DeriveGeneric #-}

data MyType f = MyType { fieldA :: Column f T }
  deriving ( GHC.Generics.Generic, Rel8able )

Instances

Instances details
Rel8able Attribute # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns Attribute 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns Attribute = GColumns TColumns (GRep Attribute Expr)
type GFromExprs Attribute 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs Attribute = Attribute Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns Attribute context -> Attribute context #

gtoColumns :: forall (context :: Context). SContext context -> Attribute context -> GColumns Attribute context #

gfromResult :: GColumns Attribute Result -> GFromExprs Attribute #

gtoResult :: GFromExprs Attribute -> GColumns Attribute Result #

Rel8able Cast # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns Cast 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns Cast = GColumns TColumns (GRep Cast Expr)
type GFromExprs Cast 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs Cast = Cast Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns Cast context -> Cast context #

gtoColumns :: forall (context :: Context). SContext context -> Cast context -> GColumns Cast context #

gfromResult :: GColumns Cast Result -> GFromExprs Cast #

gtoResult :: GFromExprs Cast -> GColumns Cast Result #

Rel8able PGAttribute # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGAttribute 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGAttribute = GColumns TColumns (GRep PGAttribute Expr)
type GFromExprs PGAttribute 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGAttribute = PGAttribute Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGAttribute context -> PGAttribute context #

gtoColumns :: forall (context :: Context). SContext context -> PGAttribute context -> GColumns PGAttribute context #

gfromResult :: GColumns PGAttribute Result -> GFromExprs PGAttribute #

gtoResult :: GFromExprs PGAttribute -> GColumns PGAttribute Result #

Rel8able PGCast # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGCast 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGCast = GColumns TColumns (GRep PGCast Expr)
type GFromExprs PGCast 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGCast = PGCast Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGCast context -> PGCast context #

gtoColumns :: forall (context :: Context). SContext context -> PGCast context -> GColumns PGCast context #

gfromResult :: GColumns PGCast Result -> GFromExprs PGCast #

gtoResult :: GFromExprs PGCast -> GColumns PGCast Result #

Rel8able PGClass # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGClass 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGClass = GColumns TColumns (GRep PGClass Expr)
type GFromExprs PGClass 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGClass = PGClass Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGClass context -> PGClass context #

gtoColumns :: forall (context :: Context). SContext context -> PGClass context -> GColumns PGClass context #

gfromResult :: GColumns PGClass Result -> GFromExprs PGClass #

gtoResult :: GFromExprs PGClass -> GColumns PGClass Result #

Rel8able PGNamespace # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGNamespace 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGNamespace = GColumns TColumns (GRep PGNamespace Expr)
type GFromExprs PGNamespace 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGNamespace = PGNamespace Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGNamespace context -> PGNamespace context #

gtoColumns :: forall (context :: Context). SContext context -> PGNamespace context -> GColumns PGNamespace context #

gfromResult :: GColumns PGNamespace Result -> GFromExprs PGNamespace #

gtoResult :: GFromExprs PGNamespace -> GColumns PGNamespace Result #

Rel8able PGTable # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGTable 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGTable = GColumns TColumns (GRep PGTable Expr)
type GFromExprs PGTable 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGTable = PGTable Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGTable context -> PGTable context #

gtoColumns :: forall (context :: Context). SContext context -> PGTable context -> GColumns PGTable context #

gfromResult :: GColumns PGTable Result -> GFromExprs PGTable #

gtoResult :: GFromExprs PGTable -> GColumns PGTable Result #

Rel8able PGType # 
Instance details

Defined in Rel8.Internal.Table.Verify

Associated Types

type GColumns PGType 
Instance details

Defined in Rel8.Internal.Table.Verify

type GColumns PGType = GColumns TColumns (GRep PGType Expr)
type GFromExprs PGType 
Instance details

Defined in Rel8.Internal.Table.Verify

type GFromExprs PGType = PGType Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns PGType context -> PGType context #

gtoColumns :: forall (context :: Context). SContext context -> PGType context -> GColumns PGType context #

gfromResult :: GColumns PGType Result -> GFromExprs PGType #

gtoResult :: GFromExprs PGType -> GColumns PGType Result #

Rel8ableRow r => Rel8able (PolyRow r) Source # 
Instance details

Defined in Polytropos.Rel8

Associated Types

type GColumns (PolyRow r) 
Instance details

Defined in Polytropos.Rel8

type GFromExprs (PolyRow r) 
Instance details

Defined in Polytropos.Rel8

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns (PolyRow r) context -> PolyRow r context #

gtoColumns :: forall (context :: Context). SContext context -> PolyRow r context -> GColumns (PolyRow r) context #

gfromResult :: GColumns (PolyRow r) Result -> GFromExprs (PolyRow r) #

gtoResult :: GFromExprs (PolyRow r) -> GColumns (PolyRow r) Result #

ADTable t => Rel8able (ADT t) # 
Instance details

Defined in Rel8.Internal.Table.ADT

Associated Types

type GColumns (ADT t) 
Instance details

Defined in Rel8.Internal.Table.ADT

type GColumns (ADT t) = GColumnsADT t
type GFromExprs (ADT t) 
Instance details

Defined in Rel8.Internal.Table.ADT

type GFromExprs (ADT t) = t Result

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns (ADT t) context -> ADT t context #

gtoColumns :: forall (context :: Context). SContext context -> ADT t context -> GColumns (ADT t) context #

gfromResult :: GColumns (ADT t) Result -> GFromExprs (ADT t) #

gtoResult :: GFromExprs (ADT t) -> GColumns (ADT t) Result #

HKDable a => Rel8able (HKD a) # 
Instance details

Defined in Rel8.Internal.Table.HKD

Associated Types

type GColumns (HKD a) 
Instance details

Defined in Rel8.Internal.Table.HKD

type GColumns (HKD a) = GColumnsHKD a
type GFromExprs (HKD a) 
Instance details

Defined in Rel8.Internal.Table.HKD

type GFromExprs (HKD a) = a

Methods

gfromColumns :: forall (context :: Context). SContext context -> GColumns (HKD a) context -> HKD a context #

gtoColumns :: forall (context :: Context). SContext context -> HKD a context -> GColumns (HKD a) context #

gfromResult :: GColumns (HKD a) Result -> GFromExprs (HKD a) #

gtoResult :: GFromExprs (HKD a) -> GColumns (HKD a) Result #

class (AllSql r, HTable (RowHTable r)) => Rel8ableRow (r :: Row) where Source #

Type class providing bidirectional conversion between a flat SmallArray of slots and the nested rel8 RowHTable column tree.

Methods

toHTable :: SmallArray (context (Any :: Type)) -> Int -> (RowHTable r context, Int) Source #

Convert a flat array into the nested HTable tree at a given starting offset.

fromHTable :: RowHTable r context -> [context (Any :: Type)] Source #

Unroll the nested HTable tree into a list of erased column context slots.

litHTable :: RowHTable r Result -> RowHTable r Expr Source #

Lift column values at Result (tIdentity) into PostgreSQL expressions (Expr).

rowArity :: Int Source #

Arity (number of columns).

Instances

Instances details
(KnownSymbol n, Sql DBType a, Rel8ableRow (r1 ': rs)) => Rel8ableRow ((n ':= a) ': (r1 ': rs)) Source # 
Instance details

Defined in Polytropos.Rel8

Methods

toHTable :: SmallArray (context (Any :: Type)) -> Int -> (RowHTable ((n ':= a) ': (r1 ': rs)) context, Int) Source #

fromHTable :: RowHTable ((n ':= a) ': (r1 ': rs)) context -> [context (Any :: Type)] Source #

litHTable :: RowHTable ((n ':= a) ': (r1 ': rs)) Result -> RowHTable ((n ':= a) ': (r1 ': rs)) Expr Source #

rowArity :: Int Source #

(KnownSymbol n, Sql DBType a) => Rel8ableRow '[n ':= a] Source # 
Instance details

Defined in Polytropos.Rel8

Methods

toHTable :: SmallArray (context (Any :: Type)) -> Int -> (RowHTable '[n ':= a] context, Int) Source #

fromHTable :: RowHTable '[n ':= a] context -> [context (Any :: Type)] Source #

litHTable :: RowHTable '[n ':= a] Result -> RowHTable '[n ':= a] Expr Source #

rowArity :: Int Source #

type family RowHTable (r :: Row) :: Context -> Type where ... Source #

Map a polytropos product row to rel8's HTable: a right-nested HProduct tree of HLabeled HIdentity columns, one per field, named by the field's Symbol.

Equations

RowHTable '[n ':= a] = HLabel n (HIdentity a) 
RowHTable ((n ':= a) ': r) = HProduct (HLabel n (HIdentity a)) (RowHTable r) 

type family AllSql (r :: Row) where ... Source #

Constraint: every field label has a KnownSymbol instance and its type is a PostgreSQL Sql DBType.

Equations

AllSql ('[] :: [Pair Symbol Type]) = () 
AllSql '[n ':= a] = (KnownSymbol n, Sql DBType a) 
AllSql ((n ':= a) ': r) = (KnownSymbol n, Sql DBType a, AllSql r) 

Entry points for Identity/Result

rowToColumns :: forall (r :: Row). Rel8ableRow r => Record r -> RowHTable r Identity Source #

Pack a Record r into its rel8 column tree at Identity.

columnsToRow :: forall (r :: Row). Rel8ableRow r => RowHTable r Identity -> Record r Source #

Unpack rel8 columns (at Identity) back into a Record r.

Lifting to SQL Expressions

litPolyRow :: forall (r :: Row). Rel8ableRow r => PolyRow r Result -> PolyRow r Expr Source #

Lift a PolyRow r Result to a PolyRow r Expr.

litRecord :: forall (r :: Row). Rel8ableRow r => Record r -> PolyRow r Expr Source #

Lift a polytropos Record r directly into a PolyRow r Expr.

Columnar Combinators

hfield :: forall (name :: Symbol) (r :: Row) context a. FieldIndex name r a => Field name -> PolyRow r context -> context a Source #

Read a field by name using FieldIndex.

hfieldAt :: forall (r :: Row) context. Int -> PolyRow r context -> context (Any :: Type) Source #

Read a field at a slot index from a PolyRow.

htabulate :: forall (r :: Row) context. Rel8ableRow r => (Int -> context (Any :: Type)) -> PolyRow r context Source #

Build a PolyRow by evaluating a generator across each column slot.

hmap :: forall (r :: Row) f g. Rel8ableRow r => (forall a. f a -> g a) -> PolyRow r f -> PolyRow r g Source #

Map a natural transformation across all columns in a PolyRow.

htraverse :: forall (r :: Row) f g m. (Applicative m, Rel8ableRow r) => (forall a. f a -> m (g a)) -> PolyRow r f -> m (PolyRow r g) Source #

Traverse all columnar fields in a PolyRow.

hzipWith :: forall (r :: Row) f g h. Rel8ableRow r => (forall a. f a -> g a -> h a) -> PolyRow r f -> PolyRow r g -> PolyRow r h Source #

Zip two columnar records slot-by-slot in a tight vector loop.