Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
e5e3a22
removed TableName and ColumnName structs
graduenz Jan 27, 2026
5059922
replaced table's AddColumn by AddColumns
graduenz Jan 27, 2026
51209b5
modified existing code to support previous changes
graduenz Jan 27, 2026
7f55398
added quoting mechanism to identifiers (tables/columns) when building…
graduenz Jan 27, 2026
674146d
implemented quoting identifiers on each dialect
graduenz Jan 27, 2026
d8f1092
fixed dialect builder tests to build
graduenz Jan 27, 2026
9dbbdb6
Merge branch 'main' into gui/remove-table-column-name-limitations
graduenz Jan 27, 2026
815f2f3
applied quoting mechanism on schema queries
graduenz Jan 27, 2026
50c2732
fixed linting problems
graduenz Jan 27, 2026
7765abc
changed sqlbuilder to be a single instance under the driver
graduenz Jan 27, 2026
d84a0b2
set QuoteIdentifier function as part of SQLBuilder interface
graduenz Jan 27, 2026
f9b4d5c
modified schema functions to rely on sql builder
graduenz Jan 27, 2026
b221e1a
applied quoting mechanism on migrator functions
graduenz Jan 27, 2026
cbbfc1e
moved default quoting behavior to generic sql builder
graduenz Jan 27, 2026
932d83d
fixed typo in assert
graduenz Jan 27, 2026
e02e356
changed structs to have pointer receivers as a standard
graduenz Jan 27, 2026
e4402b0
included quoting in expected produced SQL commands (AI agent)
graduenz Jan 27, 2026
d320e1a
quoted missing identifiers
graduenz Jan 27, 2026
c49294c
fixed broken test after changing structs to use pointer receivers
graduenz Jan 27, 2026
5a4a308
removed redundant executor from database
graduenz Jan 27, 2026
9e5c65e
grouped parameters of same type together
graduenz Jan 27, 2026
efba7c6
db schema name consistence
graduenz Jan 27, 2026
ceadebf
added simple tests for dialect-specific schema
graduenz Jan 27, 2026
776046c
removed potentially unnecessary NOSONAR comment
graduenz Jan 27, 2026
6c2bb8a
added new tests for migrator
graduenz Jan 27, 2026
899b962
added tests for generic sql builder's QuoteIdentifier
graduenz Jan 27, 2026
102693a
fixed and updated documentation
graduenz Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 29 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,23 +120,18 @@ defer db.Close()
### Create a table with the SQLBuilder

```go
table, err := ormshift.NewTable("users")
if err != nil {
// handle error
}
table := schema.NewTable("users")

columns := []schema.NewColumnParams{
{Name: "id", Type: ormshift.Integer, PrimaryKey: true, AutoIncrement: true},
{Name: "name", Type: ormshift.Varchar, Size: 50, NotNull: false},
}
err := table.AddColumns(
schema.NewColumnParams{Name: "id", Type: schema.Integer, PrimaryKey: true, AutoIncrement: true},
schema.NewColumnParams{Name: "name", Type: schema.Varchar, Size: 50, NotNull: false},
)

for _, col := range columns {
if err := table.AddColumn(col); err != nil {
// handle error
}
if err != nil {
// handle error
}

db.SQLExecutor().Exec(db.SQLBuilder().CreateTable(*table))
db.SQLExecutor().Exec(db.SQLBuilder().CreateTable(table))
```

### CRUD with the SQLBuilder and SQLExecutor
Expand Down Expand Up @@ -209,41 +204,35 @@ type M0001CreateUserTable struct{}

func (m M0001CreateUserTable) Up(migrator *migrations.Migrator) error {
db := migrator.Database()
table, err := schema.NewTable("user")
if err != nil {
return err
}
table := schema.NewTable("user")

if db.DBSchema().HasTable(table.Name()) {
// if the table already exists, nothing to do here
return nil
}

columns := []schema.NewColumnParams{
{Name: "id", Type: schema.Integer, PrimaryKey: true, AutoIncrement: true},
{Name: "name", Type: schema.Varchar, Size: 50, NotNull: false},
{Name: "email", Type: schema.Varchar, Size: 120, NotNull: false},
{Name: "is_active", Type: schema.Boolean, NotNull: false},
}

for _, col := range columns {
if err := table.AddColumn(col); err != nil {
return err
}
err := table.AddColumns(
schema.NewColumnParams{Name: "id", Type: schema.Integer, PrimaryKey: true, AutoIncrement: true},
schema.NewColumnParams{Name: "name", Type: schema.Varchar, Size: 50, NotNull: false},
schema.NewColumnParams{Name: "email", Type: schema.Varchar, Size: 120, NotNull: false},
schema.NewColumnParams{Name: "is_active", Type: schema.Boolean, NotNull: false},
)
if err != nil {
return err
}

_, err := db.SQLExecutor().Exec(db.SQLBuilder().CreateTable(*table))
_, err = db.SQLExecutor().Exec(db.SQLBuilder().CreateTable(table))
return err
}

func (m M0001CreateUserTable) Down(migrator *migrations.Migrator) error {
db := migrator.Database()
tableName, _ := schema.NewTableName("user")
if !db.DBSchema().HasTable(*tableName) {
tableName := "user"
if !db.DBSchema().HasTable(tableName) {
// if the table already doesn't exist, nothing to do here
return nil
}
_, err := db.SQLExecutor().Exec(db.SQLBuilder().DropTable(*tableName))
_, err := db.SQLExecutor().Exec(db.SQLBuilder().DropTable(tableName))
return err
}
```
Expand All @@ -256,42 +245,28 @@ type M0002AddUpdatedAtColumn struct{}

func (m M0002AddUpdatedAtColumn) Up(migrator *migrations.Migrator) error {
db := migrator.Database()
tableName, err := schema.NewTableName("user")
if err != nil {
return err
}

col, err := schema.NewColumn(schema.NewColumnParams{Name: "updated_at", Type: schema.DateTime})
if err != nil {
return err
}
tableName := "user"
col := schema.NewColumn(schema.NewColumnParams{Name: "updated_at", Type: schema.DateTime})

if db.DBSchema().HasColumn(*tableName, col.Name()) {
if db.DBSchema().HasColumn(tableName, col.Name()) {
// if the column already exists, nothing to do here
return nil
}

_, err := db.SQLExecutor().Exec(db.SQLBuilder().AlterTableAddColumn(*tableName, *col))
_, err := db.SQLExecutor().Exec(db.SQLBuilder().AlterTableAddColumn(tableName, col))
return err
}

func (m M0002AddUpdatedAtColumn) Down(migrator *migrations.Migrator) error {
db := migrator.Database()
tableName, err := schema.NewTableName("user")
if err != nil {
return err
}

colName, err := schema.NewColumnName("updated_at")
if err != nil {
return err
}
tableName := "user"
colName := "updated_at"

if !db.DBSchema().HasColumn(*tableName, *colName) {
if !db.DBSchema().HasColumn(tableName, colName) {
// if the column already doesn't exist, nothing to do here
return nil
}
_, err := db.SQLExecutor().Exec(db.SQLBuilder().AlterTableDropColumn(*tableName, *colName))
_, err := db.SQLExecutor().Exec(db.SQLBuilder().AlterTableDropColumn(tableName, colName))
return err
}
```
Expand Down
15 changes: 8 additions & 7 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
// DDSQLBuilder creates DDL (Data Definition Language) SQL commands for defining schema in DBMS.
type DDLSQLBuilder interface {
CreateTable(pTable schema.Table) string
DropTable(pTableName schema.TableName) string
AlterTableAddColumn(pTableName schema.TableName, pColumn schema.Column) string
AlterTableDropColumn(pTableName schema.TableName, pColumnName schema.ColumnName) string
DropTable(pTableName string) string
AlterTableAddColumn(pTableName string, pColumn schema.Column) string
AlterTableDropColumn(pTableName, pColumnName string) string
ColumnTypeAsString(pColumnType schema.ColumnType) string
}

Expand All @@ -24,9 +24,9 @@ type ColumnsValues map[string]any
// lColumnsValues := ColumnsValues{"id": 5, "sku": "ZTX-9000", "is_simple": true}
// lNamedArgs := lColumnsValues.ToNamedArgs()
// //lNamedArgs == []sql.NamedArg{{Name: "id", Value: 5},{Name: "is_simple", Value: true},{Name: "sku", Value: "ZTX-9000"}}
func (cv ColumnsValues) ToNamedArgs() []sql.NamedArg {
func (cv *ColumnsValues) ToNamedArgs() []sql.NamedArg {
lNamedArgs := []sql.NamedArg{}
for c, v := range cv {
for c, v := range *cv {
lNamedArgs = append(lNamedArgs, sql.Named(c, v))
}
slices.SortFunc(lNamedArgs, func(a, b sql.NamedArg) int {
Expand All @@ -39,9 +39,9 @@ func (cv ColumnsValues) ToNamedArgs() []sql.NamedArg {
}

// ToColumns returns the column names from ColumnsValues as a string array ordered by name, e.g.:
func (cv ColumnsValues) ToColumns() []string {
func (cv *ColumnsValues) ToColumns() []string {
lColumns := []string{}
for c := range cv {
for c := range *cv {
lColumns = append(lColumns, c)
}
slices.Sort(lColumns)
Expand Down Expand Up @@ -91,4 +91,5 @@ type DMLSQLBuilder interface {
type SQLBuilder interface {
DDLSQLBuilder
DMLSQLBuilder
QuoteIdentifier(pIdentifier string) string
}
15 changes: 7 additions & 8 deletions database.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,9 @@ type DatabaseDriver interface {
type Database struct {
driver DatabaseDriver
db *sql.DB
executor SQLExecutor
connectionString string
sqlBuilder SQLBuilder
schema schema.DBSchema
dbSchema *schema.DBSchema
}

func OpenDatabase(pDriver DatabaseDriver, pParams ConnectionParams) (*Database, error) {
Expand All @@ -43,17 +42,17 @@ func OpenDatabase(pDriver DatabaseDriver, pParams ConnectionParams) (*Database,
if lError != nil {
return nil, fmt.Errorf("sql.Open failed: %w", lError)
}
lSchema, lError := pDriver.DBSchema(lDB)
lDBSchema, lError := pDriver.DBSchema(lDB)
if lError != nil {
return nil, fmt.Errorf("failed to get DB schema: %w", lError)
}

return &Database{
driver: pDriver,
db: lDB,
executor: lDB,
connectionString: lConnectionString,
sqlBuilder: pDriver.SQLBuilder(),
schema: *lSchema,
dbSchema: lDBSchema,
}, nil
}

Expand All @@ -66,7 +65,7 @@ func (d *Database) DB() *sql.DB {
}

func (d *Database) SQLExecutor() SQLExecutor {
return d.executor
return d.db
}

func (d *Database) DriverName() string {
Expand All @@ -82,6 +81,6 @@ func (d *Database) SQLBuilder() SQLBuilder {
return d.sqlBuilder
}

func (d *Database) DBSchema() schema.DBSchema {
return d.schema
func (d *Database) DBSchema() *schema.DBSchema {
return d.dbSchema
}
2 changes: 1 addition & 1 deletion database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func TestDriverConnectionString(t *testing.T) {
func TestDriverSQLBuilder(t *testing.T) {
lDriver := testutils.NewFakeDriver(sqlite.Driver())
lSQLBuilder := lDriver.SQLBuilder()
testutils.AssertEqualWithLabel(t, "sqliteBuilder", reflect.TypeOf(lSQLBuilder).Name(), "FakeDriver.SQLBuilder")
testutils.AssertEqualWithLabel(t, "sqliteBuilder", reflect.TypeOf(lSQLBuilder).Elem().Name(), "FakeDriver.SQLBuilder")
}

func TestDriverDBSchema(t *testing.T) {
Expand Down
44 changes: 24 additions & 20 deletions dialects/postgresql/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ type postgresqlBuilder struct {
}

func newPostgreSQLBuilder() ormshift.SQLBuilder {
lBuilder := postgresqlBuilder{}
lBuilder.generic = internal.NewGenericSQLBuilder(lBuilder.columnDefinition, lBuilder.InteroperateSQLCommandWithNamedArgs)
return lBuilder
sb := postgresqlBuilder{}
sb.generic = internal.NewGenericSQLBuilder(sb.columnDefinition, nil, sb.InteroperateSQLCommandWithNamedArgs)
return &sb
}

func (sb postgresqlBuilder) CreateTable(pTable schema.Table) string {
func (sb *postgresqlBuilder) CreateTable(pTable schema.Table) string {
return sb.generic.CreateTable(pTable)
}

func (sb postgresqlBuilder) DropTable(pTableName schema.TableName) string {
func (sb *postgresqlBuilder) DropTable(pTableName string) string {
return sb.generic.DropTable(pTableName)
}

func (sb postgresqlBuilder) AlterTableAddColumn(pTableName schema.TableName, pColumn schema.Column) string {
func (sb *postgresqlBuilder) AlterTableAddColumn(pTableName string, pColumn schema.Column) string {
return sb.generic.AlterTableAddColumn(pTableName, pColumn)
}

func (sb postgresqlBuilder) AlterTableDropColumn(pTableName schema.TableName, pColumnName schema.ColumnName) string {
func (sb *postgresqlBuilder) AlterTableDropColumn(pTableName, pColumnName string) string {
return sb.generic.AlterTableDropColumn(pTableName, pColumnName)
}

func (sb postgresqlBuilder) ColumnTypeAsString(pColumnType schema.ColumnType) string {
func (sb *postgresqlBuilder) ColumnTypeAsString(pColumnType schema.ColumnType) string {
switch pColumnType {
case schema.Varchar:
return "VARCHAR"
Expand All @@ -58,8 +58,8 @@ func (sb postgresqlBuilder) ColumnTypeAsString(pColumnType schema.ColumnType) st
}
}

func (sb postgresqlBuilder) columnDefinition(pColumn schema.Column) string {
lColumnDef := pColumn.Name().String()
func (sb *postgresqlBuilder) columnDefinition(pColumn schema.Column) string {
lColumnDef := sb.QuoteIdentifier(pColumn.Name())
if pColumn.AutoIncrement() {
lColumnDef += " BIGSERIAL"
} else {
Expand All @@ -75,43 +75,47 @@ func (sb postgresqlBuilder) columnDefinition(pColumn schema.Column) string {
return lColumnDef
}

func (sb postgresqlBuilder) Insert(pTableName string, pColumns []string) string {
func (sb *postgresqlBuilder) Insert(pTableName string, pColumns []string) string {
return sb.generic.Insert(pTableName, pColumns)
}

func (sb postgresqlBuilder) InsertWithValues(pTableName string, pColumnsValues ormshift.ColumnsValues) (string, []any) {
func (sb *postgresqlBuilder) InsertWithValues(pTableName string, pColumnsValues ormshift.ColumnsValues) (string, []any) {
return sb.generic.InsertWithValues(pTableName, pColumnsValues)
}

func (sb postgresqlBuilder) Update(pTableName string, pColumns, pColumnsWhere []string) string {
func (sb *postgresqlBuilder) Update(pTableName string, pColumns, pColumnsWhere []string) string {
return sb.generic.Update(pTableName, pColumns, pColumnsWhere)
}

func (sb postgresqlBuilder) UpdateWithValues(pTableName string, pColumns, pColumnsWhere []string, pValues ormshift.ColumnsValues) (string, []any) {
func (sb *postgresqlBuilder) UpdateWithValues(pTableName string, pColumns, pColumnsWhere []string, pValues ormshift.ColumnsValues) (string, []any) {
return sb.generic.UpdateWithValues(pTableName, pColumns, pColumnsWhere, pValues)
}

func (sb postgresqlBuilder) Delete(pTableName string, pColumnsWhere []string) string {
func (sb *postgresqlBuilder) Delete(pTableName string, pColumnsWhere []string) string {
return sb.generic.Delete(pTableName, pColumnsWhere)
}

func (sb postgresqlBuilder) DeleteWithValues(pTableName string, pWhereColumnsValues ormshift.ColumnsValues) (string, []any) {
func (sb *postgresqlBuilder) DeleteWithValues(pTableName string, pWhereColumnsValues ormshift.ColumnsValues) (string, []any) {
return sb.generic.DeleteWithValues(pTableName, pWhereColumnsValues)
}

func (sb postgresqlBuilder) Select(pTableName string, pColumns, pColumnsWhere []string) string {
func (sb *postgresqlBuilder) Select(pTableName string, pColumns, pColumnsWhere []string) string {
return sb.generic.Select(pTableName, pColumns, pColumnsWhere)
}

func (sb postgresqlBuilder) SelectWithValues(pTableName string, pColumns []string, pWhereColumnsValues ormshift.ColumnsValues) (string, []any) {
func (sb *postgresqlBuilder) SelectWithValues(pTableName string, pColumns []string, pWhereColumnsValues ormshift.ColumnsValues) (string, []any) {
return sb.generic.SelectWithValues(pTableName, pColumns, pWhereColumnsValues)
}

func (sb postgresqlBuilder) SelectWithPagination(pSQLSelectCommand string, pRowsPerPage, pPageNumber uint) string {
func (sb *postgresqlBuilder) SelectWithPagination(pSQLSelectCommand string, pRowsPerPage, pPageNumber uint) string {
return sb.generic.SelectWithPagination(pSQLSelectCommand, pRowsPerPage, pPageNumber)
}

func (sb postgresqlBuilder) InteroperateSQLCommandWithNamedArgs(pSQLCommand string, pNamedArgs ...sql.NamedArg) (string, []any) {
func (sb *postgresqlBuilder) QuoteIdentifier(pIdentifier string) string {
return sb.generic.QuoteIdentifier(pIdentifier)
}

func (sb *postgresqlBuilder) InteroperateSQLCommandWithNamedArgs(pSQLCommand string, pNamedArgs ...sql.NamedArg) (string, []any) {
lSQLCommand := pSQLCommand
lArgs := []any{}
lIndexes := map[string]int{}
Expand Down
Loading