Add self join support.
This commit is contained in:
parent
20c6f39665
commit
1cb997fc54
5 changed files with 89 additions and 15 deletions
|
|
@ -23,7 +23,7 @@ func (c ColumnInfo) IsUnique() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ColumnInfo) ToGoVarName() string {
|
func (c ColumnInfo) ToGoVarName() string {
|
||||||
return snaker.SnakeToCamelLower(c.TableInfo.Name) + snaker.SnakeToCamel(c.Name) + "Column"
|
return snaker.SnakeToCamel(c.Name) + "Column"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c ColumnInfo) ToGoType() string {
|
func (c ColumnInfo) ToGoType() string {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@ package generator
|
||||||
|
|
||||||
var SqlBuilderTableTemplate = `package table
|
var SqlBuilderTableTemplate = `package table
|
||||||
|
|
||||||
import "github.com/sub0Zero/go-sqlbuilder/sqlbuilder"
|
import (
|
||||||
|
"github.com/sub0Zero/go-sqlbuilder/sqlbuilder"
|
||||||
|
)
|
||||||
|
|
||||||
type {{.ToGoStructName}} struct {
|
type {{.ToGoStructName}} struct {
|
||||||
sqlbuilder.Table
|
sqlbuilder.Table
|
||||||
|
|
@ -15,22 +17,36 @@ type {{.ToGoStructName}} struct {
|
||||||
AllColumns sqlbuilder.ColumnList
|
AllColumns sqlbuilder.ColumnList
|
||||||
}
|
}
|
||||||
|
|
||||||
var {{.ToGoVarName}} = &{{.ToGoStructName}}{
|
var {{.ToGoVarName}} = new{{.ToGoStructName}}()
|
||||||
Table: *sqlbuilder.NewTable("{{.DatabaseInfo.SchemaName}}", "{{.Name}}", {{.ToGoColumnFieldList ", "}}),
|
|
||||||
|
func new{{.ToGoStructName}}() *{{.ToGoStructName}} {
|
||||||
//Columns
|
var (
|
||||||
|
{{- range .Columns}}
|
||||||
|
{{.ToGoVarName}} = sqlbuilder.IntColumn("{{.Name}}", {{if .IsNullable}}sqlbuilder.Nullable{{else}}sqlbuilder.NotNullable{{end}})
|
||||||
|
{{- end}}
|
||||||
|
)
|
||||||
|
|
||||||
|
return &{{.ToGoStructName}}{
|
||||||
|
Table: *sqlbuilder.NewTable("{{.DatabaseInfo.SchemaName}}", "{{.Name}}", {{.ToGoColumnFieldList ", "}}),
|
||||||
|
|
||||||
|
//Columns
|
||||||
{{- range .Columns}}
|
{{- range .Columns}}
|
||||||
{{.ToGoFieldName}}: {{.ToGoVarName}},
|
{{.ToGoFieldName}}: {{.ToGoVarName}},
|
||||||
{{- end}}
|
{{- end}}
|
||||||
|
|
||||||
AllColumns: sqlbuilder.ColumnList{ {{.ToGoColumnFieldList ", "}} },
|
AllColumns: sqlbuilder.ColumnList{ {{.ToGoColumnFieldList ", "}} },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (a *{{.ToGoStructName}}) As(alias string) *{{.ToGoStructName}} {
|
||||||
|
aliasTable := new{{.ToGoStructName}}()
|
||||||
|
|
||||||
|
aliasTable.Table.SetAlias(alias)
|
||||||
|
|
||||||
|
return aliasTable
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
{{- range .Columns}}
|
|
||||||
{{.ToGoVarName}} = sqlbuilder.IntColumn("{{.Name}}", {{if .IsNullable}}sqlbuilder.Nullable{{else}}sqlbuilder.NotNullable{{end}})
|
|
||||||
{{- end}}
|
|
||||||
)
|
|
||||||
`
|
`
|
||||||
|
|
||||||
var DataModelTemplate = `package model
|
var DataModelTemplate = `package model
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type Column interface {
|
||||||
setTableName(table string) error
|
setTableName(table string) error
|
||||||
|
|
||||||
Eq(rhs Expression) BoolExpression
|
Eq(rhs Expression) BoolExpression
|
||||||
|
Neq(rhs Expression) BoolExpression
|
||||||
|
|
||||||
Gte(rhs Expression) BoolExpression
|
Gte(rhs Expression) BoolExpression
|
||||||
GteLiteral(rhs interface{}) BoolExpression
|
GteLiteral(rhs interface{}) BoolExpression
|
||||||
|
|
@ -109,6 +110,10 @@ func (c *baseColumn) Eq(rhs Expression) BoolExpression {
|
||||||
return Eq(c, rhs)
|
return Eq(c, rhs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *baseColumn) Neq(rhs Expression) BoolExpression {
|
||||||
|
return Neq(c, rhs)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *baseColumn) Gte(rhs Expression) BoolExpression {
|
func (c *baseColumn) Gte(rhs Expression) BoolExpression {
|
||||||
return Gte(c, rhs)
|
return Gte(c, rhs)
|
||||||
}
|
}
|
||||||
|
|
@ -198,7 +203,7 @@ type IntegerColumn struct {
|
||||||
|
|
||||||
// Representation of any integer column
|
// Representation of any integer column
|
||||||
// This function will panic if name is not valid
|
// This function will panic if name is not valid
|
||||||
func IntColumn(name string, nullable NullableColumn) NonAliasColumn {
|
func IntColumn(name string, nullable NullableColumn) *IntegerColumn {
|
||||||
if !validIdentifierName(name) {
|
if !validIdentifierName(name) {
|
||||||
panic("Invalid column name in int column")
|
panic("Invalid column name in int column")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ package sqlbuilder
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/dropbox/godropbox/errors"
|
"github.com/dropbox/godropbox/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -85,6 +84,7 @@ func NewTable(schemaName, name string, columns ...NonAliasColumn) *Table {
|
||||||
type Table struct {
|
type Table struct {
|
||||||
schemaName string
|
schemaName string
|
||||||
name string
|
name string
|
||||||
|
alias string
|
||||||
columns []NonAliasColumn
|
columns []NonAliasColumn
|
||||||
columnLookup map[string]NonAliasColumn
|
columnLookup map[string]NonAliasColumn
|
||||||
// If not empty, the name of the index to force
|
// If not empty, the name of the index to force
|
||||||
|
|
@ -119,6 +119,17 @@ func (t *Table) Projections() []Projection {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *Table) SetAlias(alias string) {
|
||||||
|
t.alias = alias
|
||||||
|
|
||||||
|
for _, c := range t.columns {
|
||||||
|
err := c.setTableName(alias)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the table's name in the database
|
// Returns the table's name in the database
|
||||||
func (t *Table) Name() string {
|
func (t *Table) Name() string {
|
||||||
return t.name
|
return t.name
|
||||||
|
|
@ -151,6 +162,11 @@ func (t *Table) SerializeSql(out *bytes.Buffer) error {
|
||||||
_, _ = out.WriteString(".")
|
_, _ = out.WriteString(".")
|
||||||
_, _ = out.WriteString(t.Name())
|
_, _ = out.WriteString(t.Name())
|
||||||
|
|
||||||
|
if len(t.alias) > 0 {
|
||||||
|
out.WriteString(" AS ")
|
||||||
|
out.WriteString(t.alias)
|
||||||
|
}
|
||||||
|
|
||||||
if t.forcedIndex != "" {
|
if t.forcedIndex != "" {
|
||||||
if !validIdentifierName(t.forcedIndex) {
|
if !validIdentifierName(t.forcedIndex) {
|
||||||
return errors.Newf("'%s' is not a valid identifier for an index", t.forcedIndex)
|
return errors.Newf("'%s' is not a valid identifier for an index", t.forcedIndex)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package tests
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/sub0Zero/go-sqlbuilder/generator"
|
"github.com/sub0Zero/go-sqlbuilder/generator"
|
||||||
"github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model"
|
"github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/model"
|
||||||
. "github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table"
|
. "github.com/sub0Zero/go-sqlbuilder/tests/.test_files/dvd_rental/dvds/table"
|
||||||
|
|
@ -290,6 +291,42 @@ func TestSelectFullCrossJoin(t *testing.T) {
|
||||||
|
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSelectSelfJoin(t *testing.T) {
|
||||||
|
|
||||||
|
f1 := Film.As("f1")
|
||||||
|
|
||||||
|
//spew.Dump(f1)
|
||||||
|
f2 := Film.As("f2")
|
||||||
|
|
||||||
|
query := f1.
|
||||||
|
InnerJoinOn(f2, f1.FilmID.Neq(f2.FilmID).And(f1.Length.Eq(f2.Length))).
|
||||||
|
Select(f1.AllColumns, f2.AllColumns).
|
||||||
|
OrderBy(f1.FilmID)
|
||||||
|
|
||||||
|
queryStr, err := query.String()
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
fmt.Println(queryStr)
|
||||||
|
|
||||||
|
type F1 model.Film
|
||||||
|
type F2 model.Film
|
||||||
|
|
||||||
|
theSameLengthFilms := []struct {
|
||||||
|
F1 F1
|
||||||
|
F2 F2
|
||||||
|
}{}
|
||||||
|
|
||||||
|
err = query.Execute(db, &theSameLengthFilms)
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
spew.Dump(theSameLengthFilms[0])
|
||||||
|
|
||||||
|
assert.Equal(t, len(theSameLengthFilms), 6972)
|
||||||
|
}
|
||||||
|
|
||||||
func int32Ptr(i int32) *int32 {
|
func int32Ptr(i int32) *int32 {
|
||||||
return &i
|
return &i
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue