Files
simpleorm/schema/table.go
T
gdulai cd1f61fb87
Go Tests / test (pull_request) Successful in 1m4s
WIP: OrderBy implementation
2026-06-05 17:19:11 +02:00

257 lines
4.6 KiB
Go

package schema
import (
"errors"
"reflect"
"strings"
"git.gdulai.com/gdulai/simpleorm/util"
)
type OrderBy struct {
Field string
Direction string
}
type Table struct {
name string
typ reflect.Type
columns []Column
constraints []Constraint
}
func (t Table) Name() string {
return t.name
}
func (t Table) Type() reflect.Type {
return t.typ
}
func (t Table) Columns() []Column {
return t.columns
}
func (t Table) Constraints() []Constraint {
return t.constraints
}
func (t Table) GetDDL() (string, error) {
var ddl strings.Builder
ddl.WriteString("CREATE TABLE IF NOT EXISTS ")
ddl.WriteString(t.name)
ddl.WriteString(" (")
for i, col := range t.columns {
if i != 0 {
ddl.WriteString(", ")
}
colDdl, err := col.GetDDL()
if err != nil {
return "", err
}
ddl.WriteString(colDdl)
}
for _, constr := range t.constraints {
constrDdl, err := constr.GetDDL()
if err != nil {
return "", err
}
ddl.WriteString(", ")
ddl.WriteString(constrDdl)
}
ddl.WriteString(");")
return ddl.String(), nil
}
func (t Table) GetSelectDML() (string, error) {
var dml strings.Builder
dml.WriteString("SELECT ")
for i, col := range t.columns {
if i != 0 {
dml.WriteString(", ")
}
colDml, err := col.GetSelectDML()
if err != nil {
return "", err
}
dml.WriteString(colDml)
}
dml.WriteString(" FROM ")
dml.WriteString(t.name)
return dml.String(), nil
}
func (t Table) GetCountDML() string {
return "SELECT COUNT(*) FROM " + t.name
}
func (t Table) GetInsertDML(count int) (string, error) {
var dml strings.Builder
dml.WriteString("INSERT INTO ")
dml.WriteString(util.CamelToSnake(t.typ.Name()))
dml.WriteString(" (")
columnsLen := len(t.columns)
effectiveColumnsLen := 0
for i, col := range t.columns {
_, ok := col.Modifiers["pk"]
if ok && t.IsPkAuto() {
continue
}
colDml, err := col.GetInsertDML()
if err != nil {
return "", err
}
dml.WriteString(colDml)
if i != columnsLen-1 {
dml.WriteString(", ")
}
effectiveColumnsLen++
}
dml.WriteString(") VALUES")
for i := range count {
if i != 0 {
dml.WriteString(", ")
}
for j := range effectiveColumnsLen {
if j == 0 {
dml.WriteString("(")
}
if j != effectiveColumnsLen-1 {
dml.WriteString("?, ")
} else {
dml.WriteString("?)")
}
}
}
dml.WriteString(" RETURNING *")
return dml.String(), nil
}
func (t Table) GetUpdateDML() (string, error) {
var dml strings.Builder
dml.WriteString("UPDATE ")
dml.WriteString(util.CamelToSnake(t.typ.Name()))
dml.WriteString(" SET ")
colLen := len(t.columns)
var pkColumns []string
// Colum names
for i, col := range t.columns {
modifiers := col.Modifiers
_, ok := modifiers["pk"]
if ok {
pkColumns = append(pkColumns, col.Name)
if t.IsPkAuto() {
continue
}
}
colDml, err := col.GetUpdateDML()
if err != nil {
return "", err
}
if i != colLen-1 {
dml.WriteString(colDml)
dml.WriteString(", ")
} else {
dml.WriteString(colDml)
dml.WriteString(" ")
}
}
dml.WriteString("WHERE ")
for i, pkCol := range pkColumns {
if i != 0 {
dml.WriteString(" AND ")
}
dml.WriteString(pkCol)
dml.WriteString(" = ?")
}
return dml.String(), nil
}
func (t Table) GetDeleteDML(count int) (string, error) {
var dml strings.Builder
dml.WriteString("DELETE FROM ")
dml.WriteString(t.name)
dml.WriteString(" WHERE ")
for _, col := range t.columns {
modifiers := col.Modifiers
_, ok := modifiers["pk"]
if ok {
if count > 1 {
dml.WriteString(col.Name)
dml.WriteString(" IN (")
} else {
dml.WriteString(col.Name)
dml.WriteString(" = ")
}
}
}
for i := range count {
if i != 0 {
dml.WriteString(", ")
}
dml.WriteString("?")
}
if count > 1 {
dml.WriteString(")")
}
return dml.String(), nil
}
func (t Table) GetOrderByDML(ordering ...OrderBy) (string, error) {
var dml strings.Builder
dml.WriteString(" ORDER BY")
for _, orderBy := range ordering {
col, err := t.getColumnByField(orderBy.Field)
if err != nil {
return "", err
}
dml.WriteString(" ")
dml.WriteString(col.Name)
dml.WriteString(" ")
dml.WriteString(orderBy.Direction)
}
return dml.String(), nil
}
func (t Table) getColumnByField(fieldName string) (Column, error) {
for _, col := range t.columns {
if col.FieldName == fieldName {
return col, nil
}
}
return Column{}, errors.New("No column for field " + fieldName + " in table " + t.name)
}
func (t Table) IsPkAuto() bool {
for _, constr := range t.constraints {
if constr.Type != "pk" {
continue
}
return len(constr.Columns) == 1
}
return true
}