Made qs package, added single templates support

This commit is contained in:
Patrick O'brien 2016-04-19 12:02:32 +10:00
parent 270fe59117
commit dc50c0d42c
14 changed files with 190 additions and 81 deletions

View file

@ -9,9 +9,6 @@ import (
"unicode" "unicode"
) )
// M type is for providing where filters to Where helpers.
type M map[string]interface{}
// SelectNames returns the column names for a select statement // SelectNames returns the column names for a select statement
// Eg: col1, col2, col3 // Eg: col1, col2, col3
func SelectNames(results interface{}) string { func SelectNames(results interface{}) string {

View file

@ -1,39 +1,35 @@
package boil package qs
type QueryMod func(q *Query) import "github.com/pobri19/sqlboiler/boil"
func (q *Query) Apply(mods ...QueryMod) { type QueryMod func(q *boil.Query)
func (q *boil.Query) Apply(mods ...QueryMod) {
for _, mod := range mods { for _, mod := range mods {
mod(q) mod(q)
} }
} }
func DB(e Executor) QueryMod {
return func(q *Query) {
q.executor = e
}
}
func Limit(limit int) QueryMod { func Limit(limit int) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.limit = limit q.limit = limit
} }
} }
func Join(join string) QueryMod { func Join(join string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.joins = append(q.joins, join) q.joins = append(q.joins, join)
} }
} }
func Select(columns ...string) QueryMod { func Select(columns ...string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.selectCols = append(q.selectCols, columns...) q.selectCols = append(q.selectCols, columns...)
} }
} }
func Where(clause string, args ...interface{}) QueryMod { func Where(clause string, args ...interface{}) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
w := where{ w := where{
clause: clause, clause: clause,
args: args, args: args,
@ -44,25 +40,25 @@ func Where(clause string, args ...interface{}) QueryMod {
} }
func GroupBy(clause string) QueryMod { func GroupBy(clause string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.groupBy = append(q.groupBy, clause) q.groupBy = append(q.groupBy, clause)
} }
} }
func OrderBy(clause string) QueryMod { func OrderBy(clause string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.orderBy = append(q.orderBy, clause) q.orderBy = append(q.orderBy, clause)
} }
} }
func Having(clause string) QueryMod { func Having(clause string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.having = append(q.having, clause) q.having = append(q.having, clause)
} }
} }
func From(table string) QueryMod { func From(table string) QueryMod {
return func(q *Query) { return func(q *boil.Query) {
q.from = table q.from = table
} }
} }

View file

@ -1,11 +1,15 @@
package boil package qs
import "testing" import (
"testing"
"github.com/pobri19/sqlboiler/boil"
)
func TestApply(t *testing.T) { func TestApply(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn1 := Limit(10) qfn1 := Limit(10)
qfn2 := Where("x > $1 AND y > $2", 5, 3) qfn2 := Where("x > $1 AND y > $2", 5, 3)
@ -43,7 +47,7 @@ func TestDB(t *testing.T) {
func TestLimit(t *testing.T) { func TestLimit(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := Limit(10) qfn := Limit(10)
qfn(q) qfn(q)
@ -57,7 +61,7 @@ func TestLimit(t *testing.T) {
func TestWhere(t *testing.T) { func TestWhere(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := Where("x > $1 AND y > $2", 5, 3) qfn := Where("x > $1 AND y > $2", 5, 3)
qfn(q) qfn(q)
@ -83,7 +87,7 @@ func TestWhere(t *testing.T) {
func TestGroupBy(t *testing.T) { func TestGroupBy(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := GroupBy("col1, col2") qfn := GroupBy("col1, col2")
qfn(q) qfn(q)
@ -97,7 +101,7 @@ func TestGroupBy(t *testing.T) {
func TestOrderBy(t *testing.T) { func TestOrderBy(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := OrderBy("col1 desc, col2 asc") qfn := OrderBy("col1 desc, col2 asc")
qfn(q) qfn(q)
@ -111,7 +115,7 @@ func TestOrderBy(t *testing.T) {
func TestHaving(t *testing.T) { func TestHaving(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := Having("count(orders.order_id) > 10") qfn := Having("count(orders.order_id) > 10")
qfn(q) qfn(q)
@ -125,7 +129,7 @@ func TestHaving(t *testing.T) {
func TestFrom(t *testing.T) { func TestFrom(t *testing.T) {
t.Parallel() t.Parallel()
q := &Query{} q := &boil.Query{}
qfn := From("videos a, orders b") qfn := From("videos a, orders b")
qfn(q) qfn(q)

View file

@ -1,5 +1,7 @@
package boil package boil
import "database/sql"
type where struct { type where struct {
clause string clause string
args []interface{} args []interface{}
@ -7,6 +9,8 @@ type where struct {
type Query struct { type Query struct {
executor Executor executor Executor
delete bool
update map[string]interface{}
selectCols []string selectCols []string
from string from string
joins []string joins []string
@ -17,19 +21,62 @@ type Query struct {
limit int limit int
} }
func (q *Query) buildQuery() string { func SetDelete(q *Query, flag bool) {
q.delete = flag
}
func SetUpdate(q *Query, cols map[string]interface{}) {
q.update = cols
}
func SetExecutor(q *Query, exec Executor) {
q.executor = exec
}
func SetSelect() {
}
func SetFrom() {
}
func SetJoins() {
}
func SetWhere() {
}
func SetGroupBy() {
}
func SetOrderBy() {
}
func SetHaving() {
}
func SetLimit() {
}
func ExecQuery(q *Query) error {
return nil
}
func ExecQueryOne(q *Query) (*sql.Row, error) {
return nil, nil
}
func ExecQueryAll(q *Query) (*sql.Rows, error) {
return nil, nil
}
func buildQuery(q *Query) string {
return "" return ""
} }
// NewQuery initializes a new Query using the passed in QueryMods
func NewQuery(mods ...QueryMod) *Query {
return NewQueryX(currentDB, mods...)
}
// NewQueryX initializes a new Query using the passed in QueryMods
func NewQueryX(executor Executor, mods ...QueryMod) *Query {
q := &Query{executor: executor}
q.Apply(mods...)
return q
}

View file

@ -42,6 +42,15 @@ var sqlBoilerImports = imports{
}, },
} }
var sqlBoilerSinglesImports = map[string]imports{
"helpers": imports{
standard: importList{},
thirdparty: importList{
`"github.com/pobri19/sqlboiler/boil"`,
},
},
}
// sqlBoilerTestImports defines the list of default test template imports. // sqlBoilerTestImports defines the list of default test template imports.
var sqlBoilerTestImports = imports{ var sqlBoilerTestImports = imports{
standard: importList{ standard: importList{

View file

@ -76,6 +76,37 @@ func generateTestOutput(cmdData *CmdData, data *tplData) error {
return nil return nil
} }
func generateSinglesOutput(cmdData *CmdData) error {
if cmdData.SingleTemplates == nil {
return errors.New("No single templates located for generation")
}
for _, template := range cmdData.SingleTemplates {
var imps imports
resp, err := generateTemplate(template, &tplData{})
if err != nil {
return fmt.Errorf("Error generating template %s: %s", template.Name(), err)
}
fName := template.Name()
ext := filepath.Ext(fName)
fName = fName[0 : len(fName)-len(ext)]
imps.standard = sqlBoilerSinglesImports[fName].standard
imps.thirdparty = sqlBoilerSinglesImports[fName].thirdparty
fName = fName + ".go"
err = outHandler(cmdData.OutFolder, fName, cmdData.PkgName, imps, [][]byte{resp})
if err != nil {
return err
}
}
return nil
}
func generateTestMainOutput(cmdData *CmdData) error { func generateTestMainOutput(cmdData *CmdData) error {
if cmdData.TestMainTemplate == nil { if cmdData.TestMainTemplate == nil {
return errors.New("No TestMain template located for generation") return errors.New("No TestMain template located for generation")

View file

@ -15,6 +15,7 @@ import (
const ( const (
templatesDirectory = "/cmds/templates" templatesDirectory = "/cmds/templates"
templatesSinglesDirectory = "/cmds/templates/singles"
templatesTestDirectory = "/cmds/templates_test" templatesTestDirectory = "/cmds/templates_test"
templatesTestMainDirectory = "/cmds/templates_test/main_test" templatesTestMainDirectory = "/cmds/templates_test/main_test"
) )
@ -27,6 +28,11 @@ func initTemplates(cmdData *CmdData) error {
return err return err
} }
cmdData.SingleTemplates, err = loadTemplates(templatesSinglesDirectory)
if err != nil {
return err
}
cmdData.TestTemplates, err = loadTemplates(templatesTestDirectory) cmdData.TestTemplates, err = loadTemplates(templatesTestDirectory)
if err != nil { if err != nil {
return err return err
@ -118,6 +124,10 @@ func (c *CmdData) run(includeTests bool) error {
} }
} }
if err := generateSinglesOutput(c); err != nil {
return fmt.Errorf("Unable to generate single templates output: %s", err)
}
for _, table := range c.Tables { for _, table := range c.Tables {
data := &tplData{ data := &tplData{
Table: table, Table: table,

View file

@ -76,6 +76,15 @@ func TestTemplates(t *testing.T) {
t.Errorf("Templates is empty.") t.Errorf("Templates is empty.")
} }
cmdData.SingleTemplates, err = loadTemplates("templates/singles")
if err != nil {
t.Fatalf("Unable to initialize single templates: %s", err)
}
if len(cmdData.SingleTemplates) == 0 {
t.Errorf("SingleTemplates is empty.")
}
cmdData.TestTemplates, err = loadTemplates("templates_test") cmdData.TestTemplates, err = loadTemplates("templates_test")
if err != nil { if err != nil {
t.Fatalf("Unable to initialize templates: %s", err) t.Fatalf("Unable to initialize templates: %s", err)

View file

@ -1,5 +1,4 @@
{{- $tableNameSingular := titleCaseSingular .Table.Name -}} {{- $tableNameSingular := titleCaseSingular .Table.Name -}}
{{- $dbName := singular .Table.Name -}}
{{- $tableNamePlural := titleCasePlural .Table.Name -}} {{- $tableNamePlural := titleCasePlural .Table.Name -}}
{{- $varNameSingular := camelCaseSingular .Table.Name -}} {{- $varNameSingular := camelCaseSingular .Table.Name -}}
{{- $varNamePlural := camelCasePlural .Table.Name -}} {{- $varNamePlural := camelCasePlural .Table.Name -}}
@ -9,32 +8,10 @@ type {{$varNameSingular}}Query struct {
// {{$tableNamePlural}}All retrieves all records. // {{$tableNamePlural}}All retrieves all records.
func {{$tableNamePlural}}(mods ...QueryMod) {{$varNameSingular}}Query { func {{$tableNamePlural}}(mods ...QueryMod) {{$varNameSingular}}Query {
var {{$varNamePlural}} []*{{$tableNameSingular}} return {{$tableNamePlural}}X(boil.GetDB(), mods...)
rows, err := boil.GetDB().Query(`SELECT {{selectParamNames $dbName .Table.Columns}} FROM {{.Table.Name}}`)
if err != nil {
return nil, fmt.Errorf("{{.PkgName}}: failed to query: %v", err)
}
for rows.Next() {
{{- $tmpVarName := (print $varNamePlural "Tmp") -}}
{{$varNamePlural}}Tmp := {{$tableNameSingular}}{}
if err := rows.Scan({{scanParamNames $tmpVarName .Table.Columns}}); err != nil {
return nil, fmt.Errorf("{{.PkgName}}: failed to scan row: %v", err)
}
{{$varNamePlural}} = append({{$varNamePlural}}, &{{$varNamePlural}}Tmp)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("{{.PkgName}}: failed to read rows: %v", err)
}
return {{$varNamePlural}}, nil
} }
func {{$tableNamePlural}}X(exec boil.Executor, mods ...QueryMod) {{$tableNameSingular}}Query { func {{$tableNamePlural}}X(exec boil.Executor, mods ...QueryMod) {{$tableNameSingular}}Query {
mods = append(mods, boil.From("{{.Table.Name}}"))
return NewQueryX(exec, mods...)
} }

View file

@ -4,14 +4,24 @@
// Delete deletes a single {{$tableNameSingular}} record. // Delete deletes a single {{$tableNameSingular}} record.
// Delete will match against the primary key column to find the record to delete. // Delete will match against the primary key column to find the record to delete.
func (o *{{$tableNameSingular}}) Delete(mods ...QueryMod) error { func (o *{{$tableNameSingular}}) Delete(mods ...QueryMod) error {
_, err := db.Exec("DELETE FROM {{.Table.Name}} WHERE {{wherePrimaryKey .Table.PKey.Columns 1}}", {{paramsPrimaryKey "o." .Table.PKey.Columns true}}) return o.DeleteX(boil.GetDB(), mods...)
}
func (o *{{$tableNameSingular}}) DeleteX(exec boil.Executor, mods ...QueryMod) error {
mods = append(mods,
boil.From("{{.table.Name}}"),
boil.Where("{{wherePrimaryKey .Table.Pkey.Columns 1}}", {{paramsPrimaryKey "o." .Table.PKey.Columns true}}),
)
query := NewQueryX(exec, mods...)
_, err := exec.Exec("DELETE FROM {{.Table.Name}} WHERE {{wherePrimaryKey .Table.PKey.Columns 1}}", {{paramsPrimaryKey "o." .Table.PKey.Columns true}})
if err != nil { if err != nil {
return fmt.Errorf("{{.PkgName}}: unable to delete from {{.Table.Name}}: %s", err) return fmt.Errorf("{{.PkgName}}: unable to delete from {{.Table.Name}}: %s", err)
} }
return nil return nil
} }
{{- end}}
func (o {{$varNameSingular}}Query) DeleteAll() error { func (o {{$varNameSingular}}Query) DeleteAll() error {
_, err := db.Exec("DELETE FROM {{.Table.Name}} WHERE {{wherePrimaryKey .Table.PKey.Columns 1}}", {{paramsPrimaryKey "o." .Table.PKey.Columns true}}) _, err := db.Exec("DELETE FROM {{.Table.Name}} WHERE {{wherePrimaryKey .Table.PKey.Columns 1}}", {{paramsPrimaryKey "o." .Table.PKey.Columns true}})
@ -21,3 +31,4 @@ func (o {{$varNameSingular}}Query) DeleteAll() error {
return nil return nil
} }
{{- end}}

View file

@ -1,6 +1,6 @@
{{- $tableNameSingular := titleCaseSingular .Table.Name -}} {{- $tableNameSingular := titleCaseSingular .Table.Name -}}
// {{$tableNameSingular}}Insert inserts a single record. // {{$tableNameSingular}}Insert inserts a single record.
func (o *{{$tableNameSingular}}) Insert(mods ...QueryMod) error { func (o *{{$tableNameSingular}}) Insert(whitelist ... string) error {
if o == nil { if o == nil {
return 0, errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion") return 0, errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
} }
@ -23,7 +23,7 @@ func (o *{{$tableNameSingular}}) Insert(mods ...QueryMod) error {
return rowID, nil return rowID, nil
} }
func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, mods ...QueryMod) error { func (o *{{$tableNameSingular}}) InsertX(exec boil.Executor, whitelist ... string) error {
if o == nil { if o == nil {
return 0, errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion") return 0, errors.New("{{.PkgName}}: no {{.Table.Name}} provided for insertion")
} }

View file

@ -0,0 +1,15 @@
// M type is for providing where filters to Where helpers.
type M map[string]interface{}
// NewQuery initializes a new Query using the passed in QueryMods
func NewQuery(mods ...qs.QueryMod) *boil.Query {
return NewQueryX(boil.GetDB(), mods...)
}
// NewQueryX initializes a new Query using the passed in QueryMods
func NewQueryX(executor boil.Executor, mods ...qs.QueryMod) *boil.Query {
q := &Query{executor: executor}
q.Apply(mods...)
return q
}

View file

@ -38,5 +38,4 @@ func (o *{{$tableNameSingular}}) UpdateX(exec boil.Executor, whitelist ... strin
func (v {{$varNameSingular}}Query) UpdateAll(cols boil.M) error { func (v {{$varNameSingular}}Query) UpdateAll(cols boil.M) error {
} }
{{- end}} {{- end}}

View file

@ -17,13 +17,17 @@ type templater []*template.Template
// the database driver chosen by the driver flag at runtime, and a pointer to the // the database driver chosen by the driver flag at runtime, and a pointer to the
// output file, if one is specified with a flag. // output file, if one is specified with a flag.
type CmdData struct { type CmdData struct {
Tables []dbdrivers.Table Tables []dbdrivers.Table
PkgName string PkgName string
OutFolder string OutFolder string
Interface dbdrivers.Interface Interface dbdrivers.Interface
DriverName string DriverName string
Config *Config Config *Config
Templates templater
Templates templater
// SingleTemplates are only created once, not per table
SingleTemplates templater
TestTemplates templater TestTemplates templater
TestMainTemplate *template.Template TestMainTemplate *template.Template
} }