2021-07-27 17:39:21 +02:00
|
|
|
package template
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2024-11-26 15:40:34 +06:00
|
|
|
"path/filepath"
|
2024-10-26 22:40:49 -04:00
|
|
|
"slices"
|
2021-10-21 13:21:01 +02:00
|
|
|
"strings"
|
2021-07-27 17:39:21 +02:00
|
|
|
"unicode"
|
2025-04-10 09:02:23 -04:00
|
|
|
|
|
|
|
|
"github.com/go-jet/jet/v2/generator/metadata"
|
2026-05-06 16:26:38 +00:00
|
|
|
"github.com/go-jet/jet/v2/internal/jet"
|
2025-04-10 09:02:23 -04:00
|
|
|
"github.com/go-jet/jet/v2/internal/utils/dbidentifier"
|
2021-07-27 17:39:21 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// SQLBuilder is template for generating sql builder files
|
|
|
|
|
type SQLBuilder struct {
|
|
|
|
|
Skip bool
|
|
|
|
|
Path string
|
|
|
|
|
Table func(table metadata.Table) TableSQLBuilder
|
|
|
|
|
View func(view metadata.Table) TableSQLBuilder
|
|
|
|
|
Enum func(enum metadata.Enum) EnumSQLBuilder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultSQLBuilder returns default SQLBuilder implementation
|
|
|
|
|
func DefaultSQLBuilder() SQLBuilder {
|
|
|
|
|
return SQLBuilder{
|
|
|
|
|
Path: "",
|
|
|
|
|
Table: DefaultTableSQLBuilder,
|
|
|
|
|
View: DefaultViewSQLBuilder,
|
|
|
|
|
Enum: DefaultEnumSQLBuilder,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UsePath returns new SQLBuilder with new relative path set
|
|
|
|
|
func (sb SQLBuilder) UsePath(path string) SQLBuilder {
|
|
|
|
|
sb.Path = path
|
|
|
|
|
return sb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseTable returns new SQLBuilder with new TableSQLBuilder template function set
|
|
|
|
|
func (sb SQLBuilder) UseTable(tableFunc func(table metadata.Table) TableSQLBuilder) SQLBuilder {
|
|
|
|
|
sb.Table = tableFunc
|
|
|
|
|
return sb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseView returns new SQLBuilder with new ViewSQLBuilder template function set
|
|
|
|
|
func (sb SQLBuilder) UseView(viewFunc func(table metadata.Table) ViewSQLBuilder) SQLBuilder {
|
|
|
|
|
sb.View = viewFunc
|
|
|
|
|
return sb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseEnum returns new SQLBuilder with new EnumSQLBuilder template function set
|
|
|
|
|
func (sb SQLBuilder) UseEnum(enumFunc func(enum metadata.Enum) EnumSQLBuilder) SQLBuilder {
|
|
|
|
|
sb.Enum = enumFunc
|
|
|
|
|
return sb
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-10 09:02:23 -04:00
|
|
|
// ShouldSkip returns new SQLBuilder with new skip flag set
|
|
|
|
|
func (sb SQLBuilder) ShouldSkip(skip bool) SQLBuilder {
|
|
|
|
|
sb.Skip = skip
|
|
|
|
|
return sb
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
// TableSQLBuilder is template for generating table SQLBuilder files
|
|
|
|
|
type TableSQLBuilder struct {
|
2026-05-06 16:26:38 +00:00
|
|
|
Column func(dialect jet.Dialect, columnMetaData metadata.Column) TableSQLBuilderColumn
|
|
|
|
|
DefaultAlias string
|
|
|
|
|
Imports []string
|
2021-07-27 17:39:21 +02:00
|
|
|
InstanceName string
|
2026-05-06 16:26:38 +00:00
|
|
|
FileName string
|
|
|
|
|
Path string
|
|
|
|
|
Skip bool
|
2021-07-27 17:39:21 +02:00
|
|
|
TypeName string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ViewSQLBuilder is template for generating view SQLBuilder files
|
|
|
|
|
type ViewSQLBuilder = TableSQLBuilder
|
|
|
|
|
|
|
|
|
|
// DefaultTableSQLBuilder returns default implementation for TableSQLBuilder
|
|
|
|
|
func DefaultTableSQLBuilder(tableMetaData metadata.Table) TableSQLBuilder {
|
2024-02-17 12:46:00 +01:00
|
|
|
tableNameGoIdentifier := dbidentifier.ToGoIdentifier(tableMetaData.Name)
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
return TableSQLBuilder{
|
2026-05-06 16:26:38 +00:00
|
|
|
Column: DefaultTableSQLBuilderColumn,
|
|
|
|
|
DefaultAlias: "",
|
2023-07-21 14:11:31 +02:00
|
|
|
FileName: dbidentifier.ToGoFileName(tableMetaData.Name),
|
2026-05-06 16:26:38 +00:00
|
|
|
Imports: []string{},
|
2024-02-17 12:46:00 +01:00
|
|
|
InstanceName: tableNameGoIdentifier,
|
2026-05-06 16:26:38 +00:00
|
|
|
Path: "/table",
|
2024-02-17 12:46:00 +01:00
|
|
|
TypeName: tableNameGoIdentifier + "Table",
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultViewSQLBuilder returns default implementation for ViewSQLBuilder
|
|
|
|
|
func DefaultViewSQLBuilder(viewMetaData metadata.Table) ViewSQLBuilder {
|
|
|
|
|
tableSQLBuilder := DefaultTableSQLBuilder(viewMetaData)
|
|
|
|
|
tableSQLBuilder.Path = "/view"
|
|
|
|
|
return tableSQLBuilder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PackageName returns package name of table sql builder types
|
|
|
|
|
func (tb TableSQLBuilder) PackageName() string {
|
2024-11-26 15:40:34 +06:00
|
|
|
return filepath.Base(tb.Path)
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UsePath returns new TableSQLBuilder with new relative path set
|
|
|
|
|
func (tb TableSQLBuilder) UsePath(path string) TableSQLBuilder {
|
|
|
|
|
tb.Path = path
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseFileName returns new TableSQLBuilder with new file name set
|
|
|
|
|
func (tb TableSQLBuilder) UseFileName(name string) TableSQLBuilder {
|
|
|
|
|
tb.FileName = name
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseInstanceName returns new TableSQLBuilder with new instance name set
|
|
|
|
|
func (tb TableSQLBuilder) UseInstanceName(name string) TableSQLBuilder {
|
|
|
|
|
tb.InstanceName = name
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseTypeName returns new TableSQLBuilder with new type name set
|
|
|
|
|
func (tb TableSQLBuilder) UseTypeName(name string) TableSQLBuilder {
|
|
|
|
|
tb.TypeName = name
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-02 10:03:59 +09:00
|
|
|
// UseDefaultAlias returns new TableSQLBuilder with new default alias set
|
|
|
|
|
func (tb TableSQLBuilder) UseDefaultAlias(defaultAlias string) TableSQLBuilder {
|
|
|
|
|
tb.DefaultAlias = defaultAlias
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
// UseColumn returns new TableSQLBuilder with new column template function set
|
2026-05-06 16:26:38 +00:00
|
|
|
func (tb TableSQLBuilder) UseColumn(columnsFunc func(dialect jet.Dialect, column metadata.Column) TableSQLBuilderColumn) TableSQLBuilder {
|
2021-07-27 17:39:21 +02:00
|
|
|
tb.Column = columnsFunc
|
|
|
|
|
return tb
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TableSQLBuilderColumn is template for table sql builder column
|
|
|
|
|
type TableSQLBuilderColumn struct {
|
2026-05-06 16:26:38 +00:00
|
|
|
Import string
|
2021-07-27 17:39:21 +02:00
|
|
|
Name string
|
2026-05-06 16:26:38 +00:00
|
|
|
PackageName string
|
|
|
|
|
Skip bool
|
2021-07-27 17:39:21 +02:00
|
|
|
Type string
|
2026-05-06 16:26:38 +00:00
|
|
|
TypeFactory string
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
|
2025-02-06 09:34:22 +01:00
|
|
|
var reservedKeywords = []string{"TableName", "Table", "SchemaName", "Alias", "AllColumns", "MutableColumns", "DefaultColumns"}
|
2024-10-26 22:40:49 -04:00
|
|
|
|
|
|
|
|
func renameIfReserved(name string) string {
|
|
|
|
|
if slices.Contains(reservedKeywords, name) {
|
|
|
|
|
return name + "_"
|
|
|
|
|
}
|
|
|
|
|
return name
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-27 17:39:21 +02:00
|
|
|
// DefaultTableSQLBuilderColumn returns default implementation of TableSQLBuilderColumn
|
2026-05-06 16:26:38 +00:00
|
|
|
func DefaultTableSQLBuilderColumn(dialect jet.Dialect, columnMetaData metadata.Column) TableSQLBuilderColumn {
|
|
|
|
|
package_name := dialect.PackageName()
|
2021-07-27 17:39:21 +02:00
|
|
|
return TableSQLBuilderColumn{
|
2026-05-06 16:26:38 +00:00
|
|
|
Import: "github.com/go-jet/jet/v2/" + package_name,
|
2024-10-26 22:40:49 -04:00
|
|
|
Name: renameIfReserved(dbidentifier.ToGoIdentifier(columnMetaData.Name)),
|
2026-05-06 16:26:38 +00:00
|
|
|
PackageName: package_name,
|
|
|
|
|
Type: "Column" + getSqlBuilderColumnType(columnMetaData),
|
|
|
|
|
TypeFactory: getSqlBuilderColumnType(columnMetaData)+"Column",
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getSqlBuilderColumnType returns type of jet sql builder column
|
|
|
|
|
func getSqlBuilderColumnType(columnMetaData metadata.Column) string {
|
2025-10-16 15:09:07 +02:00
|
|
|
switch columnMetaData.DataType.Kind {
|
|
|
|
|
case metadata.EnumType, metadata.UserDefinedType:
|
|
|
|
|
if columnMetaData.DataType.IsArray() {
|
|
|
|
|
return "StringArray"
|
|
|
|
|
}
|
2021-07-27 17:39:21 +02:00
|
|
|
return "String"
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-16 15:09:07 +02:00
|
|
|
columnType := sqlToColumnType(columnMetaData)
|
2024-09-03 15:39:36 +02:00
|
|
|
|
2025-10-16 15:09:07 +02:00
|
|
|
if columnMetaData.DataType.IsArray() {
|
2024-09-03 15:39:36 +02:00
|
|
|
if columnMetaData.DataType.Dimensions > 1 {
|
2025-10-16 15:09:07 +02:00
|
|
|
fmt.Println("- [SQL Builder] Unsupported sql array with multiple dimensions column '" +
|
|
|
|
|
columnMetaData.Name + " " + columnMetaData.DataType.Name + "', using StringColumn instead.")
|
2024-09-03 15:39:36 +02:00
|
|
|
return "String"
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-16 15:09:07 +02:00
|
|
|
columnType = columnType + "Array"
|
2024-09-03 15:39:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return columnType
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-16 15:09:07 +02:00
|
|
|
// sqlToColumnType maps the type of a SQL column type to a go jet sql builder column. The second return value returns
|
|
|
|
|
// whether the given type is supported.
|
|
|
|
|
func sqlToColumnType(columnMetaData metadata.Column) string {
|
|
|
|
|
switch strings.ToLower(columnMetaData.DataType.Name) {
|
2024-02-01 15:20:49 +01:00
|
|
|
case "boolean", "bool":
|
2021-07-27 17:39:21 +02:00
|
|
|
return "Bool"
|
2024-02-01 15:20:49 +01:00
|
|
|
case "smallint", "integer", "bigint", "int2", "int4", "int8",
|
2021-07-27 17:39:21 +02:00
|
|
|
"tinyint", "mediumint", "int", "year": //MySQL
|
|
|
|
|
return "Integer"
|
|
|
|
|
case "date":
|
|
|
|
|
return "Date"
|
|
|
|
|
case "timestamp without time zone",
|
|
|
|
|
"timestamp", "datetime": //MySQL:
|
|
|
|
|
return "Timestamp"
|
2024-02-01 15:20:49 +01:00
|
|
|
case "timestamp with time zone", "timestamptz":
|
2021-07-27 17:39:21 +02:00
|
|
|
return "Timestampz"
|
|
|
|
|
case "time without time zone",
|
|
|
|
|
"time": //MySQL
|
|
|
|
|
return "Time"
|
2024-02-01 15:20:49 +01:00
|
|
|
case "time with time zone", "timetz":
|
2021-07-27 17:39:21 +02:00
|
|
|
return "Timez"
|
|
|
|
|
case "interval":
|
|
|
|
|
return "Interval"
|
2025-02-28 18:23:15 +01:00
|
|
|
case "user-defined", "enum", "text", "character", "character varying", "uuid",
|
2021-07-27 17:39:21 +02:00
|
|
|
"tsvector", "bit", "bit varying", "money", "json", "jsonb", "xml", "point", "line", "ARRAY",
|
2025-02-28 18:23:15 +01:00
|
|
|
"char", "varchar", "nvarchar", "bpchar", "varbit",
|
|
|
|
|
"tinytext", "mediumtext", "longtext": // MySQL
|
2021-07-27 17:39:21 +02:00
|
|
|
return "String"
|
2025-02-28 18:23:15 +01:00
|
|
|
case "bytea": // postgres
|
|
|
|
|
return "Bytea"
|
|
|
|
|
case "binary", "varbinary", "tinyblob", "mediumblob", "longblob", "blob": // mysql and sqlite
|
|
|
|
|
return "Blob"
|
2024-02-01 15:20:49 +01:00
|
|
|
case "real", "numeric", "decimal", "double precision", "float", "float4", "float8",
|
2021-07-27 17:39:21 +02:00
|
|
|
"double": // MySQL
|
|
|
|
|
return "Float"
|
2024-01-31 15:30:09 +01:00
|
|
|
case "daterange":
|
|
|
|
|
return "DateRange"
|
|
|
|
|
case "tsrange":
|
|
|
|
|
return "TimestampRange"
|
|
|
|
|
case "tstzrange":
|
|
|
|
|
return "TimestampzRange"
|
|
|
|
|
case "int4range":
|
|
|
|
|
return "Int4Range"
|
|
|
|
|
case "int8range":
|
|
|
|
|
return "Int8Range"
|
|
|
|
|
case "numrange":
|
|
|
|
|
return "NumericRange"
|
2021-07-27 17:39:21 +02:00
|
|
|
default:
|
2025-10-16 15:09:07 +02:00
|
|
|
fmt.Println("- [SQL Builder] Unsupported sql column '" + columnMetaData.Name + " " + columnMetaData.DataType.Name + "', using StringColumn instead.")
|
|
|
|
|
return "String"
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EnumSQLBuilder is template for generating enum SQLBuilder files
|
|
|
|
|
type EnumSQLBuilder struct {
|
|
|
|
|
Skip bool
|
|
|
|
|
Path string
|
|
|
|
|
FileName string
|
|
|
|
|
InstanceName string
|
|
|
|
|
ValueName func(enumValue string) string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultEnumSQLBuilder returns default implementation of EnumSQLBuilder
|
|
|
|
|
func DefaultEnumSQLBuilder(enumMetaData metadata.Enum) EnumSQLBuilder {
|
|
|
|
|
return EnumSQLBuilder{
|
|
|
|
|
Path: "/enum",
|
2023-07-21 14:11:31 +02:00
|
|
|
FileName: dbidentifier.ToGoFileName(enumMetaData.Name),
|
|
|
|
|
InstanceName: dbidentifier.ToGoIdentifier(enumMetaData.Name),
|
2021-07-27 17:39:21 +02:00
|
|
|
ValueName: func(enumValue string) string {
|
|
|
|
|
return defaultEnumValueName(enumMetaData.Name, enumValue)
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PackageName returns enum sql builder package name
|
|
|
|
|
func (e EnumSQLBuilder) PackageName() string {
|
2024-11-26 15:40:34 +06:00
|
|
|
return filepath.Base(e.Path)
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UsePath returns new EnumSQLBuilder with new path set
|
|
|
|
|
func (e EnumSQLBuilder) UsePath(path string) EnumSQLBuilder {
|
|
|
|
|
e.Path = path
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseFileName returns new EnumSQLBuilder with new file name set
|
|
|
|
|
func (e EnumSQLBuilder) UseFileName(name string) EnumSQLBuilder {
|
|
|
|
|
e.FileName = name
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UseInstanceName returns new EnumSQLBuilder with instance name set
|
|
|
|
|
func (e EnumSQLBuilder) UseInstanceName(name string) EnumSQLBuilder {
|
|
|
|
|
e.InstanceName = name
|
|
|
|
|
return e
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func defaultEnumValueName(enumName, enumValue string) string {
|
2023-07-21 14:11:31 +02:00
|
|
|
enumValueName := dbidentifier.ToGoIdentifier(enumValue)
|
2021-07-27 17:39:21 +02:00
|
|
|
if !unicode.IsLetter([]rune(enumValueName)[0]) {
|
2023-07-21 14:11:31 +02:00
|
|
|
return dbidentifier.ToGoIdentifier(enumName) + enumValueName
|
2021-07-27 17:39:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return enumValueName
|
|
|
|
|
}
|