Introduce Exec interface and implementers (#1)
Go Tests / test (push) Failing after 6s

Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
2026-05-11 06:03:40 +00:00
parent dedbcc4cfe
commit ffd9cd004e
16 changed files with 1026 additions and 585 deletions
+82
View File
@@ -0,0 +1,82 @@
package schema
import (
"errors"
"reflect"
"strings"
)
type Column struct {
Name string
FieldName string
Type string
Modifiers map[string]string
}
func NewColumn(name string, typ string, fieldName string, tag reflect.StructTag) Column {
return Column{name, typ, fieldName, determineModifiers(tag)}
}
func determineModifiers(tag reflect.StructTag) map[string]string {
modifiers := make(map[string]string)
sqlTag := tag.Get("sql")
if sqlTag == "" {
return modifiers
}
rawModifiers := strings.SplitSeq(sqlTag, ";")
for rawModifier := range rawModifiers {
if strings.Contains(rawModifier, "=") {
keyValue := strings.Split(rawModifier, "=")
modifiers[keyValue[0]] = keyValue[1]
} else {
modifiers[rawModifier] = ""
}
}
return modifiers
}
func (c *Column) GetDDL() (string, error) {
var ddlBuilder strings.Builder
ddlBuilder.WriteString(c.Name + " " + c.Type)
inlineMods := c.inlineModifiers()
for _, mod := range inlineMods {
ddlBuilder.WriteString(" " + mod)
}
return ddlBuilder.String(), nil
}
func (c *Column) inlineModifiers() []string {
var mods []string
for k, _ := range c.Modifiers {
switch k {
case "nn":
mods = append(mods, "NOT NULL")
}
}
return mods
}
func (c Column) GetSelectDML() (string, error) {
return c.Name, nil
}
func (c Column) GetInsertDML() (string, error) {
return c.Name, nil
}
func (c Column) GetUpdateDML() (string, error) {
return c.Name + " = ?", nil
}
func (Column) GetDeleteDML() (string, error) {
return "", errors.New("No delete DML for columns")
}
func (c *Column) IsPK() bool {
_, ok := c.Modifiers["pk"]
return ok
}
+78
View File
@@ -0,0 +1,78 @@
package schema
import (
"errors"
"strings"
)
type Constraint struct {
Name string
Type string
Columns []Column
RefTable *Table
RefColumns []Column
}
func (c *Constraint) GetDDL() (string, error) {
switch c.Type {
case "pk":
return c.getPkDDL(), nil
case "fk":
return c.getFkDDL(), nil
}
return "", errors.New("Unimplemented constraing: " + c.Type)
}
func (c *Constraint) getPkDDL() string {
var ddl strings.Builder
ddl.WriteString("CONSTRAINT " + c.Name + " PRIMARY KEY(")
for i, col := range c.Columns {
if i != 0 {
ddl.WriteString(", ")
}
ddl.WriteString(col.Name)
}
ddl.WriteString(")")
return ddl.String()
}
func (c *Constraint) getFkDDL() string {
var ddl strings.Builder
ddl.WriteString("CONSTRAINT " + c.Name + " FOREIGN KEY(")
for i, col := range c.Columns {
if i != 0 {
ddl.WriteString(", ")
}
ddl.WriteString(col.Name)
}
ddl.WriteString(") REFERENCES " + c.RefTable.Name + "(")
for i, col := range c.RefColumns {
if i != 0 {
ddl.WriteString(", ")
}
ddl.WriteString(col.Name)
}
ddl.WriteString(")")
return ddl.String()
}
func (Constraint) GetSelectDML() (string, error) {
return "", errors.New("No DML for constraints")
}
func (Constraint) GetInsertDML() (string, error) {
return "", errors.New("No DML for constraints")
}
func (Constraint) GetUpdateDML() (string, error) {
return "", errors.New("No DML for constraints")
}
func (Constraint) GetDeleteDML() (string, error) {
return "", errors.New("No DML for constraints")
}
+11
View File
@@ -0,0 +1,11 @@
package schema
// Interface that descibes a DB schema descripotor part.
// eg.: Table, Column, Constraints etc.
type SchemaDescriptor interface {
getDDL() (string, error)
GetSelectDML() (string, error)
GetInsertDML(count int) (string, error)
GetUpdateDML() (string, error)
GetDeleteDML(count int) (string, error)
}
+176
View File
@@ -0,0 +1,176 @@
package schema
import (
"reflect"
"strings"
"git.gdulai.com/gdulai/simpleorm/util"
)
type Table struct {
Name string
Type reflect.Type
Columns []Column
Constraints []Constraint
}
func (t Table) GetDDL() (string, error) {
var ddl strings.Builder
ddl.WriteString("CREATE TABLE IF NOT EXISTS " + t.Name + " (")
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(", " + 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 " + t.Name)
return dml.String(), nil
}
func (t Table) GetInsertDML(count int) (string, error) {
var dml strings.Builder
dml.WriteString("INSERT INTO " + util.CamelToSnake(t.Type.Name()) + " (")
columnsLen := len(t.Columns)
effectiveColumnsLen := 0
for i, col := range t.Columns {
_, ok := col.Modifiers["pk"]
if ok {
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("?)")
}
}
}
return dml.String(), nil
}
func (t Table) GetUpdateDML() (string, error) {
var dml strings.Builder
dml.WriteString("UPDATE " + util.CamelToSnake(t.Type.Name()) + " 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)
continue
}
colDml, err := col.GetUpdateDML()
if err != nil {
return "", err
}
if i != colLen-1 {
dml.WriteString(colDml + ", ")
} else {
dml.WriteString(colDml + " ")
}
}
dml.WriteString("WHERE ")
for i, pkCol := range pkColumns {
if i != 0 {
dml.WriteString(" AND ")
}
dml.WriteString(pkCol + " = ?")
}
return dml.String(), nil
}
func (t Table) GetDeleteDML(count int) (string, error) {
var dml strings.Builder
dml.WriteString("DELETE FROM " + t.Name + " WHERE ")
for _, col := range t.Columns {
modifiers := col.Modifiers
_, ok := modifiers["pk"]
if ok {
if count > 1 {
dml.WriteString(col.Name + " IN (")
} else {
dml.WriteString(col.Name + " = ")
}
}
}
for i := range count {
if i != 0 {
dml.WriteString(", ")
}
dml.WriteString("?")
}
if count > 1 {
dml.WriteString(")")
}
return dml.String(), nil
}