polytropos-beam
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.Beam

Description

Enables polytropos open records to act as beam database schema tables without GHC out-of-memory compilation crashes on 50+ columns.

Architectural Overview & Rationale

Eliminating Generic Tree Explosion in Beam

A standard beam table is a nominal Haskell record whose Beamable instance is derived through GHC.Generics. The resulting binary metadata tree is what causes quadratic compile times and memory blow-up on tables with 50+ columns.

In polytropos-beam, a table is backed by a single flat SmallArray: * zipBeamFieldsM executes as a linear lockstep walk over flat array slots. * tblSkeleton builds the table spine once per row arity. * BeamTable is a zero-cost newtype wrapper around RowRep f ProductRowT r ().

When to Use This Module

  • When defining large database tables (dozens or hundreds of columns) with the beam framework while maintaining predictable, instantaneous compilation.

Worked Example

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedRecordDot #-}

import Database.Beam
import Polytropos
import Polytropos.Beam

type UserRow = '["id" ':= Int, "username" ':= String]
type UserTable f = BeamTable UserRow f

-- 1. Construct an open record using idiomatic REC syntax:
userRec :: Record UserRow
userRec = REC { id = 1, username = "Alice" }

-- 2. Convert to a Beam database table (zero-cost unwrap):
userTable :: UserTable Identity
userTable = toBeamTable userRec

-- 3. Functional updates using REC_UPD prior to database serialization:
updatedUser :: Record UserRow
updatedUser = (REC_UPD userRec) { username = "Bob" }

-- 4. Higher-Kinded Data (HKD) partial table with REC_F and REC_UPD_F:
partialUser :: RecordF Maybe UserRow
partialUser = REC_F { id = Just 1, username = Nothing }

populatedUser :: RecordF Maybe UserRow
populatedUser = (REC_UPD_F partialUser) { username = Just "Bob" }
Synopsis

Beam Tables over Polytropos Rows

newtype BeamTable (r :: Row) (f :: Type -> Type) Source #

A polytropos row presented as a beam table with column functor f.

Zero cost: unwraps to exactly the same Rep spine as the corresponding Record (for f ~ Identity).

Constructors

BeamTable (RowRep f 'ProductRowT r ()) 

Instances

Instances details
FieldNames r => Beamable (BeamTable r) Source # 
Instance details

Defined in Polytropos.Beam

Methods

zipBeamFieldsM :: forall m (f :: Type -> Type) (g :: Type -> Type) (h :: Type -> Type). Applicative m => (forall a. Columnar' f a -> Columnar' g a -> m (Columnar' h a)) -> BeamTable r f -> BeamTable r g -> m (BeamTable r h) #

tblSkeleton :: TableSkeleton (BeamTable r) #

toBeamTable :: forall (r :: Row). Record r -> BeamTable r Identity Source #

View a record as a beam table (zero-cost newtype wrap).

fromBeamTable :: forall (r :: Row). BeamTable r Identity -> Record r Source #

View a beam table as a record (zero-cost newtype unwrap).

beamTableOfSlots :: forall f (r :: Row). [f (Any :: Type)] -> BeamTable r f Source #

Build a table from payload slots, in row order. The slot list must have exactly the row's arity; a shorter list yields a partially filled table that will misbehave if traversed, so prefer toBeamTable.

Row Introspection

class FieldNames (r :: Row) where Source #

The field names of a row, in row order, reified from the type level. These are the default column names beam derives from the row symbols.

Methods

fieldNames :: Proxy r -> [String] Source #

Instances

Instances details
FieldNames ('[] :: [Pair Symbol Type]) Source # 
Instance details

Defined in Polytropos.Beam

Methods

fieldNames :: Proxy ('[] :: [Pair Symbol Type]) -> [String] Source #

(KnownSymbol n, FieldNames r) => FieldNames ((n ':= a) ': r) Source # 
Instance details

Defined in Polytropos.Beam

Methods

fieldNames :: Proxy ((n ':= a) ': r) -> [String] Source #