git.iko.soy/rowtype-yoga/purescript-yoga-sqlite
on main help sign in
commitbaf2d5fb2d4b32678c19c74d5a174ab2a80bdad1 authorMark <mark.eibes@gmail.com> dateFri 20 Feb 2026, 21:42 (7 months ago) parentb3fff51
4 files changed+67−2
src/Yoga/SQLite/SQLite.js+1 src/Yoga/SQLite/SQLite.purs+11−2 src/Yoga/SQLite/Schema.purs+17 test/Main.purs+38
src/Yoga/SQLite/SQLite.js+1
@@ -95,6 +95,7 @@ export const txExecuteImpl = async (tx, sql, args) => {
9595};
9696
9797export const txCloseImpl = (tx) => { tx.close(); };
98+export const txClosedImpl = (tx) => tx.closed;
9899
99100export const txBatchImpl = async (tx, stmts) => {
100101 const results = await tx.batch(stmts.map(s => ({ sql: s.sql, args: s.args })));
src/Yoga/SQLite/SQLite.purs+11−2
@@ -2,9 +2,9 @@ module Yoga.SQLite.SQLite where
22
33import Prelude
44
5−import Data.Maybe (Maybe)
5+import Data.Maybe (Maybe(..))
66import Data.Newtype (class Newtype)
7−import Data.Nullable (Nullable)
7+import Data.Nullable (Nullable, toNullable)
88import Data.Nullable as Nullable
99import Data.JSDate as JSDate
1010import Effect (Effect)
@@ -57,6 +57,11 @@ instance ToSQLiteValue BigInt where
5757instance ToSQLiteValue Boolean where
5858 toSQLiteValue = unsafeCoerce
5959
60+instance ToSQLiteValue a => ToSQLiteValue (Maybe a) where
61+ toSQLiteValue = case _ of
62+ Nothing -> unsafeCoerce (toNullable Nothing)
63+ Just v -> toSQLiteValue v
64+
6065instance ToSQLiteValue Foreign where
6166 toSQLiteValue = unsafeCoerce
6267
@@ -137,6 +142,7 @@ foreign import txQueryOneImpl :: EffectFn3 Transaction String (Array SQLiteValue
137142foreign import txExecuteImpl :: EffectFn3 Transaction String (Array SQLiteValue) (Promise Int)
138143
139144foreign import txCloseImpl :: EffectFn1 Transaction Unit
145+foreign import txClosedImpl :: EffectFn1 Transaction Boolean
140146foreign import txBatchImpl :: EffectFn2 Transaction (Array BatchStatement) (Promise (Array QueryResultImpl))
141147foreign import txExecuteMultipleImpl :: EffectFn2 Transaction String (Promise Unit)
142148
@@ -277,6 +283,9 @@ txExecute (SQL sql) args txn =
277283txClose :: Transaction -> Effect Unit
278284txClose = runEffectFn1 txCloseImpl
279285
286+txClosed :: Transaction -> Effect Boolean
287+txClosed = runEffectFn1 txClosedImpl
288+
280289txBatch :: Array BatchStatement -> Transaction -> Aff (Array QueryResult)
281290txBatch stmts txn =
282291 runEffectFn2 txBatchImpl txn stmts # Promise.toAffE <#> map fromQueryResultImpl
src/Yoga/SQLite/Schema.purs+17
@@ -226,6 +226,23 @@ instance ReadForeign (F64Vector dim) where
226226instance SQLite.ToSQLiteValue (F64Vector dim) where
227227 toSQLiteValue (F64Vector f) = unsafeCoerce f
228228
229+instance SQLite.ToSQLiteValue SQLiteBool where
230+ toSQLiteValue (SQLiteBool b) = unsafeCoerce (if b then 1 else 0)
231+
232+instance SQLite.ToSQLiteValue SQLDate where
233+ toSQLiteValue (SQLDate d) = unsafeCoerce (SCU.take 10 (SQLite.dateTimeToString (JSDate.fromDateTime (DateTime d bottom))))
234+
235+instance SQLite.ToSQLiteValue SQLTime where
236+ toSQLiteValue (SQLTime t) = unsafeCoerce (pad (fromEnum (hour t)) <> ":" <> pad (fromEnum (minute t)) <> ":" <> pad (fromEnum (second t)))
237+ where
238+ pad n = if n < 10 then "0" <> show n else show n
239+
240+instance SQLite.ToSQLiteValue SQLUUID where
241+ toSQLiteValue (SQLUUID uuid) = unsafeCoerce uuid
242+
243+instance SQLite.ToSQLiteValue Json where
244+ toSQLiteValue (Json f) = unsafeCoerce f
245+
229246-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
230247-- Nullability: inferred from Maybe
231248-- ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
test/Main.purs+38
@@ -648,6 +648,44 @@ spec = before setupConn do
648648 p `shouldEqual` "file"
649649 SQLite.close conn # liftEffect
650650
651+ it "empty batch returns empty array" \conn -> do
652+ results <- SQLite.batch SQLite.Write [] conn
653+ Array.length results `shouldEqual` 0
654+
655+ it "txClosed reflects transaction state" \_ -> do
656+ conn <- withTempDb
657+ SQLite.executeSimple (SQLite.SQL (createTableDDL @UsersTable)) conn # void
658+ txn <- SQLite.begin conn
659+ before_ <- SQLite.txClosed txn # liftEffect
660+ before_ `shouldEqual` false
661+ SQLite.commit txn
662+ after_ <- SQLite.txClosed txn # liftEffect
663+ after_ `shouldEqual` true
664+ SQLite.close conn # liftEffect
665+
666+ it "Maybe SQLiteValue passes null for Nothing" \conn -> do
667+ SQLite.executeSimple (SQLite.SQL (createTableDDL @UsersTable)) conn # void
668+ SQLite.execute
669+ (SQLite.SQL "INSERT INTO users (name, email, age) VALUES (?1, ?2, ?3)")
670+ [ SQLite.toSQLiteValue "Alice"
671+ , SQLite.toSQLiteValue "a@b.com"
672+ , SQLite.toSQLiteValue (Nothing :: Maybe Int)
673+ ]
674+ conn # void
675+ rows <- runQuery conn {} (from usersTable # selectAll)
676+ let ages = map (_.age) (rows :: Array { id :: Int, name :: String, email :: String, age :: Maybe Int })
677+ ages `shouldEqual` [Nothing]
678+
679+ it "SQLiteBool as SQLiteValue" \conn -> do
680+ SQLite.executeSimple (SQLite.SQL (createTableDDL @ConfigTable)) conn # void
681+ SQLite.execute
682+ (SQLite.SQL "INSERT INTO config (active) VALUES (?1)")
683+ [ SQLite.toSQLiteValue (SQLiteBool false) ]
684+ conn # void
685+ rows <- runQuery conn {} (from (Proxy :: Proxy ConfigTable) # selectAll)
686+ let actives = map (\r -> r.active) (rows :: Array { id :: Int, active :: SQLiteBool, role :: String, score :: Int })
687+ actives `shouldEqual` [SQLiteBool false]
688+
651689 describe "DDL RANDOM ROWID" do
652690 it "generates DDL with RANDOM ROWID suffix" \_ -> do
653691 let result = createTableDDL @RandomRowIdTable