@@ -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
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
}
|
||||
Reference in New Issue
Block a user