Compare commits
3
Commits
main
..
cd1f61fb87
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd1f61fb87 | ||
|
|
146f07fa02 | ||
|
|
d20184a6f0 |
@@ -1,96 +0,0 @@
|
|||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.gdulai.com/gdulai/simpleorm"
|
|
||||||
"git.gdulai.com/gdulai/simpleorm/schema"
|
|
||||||
log "gitlab.com/gdulai/simpleloglvl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Count represents a count query.
|
|
||||||
type Count[T any] struct {
|
|
||||||
target schema.Table
|
|
||||||
whereStmt string
|
|
||||||
args []any
|
|
||||||
result int64
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateCount returns a new instance of Count.
|
|
||||||
//
|
|
||||||
// orm is the simpleorm.ORM instance which connects, caches and manages the relations.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Result returns the result of the count query.
|
|
||||||
func (c *Count[T]) Result() int64 {
|
|
||||||
return c.result
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute executes the parsed count query against a connection and returns an error if there was any during the execution.
|
|
||||||
//
|
|
||||||
// conn is the simpleorm.DBConnection which handles the database connection.
|
|
||||||
func (c *Count[T]) Execute(conn *simpleorm.DBConnection) error {
|
|
||||||
return c.execute(conn, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute executes the parsed count query against a connection and transaction and returns an error if there was any during the execution.
|
|
||||||
//
|
|
||||||
// conn is the simpleorm.DBConnection which handles the database connection.
|
|
||||||
// tx is the sql.Tx transaction which the count query will be run in.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.gdulai.com/gdulai/simpleorm"
|
|
||||||
"git.gdulai.com/gdulai/simpleorm/schema"
|
|
||||||
log "gitlab.com/gdulai/simpleloglvl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Delete represents a delete operation.
|
|
||||||
type Delete[T any] struct {
|
|
||||||
target schema.Table // The table from which records will be deleted.
|
|
||||||
toDelete []T // A slice of model instances to be deleted.
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewDelete creates a new instance of Delete.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - orm: The ORM instance that manages the database connection and schema
|
|
||||||
// - toDelete: A slice of model instances to delete
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - Delete[T]: A new Delete operation instance
|
|
||||||
// - error: An error if the table could not be found in the schema cache
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute executes the delete operation.
|
|
||||||
func (d *Delete[T]) Execute(conn *simpleorm.DBConnection) error {
|
|
||||||
return d.execute(conn, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute constructs and executes the DELETE SQL statement.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - conn: The database connection to use for executing the query
|
|
||||||
// - tx: Optional transaction to use instead of a connection
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - error: An error if the operation fails
|
|
||||||
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
|
|
||||||
|
|
||||||
}
|
|
||||||
+262
@@ -157,6 +157,268 @@ type Exec[T any] interface {
|
|||||||
execute(conn *simpleorm.DBConnection, tx *sql.Tx) error
|
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 {
|
func createSelectResultContainer(t schema.Table) []any {
|
||||||
typ := t.Type()
|
typ := t.Type()
|
||||||
vals := make([]any, typ.NumField())
|
vals := make([]any, typ.NumField())
|
||||||
|
|||||||
-122
@@ -1,122 +0,0 @@
|
|||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.gdulai.com/gdulai/simpleorm"
|
|
||||||
"git.gdulai.com/gdulai/simpleorm/schema"
|
|
||||||
log "gitlab.com/gdulai/simpleloglvl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Insert represents an insert query operation.
|
|
||||||
type Insert[T any] struct {
|
|
||||||
target schema.Table
|
|
||||||
toInsert []T
|
|
||||||
results []T
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a new insert operation for the given model type.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - orm: The ORM instance that manages the database connection and schema
|
|
||||||
// - toInsert: A variadic list of model instances to insert
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - Insert[T]: A new insert operation instance
|
|
||||||
// - error: An error if the table could not be found in the schema cache
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the results of the insert operation.
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - []T: A slice of model instances representing the inserted rows
|
|
||||||
|
|
||||||
func (ins *Insert[T]) Results() []T {
|
|
||||||
return ins.results
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executes the insert operation using the provided database connection.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - conn: The database connection to use for executing the query
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - error: An error if the operation fails
|
|
||||||
func (ins *Insert[T]) Execute(conn *simpleorm.DBConnection) error {
|
|
||||||
|
|
||||||
return ins.execute(conn, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Executes the insert operation using the provided database connection or transaction.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - conn: The database connection to use for executing the query
|
|
||||||
// - tx: Optional transaction to use instead of a connection
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - error: An error if the operation fails
|
|
||||||
//
|
|
||||||
// Implementation Details:
|
|
||||||
// 1. Constructs the SQL INSERT statement using GetInsertDML
|
|
||||||
// 2. Prepares parameters by flattening nested any values
|
|
||||||
// 3. Executes the statement and maps results to model instances
|
|
||||||
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
|
|
||||||
}
|
|
||||||
+10
-10
@@ -22,7 +22,7 @@ type Select[T any] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Creates the select query builder
|
// Creates the select query builder
|
||||||
func NewSelect[T any](orm *simpleorm.ORM) (Select[T], error) {
|
func CreateSelect[T any](orm *simpleorm.ORM) (Select[T], error) {
|
||||||
table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name())
|
table, ok := orm.Cache().Get(reflect.TypeFor[T]().Name())
|
||||||
if !ok {
|
if !ok {
|
||||||
return Select[T]{}, errors.New("Failed to get table from schema cache")
|
return Select[T]{}, errors.New("Failed to get table from schema cache")
|
||||||
@@ -86,15 +86,6 @@ func (s *Select[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error {
|
|||||||
dml += " WHERE " + s.whereStmt
|
dml += " WHERE " + s.whereStmt
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(s.ordering) > 0 {
|
|
||||||
orderBy, err := s.target.GetOrderByDML(s.ordering...)
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("Failed to create ORDER BY part: %s", err)
|
|
||||||
} else {
|
|
||||||
dml += orderBy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var effectiveArgs []any = s.args
|
var effectiveArgs []any = s.args
|
||||||
if s.limit != -1 {
|
if s.limit != -1 {
|
||||||
dml += " LIMIT ?"
|
dml += " LIMIT ?"
|
||||||
@@ -106,6 +97,15 @@ func (s *Select[T]) execute(conn *simpleorm.DBConnection, tx *sql.Tx) error {
|
|||||||
effectiveArgs = append(effectiveArgs, s.offset)
|
effectiveArgs = append(effectiveArgs, s.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(s.ordering) > 0 {
|
||||||
|
orderBy, err := s.target.GetOrderByDML(s.ordering...)
|
||||||
|
if err != nil {
|
||||||
|
log.LogError("Failed to create ORDER BY part: %s", err)
|
||||||
|
} else {
|
||||||
|
dml += orderBy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.LogInfo("Preparing sql: %s", dml)
|
log.LogInfo("Preparing sql: %s", dml)
|
||||||
log.LogDebug("Preparing sql: %s, with args: %s", dml, effectiveArgs)
|
log.LogDebug("Preparing sql: %s, with args: %s", dml, effectiveArgs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
package exec
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"git.gdulai.com/gdulai/simpleorm"
|
|
||||||
"git.gdulai.com/gdulai/simpleorm/schema"
|
|
||||||
log "gitlab.com/gdulai/simpleloglvl"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Update represents an update operation.
|
|
||||||
type Update[T any] struct {
|
|
||||||
target schema.Table // The table where records will be updated.
|
|
||||||
toUpdate T // A model instance with the new values.
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewUpdate creates a new instance of Update.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - orm: The ORM instance that manages the database connection and schema
|
|
||||||
// - toUpdate: A model instance with new values
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - Update[T]: A new Update operation instance
|
|
||||||
// - error: An error if the table could not be found in the schema cache
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute executes the update operation.
|
|
||||||
func (u Update[T]) Execute(conn *simpleorm.DBConnection) error {
|
|
||||||
return u.execute(conn, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// execute constructs and executes the UPDATE SQL statement.
|
|
||||||
//
|
|
||||||
// Parameters:
|
|
||||||
// - conn: The database connection to use for executing the query
|
|
||||||
// - tx: Optional transaction to use instead of a connection
|
|
||||||
//
|
|
||||||
// Returns:
|
|
||||||
// - error: An error if the operation fails
|
|
||||||
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
|
|
||||||
}
|
|
||||||
@@ -17,9 +17,8 @@ type ORM struct {
|
|||||||
cache *cache.SchemaCache
|
cache *cache.SchemaCache
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewOrm inits and creates an instance ORM library.
|
// Inits the ORM library.
|
||||||
//
|
// Param objs is an array which should be an array of the types which describe the tables.
|
||||||
// obj is an array which should be an array of the types which describe the tables.
|
|
||||||
func NewORM(objs ...any) *ORM {
|
func NewORM(objs ...any) *ORM {
|
||||||
typeParsers := make(map[string]*schema.Parser)
|
typeParsers := make(map[string]*schema.Parser)
|
||||||
|
|
||||||
@@ -58,7 +57,7 @@ func NewORM(objs ...any) *ORM {
|
|||||||
return &ORM{cache: cache}
|
return &ORM{cache: cache}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateSchmea builds the DDL and returns it as a string
|
// Builds the DDL and returns it as a string
|
||||||
func (orm *ORM) CreateSchema() (string, error) {
|
func (orm *ORM) CreateSchema() (string, error) {
|
||||||
var ddl strings.Builder
|
var ddl strings.Builder
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ func NewRepository[T HasPK](conn *simpleorm.DBConnection, orm *simpleorm.ORM) *R
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Repository[T]) SelectAll() []*T {
|
func (r *Repository[T]) SelectAll() []*T {
|
||||||
selectExec, err := exec.NewSelect[T](r.orm)
|
selectExec, err := exec.CreateSelect[T](r.orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("Failed to create select execution: %s", err)
|
log.LogError("Failed to create select execution: %s", err)
|
||||||
return []*T{}
|
return []*T{}
|
||||||
@@ -68,7 +68,7 @@ func (r *Repository[T]) SelectByPk(pks ...any) *T {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[T](r.orm)
|
selectExec, err := exec.CreateSelect[T](r.orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("Failed to create select execution: %s", err)
|
log.LogError("Failed to create select execution: %s", err)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
+2
-5
@@ -40,14 +40,11 @@ func determineModifiers(tag reflect.StructTag) map[string]string {
|
|||||||
func (c *Column) GetDDL() (string, error) {
|
func (c *Column) GetDDL() (string, error) {
|
||||||
var ddlBuilder strings.Builder
|
var ddlBuilder strings.Builder
|
||||||
|
|
||||||
ddlBuilder.WriteString(c.Name)
|
ddlBuilder.WriteString(c.Name + " " + c.Type)
|
||||||
ddlBuilder.WriteString(" ")
|
|
||||||
ddlBuilder.WriteString(c.Type)
|
|
||||||
|
|
||||||
inlineMods := c.inlineModifiers()
|
inlineMods := c.inlineModifiers()
|
||||||
for _, mod := range inlineMods {
|
for _, mod := range inlineMods {
|
||||||
ddlBuilder.WriteString(" ")
|
ddlBuilder.WriteString(" " + mod)
|
||||||
ddlBuilder.WriteString(mod)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ddlBuilder.String(), nil
|
return ddlBuilder.String(), nil
|
||||||
|
|||||||
+5
-5
@@ -118,7 +118,7 @@ func TestInsertAndUpdate(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err)
|
log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -207,7 +207,7 @@ func TestInsertAndDelete(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestInsertAndDelete setup failed: %s", err)
|
log.LogError("TestInsertAndDelete setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -263,7 +263,7 @@ func TestBoolInsertAndSelectSingle(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[TestWithBool](orm)
|
selectExec, err := exec.CreateSelect[TestWithBool](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestBoolInsertAndSelectSingle setup failed: %s", err)
|
log.LogError("TestBoolInsertAndSelectSingle setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -317,7 +317,7 @@ func TestTimeInsertAndSelectSingle(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[TestWithTime](orm)
|
selectExec, err := exec.CreateSelect[TestWithTime](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestTimeInsertAndSelectSingle setup failed: %s", err)
|
log.LogError("TestTimeInsertAndSelectSingle setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -423,7 +423,7 @@ func TestTransactionRollback(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestTransactionRollback WHEN failed: %s", err)
|
log.LogError("TestTransactionRollback WHEN failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
|||||||
@@ -56,13 +56,6 @@ type TestWithTime struct {
|
|||||||
TimeField int64 `sql:"nn"`
|
TimeField int64 `sql:"nn"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type TestWithJsonStructTag struct {
|
|
||||||
ID int `json:"id" sql:"pk"`
|
|
||||||
Int64Field int64 `json:"int64Field" sql:"nn"`
|
|
||||||
IntField int `json:"intField" sql:"nn"`
|
|
||||||
StringField string `json:"stringField" sql:"nn"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMain(m *testing.M) {
|
func TestMain(m *testing.M) {
|
||||||
log.SetupLogs("Info")
|
log.SetupLogs("Info")
|
||||||
|
|
||||||
|
|||||||
@@ -113,23 +113,3 @@ func TestParseCompositeFk(t *testing.T) {
|
|||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseStructWithJsonTag(t *testing.T) {
|
|
||||||
// GIVEN
|
|
||||||
orm := simpleorm.NewORM(TestWithJsonStructTag{})
|
|
||||||
// WHEN
|
|
||||||
ddl, err := orm.CreateSchema()
|
|
||||||
// THEN
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("Failed to parse schema! %s", err)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedDdl := "CREATE TABLE IF NOT EXISTS TEST_WITH_JSON_STRUCT_TAG (ID INTEGER, INT64_FIELD BIGINT NOT NULL, INT_FIELD INTEGER NOT NULL, STRING_FIELD TEXT NOT NULL, CONSTRAINT pk_test_with_json_struct_tag PRIMARY KEY(ID));"
|
|
||||||
if ddl != expectedDdl {
|
|
||||||
log.LogError("Incorrect DDL.\nExpected\n%s\nActual\n%s", expectedDdl, ddl)
|
|
||||||
log.LogError("\nExpected size: %s\nActual size: %s", strconv.Itoa(len(expectedDdl)), strconv.Itoa(len(ddl)))
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
log.LogInfo("Test finished!")
|
|
||||||
}
|
|
||||||
|
|||||||
+7
-47
@@ -16,7 +16,7 @@ func TestSelectEmpty(t *testing.T) {
|
|||||||
defer cleanUp("test.db", conn)
|
defer cleanUp("test.db", conn)
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
|
|
||||||
// THEN
|
// THEN
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -55,7 +55,7 @@ func TestSelectSingle(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestInsertAndSelectSingle setup failed: %s", err)
|
log.LogError("TestInsertAndSelectSingle setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -121,7 +121,7 @@ func TestSelectWithCompositePk(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[TestWithCompositePk](orm)
|
selectExec, err := exec.CreateSelect[TestWithCompositePk](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestInsertSelectWithCompositePk setup failed: %s", err)
|
log.LogError("TestInsertSelectWithCompositePk setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -182,7 +182,7 @@ func TestSelectWithParam(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err)
|
log.LogError("TestInsertMultipleAndSelectWithParam setup failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -255,7 +255,7 @@ func TestSelectWithLimitAndOffset(t *testing.T) {
|
|||||||
}
|
}
|
||||||
// WHEN
|
// WHEN
|
||||||
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestSelectWithLimitAndOffset failed: %s", err)
|
log.LogError("TestSelectWithLimitAndOffset failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -291,7 +291,7 @@ func TestSelectOrderByDesc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestSelectOrderByDesc failed: %s", err)
|
log.LogError("TestSelectOrderByDesc failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -331,7 +331,7 @@ func TestSelectOrderByAsc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WHEN
|
// WHEN
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
selectExec, err := exec.CreateSelect[Test](orm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.LogError("TestSelectOrderByAsc failed: %s", err)
|
log.LogError("TestSelectOrderByAsc failed: %s", err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -358,46 +358,6 @@ func TestSelectOrderByAsc(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSelectOrderByAscWithLimitAndOffset(t *testing.T) {
|
|
||||||
// GIVEN
|
|
||||||
orm, conn := testSetup()
|
|
||||||
defer cleanUp("test.db", conn)
|
|
||||||
|
|
||||||
err := orderBySetup(conn, orm)
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("TestSelectOrderByAsc setup failed: %s", err)
|
|
||||||
t.Fail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// WHEN
|
|
||||||
selectExec, err := exec.NewSelect[Test](orm)
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("TestSelectOrderByAsc failed: %s", err)
|
|
||||||
t.Fail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
selectExec.OrderBy(schema.OrderBy{Field: "StringField", Direction: "ASC"}).Limit(3).Offset(0)
|
|
||||||
|
|
||||||
err = selectExec.Execute(conn)
|
|
||||||
if err != nil {
|
|
||||||
log.LogError("TestSelectOrderByAsc failed: %s", err)
|
|
||||||
t.Fail()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// THEN
|
|
||||||
var resultStr string
|
|
||||||
for _, obj := range selectExec.Results() {
|
|
||||||
resultStr += obj.StringField
|
|
||||||
}
|
|
||||||
|
|
||||||
if resultStr != "ABC" {
|
|
||||||
log.LogError("TestSelectOrderByAsc failed, epxected: ABC actual: %s", resultStr)
|
|
||||||
t.Fail()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func orderBySetup(conn *simpleorm.DBConnection, orm *simpleorm.ORM) error {
|
func orderBySetup(conn *simpleorm.DBConnection, orm *simpleorm.ORM) error {
|
||||||
insertExec, err := exec.NewInsert[Test](orm,
|
insertExec, err := exec.NewInsert[Test](orm,
|
||||||
Test{Int64Field: -1, IntField: 1, StringField: "C"},
|
Test{Int64Field: -1, IntField: 1, StringField: "C"},
|
||||||
|
|||||||
Reference in New Issue
Block a user