@@ -8,19 +8,17 @@ defmodule EctoLibSql.BatchFeaturesTest do
88 use ExUnit.Case
99
1010 setup do
11- test_db = "test_batch_#{ :erlang . unique_integer ( [ :positive ] ) } .db"
11+ test_db = "z_ecto_libsql_test-batch_#{ :erlang . unique_integer ( [ :positive ] ) } .db"
12+
13+ opts = [ database: test_db ]
1214
1315 on_exit ( fn ->
1416 File . rm ( test_db )
1517 end )
1618
17- { :ok , database: test_db }
19+ { :ok , database: test_db , opts: opts }
1820 end
1921
20- # ============================================================================
21- # Native batch execution (SQL string) - IMPLEMENTED ✅
22- # ============================================================================
23-
2422 describe "native batch execution (SQL string)" do
2523 test "execute_batch_sql executes multiple statements" , % { database: database } do
2624 { :ok , state } = EctoLibSql . connect ( database: database )
@@ -100,5 +98,156 @@ defmodule EctoLibSql.BatchFeaturesTest do
10098
10199 EctoLibSql . disconnect ( [ ] , state )
102100 end
101+
102+ test "batch operations - non-transactional" , % { database: database } do
103+ { :ok , state } = EctoLibSql . connect ( database: database )
104+
105+ # Create table
106+ create_table = % EctoLibSql.Query {
107+ statement: "CREATE TABLE IF NOT EXISTS batch_test (id INTEGER PRIMARY KEY, value TEXT)"
108+ }
109+
110+ { :ok , _ , _ , state } = EctoLibSql . handle_execute ( create_table , [ ] , [ ] , state )
111+
112+ # Execute batch of statements
113+ statements = [
114+ { "INSERT INTO batch_test (value) VALUES (?)" , [ "first" ] } ,
115+ { "INSERT INTO batch_test (value) VALUES (?)" , [ "second" ] } ,
116+ { "INSERT INTO batch_test (value) VALUES (?)" , [ "third" ] } ,
117+ { "SELECT COUNT(*) FROM batch_test" , [ ] }
118+ ]
119+
120+ { :ok , results } = EctoLibSql.Native . batch ( state , statements )
121+
122+ # Should have 4 results (3 inserts + 1 select)
123+ assert length ( results ) == 4
124+
125+ # Last result should be the count query
126+ count_result = List . last ( results )
127+ # Extract the actual count value from the result rows
128+ [ [ count ] ] = count_result . rows
129+ assert count == 3
130+
131+ EctoLibSql . disconnect ( [ ] , state )
132+ end
133+
134+ test "batch operations - transactional atomicity with floats" , % { database: database } do
135+ { :ok , state } = EctoLibSql . connect ( database: database )
136+
137+ # Create table with REAL balance (floats now supported!)
138+ create_table = % EctoLibSql.Query {
139+ statement: "CREATE TABLE IF NOT EXISTS accounts (id INTEGER PRIMARY KEY, balance REAL)"
140+ }
141+
142+ { :ok , _ , _ , state } = EctoLibSql . handle_execute ( create_table , [ ] , [ ] , state )
143+
144+ # Insert initial account with float
145+ { :ok , _ , _ , state } =
146+ EctoLibSql . handle_execute (
147+ "INSERT INTO accounts (id, balance) VALUES (?, ?)" ,
148+ [ 1 , 100.50 ] ,
149+ [ ] ,
150+ state
151+ )
152+
153+ # This batch should fail on the constraint violation and rollback everything
154+ statements = [
155+ { "UPDATE accounts SET balance = balance - 25.25 WHERE id = ?" , [ 1 ] } ,
156+ # Duplicate key - will fail
157+ { "INSERT INTO accounts (id, balance) VALUES (?, ?)" , [ 1 , 50.00 ] }
158+ ]
159+
160+ # Should return error
161+ assert { :error , _ } = EctoLibSql.Native . batch_transactional ( state , statements )
162+
163+ # Verify balance wasn't changed (rollback worked)
164+ { :ok , _ , result , _ } =
165+ EctoLibSql . handle_execute (
166+ "SELECT balance FROM accounts WHERE id = ?" ,
167+ [ 1 ] ,
168+ [ ] ,
169+ state
170+ )
171+
172+ [ [ balance ] ] = result . rows
173+ assert balance == 100.50
174+
175+ EctoLibSql . disconnect ( [ ] , state )
176+ end
177+
178+ test "batch with mixed operations" , % { database: database } do
179+ { :ok , state } = EctoLibSql . connect ( database: database )
180+
181+ # Create table
182+ { :ok , _ , _ , state } =
183+ EctoLibSql . handle_execute (
184+ "CREATE TABLE IF NOT EXISTS mixed_batch (id INTEGER PRIMARY KEY, val TEXT)" ,
185+ [ ] ,
186+ [ ] ,
187+ state
188+ )
189+
190+ # Execute batch with inserts, updates, and selects
191+ statements = [
192+ { "INSERT INTO mixed_batch (id, val) VALUES (?, ?)" , [ 1 , "alpha" ] } ,
193+ { "INSERT INTO mixed_batch (id, val) VALUES (?, ?)" , [ 2 , "beta" ] } ,
194+ { "UPDATE mixed_batch SET val = ? WHERE id = ?" , [ "gamma" , 1 ] } ,
195+ { "SELECT val FROM mixed_batch WHERE id = ?" , [ 1 ] } ,
196+ { "DELETE FROM mixed_batch WHERE id = ?" , [ 2 ] } ,
197+ { "SELECT COUNT(*) FROM mixed_batch" , [ ] }
198+ ]
199+
200+ { :ok , results } = EctoLibSql.Native . batch_transactional ( state , statements )
201+
202+ # Should get results for all statements
203+ assert length ( results ) == 6
204+
205+ # Fourth result should be the select showing "gamma"
206+ select_result = Enum . at ( results , 3 )
207+ assert select_result . rows == [ [ "gamma" ] ]
208+
209+ # Last result should show count of 1 (one deleted)
210+ count_result = List . last ( results )
211+ [ [ count ] ] = count_result . rows
212+ assert count == 1
213+
214+ EctoLibSql . disconnect ( [ ] , state )
215+ end
216+
217+ test "large result set handling with batch insert" , % { database: database } do
218+ { :ok , state } = EctoLibSql . connect ( database: database )
219+
220+ # Create table
221+ { :ok , _ , _ , state } =
222+ EctoLibSql . handle_execute (
223+ "CREATE TABLE IF NOT EXISTS large_test (id INTEGER PRIMARY KEY, category TEXT, value INTEGER)" ,
224+ [ ] ,
225+ [ ] ,
226+ state
227+ )
228+
229+ # Insert many rows using batch
230+ insert_statements =
231+ for i <- 1 .. 100 do
232+ category = if rem ( i , 2 ) == 0 , do: "even" , else: "odd"
233+ { "INSERT INTO large_test (id, category, value) VALUES (?, ?, ?)" , [ i , category , i * 10 ] }
234+ end
235+
236+ { :ok , _ } = EctoLibSql.Native . batch ( state , insert_statements )
237+
238+ # Query with filter
239+ { :ok , _ , result , _ } =
240+ EctoLibSql . handle_execute (
241+ "SELECT COUNT(*) FROM large_test WHERE category = ?" ,
242+ [ "even" ] ,
243+ [ ] ,
244+ state
245+ )
246+
247+ [ [ count ] ] = result . rows
248+ assert count == 50
249+
250+ EctoLibSql . disconnect ( [ ] , state )
251+ end
103252 end
104253end
0 commit comments