Merge branch 'dev'

This commit is contained in:
Aaron L 2016-09-24 21:49:21 -07:00
commit 05d901865a
33 changed files with 812 additions and 531 deletions

View file

@ -85,7 +85,7 @@ func Tables(db Interface, schema string, whitelist, blacklist []string) ([]Table
// A composite primary key involving two columns
// Both primary key columns are also foreign keys
func setIsJoinTable(t *Table) {
if t.PKey == nil || len(t.PKey.Columns) != 2 || len(t.FKeys) < 2 {
if t.PKey == nil || len(t.PKey.Columns) != 2 || len(t.FKeys) < 2 || len(t.Columns) > 2 {
return
}

View file

@ -1,12 +1,6 @@
package bdb
import (
"fmt"
"regexp"
"strings"
)
var rgxAutoIncColumn = regexp.MustCompile(`^nextval\(.*\)`)
import "fmt"
// PrimaryKey represents a primary key constraint in a database
type PrimaryKey struct {
@ -80,30 +74,3 @@ func SQLColDefinitions(cols []Column, names []string) SQLColumnDefs {
return ret
}
// AutoIncPrimaryKey returns the auto-increment primary key column name or an
// empty string. Primary key columns with default values are presumed
// to be auto-increment, because pkeys need to be unique and a static
// default value would cause collisions.
func AutoIncPrimaryKey(cols []Column, pkey *PrimaryKey) *Column {
if pkey == nil {
return nil
}
for _, pkeyColumn := range pkey.Columns {
for _, c := range cols {
if c.Name != pkeyColumn {
continue
}
if c.Default != "auto_increment" || c.Nullable ||
!(strings.HasPrefix(c.Type, "int") || strings.HasPrefix(c.Type, "uint")) {
continue
}
return &c
}
}
return nil
}

View file

@ -76,7 +76,7 @@ func toManyRelationships(table Table, tables []Table) []ToManyRelationship {
for _, t := range tables {
for _, f := range t.FKeys {
if f.ForeignTable == table.Name && !f.Unique {
if f.ForeignTable == table.Name && (t.IsJoinTable || !f.Unique) {
relationships = append(relationships, buildToManyRelationship(table, f, t, tables))
}
}
@ -101,12 +101,11 @@ func buildToOneRelationship(localTable Table, foreignKey ForeignKey, foreignTabl
func buildToManyRelationship(localTable Table, foreignKey ForeignKey, foreignTable Table, tables []Table) ToManyRelationship {
if !foreignTable.IsJoinTable {
col := localTable.GetColumn(foreignKey.ForeignColumn)
return ToManyRelationship{
Table: localTable.Name,
Column: foreignKey.ForeignColumn,
Nullable: col.Nullable,
Unique: col.Unique,
Nullable: foreignKey.ForeignColumnNullable,
Unique: foreignKey.ForeignColumnUnique,
ForeignTable: foreignTable.Name,
ForeignColumn: foreignKey.Column,
ForeignColumnNullable: foreignKey.Nullable,
@ -115,33 +114,33 @@ func buildToManyRelationship(localTable Table, foreignKey ForeignKey, foreignTab
}
}
col := foreignTable.GetColumn(foreignKey.Column)
relationship := ToManyRelationship{
Table: localTable.Name,
Column: foreignKey.ForeignColumn,
Nullable: col.Nullable,
Unique: col.Unique,
Table: localTable.Name,
Column: foreignKey.ForeignColumn,
Nullable: foreignKey.ForeignColumnNullable,
Unique: foreignKey.ForeignColumnUnique,
ToJoinTable: true,
JoinTable: foreignTable.Name,
JoinLocalColumn: foreignKey.Column,
JoinLocalColumnNullable: foreignKey.Nullable,
JoinLocalColumnUnique: foreignKey.Unique,
}
for _, fk := range foreignTable.FKeys {
if fk.ForeignTable != localTable.Name {
relationship.JoinForeignColumn = fk.Column
relationship.JoinForeignColumnNullable = fk.Nullable
relationship.JoinForeignColumnUnique = fk.Unique
foreignTable := GetTable(tables, fk.ForeignTable)
foreignCol := foreignTable.GetColumn(fk.ForeignColumn)
relationship.ForeignTable = fk.ForeignTable
relationship.ForeignColumn = fk.ForeignColumn
relationship.ForeignColumnNullable = foreignCol.Nullable
relationship.ForeignColumnUnique = foreignCol.Unique
} else {
relationship.JoinLocalColumn = fk.Column
relationship.JoinLocalColumnNullable = fk.Nullable
relationship.JoinLocalColumnUnique = fk.Unique
if fk.Name == foreignKey.Name {
continue
}
relationship.JoinForeignColumn = fk.Column
relationship.JoinForeignColumnNullable = fk.Nullable
relationship.JoinForeignColumnUnique = fk.Unique
relationship.ForeignTable = fk.ForeignTable
relationship.ForeignColumn = fk.ForeignColumn
relationship.ForeignColumnNullable = fk.ForeignColumnNullable
relationship.ForeignColumnUnique = fk.ForeignColumnUnique
}
return relationship

View file

@ -213,15 +213,15 @@ func TestToManyRelationshipsNull(t *testing.T) {
Name: "jets",
Columns: []Column{{Name: "id", Nullable: true}, {Name: "pilot_id", Nullable: true}, {Name: "airport_id", Nullable: true}},
FKeys: []ForeignKey{
{Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
{Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id", Nullable: true},
{Name: "jets_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, ForeignColumnNullable: true},
{Name: "jets_airport_id_fk", Column: "airport_id", ForeignTable: "airports", ForeignColumn: "id", Nullable: true, ForeignColumnNullable: true},
},
},
{
Name: "licenses",
Columns: []Column{{Name: "id", Nullable: true}, {Name: "pilot_id", Nullable: true}},
FKeys: []ForeignKey{
{Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
{Name: "licenses_pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, ForeignColumnNullable: true},
},
},
{
@ -237,8 +237,8 @@ func TestToManyRelationshipsNull(t *testing.T) {
IsJoinTable: true,
Columns: []Column{{Name: "pilot_id", Nullable: true}, {Name: "language_id", Nullable: true}},
FKeys: []ForeignKey{
{Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true},
{Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id", Nullable: true},
{Name: "pilot_id_fk", Column: "pilot_id", ForeignTable: "pilots", ForeignColumn: "id", Nullable: true, ForeignColumnNullable: true},
{Name: "language_id_fk", Column: "language_id", ForeignTable: "languages", ForeignColumn: "id", Nullable: true, ForeignColumnNullable: true},
},
},
}

View file

@ -40,3 +40,27 @@ func (t Table) GetColumn(name string) (col Column) {
panic(fmt.Sprintf("could not find column name: %s", name))
}
// CanLastInsertID checks the following:
// 1. Is there only one primary key?
// 2. Does the primary key column have a default value?
// 3. Is the primary key column type one of uintX/intX?
// If the above is all true, this table can use LastInsertId
func (t Table) CanLastInsertID() bool {
if t.PKey == nil || len(t.PKey.Columns) != 1 {
return false
}
col := t.GetColumn(t.PKey.Columns[0])
if len(col.Default) == 0 {
return false
}
switch col.Type {
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64":
default:
return false
}
return true
}

View file

@ -65,3 +65,56 @@ func TestGetColumnMissing(t *testing.T) {
table.GetColumn("missing")
}
func TestCanLastInsertID(t *testing.T) {
t.Parallel()
tests := []struct {
Can bool
PKeys []Column
}{
{true, []Column{
{Name: "id", Type: "int64", Default: "a"},
}},
{true, []Column{
{Name: "id", Type: "uint64", Default: "a"},
}},
{true, []Column{
{Name: "id", Type: "int", Default: "a"},
}},
{true, []Column{
{Name: "id", Type: "uint", Default: "a"},
}},
{true, []Column{
{Name: "id", Type: "uint", Default: "a"},
}},
{false, []Column{
{Name: "id", Type: "uint", Default: "a"},
{Name: "id2", Type: "uint", Default: "a"},
}},
{false, []Column{
{Name: "id", Type: "string", Default: "a"},
}},
{false, []Column{
{Name: "id", Type: "int", Default: ""},
}},
{false, nil},
}
for i, test := range tests {
table := Table{
Columns: test.PKeys,
PKey: &PrimaryKey{},
}
var pkeyNames []string
for _, pk := range test.PKeys {
pkeyNames = append(pkeyNames, pk.Name)
}
table.PKey.Columns = pkeyNames
if got := table.CanLastInsertID(); got != test.Can {
t.Errorf("%d) wrong: %t", i, got)
}
}
}

205
output.go
View file

@ -5,8 +5,7 @@ import (
"bytes"
"fmt"
"go/format"
"io"
"os"
"io/ioutil"
"path/filepath"
"regexp"
"strconv"
@ -15,11 +14,17 @@ import (
"github.com/pkg/errors"
)
var testHarnessStdout io.Writer = os.Stdout
var testHarnessFileOpen = func(filename string) (io.WriteCloser, error) {
file, err := os.Create(filename)
return file, err
}
var (
// templateByteBuffer is re-used by all template construction to avoid
// allocating more memory than is needed. This will later be a problem for
// concurrency, address it then.
templateByteBuffer = &bytes.Buffer{}
rgxRemoveNumberedPrefix = regexp.MustCompile(`[0-9]+_`)
rgxSyntaxError = regexp.MustCompile(`(\d+):\d+: `)
testHarnessWriteFile = ioutil.WriteFile
)
// generateOutput builds the file output and sends it to outHandler for saving
func generateOutput(state *State, data *templateData) error {
@ -88,26 +93,27 @@ func executeTemplates(e executeTemplateData) error {
return nil
}
var out [][]byte
var imps imports
out := templateByteBuffer
out.Reset()
var imps imports
imps.standard = e.importSet.standard
imps.thirdParty = e.importSet.thirdParty
for _, tplName := range e.templates.Templates() {
if e.combineImportsOnType {
imps = combineTypeImports(imps, importsBasedOnType, e.data.Table.Columns)
}
if e.combineImportsOnType {
imps = combineTypeImports(imps, importsBasedOnType, e.data.Table.Columns)
}
resp, err := executeTemplate(e.templates.Template, tplName, e.data)
if err != nil {
return errors.Wrapf(err, "Error generating template %s", tplName)
writePackageName(out, e.state.Config.PkgName)
writeImports(out, imps)
for _, tplName := range e.templates.Templates() {
if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
return err
}
out = append(out, resp)
}
fName := e.data.Table.Name + e.fileSuffix
err := outHandler(e.state.Config.OutFolder, fName, e.state.Config.PkgName, imps, out)
if err != nil {
if err := writeFile(e.state.Config.OutFolder, fName, out); err != nil {
return err
}
@ -119,31 +125,27 @@ func executeSingletonTemplates(e executeTemplateData) error {
return nil
}
rgxRemove := regexp.MustCompile(`[0-9]+_`)
out := templateByteBuffer
for _, tplName := range e.templates.Templates() {
resp, err := executeTemplate(e.templates.Template, tplName, e.data)
if err != nil {
return errors.Wrapf(err, "Error generating template %s", tplName)
}
out.Reset()
fName := tplName
ext := filepath.Ext(fName)
fName = rgxRemove.ReplaceAllString(fName[:len(fName)-len(ext)], "")
fName = rgxRemoveNumberedPrefix.ReplaceAllString(fName[:len(fName)-len(ext)], "")
imps := imports{
standard: e.importNamedSet[fName].standard,
thirdParty: e.importNamedSet[fName].thirdParty,
}
err = outHandler(
e.state.Config.OutFolder,
fName+e.fileSuffix,
e.state.Config.PkgName,
imps,
[][]byte{resp},
)
if err != nil {
writePackageName(out, e.state.Config.PkgName)
writeImports(out, imps)
if err := executeTemplate(out, e.templates.Template, tplName, e.data); err != nil {
return err
}
if err := writeFile(e.state.Config.OutFolder, fName+e.fileSuffix, out); err != nil {
return err
}
}
@ -156,95 +158,94 @@ func generateTestMainOutput(state *State, data *templateData) error {
return errors.New("No TestMain template located for generation")
}
var out [][]byte
var imps imports
out := templateByteBuffer
out.Reset()
var imps imports
imps.standard = defaultTestMainImports[state.Config.DriverName].standard
imps.thirdParty = defaultTestMainImports[state.Config.DriverName].thirdParty
resp, err := executeTemplate(state.TestMainTemplate, state.TestMainTemplate.Name(), data)
if err != nil {
writePackageName(out, state.Config.PkgName)
writeImports(out, imps)
if err := executeTemplate(out, state.TestMainTemplate, state.TestMainTemplate.Name(), data); err != nil {
return err
}
out = append(out, resp)
err = outHandler(state.Config.OutFolder, "main_test.go", state.Config.PkgName, imps, out)
if err != nil {
if err := writeFile(state.Config.OutFolder, "main_test.go", out); err != nil {
return err
}
return nil
}
func outHandler(outFolder string, fileName string, pkgName string, imps imports, contents [][]byte) error {
out := testHarnessStdout
// writePackageName writes the package name correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writePackageName(out *bytes.Buffer, pkgName string) {
_, _ = fmt.Fprintf(out, "package %s\n\n", pkgName)
}
// writeImports writes the package imports correctly, ignores errors
// since it's to the concrete buffer type which produces none
func writeImports(out *bytes.Buffer, imps imports) {
if impStr := buildImportString(imps); len(impStr) > 0 {
_, _ = fmt.Fprintf(out, "%s\n", impStr)
}
}
// writeFile writes to the given folder and filename, formatting the buffer
// given.
func writeFile(outFolder string, fileName string, input *bytes.Buffer) error {
byt, err := formatBuffer(input)
if err != nil {
return err
}
path := filepath.Join(outFolder, fileName)
outFile, err := testHarnessFileOpen(path)
if err != nil {
return errors.Wrapf(err, "Unable to create output file %s", path)
}
defer outFile.Close()
out = outFile
if _, err := fmt.Fprintf(out, "package %s\n\n", pkgName); err != nil {
return errors.Errorf("Unable to write package name %s to file: %s", pkgName, path)
}
impStr := buildImportString(imps)
if len(impStr) > 0 {
if _, err := fmt.Fprintf(out, "%s\n", impStr); err != nil {
return errors.Wrap(err, "Unable to write imports to file handle")
}
}
for _, templateOutput := range contents {
if _, err := fmt.Fprintf(out, "%s\n", templateOutput); err != nil {
return errors.Wrap(err, "Unable to write template output to file handle")
}
if err = testHarnessWriteFile(path, byt, 0666); err != nil {
return errors.Wrapf(err, "failed to write output file %s", path)
}
return nil
}
var rgxSyntaxError = regexp.MustCompile(`(\d+):\d+: `)
// executeTemplate takes a template and returns the output of the template
// execution.
func executeTemplate(t *template.Template, name string, data *templateData) ([]byte, error) {
var buf bytes.Buffer
if err := t.ExecuteTemplate(&buf, name, data); err != nil {
return nil, errors.Wrap(err, "failed to execute template")
func executeTemplate(buf *bytes.Buffer, t *template.Template, name string, data *templateData) error {
if err := t.ExecuteTemplate(buf, name, data); err != nil {
return errors.Wrapf(err, "failed to execute template: %s", name)
}
output, err := format.Source(buf.Bytes())
if err != nil {
matches := rgxSyntaxError.FindStringSubmatch(err.Error())
if matches == nil {
return nil, errors.Wrap(err, "failed to format template")
}
lineNum, _ := strconv.Atoi(matches[1])
scanner := bufio.NewScanner(&buf)
errBuf := &bytes.Buffer{}
line := 0
for ; scanner.Scan(); line++ {
if delta := line - lineNum; delta < -5 || delta > 5 {
continue
}
if line == lineNum {
errBuf.WriteString(">>> ")
} else {
fmt.Fprintf(errBuf, "% 3d ", line)
}
errBuf.Write(scanner.Bytes())
errBuf.WriteByte('\n')
}
return nil, errors.Wrapf(err, "failed to format template\n\n%s\n", errBuf.Bytes())
}
return output, nil
return nil
}
func formatBuffer(buf *bytes.Buffer) ([]byte, error) {
output, err := format.Source(buf.Bytes())
if err == nil {
return output, nil
}
matches := rgxSyntaxError.FindStringSubmatch(err.Error())
if matches == nil {
return nil, errors.Wrap(err, "failed to format template")
}
lineNum, _ := strconv.Atoi(matches[1])
scanner := bufio.NewScanner(buf)
errBuf := &bytes.Buffer{}
line := 1
for ; scanner.Scan(); line++ {
if delta := line - lineNum; delta < -5 || delta > 5 {
continue
}
if line == lineNum {
errBuf.WriteString(">>>> ")
} else {
fmt.Fprintf(errBuf, "% 4d ", line)
}
errBuf.Write(scanner.Bytes())
errBuf.WriteByte('\n')
}
return nil, errors.Wrapf(err, "failed to format template\n\n%s\n", errBuf.Bytes())
}

View file

@ -2,8 +2,10 @@ package main
import (
"bytes"
"fmt"
"io"
"sort"
"os"
"strings"
"testing"
)
@ -19,120 +21,49 @@ func nopCloser(w io.Writer) io.WriteCloser {
return NopWriteCloser{w}
}
func TestOutHandler(t *testing.T) {
func TestWriteFile(t *testing.T) {
// t.Parallel() cannot be used
// set the function pointer back to its original value
// after we modify it for the test
saveTestHarnessFileOpen := testHarnessFileOpen
saveTestHarnessWriteFile := testHarnessWriteFile
defer func() {
testHarnessFileOpen = saveTestHarnessFileOpen
testHarnessWriteFile = saveTestHarnessWriteFile
}()
var output []byte
testHarnessWriteFile = func(_ string, in []byte, _ os.FileMode) error {
output = in
return nil
}
buf := &bytes.Buffer{}
testHarnessFileOpen = func(path string) (io.WriteCloser, error) {
return nopCloser(buf), nil
}
writePackageName(buf, "pkg")
fmt.Fprintf(buf, "func hello() {}\n\n\nfunc world() {\nreturn\n}\n\n\n\n")
templateOutputs := [][]byte{[]byte("hello world"), []byte("patrick's dreams")}
if err := outHandler("", "file.go", "patrick", imports{}, templateOutputs); err != nil {
if err := writeFile("", "", buf); err != nil {
t.Error(err)
}
if out := buf.String(); out != "package patrick\n\nhello world\npatrick's dreams\n" {
t.Errorf("Wrong output: %q", out)
if string(output) != "package pkg\n\nfunc hello() {}\n\nfunc world() {\n\treturn\n}\n" {
t.Errorf("Wrong output: %q", output)
}
}
func TestOutHandlerFiles(t *testing.T) {
// t.Parallel() cannot be used
func TestFormatBuffer(t *testing.T) {
t.Parallel()
saveTestHarnessFileOpen := testHarnessFileOpen
defer func() {
testHarnessFileOpen = saveTestHarnessFileOpen
}()
buf := &bytes.Buffer{}
file := &bytes.Buffer{}
testHarnessFileOpen = func(path string) (io.WriteCloser, error) {
return nopCloser(file), nil
fmt.Fprintf(buf, "package pkg\n\nfunc() {a}\n")
// Only test error case - happy case is taken care of by template test
_, err := formatBuffer(buf)
if err == nil {
t.Error("want an error")
}
templateOutputs := [][]byte{[]byte("hello world"), []byte("patrick's dreams")}
if err := outHandler("folder", "file.go", "patrick", imports{}, templateOutputs); err != nil {
t.Error(err)
}
if out := file.String(); out != "package patrick\n\nhello world\npatrick's dreams\n" {
t.Errorf("Wrong output: %q", out)
}
a1 := imports{
standard: importList{
`"fmt"`,
},
}
file = &bytes.Buffer{}
if err := outHandler("folder", "file.go", "patrick", a1, templateOutputs); err != nil {
t.Error(err)
}
if out := file.String(); out != "package patrick\n\nimport \"fmt\"\nhello world\npatrick's dreams\n" {
t.Errorf("Wrong output: %q", out)
}
a2 := imports{
thirdParty: []string{
`"github.com/spf13/cobra"`,
},
}
file = &bytes.Buffer{}
if err := outHandler("folder", "file.go", "patrick", a2, templateOutputs); err != nil {
t.Error(err)
}
if out := file.String(); out != "package patrick\n\nimport \"github.com/spf13/cobra\"\nhello world\npatrick's dreams\n" {
t.Errorf("Wrong output: %q", out)
}
a3 := imports{
standard: importList{
`"fmt"`,
`"errors"`,
},
thirdParty: importList{
`_ "github.com/lib/pq"`,
`_ "github.com/gorilla/n"`,
`"github.com/gorilla/mux"`,
`"github.com/gorilla/websocket"`,
},
}
file = &bytes.Buffer{}
sort.Sort(a3.standard)
sort.Sort(a3.thirdParty)
if err := outHandler("folder", "file.go", "patrick", a3, templateOutputs); err != nil {
t.Error(err)
}
expectedOut := `package patrick
import (
"errors"
"fmt"
"github.com/gorilla/mux"
_ "github.com/gorilla/n"
"github.com/gorilla/websocket"
_ "github.com/lib/pq"
)
hello world
patrick's dreams
`
if out := file.String(); out != expectedOut {
t.Errorf("Wrong output (len %d, len %d): \n\n%q\n\n%q", len(out), len(expectedOut), out, expectedOut)
if txt := err.Error(); !strings.Contains(txt, ">>>> func() {a}") {
t.Error("got:\n", txt)
}
}

View file

@ -173,7 +173,6 @@ var templateFunctions = template.FuncMap{
// dbdrivers ops
"filterColumnsByDefault": bdb.FilterColumnsByDefault,
"autoIncPrimaryKey": bdb.AutoIncPrimaryKey,
"sqlColDefinitions": bdb.SQLColDefinitions,
"columnNames": bdb.ColumnNames,
"columnDBTypes": bdb.ColumnDBTypes,

View file

@ -4,17 +4,17 @@
{{- $table := .Table -}}
{{- range .Table.ToManyRelationships -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- $rel := txtsFromToMany $dot.Tables $table . -}}
{{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable -}}
// {{$rel.Function.Name}}G retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}}
{{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func (o *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
return o.{{$rel.Function.Name}}(boil.GetDB(), mods...)
{{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- $schemaForeignTable := .ForeignTable | $dot.SchemaTable}}
// {{$txt.Function.Name}}G retrieves all the {{.ForeignTable | singular}}'s {{$txt.ForeignTable.NameHumanReadable}}
{{- if not (eq $txt.Function.Name $txt.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
return o.{{$txt.Function.Name}}(boil.GetDB(), mods...)
}
// {{$rel.Function.Name}} retrieves all the {{$rel.LocalTable.NameSingular}}'s {{$rel.ForeignTable.NameHumanReadable}} with an executor
{{- if not (eq $rel.Function.Name $rel.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func (o *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query {
// {{$txt.Function.Name}} retrieves all the {{.ForeignTable | singular}}'s {{$txt.ForeignTable.NameHumanReadable}} with an executor
{{- if not (eq $txt.Function.Name $txt.ForeignTable.NamePluralGo)}} via {{.ForeignColumn}} column{{- end}}.
func (o *{{$txt.LocalTable.NameGo}}) {{$txt.Function.Name}}(exec boil.Executor, mods ...qm.QueryMod) {{$varNameSingular}}Query {
queryMods := []qm.QueryMod{
qm.Select("{{id 0 | $dot.Quotes}}.*"),
}
@ -26,15 +26,15 @@ func (o *{{$rel.LocalTable.NameGo}}) {{$rel.Function.Name}}(exec boil.Executor,
{{if .ToJoinTable -}}
queryMods = append(queryMods,
qm.InnerJoin("{{.JoinTable | $dot.SchemaTable}} as {{id 1 | $dot.Quotes}} on {{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}} = {{id 1 | $dot.Quotes}}.{{.JoinForeignColumn | $dot.Quotes}}"),
qm.Where("{{id 1 | $dot.Quotes}}.{{.JoinLocalColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$rel.LocalTable.ColumnNameGo}}),
qm.Where("{{id 1 | $dot.Quotes}}.{{.JoinLocalColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$txt.LocalTable.ColumnNameGo}}),
)
{{else -}}
queryMods = append(queryMods,
qm.Where("{{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$rel.LocalTable.ColumnNameGo}}),
qm.Where("{{id 0 | $dot.Quotes}}.{{.ForeignColumn | $dot.Quotes}}={{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}", o.{{$txt.LocalTable.ColumnNameGo}}),
)
{{end}}
query := {{$rel.ForeignTable.NamePluralGo}}(exec, queryMods...)
query := {{$txt.ForeignTable.NamePluralGo}}(exec, queryMods...)
queries.SetFrom(query.Query, "{{$schemaForeignTable}} as {{id 0 | $dot.Quotes}}")
return query
}

View file

@ -1,4 +1,3 @@
{{- /* Begin execution of template for many-to-one or many-to-many eager load */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}

View file

@ -1,11 +1,11 @@
{{- /* Begin execution of template for one-to-one setops */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- range .Table.FKeys -}}
{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- $localNameSingular := .Table | singular | camelCase}}
{{- $foreignNameSingular := .ForeignTable | singular | camelCase -}}
{{- $varNameSingular := .Table | singular | camelCase}}
{{- $schemaTable := .Table | $dot.SchemaTable}}
// Set{{$txt.Function.Name}} of the {{.Table | singular}} to the related item.
// Sets o.R.{{$txt.Function.Name}} to related.
// Adds o to related.R.{{$txt.Function.ForeignName}}.
@ -17,21 +17,29 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
}
}
oldVal := o.{{$txt.Function.LocalAssignment}}
updateQuery := fmt.Sprintf(
"UPDATE {{$schemaTable}} SET %s WHERE %s",
strmangle.SetParamNames("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}1{{else}}0{{end}}, []string{{"{"}}"{{.Column}}"{{"}"}}),
strmangle.WhereClause("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}2{{else}}0{{end}}, {{$varNameSingular}}PrimaryKeyColumns),
)
values := []interface{}{related.{{$txt.ForeignTable.ColumnNameGo}}, o.{{$dot.Table.PKey.Columns | stringMap $dot.StringFuncs.titleCase | join ", o."}}{{"}"}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, updateQuery)
fmt.Fprintln(boil.DebugWriter, values)
}
if _, err = exec.Exec(updateQuery, values...); err != nil {
return errors.Wrap(err, "failed to update local table")
}
o.{{$txt.Function.LocalAssignment}} = related.{{$txt.Function.ForeignAssignment}}
{{if .Nullable -}}
o.{{$txt.LocalTable.ColumnNameGo}}.Valid = true
{{- end}}
if err = o.Update(exec, "{{.Column}}"); err != nil {
o.{{$txt.Function.LocalAssignment}} = oldVal
{{if .Nullable -}}
o.{{$txt.LocalTable.ColumnNameGo}}.Valid = false
{{- end}}
return errors.Wrap(err, "failed to update local table")
}
if o.R == nil {
o.R = &{{$localNameSingular}}R{
o.R = &{{$varNameSingular}}R{
{{$txt.Function.Name}}: related,
}
} else {
@ -40,7 +48,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
{{if .Unique -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
related.R = &{{$foreignNameSingular}}R{
{{$txt.Function.ForeignName}}: o,
}
} else {
@ -48,7 +56,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
}
{{else -}}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
related.R = &{{$foreignNameSingular}}R{
{{$txt.Function.ForeignName}}: {{$txt.LocalTable.NameGo}}Slice{{"{"}}o{{"}"}},
}
} else {

View file

@ -3,40 +3,51 @@
{{- $dot := . -}}
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .ForeignTable | singular | camelCase -}}
{{- $localNameSingular := .Table | singular | camelCase}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $foreignPKeyCols := (getTable $dot.Tables .ForeignTable).PKey.Columns -}}
{{- $foreignSchemaTable := .ForeignTable | $dot.SchemaTable}}
// Set{{$txt.Function.Name}} of the {{.Table | singular}} to the related item.
// Sets o.R.{{$txt.Function.Name}} to related.
// Adds o to related.R.{{$txt.Function.ForeignName}}.
func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executor, insert bool, related *{{$txt.ForeignTable.NameGo}}) error {
var err error
oldVal := related.{{$txt.Function.ForeignAssignment}}
related.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
if insert {
related.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
if err = related.Insert(exec); err != nil {
related.{{$txt.Function.ForeignAssignment}} = oldVal
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
{{- end}}
return errors.Wrap(err, "failed to insert into foreign table")
}
} else {
if err = related.Update(exec, "{{.ForeignColumn}}"); err != nil {
related.{{$txt.Function.ForeignAssignment}} = oldVal
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
{{- end}}
updateQuery := fmt.Sprintf(
"UPDATE {{$foreignSchemaTable}} SET %s WHERE %s",
strmangle.SetParamNames("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}1{{else}}0{{end}}, []string{{"{"}}"{{.ForeignColumn}}"{{"}"}}),
strmangle.WhereClause("{{$dot.LQ}}", "{{$dot.RQ}}", {{if $dot.Dialect.IndexPlaceholders}}2{{else}}0{{end}}, {{$foreignVarNameSingular}}PrimaryKeyColumns),
)
values := []interface{}{o.{{$txt.LocalTable.ColumnNameGo}}, related.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", related."}}{{"}"}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, updateQuery)
fmt.Fprintln(boil.DebugWriter, values)
}
if _, err = exec.Exec(updateQuery, values...); err != nil {
return errors.Wrap(err, "failed to update foreign table")
}
related.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}}
related.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{- end}}
}
if o.R == nil {
o.R = &{{$localNameSingular}}R{
o.R = &{{$varNameSingular}}R{
{{$txt.Function.Name}}: related,
}
} else {
@ -44,7 +55,7 @@ func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executo
}
if related.R == nil {
related.R = &{{$varNameSingular}}R{
related.R = &{{$foreignVarNameSingular}}R{
{{$txt.Function.ForeignName}}: o,
}
} else {

View file

@ -1,23 +1,22 @@
{{- /* Begin execution of template for many-to-one or many-to-many setops */ -}}
{{- if .Table.IsJoinTable -}}
{{- else -}}
{{- $dot := . -}}
{{- $table := .Table -}}
{{- range .Table.ToManyRelationships -}}
{{- $rel := txtsFromToMany $dot.Tables $table . -}}
{{- $txt := txtsFromToMany $dot.Tables $table . -}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
// Add{{$rel.Function.Name}} adds the given related objects to the existing relationships
// Add{{$txt.Function.Name}} adds the given related objects to the existing relationships
// of the {{$table.Name | singular}}, optionally inserting them as new records.
// Appends related to o.R.{{$rel.Function.Name}}.
// Sets related.R.{{$rel.Function.ForeignName}} appropriately.
func (o *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error {
// Appends related to o.R.{{$txt.Function.Name}}.
// Sets related.R.{{$txt.Function.ForeignName}} appropriately.
func (o *{{$txt.LocalTable.NameGo}}) Add{{$txt.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) error {
var err error
for _, rel := range related {
{{if not .ToJoinTable -}}
rel.{{$rel.Function.ForeignAssignment}} = o.{{$rel.Function.LocalAssignment}}
rel.{{$txt.Function.ForeignAssignment}} = o.{{$txt.Function.LocalAssignment}}
{{if .ForeignColumnNullable -}}
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = true
rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = true
{{end -}}
{{end -}}
if insert {
@ -34,7 +33,7 @@ func (o *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executo
{{if .ToJoinTable -}}
for _, rel := range related {
query := "insert into {{.JoinTable | $dot.SchemaTable}} ({{.JoinLocalColumn | $dot.Quotes}}, {{.JoinForeignColumn | $dot.Quotes}}) values {{if $dot.Dialect.IndexPlaceholders}}($1, $2){{else}}(?, ?){{end}}"
values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}, rel.{{$rel.ForeignTable.ColumnNameGo}}}
values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}, rel.{{$txt.ForeignTable.ColumnNameGo}}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query)
@ -50,30 +49,30 @@ func (o *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executo
if o.R == nil {
o.R = &{{$varNameSingular}}R{
{{$rel.Function.Name}}: related,
{{$txt.Function.Name}}: related,
}
} else {
o.R.{{$rel.Function.Name}} = append(o.R.{{$rel.Function.Name}}, related...)
o.R.{{$txt.Function.Name}} = append(o.R.{{$txt.Function.Name}}, related...)
}
{{if .ToJoinTable -}}
for _, rel := range related {
if rel.R == nil {
rel.R = &{{$foreignVarNameSingular}}R{
{{$rel.Function.ForeignName}}: {{$rel.LocalTable.NameGo}}Slice{{"{"}}o{{"}"}},
{{$txt.Function.ForeignName}}: {{$txt.LocalTable.NameGo}}Slice{{"{"}}o{{"}"}},
}
} else {
rel.R.{{$rel.Function.ForeignName}} = append(rel.R.{{$rel.Function.ForeignName}}, o)
rel.R.{{$txt.Function.ForeignName}} = append(rel.R.{{$txt.Function.ForeignName}}, o)
}
}
{{else -}}
for _, rel := range related {
if rel.R == nil {
rel.R = &{{$foreignVarNameSingular}}R{
{{$rel.Function.ForeignName}}: o,
{{$txt.Function.ForeignName}}: o,
}
} else {
rel.R.{{$rel.Function.ForeignName}} = o
rel.R.{{$txt.Function.ForeignName}} = o
}
}
{{end -}}
@ -82,19 +81,19 @@ func (o *{{$rel.LocalTable.NameGo}}) Add{{$rel.Function.Name}}(exec boil.Executo
}
{{- if (or .ForeignColumnNullable .ToJoinTable)}}
// Set{{$rel.Function.Name}} removes all previously related items of the
// Set{{$txt.Function.Name}} removes all previously related items of the
// {{$table.Name | singular}} replacing them completely with the passed
// in related items, optionally inserting them as new records.
// Sets o.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly.
// Replaces o.R.{{$rel.Function.Name}} with related.
// Sets related.R.{{$rel.Function.ForeignName}}'s {{$rel.Function.Name}} accordingly.
func (o *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$rel.ForeignTable.NameGo}}) error {
// Sets o.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
// Replaces o.R.{{$txt.Function.Name}} with related.
// Sets related.R.{{$txt.Function.ForeignName}}'s {{$txt.Function.Name}} accordingly.
func (o *{{$txt.LocalTable.NameGo}}) Set{{$txt.Function.Name}}(exec boil.Executor, insert bool, related ...*{{$txt.ForeignTable.NameGo}}) error {
{{if .ToJoinTable -}}
query := "delete from {{.JoinTable | $dot.SchemaTable}} where {{.JoinLocalColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}"
values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
{{else -}}
query := "update {{.ForeignTable | $dot.SchemaTable}} set {{.ForeignColumn | $dot.Quotes}} = null where {{.ForeignColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}}"
values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
{{end -}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query)
@ -107,37 +106,37 @@ func (o *{{$rel.LocalTable.NameGo}}) Set{{$rel.Function.Name}}(exec boil.Executo
}
{{if .ToJoinTable -}}
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o, related)
o.R.{{$rel.Function.Name}} = nil
remove{{$txt.Function.Name}}From{{$txt.Function.ForeignName}}Slice(o, related)
o.R.{{$txt.Function.Name}} = nil
{{else -}}
if o.R != nil {
for _, rel := range o.R.{{$rel.Function.Name}} {
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false
for _, rel := range o.R.{{$txt.Function.Name}} {
rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
if rel.R == nil {
continue
}
rel.R.{{$rel.Function.ForeignName}} = nil
rel.R.{{$txt.Function.ForeignName}} = nil
}
o.R.{{$rel.Function.Name}} = nil
o.R.{{$txt.Function.Name}} = nil
}
{{end -}}
return o.Add{{$rel.Function.Name}}(exec, insert, related...)
return o.Add{{$txt.Function.Name}}(exec, insert, related...)
}
// Remove{{$rel.Function.Name}} relationships from objects passed in.
// Removes related items from R.{{$rel.Function.Name}} (uses pointer comparison, removal does not keep order)
// Sets related.R.{{$rel.Function.ForeignName}}.
func (o *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Executor, related ...*{{$rel.ForeignTable.NameGo}}) error {
// Remove{{$txt.Function.Name}} relationships from objects passed in.
// Removes related items from R.{{$txt.Function.Name}} (uses pointer comparison, removal does not keep order)
// Sets related.R.{{$txt.Function.ForeignName}}.
func (o *{{$txt.LocalTable.NameGo}}) Remove{{$txt.Function.Name}}(exec boil.Executor, related ...*{{$txt.ForeignTable.NameGo}}) error {
var err error
{{if .ToJoinTable -}}
query := fmt.Sprintf(
"delete from {{.JoinTable | $dot.SchemaTable}} where {{.JoinLocalColumn | $dot.Quotes}} = {{if $dot.Dialect.IndexPlaceholders}}$1{{else}}?{{end}} and {{.JoinForeignColumn | $dot.Quotes}} in (%s)",
strmangle.Placeholders(dialect.IndexPlaceholders, len(related), 1, 1),
)
values := []interface{}{{"{"}}o.{{$rel.LocalTable.ColumnNameGo}}}
values := []interface{}{{"{"}}o.{{$txt.LocalTable.ColumnNameGo}}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, query)
@ -150,10 +149,10 @@ func (o *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Exec
}
{{else -}}
for _, rel := range related {
rel.{{$rel.ForeignTable.ColumnNameGo}}.Valid = false
rel.{{$txt.ForeignTable.ColumnNameGo}}.Valid = false
{{if not .ToJoinTable -}}
if rel.R != nil {
rel.R.{{$rel.Function.ForeignName}} = nil
rel.R.{{$txt.Function.ForeignName}} = nil
}
{{end -}}
if err = rel.Update(exec, "{{.ForeignColumn}}"); err != nil {
@ -163,23 +162,23 @@ func (o *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Exec
{{end -}}
{{if .ToJoinTable -}}
remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o, related)
remove{{$txt.Function.Name}}From{{$txt.Function.ForeignName}}Slice(o, related)
{{end -}}
if o.R == nil {
return nil
}
for _, rel := range related {
for i, ri := range o.R.{{$rel.Function.Name}} {
for i, ri := range o.R.{{$txt.Function.Name}} {
if rel != ri {
continue
}
ln := len(o.R.{{$rel.Function.Name}})
ln := len(o.R.{{$txt.Function.Name}})
if ln > 1 && i < ln-1 {
o.R.{{$rel.Function.Name}}[i] = o.R.{{$rel.Function.Name}}[ln-1]
o.R.{{$txt.Function.Name}}[i] = o.R.{{$txt.Function.Name}}[ln-1]
}
o.R.{{$rel.Function.Name}} = o.R.{{$rel.Function.Name}}[:ln-1]
o.R.{{$txt.Function.Name}} = o.R.{{$txt.Function.Name}}[:ln-1]
break
}
}
@ -188,25 +187,25 @@ func (o *{{$rel.LocalTable.NameGo}}) Remove{{$rel.Function.Name}}(exec boil.Exec
}
{{if .ToJoinTable -}}
func remove{{$rel.LocalTable.NameGo}}From{{$rel.ForeignTable.NameGo}}Slice(o *{{$rel.LocalTable.NameGo}}, related []*{{$rel.ForeignTable.NameGo}}) {
func remove{{$txt.Function.Name}}From{{$txt.Function.ForeignName}}Slice(o *{{$txt.LocalTable.NameGo}}, related []*{{$txt.ForeignTable.NameGo}}) {
for _, rel := range related {
if rel.R == nil {
continue
}
for i, ri := range rel.R.{{$rel.Function.ForeignName}} {
{{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(o.{{$rel.Function.LocalAssignment}}, ri.{{$rel.Function.LocalAssignment}}) {
for i, ri := range rel.R.{{$txt.Function.ForeignName}} {
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(o.{{$txt.Function.LocalAssignment}}, ri.{{$txt.Function.LocalAssignment}}) {
{{else -}}
if o.{{$rel.Function.LocalAssignment}} != ri.{{$rel.Function.LocalAssignment}} {
if o.{{$txt.Function.LocalAssignment}} != ri.{{$txt.Function.LocalAssignment}} {
{{end -}}
continue
}
ln := len(rel.R.{{$rel.Function.ForeignName}})
ln := len(rel.R.{{$txt.Function.ForeignName}})
if ln > 1 && i < ln-1 {
rel.R.{{$rel.Function.ForeignName}}[i] = rel.R.{{$rel.Function.ForeignName}}[ln-1]
rel.R.{{$txt.Function.ForeignName}}[i] = rel.R.{{$txt.Function.ForeignName}}[ln-1]
}
rel.R.{{$rel.Function.ForeignName}} = rel.R.{{$rel.Function.ForeignName}}[:ln-1]
rel.R.{{$txt.Function.ForeignName}} = rel.R.{{$txt.Function.ForeignName}}[:ln-1]
break
}
}

View file

@ -1,5 +1,5 @@
{{- $tableNamePlural := .Table.Name | plural | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase}}
// {{$tableNamePlural}}G retrieves all records.
func {{$tableNamePlural}}G(mods ...qm.QueryMod) {{$varNameSingular}}Query {
return {{$tableNamePlural}}(boil.GetDB(), mods...)

View file

@ -2,7 +2,7 @@
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}
{{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", " -}}
{{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", "}}
// Find{{$tableNameSingular}}G retrieves a single record by ID.
func Find{{$tableNameSingular}}G({{$pkArgs}}, selectCols ...string) (*{{$tableNameSingular}}, error) {
return Find{{$tableNameSingular}}(boil.GetDB(), {{$pkNames | join ", "}}, selectCols...)

View file

@ -1,6 +1,6 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// InsertG a single record. See Insert for whitelist behavior description.
func (o *{{$tableNameSingular}}) InsertG(whitelist ... string) error {
return o.Insert(boil.GetDB(), whitelist...)
@ -78,56 +78,61 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
value := reflect.Indirect(reflect.ValueOf(o))
vals := queries.ValuesFromMapping(value, cache.valueMapping)
{{if .UseLastInsertID}}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.query)
fmt.Fprintln(boil.DebugWriter, vals)
}
{{if .UseLastInsertID -}}
{{- $canLastInsertID := .Table.CanLastInsertID -}}
{{if $canLastInsertID -}}
result, err := exec.Exec(cache.query, vals...)
{{else -}}
_, err = exec.Exec(cache.query, vals...)
{{- end}}
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
var lastID int64
{{if $canLastInsertID -}}
var lastID int64
{{- end}}
var identifierCols []interface{}
if len(cache.retMapping) == 0 {
goto CacheNoHooks
}
{{if $canLastInsertID -}}
lastID, err = result.LastInsertId()
if err != nil {
return ErrSyncFail
}
{{- $colName := index .Table.PKey.Columns 0 -}}
{{$colName := index .Table.PKey.Columns 0 -}}
{{- $col := .Table.GetColumn $colName -}}
{{- $colTitled := $colName | singular | titleCase}}
{{if eq 1 (len .Table.PKey.Columns)}}
{{$cnames := .Table.Columns | filterColumnsByDefault true | columnNames}}
{{if setInclude $colName $cnames}}
{{- $colTitled := $colName | titleCase}}
o.{{$colTitled}} = {{$col.Type}}(lastID)
identifierCols = []interface{}{lastID}
{{end}}
{{else}}
if lastID != 0 && len(cache.retMapping) == 1 && cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
goto CacheNoHooks
}
{{- end}}
identifierCols = []interface{}{
{{range .Table.PKey.Columns -}}
o.{{. | singular | titleCase}},
o.{{. | titleCase}},
{{end -}}
}
{{end}}
if lastID == 0 || len(cache.retMapping) != 1 || cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...)
}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...)
}
err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
}
err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(queries.PtrsFromMapping(value, cache.retMapping)...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
}
{{else}}
if len(cache.retMapping) != 0 {
@ -136,15 +141,11 @@ func (o *{{$tableNameSingular}}) Insert(exec boil.Executor, whitelist ... string
_, err = exec.Exec(cache.query, vals...)
}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.query)
fmt.Fprintln(boil.DebugWriter, vals)
}
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to insert into {{.Table.Name}}")
}
{{end}}
{{if .UseLastInsertID -}}
CacheNoHooks:
{{- end}}

View file

@ -1,6 +1,6 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// UpdateG a single {{$tableNameSingular}} record. See Update for
// whitelist behavior description.
func (o *{{$tableNameSingular}}) UpdateG(whitelist ...string) error {

View file

@ -1,6 +1,6 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// UpsertG attempts an insert, and does an update or ignore on conflict.
func (o *{{$tableNameSingular}}) UpsertG({{if ne .DriverName "mysql"}}updateOnConflict bool, conflictColumns []string, {{end}}updateColumns []string, whitelist ...string) error {
return o.Upsert(boil.GetDB(), {{if ne .DriverName "mysql"}}updateOnConflict, conflictColumns, {{end}}updateColumns, whitelist...)
@ -117,7 +117,7 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
}
value := reflect.Indirect(reflect.ValueOf(o))
values := queries.ValuesFromMapping(value, cache.valueMapping)
vals := queries.ValuesFromMapping(value, cache.valueMapping)
var returns []interface{}
if len(cache.retMapping) != 0 {
returns = queries.PtrsFromMapping(value, cache.retMapping)
@ -125,59 +125,64 @@ func (o *{{$tableNameSingular}}) Upsert(exec boil.Executor, {{if ne .DriverName
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.query)
fmt.Fprintln(boil.DebugWriter, values)
fmt.Fprintln(boil.DebugWriter, vals)
}
{{- if .UseLastInsertID}}
result, err := exec.Exec(cache.query, values...)
{{if .UseLastInsertID -}}
{{- $canLastInsertID := .Table.CanLastInsertID -}}
{{if $canLastInsertID -}}
result, err := exec.Exec(cache.query, vals...)
{{else -}}
_, err = exec.Exec(cache.query, vals...)
{{- end}}
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}")
}
{{if $canLastInsertID -}}
var lastID int64
{{- end}}
var identifierCols []interface{}
if len(cache.retMapping) == 0 {
goto CacheNoHooks
}
{{if $canLastInsertID -}}
lastID, err = result.LastInsertId()
if err != nil {
return ErrSyncFail
}
{{- $colName := index .Table.PKey.Columns 0 -}}
{{$colName := index .Table.PKey.Columns 0 -}}
{{- $col := .Table.GetColumn $colName -}}
{{- $colTitled := $colName | singular | titleCase}}
{{if eq 1 (len .Table.PKey.Columns)}}
{{$cnames := .Table.Columns | filterColumnsByDefault true | columnNames}}
{{if setInclude $colName $cnames}}
{{- $colTitled := $colName | titleCase}}
o.{{$colTitled}} = {{$col.Type}}(lastID)
identifierCols = []interface{}{lastID}
{{end}}
{{else}}
if lastID != 0 && len(cache.retMapping) == 1 && cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
goto CacheNoHooks
}
{{- end}}
identifierCols = []interface{}{
{{range .Table.PKey.Columns -}}
o.{{. | singular | titleCase}},
o.{{. | titleCase}},
{{end -}}
}
{{end}}
if lastID == 0 || len(cache.retMapping) != 1 || cache.retMapping[0] == {{$varNameSingular}}Mapping["{{$colTitled}}"] {
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...)
}
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, cache.retQuery)
fmt.Fprintln(boil.DebugWriter, identifierCols...)
}
err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(returns...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
}
err = exec.QueryRow(cache.retQuery, identifierCols...).Scan(returns...)
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to populate default values for {{.Table.Name}}")
}
{{- else}}
if len(cache.retMapping) != 0 {
err = exec.QueryRow(cache.query, values...).Scan(returns...)
err = exec.QueryRow(cache.query, vals...).Scan(returns...)
} else {
_, err = exec.Exec(cache.query, values...)
_, err = exec.Exec(cache.query, vals...)
}
if err != nil {
return errors.Wrap(err, "{{.PkgName}}: unable to upsert for {{.Table.Name}}")

View file

@ -1,6 +1,6 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// DeleteP deletes a single {{$tableNameSingular}} record with an executor.
// DeleteP will match against the primary key column to find the record to delete.
// Panics on error.

View file

@ -1,7 +1,7 @@
{{- $tableNameSingular := .Table.Name | singular | titleCase -}}
{{- $varNameSingular := .Table.Name | singular | camelCase -}}
{{- $varNamePlural := .Table.Name | plural | camelCase -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// ReloadGP refetches the object from the database and panics on error.
func (o *{{$tableNameSingular}}) ReloadGP() {
if err := o.ReloadG(); err != nil {

View file

@ -2,7 +2,7 @@
{{- $colDefs := sqlColDefinitions .Table.Columns .Table.PKey.Columns -}}
{{- $pkNames := $colDefs.Names | stringMap .StringFuncs.camelCase -}}
{{- $pkArgs := joinSlices " " $pkNames $colDefs.Types | join ", " -}}
{{- $schemaTable := .Table.Name | .SchemaTable -}}
{{- $schemaTable := .Table.Name | .SchemaTable}}
// {{$tableNameSingular}}Exists checks if the {{$tableNameSingular}} row exists.
func {{$tableNameSingular}}Exists(exec boil.Executor, {{$pkArgs}}) (bool, error) {
var exists bool

View file

@ -101,7 +101,7 @@ func (p *pgTester) pgEnv() []string {
fmt.Sprintf("PGHOST=%s", p.host),
fmt.Sprintf("PGPORT=%d", p.port),
fmt.Sprintf("PGUSER=%s", p.user),
fmt.Sprintf("PGPASS=%s", p.pgPassFile),
fmt.Sprintf("PGPASSFILE=%s", p.pgPassFile),
}
}
@ -111,6 +111,12 @@ func (p *pgTester) makePGPassFile() error {
return errors.Wrap(err, "failed to create option file")
}
fmt.Fprintf(tmp, "%s:%d:postgres:%s", p.host, p.port, p.user)
if len(p.pass) != 0 {
fmt.Fprintf(tmp, ":%s", p.pass)
}
fmt.Fprintln(tmp)
fmt.Fprintf(tmp, "%s:%d:%s:%s", p.host, p.port, p.dbName, p.user)
if len(p.pass) != 0 {
fmt.Fprintf(tmp, ":%s", p.pass)

View file

@ -4,7 +4,7 @@
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
func test{{$txt.LocalTable.NameGo}}OneToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
tx := MustTx(boil.Begin())
defer tx.Rollback()
@ -65,5 +65,6 @@ func test{{$txt.LocalTable.NameGo}}OneToOne{{$txt.ForeignTable.NameGo}}Using{{$t
t.Error("struct should have been eager loaded")
}
}
{{end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -4,7 +4,8 @@
{{- range .Table.ToOneRelationships -}}
{{- $txt := txtsFromOneToOne $dot.Tables $dot.Table .}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $foreignPKeyCols := (getTable $dot.Tables .ForeignTable).PKey.Columns}}
func test{{$txt.LocalTable.NameGo}}OneToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
var err error
@ -53,12 +54,20 @@ func test{{$txt.LocalTable.NameGo}}OneToOneSetOp{{$txt.ForeignTable.NameGo}}Usin
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}})
}
{{if setInclude .ForeignColumn $foreignPKeyCols -}}
if exists, err := {{$txt.ForeignTable.NameGo}}Exists(tx, x.{{$foreignPKeyCols | stringMap $dot.StringFuncs.titleCase | join ", x."}}); err != nil {
t.Fatal(err)
} else if !exists {
t.Error("want 'x' to exist")
}
{{else -}}
zero := reflect.Zero(reflect.TypeOf(x.{{$txt.Function.ForeignAssignment}}))
reflect.Indirect(reflect.ValueOf(&x.{{$txt.Function.ForeignAssignment}})).Set(zero)
if err = x.Reload(tx); err != nil {
t.Fatal("failed to reload", err)
}
{{- end}}
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}}) {

View file

@ -5,6 +5,7 @@
{{- range .Table.ToManyRelationships -}}
{{- $txt := txtsFromToMany $dot.Tables $table .}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
func test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
@ -22,8 +23,8 @@ func test{{$txt.LocalTable.NameGo}}ToMany{{$txt.Function.Name}}(t *testing.T) {
t.Fatal(err)
}
randomize.Struct(seed, &b, {{$txt.ForeignTable.NameSingular | camelCase}}DBTypes, false{{if not $txt.Function.UsesBytes}}, "{{.ForeignColumn}}"{{end}})
randomize.Struct(seed, &c, {{$txt.ForeignTable.NameSingular | camelCase}}DBTypes, false{{if not $txt.Function.UsesBytes}}, "{{.ForeignColumn}}"{{end}})
randomize.Struct(seed, &b, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}ColumnsWithDefault...)
randomize.Struct(seed, &c, {{$foreignVarNameSingular}}DBTypes, false, {{$foreignVarNameSingular}}ColumnsWithDefault...)
{{if .Nullable -}}
a.{{.Column | titleCase}}.Valid = true
{{- end}}

View file

@ -5,21 +5,21 @@
{{- range .Table.ToManyRelationships -}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $rel := txtsFromToMany $dot.Tables $table .}}
func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.T) {
{{- $txt := txtsFromToMany $dot.Tables $table .}}
func test{{$txt.LocalTable.NameGo}}ToManyAddOp{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
defer tx.Rollback()
var a {{$rel.LocalTable.NameGo}}
var b, c, d, e {{$rel.ForeignTable.NameGo}}
var a {{$txt.LocalTable.NameGo}}
var b, c, d, e {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
foreigners := []*{{$txt.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
@ -36,13 +36,13 @@ func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.
t.Fatal(err)
}
foreignersSplitByInsertion := [][]*{{$rel.ForeignTable.NameGo}}{
foreignersSplitByInsertion := [][]*{{$txt.ForeignTable.NameGo}}{
{&b, &c},
{&d, &e},
}
for i, x := range foreignersSplitByInsertion {
err = a.Add{{$rel.Function.Name}}(tx, i != 0, x...)
err = a.Add{{$txt.Function.Name}}(tx, i != 0, x...)
if err != nil {
t.Fatal(err)
}
@ -51,46 +51,46 @@ func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.
second := x[1]
{{- if .ToJoinTable}}
if first.R.{{$rel.Function.ForeignName}}[0] != &a {
if first.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the slice")
}
if second.R.{{$rel.Function.ForeignName}}[0] != &a {
if second.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the slice")
}
{{- else}}
{{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}})
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, first.{{$txt.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, first.{{$txt.Function.ForeignAssignment}})
}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}})
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, second.{{$txt.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, second.{{$txt.Function.ForeignAssignment}})
}
{{else -}}
if a.{{$rel.Function.LocalAssignment}} != first.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, first.{{$rel.Function.ForeignAssignment}})
if a.{{$txt.Function.LocalAssignment}} != first.{{$txt.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, first.{{$txt.Function.ForeignAssignment}})
}
if a.{{$rel.Function.LocalAssignment}} != second.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, second.{{$rel.Function.ForeignAssignment}})
if a.{{$txt.Function.LocalAssignment}} != second.{{$txt.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, second.{{$txt.Function.ForeignAssignment}})
}
{{- end}}
if first.R.{{$rel.Function.ForeignName}} != &a {
if first.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship was not added properly to the foreign slice")
}
if second.R.{{$rel.Function.ForeignName}} != &a {
if second.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship was not added properly to the foreign slice")
}
{{- end}}
if a.R.{{$rel.Function.Name}}[i*2] != first {
if a.R.{{$txt.Function.Name}}[i*2] != first {
t.Error("relationship struct slice not set to correct value")
}
if a.R.{{$rel.Function.Name}}[i*2+1] != second {
if a.R.{{$txt.Function.Name}}[i*2+1] != second {
t.Error("relationship struct slice not set to correct value")
}
count, err := a.{{$rel.Function.Name}}(tx).Count()
count, err := a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Fatal(err)
}
@ -101,20 +101,20 @@ func test{{$rel.LocalTable.NameGo}}ToManyAddOp{{$rel.Function.Name}}(t *testing.
}
{{- if (or .ForeignColumnNullable .ToJoinTable)}}
func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.T) {
func test{{$txt.LocalTable.NameGo}}ToManySetOp{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
defer tx.Rollback()
var a {{$rel.LocalTable.NameGo}}
var b, c, d, e {{$rel.ForeignTable.NameGo}}
var a {{$txt.LocalTable.NameGo}}
var b, c, d, e {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
foreigners := []*{{$txt.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
@ -131,12 +131,12 @@ func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.
t.Fatal(err)
}
err = a.Set{{$rel.Function.Name}}(tx, false, &b, &c)
err = a.Set{{$txt.Function.Name}}(tx, false, &b, &c)
if err != nil {
t.Fatal(err)
}
count, err := a.{{$rel.Function.Name}}(tx).Count()
count, err := a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Fatal(err)
}
@ -144,12 +144,12 @@ func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.
t.Error("count was wrong:", count)
}
err = a.Set{{$rel.Function.Name}}(tx, true, &d, &e)
err = a.Set{{$txt.Function.Name}}(tx, true, &d, &e)
if err != nil {
t.Fatal(err)
}
count, err = a.{{$rel.Function.Name}}(tx).Count()
count, err = a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Fatal(err)
}
@ -159,78 +159,78 @@ func test{{$rel.LocalTable.NameGo}}ToManySetOp{{$rel.Function.Name}}(t *testing.
{{- if .ToJoinTable}}
if len(b.R.{{$rel.Function.ForeignName}}) != 0 {
if len(b.R.{{$txt.Function.ForeignName}}) != 0 {
t.Error("relationship was not removed properly from the slice")
}
if len(c.R.{{$rel.Function.ForeignName}}) != 0 {
if len(c.R.{{$txt.Function.ForeignName}}) != 0 {
t.Error("relationship was not removed properly from the slice")
}
if d.R.{{$rel.Function.ForeignName}}[0] != &a {
if d.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the slice")
}
if e.R.{{$rel.Function.ForeignName}}[0] != &a {
if e.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the slice")
}
{{- else}}
if b.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
if b.{{$txt.ForeignTable.ColumnNameGo}}.Valid {
t.Error("want b's foreign key value to be nil")
}
if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
if c.{{$txt.ForeignTable.ColumnNameGo}}.Valid {
t.Error("want c's foreign key value to be nil")
}
{{if $rel.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}})
{{if $txt.Function.UsesBytes -}}
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, d.{{$txt.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, d.{{$txt.Function.ForeignAssignment}})
}
if 0 != bytes.Compare(a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}})
if 0 != bytes.Compare(a.{{$txt.Function.LocalAssignment}}, e.{{$txt.Function.ForeignAssignment}}) {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, e.{{$txt.Function.ForeignAssignment}})
}
{{else -}}
if a.{{$rel.Function.LocalAssignment}} != d.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, d.{{$rel.Function.ForeignAssignment}})
if a.{{$txt.Function.LocalAssignment}} != d.{{$txt.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, d.{{$txt.Function.ForeignAssignment}})
}
if a.{{$rel.Function.LocalAssignment}} != e.{{$rel.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$rel.Function.LocalAssignment}}, e.{{$rel.Function.ForeignAssignment}})
if a.{{$txt.Function.LocalAssignment}} != e.{{$txt.Function.ForeignAssignment}} {
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, e.{{$txt.Function.ForeignAssignment}})
}
{{- end}}
if b.R.{{$rel.Function.ForeignName}} != nil {
if b.R.{{$txt.Function.ForeignName}} != nil {
t.Error("relationship was not removed properly from the foreign struct")
}
if c.R.{{$rel.Function.ForeignName}} != nil {
if c.R.{{$txt.Function.ForeignName}} != nil {
t.Error("relationship was not removed properly from the foreign struct")
}
if d.R.{{$rel.Function.ForeignName}} != &a {
if d.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship was not added properly to the foreign struct")
}
if e.R.{{$rel.Function.ForeignName}} != &a {
if e.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship was not added properly to the foreign struct")
}
{{- end}}
if a.R.{{$rel.Function.Name}}[0] != &d {
if a.R.{{$txt.Function.Name}}[0] != &d {
t.Error("relationship struct slice not set to correct value")
}
if a.R.{{$rel.Function.Name}}[1] != &e {
if a.R.{{$txt.Function.Name}}[1] != &e {
t.Error("relationship struct slice not set to correct value")
}
}
func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testing.T) {
func test{{$txt.LocalTable.NameGo}}ToManyRemoveOp{{$txt.Function.Name}}(t *testing.T) {
var err error
tx := MustTx(boil.Begin())
defer tx.Rollback()
var a {{$rel.LocalTable.NameGo}}
var b, c, d, e {{$rel.ForeignTable.NameGo}}
var a {{$txt.LocalTable.NameGo}}
var b, c, d, e {{$txt.ForeignTable.NameGo}}
seed := randomize.NewSeed()
if err = randomize.Struct(seed, &a, {{$varNameSingular}}DBTypes, false, strmangle.SetComplement({{$varNameSingular}}PrimaryKeyColumns, {{$varNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
}
foreigners := []*{{$rel.ForeignTable.NameGo}}{&b, &c, &d, &e}
foreigners := []*{{$txt.ForeignTable.NameGo}}{&b, &c, &d, &e}
for _, x := range foreigners {
if err = randomize.Struct(seed, x, {{$foreignVarNameSingular}}DBTypes, false, strmangle.SetComplement({{$foreignVarNameSingular}}PrimaryKeyColumns, {{$foreignVarNameSingular}}ColumnsWithoutDefault)...); err != nil {
t.Fatal(err)
@ -241,12 +241,12 @@ func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testi
t.Fatal(err)
}
err = a.Add{{$rel.Function.Name}}(tx, true, foreigners...)
err = a.Add{{$txt.Function.Name}}(tx, true, foreigners...)
if err != nil {
t.Fatal(err)
}
count, err := a.{{$rel.Function.Name}}(tx).Count()
count, err := a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Fatal(err)
}
@ -254,12 +254,12 @@ func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testi
t.Error("count was wrong:", count)
}
err = a.Remove{{$rel.Function.Name}}(tx, foreigners[:2]...)
err = a.Remove{{$txt.Function.Name}}(tx, foreigners[:2]...)
if err != nil {
t.Fatal(err)
}
count, err = a.{{$rel.Function.Name}}(tx).Count()
count, err = a.{{$txt.Function.Name}}(tx).Count()
if err != nil {
t.Fatal(err)
}
@ -269,50 +269,50 @@ func test{{$rel.LocalTable.NameGo}}ToManyRemoveOp{{$rel.Function.Name}}(t *testi
{{- if .ToJoinTable}}
if len(b.R.{{$rel.Function.ForeignName}}) != 0 {
if len(b.R.{{$txt.Function.ForeignName}}) != 0 {
t.Error("relationship was not removed properly from the slice")
}
if len(c.R.{{$rel.Function.ForeignName}}) != 0 {
if len(c.R.{{$txt.Function.ForeignName}}) != 0 {
t.Error("relationship was not removed properly from the slice")
}
if d.R.{{$rel.Function.ForeignName}}[0] != &a {
if d.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the foreign struct")
}
if e.R.{{$rel.Function.ForeignName}}[0] != &a {
if e.R.{{$txt.Function.ForeignName}}[0] != &a {
t.Error("relationship was not added properly to the foreign struct")
}
{{- else}}
if b.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
if b.{{$txt.ForeignTable.ColumnNameGo}}.Valid {
t.Error("want b's foreign key value to be nil")
}
if c.{{$rel.ForeignTable.ColumnNameGo}}.Valid {
if c.{{$txt.ForeignTable.ColumnNameGo}}.Valid {
t.Error("want c's foreign key value to be nil")
}
if b.R.{{$rel.Function.ForeignName}} != nil {
if b.R.{{$txt.Function.ForeignName}} != nil {
t.Error("relationship was not removed properly from the foreign struct")
}
if c.R.{{$rel.Function.ForeignName}} != nil {
if c.R.{{$txt.Function.ForeignName}} != nil {
t.Error("relationship was not removed properly from the foreign struct")
}
if d.R.{{$rel.Function.ForeignName}} != &a {
if d.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship to a should have been preserved")
}
if e.R.{{$rel.Function.ForeignName}} != &a {
if e.R.{{$txt.Function.ForeignName}} != &a {
t.Error("relationship to a should have been preserved")
}
{{- end}}
if len(a.R.{{$rel.Function.Name}}) != 2 {
if len(a.R.{{$txt.Function.Name}}) != 2 {
t.Error("should have preserved two relationships")
}
// Removal doesn't do a stable deletion for performance so we have to flip the order
if a.R.{{$rel.Function.Name}}[1] != &d {
if a.R.{{$txt.Function.Name}}[1] != &d {
t.Error("relationship to d should have been preserved")
}
if a.R.{{$rel.Function.Name}}[0] != &e {
if a.R.{{$txt.Function.Name}}[0] != &e {
t.Error("relationship to e should have been preserved")
}
}

View file

@ -4,7 +4,7 @@
{{- range .Table.FKeys -}}
{{- $txt := txtsFromFKey $dot.Tables $dot.Table . -}}
{{- $varNameSingular := .Table | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase -}}
{{- $foreignVarNameSingular := .ForeignTable | singular | camelCase}}
func test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.Function.Name}}(t *testing.T) {
tx := MustTx(boil.Begin())
defer tx.Rollback()
@ -65,5 +65,6 @@ func test{{$txt.LocalTable.NameGo}}ToOne{{$txt.ForeignTable.NameGo}}Using{{$txt.
t.Error("struct should have been eager loaded")
}
}
{{end -}}{{/* range */}}
{{- end -}}{{/* join table */}}

View file

@ -60,6 +60,13 @@ func test{{$txt.LocalTable.NameGo}}ToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}})
}
{{if setInclude .Column $dot.Table.PKey.Columns -}}
if exists, err := {{$txt.LocalTable.NameGo}}Exists(tx, a.{{$dot.Table.PKey.Columns | stringMap $dot.StringFuncs.titleCase | join ", a."}}); err != nil {
t.Fatal(err)
} else if !exists {
t.Error("want 'a' to exist")
}
{{else -}}
zero := reflect.Zero(reflect.TypeOf(a.{{$txt.Function.LocalAssignment}}))
reflect.Indirect(reflect.ValueOf(&a.{{$txt.Function.LocalAssignment}})).Set(zero)
@ -74,6 +81,7 @@ func test{{$txt.LocalTable.NameGo}}ToOneSetOp{{$txt.ForeignTable.NameGo}}Using{{
{{end -}}
t.Error("foreign key was wrong value", a.{{$txt.Function.LocalAssignment}}, x.{{$txt.Function.ForeignAssignment}})
}
{{- end}}
}
}
{{- if .Nullable}}

View file

@ -285,3 +285,47 @@ create table byte_pilot_languages (
foreign key (byte_pilot_id) references byte_pilots (id),
foreign key (byte_language_id) references byte_languages (id)
);
create table cars (
id integer not null,
name text,
primary key (id)
);
create table car_cars (
car_id integer not null,
awesome_car_id integer not null,
relation text not null,
primary key (car_id, awesome_car_id),
foreign key (car_id) references cars(id),
foreign key (awesome_car_id) references cars(id)
);
create table trucks (
id integer not null,
parent_id integer,
name text,
primary key (id),
foreign key (parent_id) references trucks(id)
);
CREATE TABLE race (
id integer PRIMARY KEY NOT NULL,
race_date timestamp,
track text
);
CREATE TABLE race_results (
id integer PRIMARY KEY NOT NULL,
race_id integer,
name text,
foreign key (race_id) references race(id)
);
CREATE TABLE race_result_scratchings (
id integer PRIMARY KEY NOT NULL,
results_id integer NOT NULL,
name text NOT NULL,
foreign key (results_id) references race_results(id)
);

View file

@ -326,3 +326,46 @@ create table byte_pilot_languages (
foreign key (byte_pilot_id) references byte_pilots (id),
foreign key (byte_language_id) references byte_languages (id)
);
create table cars (
id integer not null,
name text,
primary key (id)
);
create table car_cars (
car_id integer not null,
awesome_car_id integer not null,
relation text not null,
primary key (car_id, awesome_car_id),
foreign key (car_id) references cars(id),
foreign key (awesome_car_id) references cars(id)
);
create table trucks (
id integer not null,
parent_id integer,
name text,
primary key (id),
foreign key (parent_id) references trucks(id)
);
CREATE TABLE race (
id integer PRIMARY KEY NOT NULL,
race_date timestamp,
track text
);
CREATE TABLE race_results (
id integer PRIMARY KEY NOT NULL,
race_id integer,
name text,
foreign key (race_id) references race(id)
);
CREATE TABLE race_result_scratchings (
id integer PRIMARY KEY NOT NULL,
results_id integer NOT NULL,
name text NOT NULL,
foreign key (results_id) references race_results(id)
);

View file

@ -29,7 +29,6 @@ type TxtToOne struct {
Name string
ForeignName string
Varname string
UsesBytes bool
LocalAssignment string
@ -50,13 +49,7 @@ func txtsFromFKey(tables []bdb.Table, table bdb.Table, fkey bdb.ForeignKey) TxtT
r.ForeignTable.ColumnName = fkey.ForeignColumn
r.ForeignTable.ColumnNameGo = strmangle.TitleCase(strmangle.Singular(fkey.ForeignColumn))
r.Function.Name = strmangle.TitleCase(strmangle.Singular(trimSuffixes(fkey.Column)))
plurality := strmangle.Plural
if fkey.Unique {
plurality = strmangle.Singular
}
r.Function.ForeignName = mkFunctionName(strmangle.Singular(fkey.ForeignTable), strmangle.TitleCase(plurality(fkey.Table)), fkey.Column, false)
r.Function.Varname = strmangle.CamelCase(strmangle.Singular(fkey.ForeignTable))
r.Function.Name, r.Function.ForeignName = txtNameToOne(fkey)
if fkey.Nullable {
col := table.GetColumn(fkey.Column)
@ -101,10 +94,14 @@ func txtsFromOneToOne(tables []bdb.Table, table bdb.Table, oneToOne bdb.ToOneRel
rel.ForeignKey.Column, rel.ForeignKey.ForeignColumn = rel.ForeignKey.ForeignColumn, rel.ForeignKey.Column
rel.ForeignKey.Nullable, rel.ForeignKey.ForeignColumnNullable = rel.ForeignKey.ForeignColumnNullable, rel.ForeignKey.Nullable
rel.ForeignKey.Unique, rel.ForeignKey.ForeignColumnUnique = rel.ForeignKey.ForeignColumnUnique, rel.ForeignKey.Unique
rel.Function.Name = strmangle.TitleCase(strmangle.Singular(oneToOne.ForeignTable))
rel.Function.ForeignName = mkFunctionName(strmangle.Singular(oneToOne.Table), strmangle.TitleCase(strmangle.Singular(oneToOne.Table)), oneToOne.ForeignColumn, false)
rel.Function.UsesBytes = col.Type == "[]byte"
rel.Function.ForeignName, rel.Function.Name = txtNameToOne(bdb.ForeignKey{
Table: oneToOne.ForeignTable,
Column: oneToOne.ForeignColumn,
Unique: true,
ForeignTable: oneToOne.Table,
ForeignColumn: oneToOne.Column,
})
return rel
}
@ -112,13 +109,11 @@ func txtsFromOneToOne(tables []bdb.Table, table bdb.Table, oneToOne bdb.ToOneRel
type TxtToMany struct {
LocalTable struct {
NameGo string
NameSingular string
ColumnNameGo string
}
ForeignTable struct {
NameGo string
NameSingular string
NamePluralGo string
NameHumanReadable string
ColumnNameGo string
@ -140,25 +135,17 @@ type TxtToMany struct {
// transformation in advance for a given relationship.
func txtsFromToMany(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRelationship) TxtToMany {
r := TxtToMany{}
r.LocalTable.NameSingular = strmangle.Singular(table.Name)
r.LocalTable.NameGo = strmangle.TitleCase(r.LocalTable.NameSingular)
r.LocalTable.NameGo = strmangle.TitleCase(strmangle.Singular(table.Name))
r.LocalTable.ColumnNameGo = strmangle.TitleCase(rel.Column)
r.ForeignTable.NameSingular = strmangle.Singular(rel.ForeignTable)
foreignNameSingular := strmangle.Singular(rel.ForeignTable)
r.ForeignTable.NamePluralGo = strmangle.TitleCase(strmangle.Plural(rel.ForeignTable))
r.ForeignTable.NameGo = strmangle.TitleCase(r.ForeignTable.NameSingular)
r.ForeignTable.NameGo = strmangle.TitleCase(foreignNameSingular)
r.ForeignTable.ColumnNameGo = strmangle.TitleCase(rel.ForeignColumn)
r.ForeignTable.Slice = fmt.Sprintf("%sSlice", strmangle.TitleCase(r.ForeignTable.NameSingular))
r.ForeignTable.Slice = fmt.Sprintf("%sSlice", strmangle.TitleCase(foreignNameSingular))
r.ForeignTable.NameHumanReadable = strings.Replace(rel.ForeignTable, "_", " ", -1)
r.Function.Name = mkFunctionName(r.LocalTable.NameSingular, r.ForeignTable.NamePluralGo, rel.ForeignColumn, rel.ToJoinTable)
plurality := strmangle.Singular
foreignNamingColumn := rel.ForeignColumn
if rel.ToJoinTable {
plurality = strmangle.Plural
foreignNamingColumn = rel.JoinLocalColumn
}
r.Function.ForeignName = strmangle.TitleCase(plurality(trimSuffixes(foreignNamingColumn)))
r.Function.Name, r.Function.ForeignName = txtNameToMany(rel)
col := table.GetColumn(rel.Column)
if rel.Nullable {
@ -180,6 +167,99 @@ func txtsFromToMany(tables []bdb.Table, table bdb.Table, rel bdb.ToManyRelations
return r
}
// txtNameToOne creates the local and foreign function names for
// one-to-many and one-to-one relationships, where local == lhs (one).
//
// = many-to-one
// users - videos : user_id
// users - videos : producer_id
//
// fk == table = user.Videos | video.User
// fk != table = user.ProducerVideos | video.Producer
//
// = many-to-one
// industries - industries : parent_id
//
// fk == table = industry.Industries | industry.Industry
// fk != table = industry.ParentIndustries | industry.Parent
//
// = one-to-one
// users - videos : user_id
// users - videos : producer_id
//
// fk == table = user.Video | video.User
// fk != table = user.ProducerVideo | video.Producer
//
// = one-to-one
// industries - industries : parent_id
//
// fk == table = industry.Industry | industry.Industry
// fk != table = industry.ParentIndustry | industry.Industry
func txtNameToOne(fk bdb.ForeignKey) (localFn, foreignFn string) {
localFn = strmangle.Singular(trimSuffixes(fk.Column))
fkeyIsTableName := localFn != strmangle.Singular(fk.ForeignTable)
localFn = strmangle.TitleCase(localFn)
if fkeyIsTableName {
foreignFn = localFn
}
plurality := strmangle.Plural
if fk.Unique {
plurality = strmangle.Singular
}
foreignFn += strmangle.TitleCase(plurality(fk.Table))
return localFn, foreignFn
}
// txtNameToMany creates the local and foreign function names for
// many-to-one and many-to-many relationship, where local == lhs (many)
//
// cases:
// = many-to-many
// sponsors - constests
// sponsor_id contest_id
// fk == table = sponsor.Contests | contest.Sponsors
//
// = many-to-many
// sponsors - constests
// wiggle_id jiggle_id
// fk != table = sponsor.JiggleSponsors | contest.WiggleContests
//
// = many-to-many
// industries - industries
// industry_id mapped_industry_id
//
// fk == table = industry.Industries
// fk != table = industry.MappedIndustryIndustry
func txtNameToMany(toMany bdb.ToManyRelationship) (localFn, foreignFn string) {
if toMany.ToJoinTable {
localFkey := strmangle.Singular(trimSuffixes(toMany.JoinLocalColumn))
foreignFkey := strmangle.Singular(trimSuffixes(toMany.JoinForeignColumn))
if localFkey != strmangle.Singular(toMany.Table) {
foreignFn = strmangle.TitleCase(localFkey)
}
foreignFn += strmangle.TitleCase(strmangle.Plural(toMany.Table))
if foreignFkey != strmangle.Singular(toMany.ForeignTable) {
localFn = strmangle.TitleCase(foreignFkey)
}
localFn += strmangle.TitleCase(strmangle.Plural(toMany.ForeignTable))
return localFn, foreignFn
}
fkeyName := strmangle.Singular(trimSuffixes(toMany.ForeignColumn))
if fkeyName != strmangle.Singular(toMany.Table) {
localFn = strmangle.TitleCase(fkeyName)
}
localFn += strmangle.TitleCase(strmangle.Plural(toMany.ForeignTable))
foreignFn = strmangle.TitleCase(strmangle.Singular(fkeyName))
return localFn, foreignFn
}
// mkFunctionName checks to see if the foreign key name is the same as the local table name (minus _id suffix)
// Simple case: yes - we can name the function the same as the plural table name
// Not simple case: We have to name the function based off the foreign key and the foreign table name

View file

@ -33,7 +33,6 @@ func TestTxtsFromOne(t *testing.T) {
expect.Function.Name = "Pilot"
expect.Function.ForeignName = "Jet"
expect.Function.Varname = "pilot"
expect.Function.LocalAssignment = "PilotID.Int"
expect.Function.ForeignAssignment = "ID"
@ -56,7 +55,6 @@ func TestTxtsFromOne(t *testing.T) {
expect.Function.Name = "Airport"
expect.Function.ForeignName = "Jets"
expect.Function.Varname = "airport"
expect.Function.LocalAssignment = "AirportID"
expect.Function.ForeignAssignment = "ID"
@ -106,7 +104,6 @@ func TestTxtsFromOneToOne(t *testing.T) {
expect.Function.Name = "Jet"
expect.Function.ForeignName = "Pilot"
expect.Function.Varname = "jet"
expect.Function.LocalAssignment = "ID"
expect.Function.ForeignAssignment = "PilotID.Int"
@ -128,11 +125,9 @@ func TestTxtsFromMany(t *testing.T) {
texts := txtsFromToMany(tables, pilots, pilots.ToManyRelationships[0])
expect := TxtToMany{}
expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.NameSingular = "pilot"
expect.LocalTable.ColumnNameGo = "ID"
expect.ForeignTable.NameGo = "License"
expect.ForeignTable.NameSingular = "license"
expect.ForeignTable.NamePluralGo = "Licenses"
expect.ForeignTable.NameHumanReadable = "licenses"
expect.ForeignTable.ColumnNameGo = "PilotID"
@ -150,11 +145,9 @@ func TestTxtsFromMany(t *testing.T) {
texts = txtsFromToMany(tables, pilots, pilots.ToManyRelationships[1])
expect = TxtToMany{}
expect.LocalTable.NameGo = "Pilot"
expect.LocalTable.NameSingular = "pilot"
expect.LocalTable.ColumnNameGo = "ID"
expect.ForeignTable.NameGo = "Language"
expect.ForeignTable.NameSingular = "language"
expect.ForeignTable.NamePluralGo = "Languages"
expect.ForeignTable.NameHumanReadable = "languages"
expect.ForeignTable.ColumnNameGo = "ID"
@ -170,6 +163,104 @@ func TestTxtsFromMany(t *testing.T) {
}
}
func TestTxtNameToOne(t *testing.T) {
t.Parallel()
tests := []struct {
Table string
Column string
Unique bool
ForeignTable string
ForeignColumn string
ForeignColumnUnique bool
LocalFn string
ForeignFn string
}{
{"jets", "airport_id", false, "airports", "id", true, "Airport", "Jets"},
{"jets", "airport_id", true, "airports", "id", true, "Airport", "Jet"},
{"jets", "holiday_id", false, "airports", "id", true, "Holiday", "HolidayJets"},
{"jets", "holiday_id", true, "airports", "id", true, "Holiday", "HolidayJet"},
{"jets", "holiday_airport_id", false, "airports", "id", true, "HolidayAirport", "HolidayAirportJets"},
{"jets", "holiday_airport_id", true, "airports", "id", true, "HolidayAirport", "HolidayAirportJet"},
{"jets", "jet_id", false, "jets", "id", true, "Jet", "Jets"},
{"jets", "jet_id", true, "jets", "id", true, "Jet", "Jet"},
{"jets", "plane_id", false, "jets", "id", true, "Plane", "PlaneJets"},
{"jets", "plane_id", true, "jets", "id", true, "Plane", "PlaneJet"},
{"race_result_scratchings", "results_id", false, "race_results", "id", true, "Result", "ResultRaceResultScratchings"},
}
for i, test := range tests {
fk := bdb.ForeignKey{
Table: test.Table, Column: test.Column, Unique: test.Unique,
ForeignTable: test.ForeignTable, ForeignColumn: test.ForeignColumn, ForeignColumnUnique: test.ForeignColumnUnique,
}
local, foreign := txtNameToOne(fk)
if local != test.LocalFn {
t.Error(i, "local wrong:", local, "want:", test.LocalFn)
}
if foreign != test.ForeignFn {
t.Error(i, "foreign wrong:", foreign, "want:", test.ForeignFn)
}
}
}
func TestTxtNameToMany(t *testing.T) {
t.Parallel()
tests := []struct {
Table string
Column string
ForeignTable string
ForeignColumn string
ToJoinTable bool
JoinLocalColumn string
JoinForeignColumn string
LocalFn string
ForeignFn string
}{
{"airports", "id", "jets", "airport_id", false, "", "", "Jets", "Airport"},
{"airports", "id", "jets", "holiday_airport_id", false, "", "", "HolidayAirportJets", "HolidayAirport"},
{"jets", "id", "jets", "jet_id", false, "", "", "Jets", "Jet"},
{"jets", "id", "jets", "plane_id", false, "", "", "PlaneJets", "Plane"},
{"pilots", "id", "languages", "id", true, "pilot_id", "language_id", "Languages", "Pilots"},
{"pilots", "id", "languages", "id", true, "captain_id", "lingo_id", "LingoLanguages", "CaptainPilots"},
{"pilots", "id", "pilots", "id", true, "pilot_id", "mentor_id", "MentorPilots", "Pilots"},
{"pilots", "id", "pilots", "id", true, "mentor_id", "pilot_id", "Pilots", "MentorPilots"},
{"pilots", "id", "pilots", "id", true, "captain_id", "mentor_id", "MentorPilots", "CaptainPilots"},
{"race_results", "id", "race_result_scratchings", "results_id", false, "", "", "ResultRaceResultScratchings", "Result"},
}
for i, test := range tests {
fk := bdb.ToManyRelationship{
Table: test.Table, Column: test.Column,
ForeignTable: test.ForeignTable, ForeignColumn: test.ForeignColumn,
ToJoinTable: test.ToJoinTable,
JoinLocalColumn: test.JoinLocalColumn, JoinForeignColumn: test.JoinForeignColumn,
}
local, foreign := txtNameToMany(fk)
if local != test.LocalFn {
t.Error(i, "local wrong:", local, "want:", test.LocalFn)
}
if foreign != test.ForeignFn {
t.Error(i, "foreign wrong:", foreign, "want:", test.ForeignFn)
}
}
}
func TestTrimSuffixes(t *testing.T) {
t.Parallel()