[MySQL] Add NEW alias for the rows to be inserted.

This commit is contained in:
go-jet 2022-08-23 12:23:46 +02:00
parent c264529e95
commit 4e1ff65023
6 changed files with 135 additions and 107 deletions

View file

@ -26,80 +26,6 @@ import (
var {{tableTemplate.InstanceName}} = new{{tableTemplate.TypeName}}("{{schemaName}}", "{{.Name}}", "") var {{tableTemplate.InstanceName}} = new{{tableTemplate.TypeName}}("{{schemaName}}", "{{.Name}}", "")
type {{tableTemplate.TypeName}} struct {
{{dialect.PackageName}}.Table
//Columns
{{- range $i, $c := .Columns}}
{{- $field := columnField $c}}
{{$field.Name}} {{dialect.PackageName}}.Column{{$field.Type}}
{{- end}}
AllColumns {{dialect.PackageName}}.ColumnList
MutableColumns {{dialect.PackageName}}.ColumnList
}
// AS creates new {{tableTemplate.TypeName}} with assigned alias
func (a {{tableTemplate.TypeName}}) AS(alias string) {{tableTemplate.TypeName}} {
return new{{tableTemplate.TypeName}}(a.SchemaName(), a.TableName(), alias)
}
// Schema creates new {{tableTemplate.TypeName}} with assigned schema name
func (a {{tableTemplate.TypeName}}) FromSchema(schemaName string) {{tableTemplate.TypeName}} {
return new{{tableTemplate.TypeName}}(schemaName, a.TableName(), a.Alias())
}
// WithPrefix creates new {{tableTemplate.TypeName}} with assigned table prefix
func (a {{tableTemplate.TypeName}}) WithPrefix(prefix string) {{tableTemplate.TypeName}} {
return new{{tableTemplate.TypeName}}(a.SchemaName(), prefix+a.TableName(), a.TableName())
}
// WithSuffix creates new {{tableTemplate.TypeName}} with assigned table suffix
func (a {{tableTemplate.TypeName}}) WithSuffix(suffix string) {{tableTemplate.TypeName}} {
return new{{tableTemplate.TypeName}}(a.SchemaName(), a.TableName()+suffix, a.TableName())
}
func new{{tableTemplate.TypeName}}(schemaName, tableName, alias string) {{tableTemplate.TypeName}} {
var (
{{- range $i, $c := .Columns}}
{{- $field := columnField $c}}
{{$field.Name}}Column = {{dialect.PackageName}}.{{$field.Type}}Column("{{$c.Name}}")
{{- end}}
allColumns = {{dialect.PackageName}}.ColumnList{ {{template "column-list" .Columns}} }
mutableColumns = {{dialect.PackageName}}.ColumnList{ {{template "column-list" .MutableColumns}} }
)
return {{tableTemplate.TypeName}}{
Table: {{dialect.PackageName}}.NewTable(schemaName, tableName, alias, allColumns...),
//Columns
{{- range $i, $c := .Columns}}
{{- $field := columnField $c}}
{{$field.Name}}: {{$field.Name}}Column,
{{- end}}
AllColumns: allColumns,
MutableColumns: mutableColumns,
}
}
`
var tableSQLBuilderTemplateWithEXCLUDED = `
{{define "column-list" -}}
{{- range $i, $c := . }}
{{- $field := columnField $c}}
{{- if gt $i 0 }}, {{end}}{{$field.Name}}Column
{{- end}}
{{- end}}
package {{package}}
import (
"github.com/go-jet/jet/v2/{{dialect.PackageName}}"
)
var {{tableTemplate.InstanceName}} = new{{tableTemplate.TypeName}}("{{schemaName}}", "{{.Name}}", "")
type {{structImplName}} struct { type {{structImplName}} struct {
{{dialect.PackageName}}.Table {{dialect.PackageName}}.Table
@ -116,7 +42,7 @@ type {{structImplName}} struct {
type {{tableTemplate.TypeName}} struct { type {{tableTemplate.TypeName}} struct {
{{structImplName}} {{structImplName}}
EXCLUDED {{structImplName}} {{toUpper insertedRowAlias}} {{structImplName}}
} }
// AS creates new {{tableTemplate.TypeName}} with assigned alias // AS creates new {{tableTemplate.TypeName}} with assigned alias
@ -142,7 +68,7 @@ func (a {{tableTemplate.TypeName}}) WithSuffix(suffix string) *{{tableTemplate.T
func new{{tableTemplate.TypeName}}(schemaName, tableName, alias string) *{{tableTemplate.TypeName}} { func new{{tableTemplate.TypeName}}(schemaName, tableName, alias string) *{{tableTemplate.TypeName}} {
return &{{tableTemplate.TypeName}}{ return &{{tableTemplate.TypeName}}{
{{structImplName}}: new{{tableTemplate.TypeName}}Impl(schemaName, tableName, alias), {{structImplName}}: new{{tableTemplate.TypeName}}Impl(schemaName, tableName, alias),
EXCLUDED: new{{tableTemplate.TypeName}}Impl("", "excluded", ""), {{toUpper insertedRowAlias}}: new{{tableTemplate.TypeName}}Impl("", "{{insertedRowAlias}}", ""),
} }
} }

View file

@ -120,29 +120,29 @@ func processTableSQLBuilder(fileTypes, dirPath string,
for _, tableMetaData := range tablesMetaData { for _, tableMetaData := range tablesMetaData {
var tableSQLBuilderTemplate TableSQLBuilder var tableSQLBuilder TableSQLBuilder
if fileTypes == "view" { if fileTypes == "view" {
tableSQLBuilderTemplate = sqlBuilderTemplate.View(tableMetaData) tableSQLBuilder = sqlBuilderTemplate.View(tableMetaData)
} else { } else {
tableSQLBuilderTemplate = sqlBuilderTemplate.Table(tableMetaData) tableSQLBuilder = sqlBuilderTemplate.Table(tableMetaData)
} }
if tableSQLBuilderTemplate.Skip { if tableSQLBuilder.Skip {
continue continue
} }
tableSQLBuilderPath := path.Join(dirPath, tableSQLBuilderTemplate.Path) tableSQLBuilderPath := path.Join(dirPath, tableSQLBuilder.Path)
err := utils.EnsureDirPath(tableSQLBuilderPath) err := utils.EnsureDirPath(tableSQLBuilderPath)
throw.OnError(err) throw.OnError(err)
text, err := generateTemplate( text, err := generateTemplate(
autoGenWarningTemplate+getTableSQLBuilderTemplate(dialect), autoGenWarningTemplate+tableSQLBuilderTemplate,
tableMetaData, tableMetaData,
template.FuncMap{ template.FuncMap{
"package": func() string { "package": func() string {
return tableSQLBuilderTemplate.PackageName() return tableSQLBuilder.PackageName()
}, },
"dialect": func() jet.Dialect { "dialect": func() jet.Dialect {
return dialect return dialect
@ -151,29 +151,33 @@ func processTableSQLBuilder(fileTypes, dirPath string,
return schemaMetaData.Name return schemaMetaData.Name
}, },
"tableTemplate": func() TableSQLBuilder { "tableTemplate": func() TableSQLBuilder {
return tableSQLBuilderTemplate return tableSQLBuilder
}, },
"structImplName": func() string { // postgres only "structImplName": func() string { // postgres only
structName := tableSQLBuilderTemplate.TypeName structName := tableSQLBuilder.TypeName
return string(strings.ToLower(structName)[0]) + structName[1:] return string(strings.ToLower(structName)[0]) + structName[1:]
}, },
"columnField": func(columnMetaData metadata.Column) TableSQLBuilderColumn { "columnField": func(columnMetaData metadata.Column) TableSQLBuilderColumn {
return tableSQLBuilderTemplate.Column(columnMetaData) return tableSQLBuilder.Column(columnMetaData)
},
"toUpper": strings.ToUpper,
"insertedRowAlias": func() string {
return insertedRowAlias(dialect)
}, },
}) })
throw.OnError(err) throw.OnError(err)
err = utils.SaveGoFile(tableSQLBuilderPath, tableSQLBuilderTemplate.FileName, text) err = utils.SaveGoFile(tableSQLBuilderPath, tableSQLBuilder.FileName, text)
throw.OnError(err) throw.OnError(err)
} }
} }
func getTableSQLBuilderTemplate(dialect jet.Dialect) string { func insertedRowAlias(dialect jet.Dialect) string {
if dialect.Name() == "PostgreSQL" || dialect.Name() == "SQLite" { if dialect.Name() == "MySQL" {
return tableSQLBuilderTemplateWithEXCLUDED return "new"
} }
return tableSQLBuilderTemplate return "excluded"
} }
func processTableModels(fileTypes, modelDirPath string, tablesMetaData []metadata.Table, modelTemplate Model) { func processTableModels(fileTypes, modelDirPath string, tablesMetaData []metadata.Table, modelTemplate Model) {

View file

@ -392,6 +392,7 @@ func (v *ClauseValuesQuery) Serialize(statementType StatementType, out *SQLBuild
// ClauseValues struct // ClauseValues struct
type ClauseValues struct { type ClauseValues struct {
Rows [][]Serializer Rows [][]Serializer
As string
} }
// Serialize serializes clause into SQLBuilder // Serialize serializes clause into SQLBuilder
@ -417,6 +418,12 @@ func (v *ClauseValues) Serialize(statementType StatementType, out *SQLBuilder, o
out.WriteByte(')') out.WriteByte(')')
} }
if len(v.As) > 0 {
out.WriteString("AS")
out.WriteIdentifier(v.As)
}
out.DecreaseIdent(7) out.DecreaseIdent(7)
} }

View file

@ -12,6 +12,7 @@ type InsertStatement interface {
// If data is not struct or there is no field for every column selected, this method will panic. // If data is not struct or there is no field for every column selected, this method will panic.
MODEL(data interface{}) InsertStatement MODEL(data interface{}) InsertStatement
MODELS(data interface{}) InsertStatement MODELS(data interface{}) InsertStatement
AS_NEW() InsertStatement
ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement
@ -52,6 +53,11 @@ func (is *insertStatementImpl) MODELS(data interface{}) InsertStatement {
return is return is
} }
func (is *insertStatementImpl) AS_NEW() InsertStatement {
is.ValuesQuery.As = "new"
return is
}
func (is *insertStatementImpl) ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement { func (is *insertStatementImpl) ON_DUPLICATE_KEY_UPDATE(assigments ...ColumnAssigment) InsertStatement {
is.OnDuplicateKey = assigments is.OnDuplicateKey = assigments
return is return is
@ -79,7 +85,7 @@ func (s onDuplicateKeyUpdateClause) Serialize(statementType jet.StatementType, o
out.NewLine() out.NewLine()
} }
jet.Serialize(assigment, statementType, out, jet.ShortName.WithFallTrough(options)...) jet.Serialize(assigment, statementType, out, jet.FallTrough(options)...)
} }
out.DecreaseIdent(24) out.DecreaseIdent(24)

View file

@ -238,7 +238,7 @@ import (
var Actor = newActorTable("dvds", "actor", "") var Actor = newActorTable("dvds", "actor", "")
type ActorTable struct { type actorTable struct {
mysql.Table mysql.Table
//Columns //Columns
@ -251,27 +251,40 @@ type ActorTable struct {
MutableColumns mysql.ColumnList MutableColumns mysql.ColumnList
} }
type ActorTable struct {
actorTable
NEW actorTable
}
// AS creates new ActorTable with assigned alias // AS creates new ActorTable with assigned alias
func (a ActorTable) AS(alias string) ActorTable { func (a ActorTable) AS(alias string) *ActorTable {
return newActorTable(a.SchemaName(), a.TableName(), alias) return newActorTable(a.SchemaName(), a.TableName(), alias)
} }
// Schema creates new ActorTable with assigned schema name // Schema creates new ActorTable with assigned schema name
func (a ActorTable) FromSchema(schemaName string) ActorTable { func (a ActorTable) FromSchema(schemaName string) *ActorTable {
return newActorTable(schemaName, a.TableName(), a.Alias()) return newActorTable(schemaName, a.TableName(), a.Alias())
} }
// WithPrefix creates new ActorTable with assigned table prefix // WithPrefix creates new ActorTable with assigned table prefix
func (a ActorTable) WithPrefix(prefix string) ActorTable { func (a ActorTable) WithPrefix(prefix string) *ActorTable {
return newActorTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) return newActorTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
} }
// WithSuffix creates new ActorTable with assigned table suffix // WithSuffix creates new ActorTable with assigned table suffix
func (a ActorTable) WithSuffix(suffix string) ActorTable { func (a ActorTable) WithSuffix(suffix string) *ActorTable {
return newActorTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) return newActorTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
} }
func newActorTable(schemaName, tableName, alias string) ActorTable { func newActorTable(schemaName, tableName, alias string) *ActorTable {
return &ActorTable{
actorTable: newActorTableImpl(schemaName, tableName, alias),
NEW: newActorTableImpl("", "new", ""),
}
}
func newActorTableImpl(schemaName, tableName, alias string) actorTable {
var ( var (
ActorIDColumn = mysql.IntegerColumn("actor_id") ActorIDColumn = mysql.IntegerColumn("actor_id")
FirstNameColumn = mysql.StringColumn("first_name") FirstNameColumn = mysql.StringColumn("first_name")
@ -281,7 +294,7 @@ func newActorTable(schemaName, tableName, alias string) ActorTable {
mutableColumns = mysql.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn} mutableColumns = mysql.ColumnList{FirstNameColumn, LastNameColumn, LastUpdateColumn}
) )
return ActorTable{ return actorTable{
Table: mysql.NewTable(schemaName, tableName, alias, allColumns...), Table: mysql.NewTable(schemaName, tableName, alias, allColumns...),
//Columns //Columns
@ -334,7 +347,7 @@ import (
var ActorInfo = newActorInfoTable("dvds", "actor_info", "") var ActorInfo = newActorInfoTable("dvds", "actor_info", "")
type ActorInfoTable struct { type actorInfoTable struct {
mysql.Table mysql.Table
//Columns //Columns
@ -347,27 +360,40 @@ type ActorInfoTable struct {
MutableColumns mysql.ColumnList MutableColumns mysql.ColumnList
} }
type ActorInfoTable struct {
actorInfoTable
NEW actorInfoTable
}
// AS creates new ActorInfoTable with assigned alias // AS creates new ActorInfoTable with assigned alias
func (a ActorInfoTable) AS(alias string) ActorInfoTable { func (a ActorInfoTable) AS(alias string) *ActorInfoTable {
return newActorInfoTable(a.SchemaName(), a.TableName(), alias) return newActorInfoTable(a.SchemaName(), a.TableName(), alias)
} }
// Schema creates new ActorInfoTable with assigned schema name // Schema creates new ActorInfoTable with assigned schema name
func (a ActorInfoTable) FromSchema(schemaName string) ActorInfoTable { func (a ActorInfoTable) FromSchema(schemaName string) *ActorInfoTable {
return newActorInfoTable(schemaName, a.TableName(), a.Alias()) return newActorInfoTable(schemaName, a.TableName(), a.Alias())
} }
// WithPrefix creates new ActorInfoTable with assigned table prefix // WithPrefix creates new ActorInfoTable with assigned table prefix
func (a ActorInfoTable) WithPrefix(prefix string) ActorInfoTable { func (a ActorInfoTable) WithPrefix(prefix string) *ActorInfoTable {
return newActorInfoTable(a.SchemaName(), prefix+a.TableName(), a.TableName()) return newActorInfoTable(a.SchemaName(), prefix+a.TableName(), a.TableName())
} }
// WithSuffix creates new ActorInfoTable with assigned table suffix // WithSuffix creates new ActorInfoTable with assigned table suffix
func (a ActorInfoTable) WithSuffix(suffix string) ActorInfoTable { func (a ActorInfoTable) WithSuffix(suffix string) *ActorInfoTable {
return newActorInfoTable(a.SchemaName(), a.TableName()+suffix, a.TableName()) return newActorInfoTable(a.SchemaName(), a.TableName()+suffix, a.TableName())
} }
func newActorInfoTable(schemaName, tableName, alias string) ActorInfoTable { func newActorInfoTable(schemaName, tableName, alias string) *ActorInfoTable {
return &ActorInfoTable{
actorInfoTable: newActorInfoTableImpl(schemaName, tableName, alias),
NEW: newActorInfoTableImpl("", "new", ""),
}
}
func newActorInfoTableImpl(schemaName, tableName, alias string) actorInfoTable {
var ( var (
ActorIDColumn = mysql.IntegerColumn("actor_id") ActorIDColumn = mysql.IntegerColumn("actor_id")
FirstNameColumn = mysql.StringColumn("first_name") FirstNameColumn = mysql.StringColumn("first_name")
@ -377,7 +403,7 @@ func newActorInfoTable(schemaName, tableName, alias string) ActorInfoTable {
mutableColumns = mysql.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, FilmInfoColumn} mutableColumns = mysql.ColumnList{ActorIDColumn, FirstNameColumn, LastNameColumn, FilmInfoColumn}
) )
return ActorInfoTable{ return actorInfoTable{
Table: mysql.NewTable(schemaName, tableName, alias, allColumns...), Table: mysql.NewTable(schemaName, tableName, alias, allColumns...),
//Columns //Columns

View file

@ -255,7 +255,7 @@ func TestInsertOnDuplicateKey(t *testing.T) {
INSERT INTO test_sample.link INSERT INTO test_sample.link
VALUES (?, ?, ?, DEFAULT), VALUES (?, ?, ?, DEFAULT),
(?, ?, ?, DEFAULT) (?, ?, ?, DEFAULT)
ON DUPLICATE KEY UPDATE id = (id + ?), ON DUPLICATE KEY UPDATE id = (link.id + ?),
name = ?; name = ?;
`, randId, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", `, randId, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
randId, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", randId, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial",
@ -283,6 +283,65 @@ ON DUPLICATE KEY UPDATE id = (id + ?),
}) })
} }
func TestInsertOnDuplicateKeyUpdateNEW(t *testing.T) {
skipForMariaDB(t)
randId := rand.Int31()
stmt := Link.INSERT().
MODELS([]model.Link{
{
ID: randId,
URL: "https://www.postgresqltutorial.com",
Name: "PostgreSQL Tutorial",
Description: nil,
},
{
ID: randId,
URL: "https://www.yahoo.com",
Name: "Yahoo",
Description: testutils.StringPtr("web portal and search engine"),
},
}).AS_NEW().
ON_DUPLICATE_KEY_UPDATE(
Link.ID.SET(Link.ID.ADD(Int(11))),
Link.URL.SET(Link.NEW.URL),
Link.Name.SET(Link.NEW.Name),
Link.Description.SET(Link.NEW.Description),
)
testutils.AssertStatementSql(t, stmt, `
INSERT INTO test_sample.link
VALUES (?, ?, ?, ?),
(?, ?, ?, ?) AS new
ON DUPLICATE KEY UPDATE id = (link.id + ?),
url = new.url,
name = new.name,
description = new.description;
`)
testutils.ExecuteInTxAndRollback(t, db, func(tx *sql.Tx) {
_, err := stmt.Exec(tx)
require.NoError(t, err)
stmt := SELECT(Link.AllColumns).
FROM(Link).
WHERE(Link.ID.EQ(Int32(randId + 11)))
var dest model.Link
err = stmt.Query(tx, &dest)
require.NoError(t, err)
testutils.AssertDeepEqual(t, dest, model.Link{
ID: randId + 11,
URL: "https://www.yahoo.com",
Name: "Yahoo",
Description: testutils.StringPtr("web portal and search engine"),
})
})
}
func TestInsertWithQueryContext(t *testing.T) { func TestInsertWithQueryContext(t *testing.T) {
stmt := Link.INSERT(). stmt := Link.INSERT().
VALUES(1100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT) VALUES(1100, "http://www.postgresqltutorial.com", "PostgreSQL Tutorial", DEFAULT)