1- package database
1+ package sqlite3
22
33import (
44 "database/sql"
5+ "encoding/json"
56 "fmt"
6- _ "github.com/mattn/go-sqlite3"
77 "os"
8+ "strconv"
89 "strings"
910 "sync"
11+
12+ _ "github.com/mattn/go-sqlite3"
1013)
1114
1215// IDatabase defines the database interface
@@ -27,16 +30,16 @@ type IDatabase interface {
2730type SDatabase struct {
2831 dbAbsPath string
2932 queries * Queries
30- sqlDB ISqlDb
33+ sqlDB IDatabaseSqlDB
3134 initialized bool
3235}
3336
3437// For mocking 🥸.
3538var (
36- db ISqlDb
39+ db IDatabaseSqlDB
3740 dbMutex sync.Mutex // sync.Locker
3841 initialized bool
39- sqlOpen = func (driverName , dataSourceName string ) (ISqlDb , error ) {
42+ sqlOpen = func (driverName , dataSourceName string ) (IDatabaseSqlDB , error ) {
4043 return sql .Open (driverName , dataSourceName )
4144 }
4245 osRemove = os .Remove
@@ -257,68 +260,159 @@ func (s *SDatabase) Apply() error {
257260 return fmt .Errorf ("error starting transaction: %w" , err )
258261 }
259262
260- // Merge all queries in the desired order.
261- var allQueries []string
263+ /*
264+ for _, q := range s.queries.DropTable {
265+ _, err = s.exec(sqlTx, q.Query, q.Values)
266+ if err != nil {
267+ return err
268+ }
269+ //allQueries = append(allQueries, q.Query)
270+ }*/
271+
272+ // Execute CREATE TABLE queries directly (no values binding)
262273 for _ , q := range s .queries .CreateTable {
263- allQueries = append (allQueries , q .Query )
264- }
265- for _ , q := range s .queries .DropTable {
266- allQueries = append (allQueries , q .Query )
267- }
268- for _ , q := range s .queries .Insert {
269- allQueries = append (allQueries , q .Query )
270- }
271- for _ , q := range s .queries .Update {
272- allQueries = append (allQueries , q .Query )
273- }
274- for _ , q := range s .queries .Delete {
275- allQueries = append (allQueries , q .Query )
276- }
277- for _ , q := range s .queries .Select {
278- allQueries = append (allQueries , q .Query )
274+ _ , err = sqlTx .Exec (q .Query )
275+ if err != nil {
276+ err := sqlTx .Rollback ()
277+ if err != nil {
278+ return err
279+ } // Rollback transaction if there's an error
280+ return fmt .Errorf ("error creating table: %w" , err )
281+ }
279282 }
280283
281- if len (allQueries ) == 0 {
282- return fmt .Errorf ("error no queries" )
284+ // Execute other queries with values
285+ queryTypes := []* []Query {
286+ & s .queries .Insert ,
287+ & s .queries .Update ,
288+ & s .queries .Delete ,
283289 }
284290
285- err = s .exec (sqlTx , allQueries )
286- if err != nil {
287- return err
291+ for _ , querySet := range queryTypes {
292+ for _ , q := range * querySet {
293+ dbResult , err := s .exec (sqlTx , q .Query , q .Values )
294+ if err != nil {
295+ err := sqlTx .Rollback ()
296+ if err != nil {
297+ return err
298+ } // Rollback if any query fails
299+ return err
300+ }
301+ lastInsertId , err := dbResult .LastInsertId ()
302+ if err != nil {
303+ return err
304+ }
305+ q .Result = strconv .FormatInt (lastInsertId , 10 )
306+ }
288307 }
289308
290- return nil
291- }
292-
293- // exec loops through all the queries and executes them
294- func (s * SDatabase ) exec (sqlTx ISqlTx , allQueries []string ) error {
295- // Execute each query individually within the transaction.
296- // This approach is more flexible if you want to handle parameter binding or errors per query.
297- for _ , queryString := range allQueries {
298- _ , execErr := sqlTx .Exec (queryString )
299- if execErr != nil {
300- // Roll back the entire transaction on error
301- rbErr := sqlTx .Rollback ()
302- if rbErr != nil {
303- return fmt .Errorf ("error rolling back transaction: %w (original error: %v)" , rbErr , execErr )
309+ // Handle SELECT queries separately
310+ for _ , q := range s .queries .Select {
311+ q .Result , err = s .querySelect (sqlTx , q .Query , q .Values )
312+ if err != nil {
313+ err := sqlTx .Rollback ()
314+ if err != nil {
315+ return err
304316 }
305- return fmt . Errorf ( "error applying query (%s): %w" , queryString , execErr )
317+ return err
306318 }
307319 }
308320
309- // If all queries succeeded, commit the transaction
310- if err := sqlTx .Commit (); err != nil {
321+ // **Commit transaction once after all queries execute**
322+ if err = sqlTx .Commit (); err != nil {
323+ err = sqlTx .Rollback ()
324+ if err != nil {
325+ return err
326+ } // Ensure rollback on commit failure
311327 return fmt .Errorf ("error committing transaction: %w" , err )
312328 }
313329
314330 // Optionally, clear the queries after applying
315- s .queries = & Queries {
331+ /* s.queries = &Queries{
316332 CreateTable: []Query{},
317333 DropTable: []Query{},
318334 Insert: []Query{},
319335 Update: []Query{},
320336 Delete: []Query{},
321337 Select: []Query{},
322- }
338+ }*/
339+
323340 return nil
324341}
342+
343+ // exec loops through all the queries and executes them
344+ func (s * SDatabase ) exec (sqlTx IDatabaseSqlTx , query string , values []any ) (sql.Result , error ) {
345+ dbResult , err := sqlTx .Exec (query , values ... )
346+ if err != nil {
347+ // Roll back the entire transaction on error
348+ rbErr := sqlTx .Rollback ()
349+ if rbErr != nil {
350+ return nil , fmt .Errorf ("error rolling back transaction: %w (original error: %v)" , rbErr , err )
351+ }
352+ return nil , fmt .Errorf ("error applying query (%s): %w" , query , err )
353+ }
354+ return dbResult , nil
355+ }
356+
357+ func (s * SDatabase ) querySelect (sqlTx IDatabaseSqlTx , query string , values []any ) (string , error ) {
358+
359+ //exec, err := db
360+ //if err != nil {
361+ // return "", err
362+ //}
363+
364+ rows , err := sqlTx .Query (query , values ... )
365+ if err != nil {
366+ return "" , fmt .Errorf ("error executing SELECT query (%s): %w" , query , err )
367+ }
368+ defer rows .Close ()
369+
370+ // Get column names
371+ columns , err := rows .Columns ()
372+ if err != nil {
373+ return "" , fmt .Errorf ("error fetching column names: %w" , err )
374+ }
375+
376+ // Prepare a slice to store the results
377+ var results []map [string ]interface {}
378+
379+ // Iterate over rows
380+ for rows .Next () {
381+ // Create a slice of `interface{}` to hold each column value
382+ values := make ([]interface {}, len (columns ))
383+ valuePtrs := make ([]interface {}, len (columns ))
384+
385+ // Assign pointers to values slice
386+ for i := range values {
387+ valuePtrs [i ] = & values [i ]
388+ }
389+
390+ // Scan the row into value pointers
391+ if err := rows .Scan (valuePtrs ... ); err != nil {
392+ return "" , fmt .Errorf ("error scanning row: %w" , err )
393+ }
394+
395+ // Convert values to a map
396+ rowMap := make (map [string ]interface {})
397+ for i , colName := range columns {
398+ val := values [i ]
399+
400+ // Convert `[]byte` to string if necessary
401+ if b , ok := val .([]byte ); ok {
402+ val = string (b )
403+ }
404+
405+ rowMap [colName ] = val
406+ }
407+
408+ results = append (results , rowMap )
409+ }
410+
411+ // Convert results to JSON
412+ jsonData , err := json .Marshal (results )
413+ if err != nil {
414+ return "" , fmt .Errorf ("error converting result to JSON: %w" , err )
415+ }
416+
417+ return string (jsonData ), nil
418+ }
0 commit comments