Merge branch 'master' of github.com:nullbio/sqlboiler

This commit is contained in:
Patrick O'brien 2016-07-06 16:04:54 +10:00
commit 0275677216
7 changed files with 169 additions and 21 deletions

View file

@ -179,7 +179,7 @@ func (p *PostgresDriver) ForeignKeyInfo(tableName string) ([]bdb.ForeignKey, err
from information_schema.table_constraints as tc
inner join information_schema.key_column_usage as kcu ON tc.constraint_name = kcu.constraint_name
inner join information_schema.constraint_column_usage as ccu ON tc.constraint_name = ccu.constraint_name
where tc.table_name = $1 and tc.constraint_type = 'FOREIGN KEY' and tc.table_schema = 'information_schema';`
where tc.table_name = $1 and tc.constraint_type = 'FOREIGN KEY' and tc.table_schema = 'public';`
var rows *sql.Rows
var err error

View file

@ -7,7 +7,11 @@ type ToManyRelationship struct {
Column string
ForeignTable string
ForeignColumn string
ToJoinTable bool
ToJoinTable bool
JoinTable string
JoinLocalColumn string
JoinForeignColumn string
}
// ToManyRelationships relationship lookups
@ -25,16 +29,38 @@ func ToManyRelationships(table string, tables []Table) []ToManyRelationship {
continue
}
relationship := ToManyRelationship{
Column: f.ForeignColumn,
ForeignTable: t.Name,
ForeignColumn: f.Column,
ToJoinTable: t.IsJoinTable,
}
relationships = append(relationships, relationship)
relationships = append(relationships, buildRelationship(table, f, t))
}
}
return relationships
}
func buildRelationship(localTable string, foreignKey ForeignKey, foreignTable Table) ToManyRelationship {
if !foreignTable.IsJoinTable {
return ToManyRelationship{
Column: foreignKey.ForeignColumn,
ForeignTable: foreignTable.Name,
ForeignColumn: foreignKey.Column,
ToJoinTable: foreignTable.IsJoinTable,
}
}
relationship := ToManyRelationship{
Column: foreignKey.ForeignColumn,
ToJoinTable: true,
JoinTable: foreignTable.Name,
}
for _, fk := range foreignTable.FKeys {
if fk.ForeignTable != localTable {
relationship.JoinForeignColumn = fk.Column
relationship.ForeignTable = fk.ForeignTable
relationship.ForeignColumn = fk.ForeignColumn
} else {
relationship.JoinLocalColumn = fk.Column
}
}
return relationship
}

View file

@ -1,14 +1,17 @@
package bdb
import "testing"
import (
"testing"
"github.com/davecgh/go-spew/spew"
)
func TestToManyRelationships(t *testing.T) {
t.Parallel()
tables := []Table{
Table{
Name: "videos",
IsJoinTable: true,
Name: "videos",
FKeys: []ForeignKey{
{Name: "videos_user_id_fk", Column: "user_id", ForeignTable: "users", ForeignColumn: "id"},
{Name: "videos_contest_id_fk", Column: "contest_id", ForeignTable: "contests", ForeignColumn: "id"},
@ -21,9 +24,22 @@ func TestToManyRelationships(t *testing.T) {
{Name: "notifications_source_id_fk", Column: "source_id", ForeignTable: "users", ForeignColumn: "id"},
},
},
Table{
Name: "users_video_tags",
IsJoinTable: true,
FKeys: []ForeignKey{
{Name: "user_id_fk", Column: "user_id", ForeignTable: "users", ForeignColumn: "id"},
{Name: "video_id_fk", Column: "video_id", ForeignTable: "videos", ForeignColumn: "id"},
},
},
}
relationships := ToManyRelationships("users", tables)
spew.Dump(relationships)
if len(relationships) != 4 {
t.Error("wrong # of relationships:", len(relationships))
}
r := relationships[0]
if r.Column != "id" {
t.Error("wrong local column:", r.Column)
@ -34,7 +50,58 @@ func TestToManyRelationships(t *testing.T) {
if r.ForeignColumn != "user_id" {
t.Error("wrong foreign column:", r.ForeignColumn)
}
if r.ToJoinTable {
t.Error("not a join table")
}
r = relationships[1]
if r.Column != "id" {
t.Error("wrong local column:", r.Column)
}
if r.ForeignTable != "notifications" {
t.Error("wrong foreign table:", r.ForeignTable)
}
if r.ForeignColumn != "user_id" {
t.Error("wrong foreign column:", r.ForeignColumn)
}
if r.ToJoinTable {
t.Error("not a join table")
}
r = relationships[2]
if r.Column != "id" {
t.Error("wrong local column:", r.Column)
}
if r.ForeignTable != "notifications" {
t.Error("wrong foreign table:", r.ForeignTable)
}
if r.ForeignColumn != "source_id" {
t.Error("wrong foreign column:", r.ForeignColumn)
}
if r.ToJoinTable {
t.Error("not a join table")
}
r = relationships[3]
if r.Column != "id" {
t.Error("wrong local column:", r.Column)
}
if r.ForeignColumn != "id" {
t.Error("wrong foreign column:", r.Column)
}
if r.ForeignTable != "videos" {
t.Error("wrong foreign table:", r.ForeignTable)
}
if r.JoinTable != "users_video_tags" {
t.Error("wrong join table:", r.ForeignTable)
}
if r.JoinLocalColumn != "user_id" {
t.Error("wrong local join column:", r.JoinLocalColumn)
}
if r.JoinForeignColumn != "video_id" {
t.Error("wrong foreign join column:", r.JoinForeignColumn)
}
if !r.ToJoinTable {
t.Error("expected a join table - kind of - not really but we're faking it")
t.Error("expected a join table")
}
}

View file

@ -6,11 +6,42 @@ package strmangle
import (
"fmt"
"math"
"strings"
"github.com/jinzhu/inflection"
)
var (
idAlphabet = []byte("abcdefghijklmnopqrstuvwxyz")
)
// Identifier creates an identifier useful for a query
// This is essentially a base conversion from Base 10 integers to Base 26
// integers that are represented by an alphabet from a-z
// See tests for example outputs.
func Identifier(in int) string {
ln := len(idAlphabet)
var n int
if in == 0 {
n = 1
} else {
n = 1 + int(math.Log(float64(in))/math.Log(float64(ln)))
}
cols := make([]byte, n)
for i := 0; i < n; i++ {
divisor := int(math.Pow(float64(ln), float64(n-i-1)))
rem := in / divisor
cols[i] = idAlphabet[rem]
in -= rem * divisor
}
return string(cols)
}
// Plural converts singular words to plural words (eg: person to people)
func Plural(name string) string {
splits := strings.Split(name, "_")

View file

@ -5,6 +5,28 @@ import (
"testing"
)
func TestIDGen(t *testing.T) {
t.Parallel()
tests := []struct {
In int
Out string
}{
{In: 0, Out: "a"},
{In: 25, Out: "z"},
{In: 26, Out: "ba"},
{In: 52, Out: "ca"},
{In: 675, Out: "zz"},
{In: 676, Out: "baa"},
}
for _, test := range tests {
if got := Identifier(test.In); got != test.Out {
t.Errorf("[%d] want: %q, got: %q", test.In, test.Out, got)
}
}
}
func TestDriverUsesLastInsertID(t *testing.T) {
t.Parallel()

View file

@ -111,6 +111,7 @@ var templateFunctions = template.FuncMap{
"replace": func(rep, with, str string) string { return strings.Replace(str, rep, with, -1) },
"prefix": func(add, str string) string { return fmt.Sprintf("%s%s", add, str) },
"quoteWrap": func(a string) string { return fmt.Sprintf(`"%s"`, a) },
"id": strmangle.Identifier,
// Pluralization
"singular": strmangle.Singular,

View file

@ -7,16 +7,14 @@
{{- $colName := $localTableSing | printf "%s_id" -}}
{{- $receiver := .Table.Name | toLower | substring 0 1 -}}
{{- range toManyRelationships .Table.Name .Tables -}}
{{- if .ToJoinTable -}}
{{- else -}}
{{- $foreignTableSing := .ForeignTable | singular}}
{{- $foreignTable := $foreignTableSing | titleCase}}
{{- $foreignSlice := $foreignTableSing | camelCase | printf "%sSlice"}}
{{- $foreignTableHumanReadable := .ForeignTable | replace "_" " " -}}
{{- $foreignPluralNoun := .ForeignTable | plural | titleCase -}}
{{- $isNormal := eq $colName .ForeignColumn -}}
{{- $isForeignKeySimplyTableName := or (eq $colName .ForeignColumn) .ToJoinTable -}}
{{- if $isNormal -}}
{{- if $isForeignKeySimplyTableName -}}
// {{$foreignPluralNoun}} retrieves all the {{$localTableSing}}'s {{$foreignTableHumanReadable}}.
func ({{$receiver}} *{{$localTable}}) {{$foreignPluralNoun}}(
@ -29,7 +27,11 @@ func ({{$receiver}} *{{$localTable}}) {{$fnName}}(
exec boil.Executor, selectCols ...string) ({{$foreignSlice}}, error) {
var ret {{$foreignSlice}}
{{if .ToJoinTable -}}
query := fmt.Sprintf(`select "%s" from {{.ForeignTable}} "{{id 0}}" inner join {{.JoinTable}} as "{{id 1}}" on "{{id 1}}"."{{.JoinForeignColumn}}" = "{{id 0}}"."{{.ForeignColumn}}" where "{{id 1}}"."{{.JoinLocalColumn}}"=$1`, `"{{id 1}}".` + strings.Join(selectCols, `","{{id 0}}"."`))
{{else -}}
query := fmt.Sprintf(`select "%s" from {{.ForeignTable}} where "{{.ForeignColumn}}"=$1`, strings.Join(selectCols, `","`))
{{end}}
rows, err := exec.Query(query, {{.Column | titleCase | printf "%s.%s" $receiver }})
if err != nil {
return nil, fmt.Errorf(`{{$dot.PkgName}}: unable to select from {{.ForeignTable}}: %v`, err)
@ -53,6 +55,5 @@ exec boil.Executor, selectCols ...string) ({{$foreignSlice}}, error) {
return ret, nil
}
{{end -}}{{/* if join table */}}
{{- end -}}{{/* range relationships */}}
{{- end -}}{{/* outer if join table */}}
{{end -}}{{- /* range relationships */ -}}
{{- end -}}{{- /* outer if join table */ -}}