2024-01-05 16:53:14 +01:00
|
|
|
package sq
|
|
|
|
|
|
|
|
import (
|
2024-02-09 15:17:51 +01:00
|
|
|
"errors"
|
2024-01-05 16:53:14 +01:00
|
|
|
"fmt"
|
|
|
|
"gogs.mikescher.com/BlackForestBytes/goext/exerr"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2024-02-09 15:17:51 +01:00
|
|
|
func BuildUpdateStatement[TData any](q Queryable, tableName string, obj TData, idColumn string) (string, PP, error) {
|
2024-01-05 16:53:14 +01:00
|
|
|
rval := reflect.ValueOf(obj)
|
|
|
|
rtyp := rval.Type()
|
|
|
|
|
|
|
|
params := PP{}
|
|
|
|
|
|
|
|
setClauses := make([]string, 0)
|
|
|
|
|
|
|
|
matchClause := ""
|
|
|
|
|
|
|
|
for i := 0; i < rtyp.NumField(); i++ {
|
|
|
|
|
|
|
|
rsfield := rtyp.Field(i)
|
|
|
|
rvfield := rval.Field(i)
|
|
|
|
|
|
|
|
if !rsfield.IsExported() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
columnName := rsfield.Tag.Get("db")
|
|
|
|
if columnName == "" || columnName == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if idColumn == columnName {
|
|
|
|
idValue, err := convertValueToDB(q, rvfield.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
matchClause = fmt.Sprintf("(%s = :%s)", columnName, params.Add(idValue))
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if rsfield.Type.Kind() == reflect.Ptr && rvfield.IsNil() {
|
|
|
|
|
|
|
|
setClauses = append(setClauses, fmt.Sprintf("%s = NULL", columnName))
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
val, err := convertValueToDB(q, rvfield.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
2024-01-13 01:29:40 +01:00
|
|
|
setClauses = append(setClauses, fmt.Sprintf("%s = :%s", columnName, params.Add(val)))
|
2024-01-05 16:53:14 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(setClauses) == 0 {
|
|
|
|
return "", nil, exerr.New(exerr.TypeSQLBuild, "no updates clauses found in object").Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
if matchClause == "" {
|
|
|
|
return "", nil, exerr.New(exerr.TypeSQLBuild, "id column not found in object").Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
//goland:noinspection SqlNoDataSourceInspection
|
|
|
|
return fmt.Sprintf("UPDATE %s SET %s WHERE %s", tableName, strings.Join(setClauses, ", "), matchClause), params, nil
|
|
|
|
}
|
2024-01-14 00:07:01 +01:00
|
|
|
|
2024-02-09 15:17:51 +01:00
|
|
|
func BuildInsertStatement[TData any](q Queryable, tableName string, obj TData) (string, PP, error) {
|
2024-01-14 00:07:01 +01:00
|
|
|
rval := reflect.ValueOf(obj)
|
|
|
|
rtyp := rval.Type()
|
|
|
|
|
|
|
|
params := PP{}
|
|
|
|
|
|
|
|
fields := make([]string, 0)
|
|
|
|
values := make([]string, 0)
|
|
|
|
|
|
|
|
for i := 0; i < rtyp.NumField(); i++ {
|
|
|
|
|
|
|
|
rsfield := rtyp.Field(i)
|
|
|
|
rvfield := rval.Field(i)
|
|
|
|
|
|
|
|
if !rsfield.IsExported() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
columnName := rsfield.Tag.Get("db")
|
|
|
|
if columnName == "" || columnName == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if rsfield.Type.Kind() == reflect.Ptr && rvfield.IsNil() {
|
|
|
|
|
|
|
|
fields = append(fields, columnName)
|
2024-01-14 01:52:52 +01:00
|
|
|
values = append(values, "NULL")
|
2024-01-14 00:07:01 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
val, err := convertValueToDB(q, rvfield.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
fields = append(fields, columnName)
|
2024-01-14 01:52:52 +01:00
|
|
|
values = append(values, ":"+params.Add(val))
|
2024-01-14 00:07:01 +01:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(fields) == 0 {
|
|
|
|
return "", nil, exerr.New(exerr.TypeSQLBuild, "no fields found in object").Build()
|
|
|
|
}
|
|
|
|
|
|
|
|
//goland:noinspection SqlNoDataSourceInspection
|
2024-01-14 01:50:48 +01:00
|
|
|
return fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", tableName, strings.Join(fields, ", "), strings.Join(values, ", ")), params, nil
|
2024-01-14 00:07:01 +01:00
|
|
|
}
|
2024-02-09 15:17:51 +01:00
|
|
|
|
|
|
|
func BuildInsertMultipleStatement[TData any](q Queryable, tableName string, vArr []TData) (string, PP, error) {
|
|
|
|
|
|
|
|
if len(vArr) == 0 {
|
|
|
|
return "", nil, errors.New("no data supplied")
|
|
|
|
}
|
|
|
|
|
|
|
|
rtyp := reflect.ValueOf(vArr[0]).Type()
|
|
|
|
|
|
|
|
sqlPrefix := ""
|
|
|
|
{
|
|
|
|
columns := make([]string, 0)
|
|
|
|
|
|
|
|
for i := 0; i < rtyp.NumField(); i++ {
|
|
|
|
rsfield := rtyp.Field(i)
|
|
|
|
|
|
|
|
if !rsfield.IsExported() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
columnName := rsfield.Tag.Get("db")
|
|
|
|
if columnName == "" || columnName == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
columns = append(columns, "\""+columnName+"\"")
|
|
|
|
}
|
|
|
|
|
|
|
|
sqlPrefix = fmt.Sprintf("INSERT"+" INTO \"%s\" (%s) VALUES", tableName, strings.Join(columns, ", "))
|
|
|
|
}
|
|
|
|
|
|
|
|
pp := PP{}
|
|
|
|
|
|
|
|
sqlValuesArr := make([]string, 0)
|
|
|
|
|
|
|
|
for _, v := range vArr {
|
|
|
|
|
|
|
|
rval := reflect.ValueOf(v)
|
|
|
|
|
|
|
|
params := make([]string, 0)
|
|
|
|
|
|
|
|
for i := 0; i < rtyp.NumField(); i++ {
|
|
|
|
|
|
|
|
rsfield := rtyp.Field(i)
|
|
|
|
rvfield := rval.Field(i)
|
|
|
|
|
|
|
|
if !rsfield.IsExported() {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
columnName := rsfield.Tag.Get("db")
|
|
|
|
if columnName == "" || columnName == "-" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if rsfield.Type.Kind() == reflect.Ptr && rvfield.IsNil() {
|
|
|
|
|
|
|
|
params = append(params, "NULL")
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
val, err := convertValueToDB(q, rvfield.Interface())
|
|
|
|
if err != nil {
|
|
|
|
return "", nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
params = append(params, ":"+pp.Add(val))
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sqlValuesArr = append(sqlValuesArr, fmt.Sprintf("(%s)", strings.Join(params, ", ")))
|
|
|
|
}
|
|
|
|
|
|
|
|
sqlstr := fmt.Sprintf("%s %s", sqlPrefix, strings.Join(sqlValuesArr, ", "))
|
|
|
|
|
|
|
|
return sqlstr, pp, nil
|
|
|
|
}
|