beam-duckdb 0.1.0.0 → 0.1.1.0
raw patch · 6 files changed
+72/−30 lines, 6 filesdep +scientificPVP ok
version bump matches the API change (PVP)
Dependencies added: scientific
API changes (from Hackage documentation)
+ Database.Beam.DuckDB: runBeamDuckDBDebugString :: (String -> IO ()) -> Connection -> DuckDBM a -> IO a
Files
- CHANGELOG.md +5/−0
- README.md +13/−0
- beam-duckdb.cabal +2/−1
- src/Database/Beam/DuckDB.hs +8/−0
- src/Database/Beam/DuckDB/Backend.hs +38/−21
- src/Database/Beam/DuckDB/Syntax.hs +6/−8
CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for beam-duckdb +## 0.1.1.0 -- unreleased++* Fixed an issue with modeling boolean conditions, whereby, for example, checking if something was true was modeled as `... IS 1` (as for Sqlite), rather than `... IS TRUE` (like Postgres).+* Added a `FromBackendRow DuckDB Scientific`, `HasSqlEqualityCheck DuckDB Scientific`, and `HasSqlQuantifiedEqualityCheck DuckDB Scientific` instances, which are required to build the documentation.+ ## 0.1.0.0 -- 2026-02-26 * First version. Released on an unsuspecting world.
README.md view
@@ -10,3 +10,16 @@ `beam-duckdb` is the most recent backend for beam; do not hesitate to raise an issue if you'd like us to add support for something that isn't currently covered!++## Installation++The underlying duckdb-ffi needs to link to libduckdb. By default the installation assumes:++* The duckdb files are in `/usr/lib/duckdb`+* You're using duckdb 1.4.*++For Linux you can install a blessed version of duckdb in the correct path by cloining the duckdb-hasekll repo and running `make install` in the [duckdb-ffi cbits folder](https://github.com/Tritlo/duckdb-haskell/tree/main/duckdb-ffi/cbits).++## Example++From the project root directory, execute `cabal run ./examples/ExamScores.hs`.
beam-duckdb.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: beam-duckdb-version: 0.1.0.0+version: 0.1.1.0 synopsis: DuckDB backend for Beam description: Beam driver for DuckDB, an analytics-focused open-source in-process database. license: MIT@@ -44,6 +44,7 @@ , duckdb-simple ^>=0.1 , dlist >=0.8 && <1.1 , free >=4.12 && <5.3+ , scientific ^>=0.3 , text >=1.0 && <2.2 , time >=1.6 && <1.16 , transformers >=0.3 && <0.7
src/Database/Beam/DuckDB.hs view
@@ -20,7 +20,9 @@ module Database.Beam.DuckDB ( -- * Executing DuckDB queries runBeamDuckDB,+ -- ** Executing DuckDB queries with debugging runBeamDuckDBDebug,+ runBeamDuckDBDebugString, -- * Backend datatype DuckDB,@@ -108,6 +110,12 @@ runBeamDuckDBDebug :: (Text -> IO ()) -> Connection -> DuckDBM a -> IO a runBeamDuckDBDebug debug conn action = runReaderT (runDuckDBM action) (debug, conn)++-- | Like 'runBeamDuckDBDebug', but accepts a 'String' argument instead of 'Text'.+--+-- This is provided for compatibility with other backends+runBeamDuckDBDebugString :: (String -> IO ()) -> Connection -> DuckDBM a -> IO a+runBeamDuckDBDebugString debug = runBeamDuckDBDebug (debug . Text.unpack) newtype BeamDuckDBParams = BeamDuckDBParams [SomeField]
src/Database/Beam/DuckDB/Backend.hs view
@@ -3,6 +3,7 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeFamilies #-}@@ -12,36 +13,37 @@ import Data.ByteString (ByteString) import Data.Data (Proxy (Proxy))-import Data.Functor (($>))+import Data.Functor (($>), (<&>)) import Data.Int (Int16, Int32, Int64, Int8)+import Data.Scientific (Scientific, scientific) import Data.Text (Text) import Data.Time (Day, LocalTime, TimeOfDay, UTCTime) import Data.UUID.Types (UUID) import Data.Word (Word16, Word32, Word64, Word8) import Database.Beam (HasQBuilder, HasSqlEqualityCheck, HasSqlInTable (..), HasSqlQuantifiedEqualityCheck)-import Database.Beam.Backend (- BeamBackend (..),+import Database.Beam.Backend+ ( BeamBackend (..), BeamSqlBackend, BeamSqlBackendIsString, BeamSqlBackendSyntax, FromBackendRow, SqlNull (..), parseOneField,- )+ ) import Database.Beam.Backend.SQL (FromBackendRow (..))-import Database.Beam.DuckDB.Syntax (- DuckDBCommandSyntax,+import Database.Beam.DuckDB.Syntax+ ( DuckDBCommandSyntax, DuckDBExpressionSyntax (..),- )-import Database.Beam.DuckDB.Syntax.Builder (- commas,+ )+import Database.Beam.DuckDB.Syntax.Builder+ ( commas, emit, parens,- )+ ) import Database.Beam.Query.SQL92 (buildSql92Query') import Database.Beam.Query.Types (HasQBuilder (..)) import Database.DuckDB.Simple (Null)-import Database.DuckDB.Simple.FromField (FromField)+import Database.DuckDB.Simple.FromField (DecimalValue (..), FromField) data DuckDB @@ -50,26 +52,26 @@ instance BeamSqlBackend DuckDB instance HasQBuilder DuckDB where- buildSqlQuery = buildSql92Query' True+ buildSqlQuery = buildSql92Query' True instance HasSqlInTable DuckDB where- inRowValuesE Proxy e es =- DuckDBExpressionSyntax $- mconcat- [ parens $ fromDuckDBExpression e- , emit " IN "- , parens $ emit "VALUES " <> commas (map fromDuckDBExpression es)- ]+ inRowValuesE Proxy e es =+ DuckDBExpressionSyntax $+ mconcat+ [ parens $ fromDuckDBExpression e,+ emit " IN ",+ parens $ emit "VALUES " <> commas (map fromDuckDBExpression es)+ ] instance BeamSqlBackendIsString DuckDB Text instance BeamSqlBackendIsString DuckDB String instance BeamBackend DuckDB where- type BackendFromField DuckDB = FromField+ type BackendFromField DuckDB = FromField instance FromBackendRow DuckDB SqlNull where- fromBackendRow = parseOneField @DuckDB @Null $> SqlNull+ fromBackendRow = parseOneField @DuckDB @Null $> SqlNull instance FromBackendRow DuckDB Bool @@ -113,6 +115,17 @@ instance FromBackendRow DuckDB UTCTime +instance FromBackendRow DuckDB Scientific where+ fromBackendRow =+ parseOneField @DuckDB @DecimalValue+ <&> decimalToScientific++decimalToScientific :: DecimalValue -> Scientific+decimalToScientific decimalValue =+ scientific+ decimalValue.decimalInteger+ (negate (fromIntegral decimalValue.decimalScale))+ instance HasSqlEqualityCheck DuckDB Bool instance HasSqlEqualityCheck DuckDB Float@@ -155,6 +168,8 @@ instance HasSqlEqualityCheck DuckDB UTCTime +instance HasSqlEqualityCheck DuckDB Scientific+ instance HasSqlQuantifiedEqualityCheck DuckDB Bool instance HasSqlQuantifiedEqualityCheck DuckDB Float@@ -196,3 +211,5 @@ instance HasSqlQuantifiedEqualityCheck DuckDB LocalTime instance HasSqlQuantifiedEqualityCheck DuckDB UTCTime++instance HasSqlQuantifiedEqualityCheck DuckDB Scientific
src/Database/Beam/DuckDB/Syntax.hs view
@@ -399,14 +399,12 @@ isNotNullE = postFix "IS NOT NULL" isNullE = postFix "IS NULL"-- -- SQLite doesn't handle tri-state booleans properly- isTrueE = postFix "IS 1"- isNotTrueE = postFix "IS NOT 1"- isFalseE = postFix "IS 0"- isNotFalseE = postFix "IS NOT 0"- isUnknownE = postFix "IS NULL"- isNotUnknownE = postFix "IS NOT NULL"+ isTrueE = postFix "IS TRUE"+ isFalseE = postFix "IS FALSE"+ isNotTrueE = postFix "IS NOT TRUE"+ isNotFalseE = postFix "IS NOT FALSE"+ isUnknownE = postFix "IS UNKNOWN"+ isNotUnknownE = postFix "IS NOT UNKNOWN" existsE select = DuckDBExpressionSyntax (emit "EXISTS " <> parens (fromDuckDBSelect select)) uniqueE select = DuckDBExpressionSyntax (emit "UNIQUE " <> parens (fromDuckDBSelect select))