Initial source commit
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OrmCache struct {
|
||||||
|
mu sync.RWMutex
|
||||||
|
data map[string]*Table
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOrmCache(tables []*Table) *OrmCache {
|
||||||
|
cache := &OrmCache{
|
||||||
|
data: make(map[string]*Table),
|
||||||
|
}
|
||||||
|
for _, table := range tables {
|
||||||
|
cache.add(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
return cache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrmCache) add(table *Table) {
|
||||||
|
o.mu.Lock()
|
||||||
|
defer o.mu.Unlock()
|
||||||
|
o.data[table.TypeName] = table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrmCache) Get(tableName string) (*Table, bool) {
|
||||||
|
o.mu.RLock()
|
||||||
|
defer o.mu.RUnlock()
|
||||||
|
table, ok := o.data[tableName]
|
||||||
|
return table, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *OrmCache) GetAll() []*Table {
|
||||||
|
o.mu.RLock()
|
||||||
|
defer o.mu.RUnlock()
|
||||||
|
var result []*Table
|
||||||
|
|
||||||
|
for _, v := range o.data {
|
||||||
|
result = append(result, v)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"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) ToDDL() string {
|
||||||
|
var ddlBuilder strings.Builder
|
||||||
|
|
||||||
|
ddlBuilder.WriteString(c.Name + " " + c.Type)
|
||||||
|
|
||||||
|
inlineMods := c.inlineModifiers()
|
||||||
|
for _, mod := range inlineMods {
|
||||||
|
ddlBuilder.WriteString(" " + mod)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ddlBuilder.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) IsPK() bool {
|
||||||
|
_, ok := c.Modifiers["pk"]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
type Constraint struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
Columns []Column
|
||||||
|
RefTable *Table
|
||||||
|
RefColumns []Column
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Constraint) ToDDL() string {
|
||||||
|
switch c.Type {
|
||||||
|
case "pk":
|
||||||
|
return c.toPkDDL()
|
||||||
|
case "fk":
|
||||||
|
return c.toFkDDL()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Constraint) toPkDDL() 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) toFkDDL() 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()
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
module simpleorm
|
||||||
|
|
||||||
|
go 1.26.2
|
||||||
|
|
||||||
|
require gitlab.com/gdulai/simpleloglvl v0.0.0-20260418080844-d5cca4888d97 // indirect
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
gitlab.com/gdulai/simpleloglvl v0.0.0-20260418080844-d5cca4888d97 h1:f6UvrrilTIgQ2jWMJEEObZwAQQPykoWY2ju3Bq2qaGA=
|
||||||
|
gitlab.com/gdulai/simpleloglvl v0.0.0-20260418080844-d5cca4888d97/go.mod h1:H7XPunUrSyAvPa9nx8UbKnThEQJDmj3mdt+9ZtqDth4=
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package simpleorm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
log "gitlab.com/gdulai/simpleloglvl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
log.SetupLogs("Debug")
|
||||||
|
|
||||||
|
code := m.Run()
|
||||||
|
|
||||||
|
os.Exit(code)
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
// Package simpleorm provies a simple, basic ORM functionalities for making
|
||||||
|
// interaction with relational databses easier.
|
||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
log "gitlab.com/gdulai/simpleloglvl"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Type to access the ORM functionalities in a structured manner-
|
||||||
|
type ORM struct {
|
||||||
|
cache *OrmCache
|
||||||
|
}
|
||||||
|
|
||||||
|
// Inits the ORM library.
|
||||||
|
// Param objs is an array which should be an array of the types which describe the tables.
|
||||||
|
func NewORM(objs ...any) *ORM {
|
||||||
|
var parsers []*Parser
|
||||||
|
var tables []*Table
|
||||||
|
for _, obj := range objs {
|
||||||
|
log.LogDebug("[ORM] Mapping type for: %s", reflect.TypeOf(obj).Name())
|
||||||
|
parser := NewParser(obj)
|
||||||
|
parsers = append(parsers, parser)
|
||||||
|
tables = append(tables, parser.ParseColumns())
|
||||||
|
}
|
||||||
|
|
||||||
|
log.LogDebug("[ORM] Tables initiated, creating cache.")
|
||||||
|
|
||||||
|
// Create cache with the initialized tables
|
||||||
|
cache := NewOrmCache(tables)
|
||||||
|
|
||||||
|
log.LogDebug("[ORM] Cache created.")
|
||||||
|
|
||||||
|
// Finish the parsing with the constraints and add the to the tables
|
||||||
|
for _, parser := range parsers {
|
||||||
|
log.LogDebug("[ORM] Parsing constraing for: %s", parser.Table.Name)
|
||||||
|
parser.ParseConstraints(cache)
|
||||||
|
log.LogDebug("[ORM] Parsed constraints for: %s", parser.Table.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &ORM{cache: cache}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (orm *ORM) CreateDDL() string {
|
||||||
|
var ddl strings.Builder
|
||||||
|
|
||||||
|
tables := orm.cache.GetAll()
|
||||||
|
|
||||||
|
for i, table := range tables {
|
||||||
|
if i != 0 {
|
||||||
|
ddl.WriteString("\n")
|
||||||
|
}
|
||||||
|
ddl.WriteString(table.ToDDL())
|
||||||
|
}
|
||||||
|
|
||||||
|
return ddl.String()
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"unicode"
|
||||||
|
|
||||||
|
log "gitlab.com/gdulai/simpleloglvl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Parser struct {
|
||||||
|
typ reflect.Type
|
||||||
|
Table *Table
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewParser(obj any) *Parser {
|
||||||
|
objType := reflect.TypeOf(obj)
|
||||||
|
return &Parser{typ: objType}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is step 1 of the parsing, it creates the table instance and
|
||||||
|
func (p *Parser) ParseColumns() *Table {
|
||||||
|
table := Table{Name: camelToSnake(p.typ.Name()), TypeName: p.typ.Name()}
|
||||||
|
|
||||||
|
var columns []Column
|
||||||
|
for field := range p.typ.Fields() {
|
||||||
|
field := field
|
||||||
|
col := NewColumn(camelToSnake((field.Name)), field.Name, determineType(field.Type), field.Tag)
|
||||||
|
columns = append(columns, col)
|
||||||
|
}
|
||||||
|
|
||||||
|
table.Columns = columns
|
||||||
|
p.Table = &table
|
||||||
|
return p.Table
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Parser) ParseConstraints(cache *OrmCache) {
|
||||||
|
pkConstraint := Constraint{Name: "pk_" + strings.ToLower(p.Table.Name), Type: "pk"}
|
||||||
|
fkConstraints := make(map[string]Constraint)
|
||||||
|
for _, col := range p.Table.Columns {
|
||||||
|
_, ok := col.Modifiers["pk"]
|
||||||
|
if ok {
|
||||||
|
pkConstraint.Columns = append(pkConstraint.Columns, col)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fkMod, ok := col.Modifiers["fk"]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fkModParts := strings.Split(fkMod, ".")
|
||||||
|
refTable, ok := cache.Get(fkModParts[0])
|
||||||
|
if !ok {
|
||||||
|
log.LogError("[ORM] Table %s not found in OrmCache!", fkModParts[0])
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fkId, ok := col.Modifiers["fk_id"]
|
||||||
|
if fkId == "" {
|
||||||
|
fkId = "fk_" + strings.ToLower(refTable.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fkConstraint, ok := fkConstraints[fkId]
|
||||||
|
if !ok {
|
||||||
|
fkConstraint = Constraint{Name: fkId, Type: "fk", RefTable: refTable}
|
||||||
|
}
|
||||||
|
|
||||||
|
fkConstraint.Columns = append(fkConstraint.Columns, col)
|
||||||
|
|
||||||
|
refField := fkModParts[1]
|
||||||
|
for _, refC := range refTable.Columns {
|
||||||
|
if refC.FieldName == refField {
|
||||||
|
fkConstraint.RefColumns = append(fkConstraint.RefColumns, refC)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fkConstraints[fkId] = fkConstraint
|
||||||
|
}
|
||||||
|
p.Table.Constraints = append(p.Table.Constraints, pkConstraint)
|
||||||
|
for _, fkConstraint := range fkConstraints {
|
||||||
|
p.Table.Constraints = append(p.Table.Constraints, fkConstraint)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func determineType(typ reflect.Type) string {
|
||||||
|
typStr := typ.String()
|
||||||
|
switch typStr {
|
||||||
|
case "string":
|
||||||
|
return "TEXT"
|
||||||
|
case "int":
|
||||||
|
return "INTEGER"
|
||||||
|
case "time.Time", "int64":
|
||||||
|
return "BIGINT"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "VARCHAR(255)"
|
||||||
|
}
|
||||||
|
|
||||||
|
func camelToSnake(str string) string {
|
||||||
|
var snake strings.Builder
|
||||||
|
isPrevUpper := true
|
||||||
|
for _, c := range str {
|
||||||
|
if unicode.IsUpper(c) && !isPrevUpper {
|
||||||
|
snake.WriteString("_" + string(unicode.ToUpper(c)))
|
||||||
|
isPrevUpper = true
|
||||||
|
} else {
|
||||||
|
snake.WriteString(string(unicode.ToUpper(c)))
|
||||||
|
isPrevUpper = unicode.IsUpper(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return snake.String()
|
||||||
|
}
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
package simpleorm_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"simpleorm"
|
||||||
|
"strconv"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
log "gitlab.com/gdulai/simpleloglvl"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Test struct {
|
||||||
|
ID int `sql:"pk"`
|
||||||
|
Int64Field int64 `sql:"nn"`
|
||||||
|
IntField int `sql:"nn"`
|
||||||
|
StringField string `sql:"nn"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseSimple(t *testing.T) {
|
||||||
|
log.LogInfo("Test start...")
|
||||||
|
// GIVEN
|
||||||
|
orm := simpleorm.NewORM(Test{})
|
||||||
|
// WHEN
|
||||||
|
ddl := orm.CreateDDL()
|
||||||
|
// THEN
|
||||||
|
expectedDdl := "CREATE TABLE IF NOT EXISTS TEST (ID INTEGER, INT64_FIELD BIGINT NOT NULL, INT_FIELD INTEGER NOT NULL, STRING_FIELD TEXT NOT NULL, CONSTRAINT pk_test 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!")
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestWithFk struct {
|
||||||
|
ID int `sql:"pk"`
|
||||||
|
TestID int `sql:"nn;fk=Test.ID"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseFk(t *testing.T) {
|
||||||
|
log.LogInfo("Test start...")
|
||||||
|
// GIVEN
|
||||||
|
orm := simpleorm.NewORM(Test{}, TestWithFk{})
|
||||||
|
// WHEN
|
||||||
|
ddl := orm.CreateDDL()
|
||||||
|
// THEN
|
||||||
|
expectedDdl :=
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST (ID INTEGER, INT64_FIELD BIGINT NOT NULL, INT_FIELD INTEGER NOT NULL, STRING_FIELD TEXT NOT NULL, CONSTRAINT pk_test PRIMARY KEY(ID));\n" +
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST_WITH_FK (ID INTEGER, TEST_ID INTEGER NOT NULL, CONSTRAINT pk_test_with_fk PRIMARY KEY(ID), CONSTRAINT fk_test FOREIGN KEY(TEST_ID) REFERENCES TEST(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!")
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestWithFkAndFkId struct {
|
||||||
|
ID int `sql:"pk"`
|
||||||
|
TestID int `sql:"nn;fk=Test.ID;fk_id=custom_fk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseFkAndFkId(t *testing.T) {
|
||||||
|
// GIVEN
|
||||||
|
orm := simpleorm.NewORM(Test{}, TestWithFkAndFkId{})
|
||||||
|
// WHEN
|
||||||
|
ddl := orm.CreateDDL()
|
||||||
|
// THEN
|
||||||
|
expectedDdl :=
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST (ID INTEGER, INT64_FIELD BIGINT NOT NULL, INT_FIELD INTEGER NOT NULL, STRING_FIELD TEXT NOT NULL, CONSTRAINT pk_test PRIMARY KEY(ID));\n" +
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST_WITH_FK_AND_FK_ID (ID INTEGER, TEST_ID INTEGER NOT NULL, CONSTRAINT pk_test_with_fk_and_fk_id PRIMARY KEY(ID), CONSTRAINT custom_fk FOREIGN KEY(TEST_ID) REFERENCES TEST(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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestWithCompositePk struct {
|
||||||
|
ID int `sql:"nn;pk"`
|
||||||
|
Name string `sql:"nn;pk"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseCompositePk(t *testing.T) {
|
||||||
|
// GIVEN
|
||||||
|
orm := simpleorm.NewORM(TestWithCompositePk{})
|
||||||
|
// WHEN
|
||||||
|
ddl := orm.CreateDDL()
|
||||||
|
// THEN
|
||||||
|
expectedDdl := "CREATE TABLE IF NOT EXISTS TEST_WITH_COMPOSITE_PK (ID INTEGER NOT NULL, NAME TEXT NOT NULL, CONSTRAINT pk_test_with_composite_pk PRIMARY KEY(ID, NAME));"
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type TestWithCompositeFk struct {
|
||||||
|
ID int `sql:"nn;pk"`
|
||||||
|
CompositeFkId int `sql:"nn;fk=TestWithCompositePk.ID;"`
|
||||||
|
CompositeFkName string `sql:"nn;fk=TestWithCompositePk.Name;"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseCompositeFk(t *testing.T) {
|
||||||
|
// GIVEN
|
||||||
|
orm := simpleorm.NewORM(TestWithCompositePk{}, TestWithCompositeFk{})
|
||||||
|
// WHEN
|
||||||
|
ddl := orm.CreateDDL()
|
||||||
|
// THEN
|
||||||
|
expectedDdl :=
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST_WITH_COMPOSITE_PK (ID INTEGER NOT NULL, NAME TEXT NOT NULL, CONSTRAINT pk_test_with_composite_pk PRIMARY KEY(ID, NAME));\n" +
|
||||||
|
"CREATE TABLE IF NOT EXISTS TEST_WITH_COMPOSITE_FK (ID INTEGER NOT NULL, COMPOSITE_FK_ID INTEGER NOT NULL, COMPOSITE_FK_NAME TEXT NOT NULL, CONSTRAINT pk_test_with_composite_fk PRIMARY KEY(ID), CONSTRAINT fk_test_with_composite_pk FOREIGN KEY(COMPOSITE_FK_ID, COMPOSITE_FK_NAME) REFERENCES TEST_WITH_COMPOSITE_PK(ID, NAME));"
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package simpleorm
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Table struct {
|
||||||
|
Name string
|
||||||
|
TypeName string
|
||||||
|
Columns []Column
|
||||||
|
Constraints []Constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Table) ToDDL() string {
|
||||||
|
var ddl strings.Builder
|
||||||
|
ddl.WriteString("CREATE TABLE IF NOT EXISTS " + t.Name + " (")
|
||||||
|
for i, col := range t.Columns {
|
||||||
|
if i != 0 {
|
||||||
|
ddl.WriteString(", ")
|
||||||
|
}
|
||||||
|
ddl.WriteString(col.ToDDL())
|
||||||
|
}
|
||||||
|
for _, constr := range t.Constraints {
|
||||||
|
ddl.WriteString(", " + constr.ToDDL())
|
||||||
|
}
|
||||||
|
|
||||||
|
ddl.WriteString(");")
|
||||||
|
return ddl.String()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user