From 8d91fc9aab011a6b0d399f0284c2301554499779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C5=91=20Dulai?= Date: Sun, 5 Jul 2026 08:45:45 +0200 Subject: [PATCH] Separate execs into their own files --- exec/count.go | 84 +++++++++++++ exec/delete.go | 71 +++++++++++ exec/exec.go | 262 --------------------------------------- exec/insert.go | 85 +++++++++++++ exec/select.go | 2 +- exec/update.go | 66 ++++++++++ repository/repository.go | 4 +- test/exec_test.go | 10 +- test/select_test.go | 16 +-- 9 files changed, 322 insertions(+), 278 deletions(-) create mode 100644 exec/count.go create mode 100644 exec/delete.go create mode 100644 exec/insert.go create mode 100644 exec/update.go diff --git a/exec/count.go b/exec/count.go new file mode 100644 index 0000000..6f39da2 --- /dev/null +++ b/exec/count.go @@ -0,0 +1,84 @@ +package exec + +import ( + "database/sql" + "errors" + "reflect" + + "git.gdulai.com/gdulai/simpleorm" + "git.gdulai.com/gdulai/simpleorm/schema" + log "gitlab.com/gdulai/simpleloglvl" +) + +type Count[T any] struct { + target schema.Table + whereStmt string + args []any + result int64 +} + +func CreateCount[T any](orm *simpleorm.ORM, whereStmt string, args ...any) (Count[T], error) { + table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) + if !ok { + return Count[T]{}, errors.New("Failed to get table from schema cache") + } + + return Count[T]{target: *table, whereStmt: whereStmt, args: args}, nil +} + +func (c *Count[T]) Result() int64 { + return c.result +} + +func (c *Count[T]) Execute(conn *simpleorm.DBConnection) error { + return c.execute(conn, nil) +} + +func (c *Count[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { + // Reinit the results, new execution + c.result = -1 + dml := c.target.GetCountDML() + + if c.whereStmt != "" { + dml += " WHERE " + c.whereStmt + } + + log.LogDebug("Preparing sql: %s, with args: %s", dml, c.args) + + var stmt *sql.Stmt + var err error + if tx != nil { + stmt, err = tx.Prepare(dml) + } else { + stmt, err = conn.Prepare(dml) + } + + if err != nil { + return err + } + defer stmt.Close() + + log.LogDebug("Executing statement: %s", stmt) + + if len(c.args) == 0 { + err = stmt.QueryRow().Scan(&c.result) + } else { + // Flattent args to make sure it can be parsed correctly + var flatArgs []any + for _, a := range c.args { + if s, ok := a.([]any); ok { + flatArgs = append(flatArgs, s...) + } else { + flatArgs = append(flatArgs, a) + } + } + + err = stmt.QueryRow(flatArgs...).Scan(&c.result) + + } + if err != nil { + return err + } + + return nil +} diff --git a/exec/delete.go b/exec/delete.go new file mode 100644 index 0000000..9bae265 --- /dev/null +++ b/exec/delete.go @@ -0,0 +1,71 @@ +package exec + +import ( + "database/sql" + "errors" + "reflect" + + "git.gdulai.com/gdulai/simpleorm" + "git.gdulai.com/gdulai/simpleorm/schema" + log "gitlab.com/gdulai/simpleloglvl" +) + +type Delete[T any] struct { + target schema.Table + toDelete []T +} + +func NewDelete[T any](orm *simpleorm.ORM, toDelete []T) (Delete[T], error) { + table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) + if !ok { + return Delete[T]{}, errors.New("Failed to get table from schema cache") + } + + return Delete[T]{target: *table, toDelete: toDelete}, nil +} + +func (d *Delete[T]) Execute(conn *simpleorm.DBConnection) error { + return d.execute(conn, nil) +} + +func (d *Delete[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { + count := len(d.toDelete) + dml, err := d.target.GetDeleteDML(count) + if err != nil { + return err + } + + var params []any + + for _, del := range d.toDelete { + pkCols, err := getPk(del, d.target) + if err != nil { + return err + } + + for _, pk := range pkCols { + params = append(params, pk) + } + } + + log.LogDebug("%s [%s]", dml, params) + + var stmt *sql.Stmt + if tx != nil { + stmt, err = tx.Prepare(dml) + } else { + stmt, err = conn.Prepare(dml) + } + defer stmt.Close() + + result, err := stmt.Exec(params...) + if err != nil { + return err + } else { + rowsAffected, _ := result.RowsAffected() + log.LogInfo("Deleted %s row", rowsAffected) + } + + return nil + +} diff --git a/exec/exec.go b/exec/exec.go index 6caa9cb..6f11787 100644 --- a/exec/exec.go +++ b/exec/exec.go @@ -157,268 +157,6 @@ type Exec[T any] interface { execute(conn *simpleorm.DBConnection, tx *sql.Tx) error } -type Count[T any] struct { - target schema.Table - whereStmt string - args []any - result int64 -} - -func CreateCount[T any](orm *simpleorm.ORM, whereStmt string, args ...any) (Count[T], error) { - table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) - if !ok { - return Count[T]{}, errors.New("Failed to get table from schema cache") - } - - return Count[T]{target: *table, whereStmt: whereStmt, args: args}, nil -} - -func (c *Count[T]) Result() int64 { - return c.result -} - -func (c *Count[T]) Execute(conn *simpleorm.DBConnection) error { - return c.execute(conn, nil) -} - -func (c *Count[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { - // Reinit the results, new execution - c.result = -1 - dml := c.target.GetCountDML() - - if c.whereStmt != "" { - dml += " WHERE " + c.whereStmt - } - - log.LogDebug("Preparing sql: %s, with args: %s", dml, c.args) - - var stmt *sql.Stmt - var err error - if tx != nil { - stmt, err = tx.Prepare(dml) - } else { - stmt, err = conn.Prepare(dml) - } - - if err != nil { - return err - } - defer stmt.Close() - - log.LogDebug("Executing statement: %s", stmt) - - if len(c.args) == 0 { - err = stmt.QueryRow().Scan(&c.result) - } else { - // Flattent args to make sure it can be parsed correctly - var flatArgs []any - for _, a := range c.args { - if s, ok := a.([]any); ok { - flatArgs = append(flatArgs, s...) - } else { - flatArgs = append(flatArgs, a) - } - } - - err = stmt.QueryRow(flatArgs...).Scan(&c.result) - - } - if err != nil { - return err - } - - return nil -} - -type Insert[T any] struct { - target schema.Table - toInsert []T - results []T -} - -func NewInsert[T any](orm *simpleorm.ORM, toInsert ...T) (Insert[T], error) { - table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) - if !ok { - return Insert[T]{}, errors.New("Failed to get table from schema cache") - } - - return Insert[T]{target: *table, toInsert: toInsert}, nil -} - -func (ins *Insert[T]) Results() []T { - return ins.results -} - -func (ins *Insert[T]) Execute(conn *simpleorm.DBConnection) error { - return ins.execute(conn, nil) -} - -func (ins *Insert[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { - dml, err := ins.target.GetInsertDML(len(ins.toInsert)) - if err != nil { - return err - } - - var params []any - for i := range len(ins.toInsert) { - actualParams := prepareParams(ins.toInsert[i], ins.target) - if len(params) == 0 { - params = make([]any, len(ins.toInsert)*len(actualParams)) - } - for j := range actualParams { - params[(i*len(actualParams))+j] = actualParams[j] - } - } - - log.LogDebug("%s [%s]", dml, params) - - var stmt *sql.Stmt - if tx != nil { - stmt, err = tx.Prepare(dml) - } else { - stmt, err = conn.Prepare(dml) - } - defer stmt.Close() - - // Flattent args to make sure it can be parsed correctly - var flatParams []any - for _, param := range params { - if s, ok := param.([]any); ok { - flatParams = append(flatParams, s...) - } else { - flatParams = append(flatParams, param) - } - } - - rows, err := stmt.Query(flatParams...) - - if err != nil { - return err - } - - ins.results, err = readRows[T](ins.target, rows) - if err != nil { - return err - } - - return nil -} - -type Update[T any] struct { - target schema.Table - toUpdate T -} - -func NewUpdate[T any](orm *simpleorm.ORM, toUpdate T) (Update[T], error) { - table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) - if !ok { - return Update[T]{}, errors.New("Failed to get table from schema cache") - } - - return Update[T]{target: *table, toUpdate: toUpdate}, nil -} - -func (u Update[T]) Execute(conn *simpleorm.DBConnection) error { - return u.execute(conn, nil) -} - -func (u Update[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { - dml, err := u.target.GetUpdateDML() - if err != nil { - return err - } - - params := prepareParams(u.toUpdate, u.target) - - pkCols, err := getPk(u.toUpdate, u.target) - if err != nil { - return err - } - // Put the pks back at the end - for _, pk := range pkCols { - params = append(params, pk) - } - - log.LogDebug("%s [%s]", dml, params) - - var stmt *sql.Stmt - if tx != nil { - stmt, err = tx.Prepare(dml) - } else { - stmt, err = conn.Prepare(dml) - } - defer stmt.Close() - - result, err := stmt.Exec(params...) - if err != nil { - return err - } else { - rowsAffected, _ := result.RowsAffected() - log.LogInfo("Updated %s row", rowsAffected) - } - return nil -} - -type Delete[T any] struct { - target schema.Table - toDelete []T -} - -func NewDelete[T any](orm *simpleorm.ORM, toDelete []T) (Delete[T], error) { - table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) - if !ok { - return Delete[T]{}, errors.New("Failed to get table from schema cache") - } - - return Delete[T]{target: *table, toDelete: toDelete}, nil -} - -func (d *Delete[T]) Execute(conn *simpleorm.DBConnection) error { - return d.execute(conn, nil) -} - -func (d *Delete[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { - count := len(d.toDelete) - dml, err := d.target.GetDeleteDML(count) - if err != nil { - return err - } - - var params []any - - for _, del := range d.toDelete { - pkCols, err := getPk(del, d.target) - if err != nil { - return err - } - - for _, pk := range pkCols { - params = append(params, pk) - } - } - - log.LogDebug("%s [%s]", dml, params) - - var stmt *sql.Stmt - if tx != nil { - stmt, err = tx.Prepare(dml) - } else { - stmt, err = conn.Prepare(dml) - } - defer stmt.Close() - - result, err := stmt.Exec(params...) - if err != nil { - return err - } else { - rowsAffected, _ := result.RowsAffected() - log.LogInfo("Deleted %s row", rowsAffected) - } - - return nil - -} - func createSelectResultContainer(t schema.Table) []any { typ := t.Type() vals := make([]any, typ.NumField()) diff --git a/exec/insert.go b/exec/insert.go new file mode 100644 index 0000000..41fd5c3 --- /dev/null +++ b/exec/insert.go @@ -0,0 +1,85 @@ +package exec + +import ( + "database/sql" + "errors" + "reflect" + + "git.gdulai.com/gdulai/simpleorm" + "git.gdulai.com/gdulai/simpleorm/schema" + log "gitlab.com/gdulai/simpleloglvl" +) + +type Insert[T any] struct { + target schema.Table + toInsert []T + results []T +} + +func NewInsert[T any](orm *simpleorm.ORM, toInsert ...T) (Insert[T], error) { + table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) + if !ok { + return Insert[T]{}, errors.New("Failed to get table from schema cache") + } + + return Insert[T]{target: *table, toInsert: toInsert}, nil +} + +func (ins *Insert[T]) Results() []T { + return ins.results +} + +func (ins *Insert[T]) Execute(conn *simpleorm.DBConnection) error { + return ins.execute(conn, nil) +} + +func (ins *Insert[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { + dml, err := ins.target.GetInsertDML(len(ins.toInsert)) + if err != nil { + return err + } + + var params []any + for i := range len(ins.toInsert) { + actualParams := prepareParams(ins.toInsert[i], ins.target) + if len(params) == 0 { + params = make([]any, len(ins.toInsert)*len(actualParams)) + } + for j := range actualParams { + params[(i*len(actualParams))+j] = actualParams[j] + } + } + + log.LogDebug("%s [%s]", dml, params) + + var stmt *sql.Stmt + if tx != nil { + stmt, err = tx.Prepare(dml) + } else { + stmt, err = conn.Prepare(dml) + } + defer stmt.Close() + + // Flattent args to make sure it can be parsed correctly + var flatParams []any + for _, param := range params { + if s, ok := param.([]any); ok { + flatParams = append(flatParams, s...) + } else { + flatParams = append(flatParams, param) + } + } + + rows, err := stmt.Query(flatParams...) + + if err != nil { + return err + } + + ins.results, err = readRows[T](ins.target, rows) + if err != nil { + return err + } + + return nil +} diff --git a/exec/select.go b/exec/select.go index f226e40..7badcaf 100644 --- a/exec/select.go +++ b/exec/select.go @@ -22,7 +22,7 @@ type Select[T any] struct { } // Creates the select query builder -func CreateSelect[T any](orm *simpleorm.ORM) (Select[T], error) { +func NewSelect[T any](orm *simpleorm.ORM) (Select[T], error) { table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) if !ok { return Select[T]{}, errors.New("Failed to get table from schema cache") diff --git a/exec/update.go b/exec/update.go new file mode 100644 index 0000000..9bc1f1a --- /dev/null +++ b/exec/update.go @@ -0,0 +1,66 @@ +package exec + +import ( + "database/sql" + "errors" + "reflect" + + "git.gdulai.com/gdulai/simpleorm" + "git.gdulai.com/gdulai/simpleorm/schema" + log "gitlab.com/gdulai/simpleloglvl" +) + +type Update[T any] struct { + target schema.Table + toUpdate T +} + +func NewUpdate[T any](orm *simpleorm.ORM, toUpdate T) (Update[T], error) { + table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name()) + if !ok { + return Update[T]{}, errors.New("Failed to get table from schema cache") + } + + return Update[T]{target: *table, toUpdate: toUpdate}, nil +} + +func (u Update[T]) Execute(conn *simpleorm.DBConnection) error { + return u.execute(conn, nil) +} + +func (u Update[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error { + dml, err := u.target.GetUpdateDML() + if err != nil { + return err + } + + params := prepareParams(u.toUpdate, u.target) + + pkCols, err := getPk(u.toUpdate, u.target) + if err != nil { + return err + } + // Put the pks back at the end + for _, pk := range pkCols { + params = append(params, pk) + } + + log.LogDebug("%s [%s]", dml, params) + + var stmt *sql.Stmt + if tx != nil { + stmt, err = tx.Prepare(dml) + } else { + stmt, err = conn.Prepare(dml) + } + defer stmt.Close() + + result, err := stmt.Exec(params...) + if err != nil { + return err + } else { + rowsAffected, _ := result.RowsAffected() + log.LogInfo("Updated %s row", rowsAffected) + } + return nil +} diff --git a/repository/repository.go b/repository/repository.go index 04763a7..cacacb3 100644 --- a/repository/repository.go +++ b/repository/repository.go @@ -23,7 +23,7 @@ func NewRepository[T HasPK](conn *simpleorm.DBConnection, orm *simpleorm.ORM) *R } func (r *Repository[T]) SelectAll() []*T { - selectExec, err := exec.CreateSelect[T](r.orm) + selectExec, err := exec.NewSelect[T](r.orm) if err != nil { log.LogError("Failed to create select execution: %s", err) return []*T{} @@ -68,7 +68,7 @@ func (r *Repository[T]) SelectByPk(pks ...any) *T { } - selectExec, err := exec.CreateSelect[T](r.orm) + selectExec, err := exec.NewSelect[T](r.orm) if err != nil { log.LogError("Failed to create select execution: %s", err) return nil diff --git a/test/exec_test.go b/test/exec_test.go index b56f645..a9c5e51 100644 --- a/test/exec_test.go +++ b/test/exec_test.go @@ -118,7 +118,7 @@ func TestInsertAndUpdate(t *testing.T) { return } - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err) t.Fail() @@ -207,7 +207,7 @@ func TestInsertAndDelete(t *testing.T) { return } - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestInsertAndDelete setup failed: %s", err) t.Fail() @@ -263,7 +263,7 @@ func TestBoolInsertAndSelectSingle(t *testing.T) { return } - selectExec, err := exec.CreateSelect[TestWithBool](orm) + selectExec, err := exec.NewSelect[TestWithBool](orm) if err != nil { log.LogError("TestBoolInsertAndSelectSingle setup failed: %s", err) t.Fail() @@ -317,7 +317,7 @@ func TestTimeInsertAndSelectSingle(t *testing.T) { return } - selectExec, err := exec.CreateSelect[TestWithTime](orm) + selectExec, err := exec.NewSelect[TestWithTime](orm) if err != nil { log.LogError("TestTimeInsertAndSelectSingle setup failed: %s", err) t.Fail() @@ -423,7 +423,7 @@ func TestTransactionRollback(t *testing.T) { return } - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestTransactionRollback WHEN failed: %s", err) t.Fail() diff --git a/test/select_test.go b/test/select_test.go index 052c5bd..4db1ced 100644 --- a/test/select_test.go +++ b/test/select_test.go @@ -16,7 +16,7 @@ func TestSelectEmpty(t *testing.T) { defer cleanUp("test.db", conn) // WHEN - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) // THEN if err != nil { @@ -55,7 +55,7 @@ func TestSelectSingle(t *testing.T) { return } - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestInsertAndSelectSingle setup failed: %s", err) t.Fail() @@ -121,7 +121,7 @@ func TestSelectWithCompositePk(t *testing.T) { return } - selectExec, err := exec.CreateSelect[TestWithCompositePk](orm) + selectExec, err := exec.NewSelect[TestWithCompositePk](orm) if err != nil { log.LogError("TestInsertSelectWithCompositePk setup failed: %s", err) t.Fail() @@ -182,7 +182,7 @@ func TestSelectWithParam(t *testing.T) { return } - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err) t.Fail() @@ -255,7 +255,7 @@ func TestSelectWithLimitAndOffset(t *testing.T) { } // WHEN - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestSelectWithLimitAndOffset failed: %s", err) t.Fail() @@ -291,7 +291,7 @@ func TestSelectOrderByDesc(t *testing.T) { } // WHEN - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestSelectOrderByDesc failed: %s", err) t.Fail() @@ -331,7 +331,7 @@ func TestSelectOrderByAsc(t *testing.T) { } // WHEN - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestSelectOrderByAsc failed: %s", err) t.Fail() @@ -371,7 +371,7 @@ func TestSelectOrderByAscWithLimitAndOffset(t *testing.T) { } // WHEN - selectExec, err := exec.CreateSelect[Test](orm) + selectExec, err := exec.NewSelect[Test](orm) if err != nil { log.LogError("TestSelectOrderByAsc failed: %s", err) t.Fail()