Move everything to better package structure

This commit is contained in:
Aaron L 2016-09-14 20:45:09 -07:00
parent f6b4d3c6fd
commit 5149df8359
40 changed files with 241 additions and 86 deletions

View file

@ -153,7 +153,7 @@ var defaultTemplateImports = imports{
thirdParty: importList{
`"github.com/pkg/errors"`,
`"github.com/vattle/sqlboiler/boil"`,
`"github.com/vattle/sqlboiler/boil/qm"`,
`"github.com/vattle/sqlboiler/queries/qm"`,
`"github.com/vattle/sqlboiler/strmangle"`,
},
}
@ -162,7 +162,7 @@ var defaultSingletonTemplateImports = map[string]imports{
"boil_queries": {
thirdParty: importList{
`"github.com/vattle/sqlboiler/boil"`,
`"github.com/vattle/sqlboiler/boil/qm"`,
`"github.com/vattle/sqlboiler/queries/qm"`,
},
},
"boil_types": {
@ -180,7 +180,7 @@ var defaultTestTemplateImports = imports{
},
thirdParty: importList{
`"github.com/vattle/sqlboiler/boil"`,
`"github.com/vattle/sqlboiler/boil/randomize"`,
`"github.com/vattle/sqlboiler/randomize"`,
`"github.com/vattle/sqlboiler/strmangle"`,
},
}
@ -240,7 +240,7 @@ var defaultTestMainImports = map[string]imports{
`"github.com/pkg/errors"`,
`"github.com/spf13/viper"`,
`"github.com/vattle/sqlboiler/bdb/drivers"`,
`"github.com/vattle/sqlboiler/boil/randomize"`,
`"github.com/vattle/sqlboiler/randomize"`,
`_ "github.com/lib/pq"`,
},
},
@ -259,7 +259,7 @@ var defaultTestMainImports = map[string]imports{
`"github.com/pkg/errors"`,
`"github.com/spf13/viper"`,
`"github.com/vattle/sqlboiler/bdb/drivers"`,
`"github.com/vattle/sqlboiler/boil/randomize"`,
`"github.com/vattle/sqlboiler/randomize"`,
`_ "github.com/go-sql-driver/mysql"`,
},
},
@ -324,21 +324,21 @@ var importsBasedOnType = map[string]imports{
standard: importList{`"time"`},
},
"types.JSON": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
"types.BytesArray": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
"types.Int64Array": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
"types.Float64Array": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
"types.BoolArray": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
"types.Hstore": {
thirdParty: importList{`"github.com/vattle/sqlboiler/boil/types"`},
thirdParty: importList{`"github.com/vattle/sqlboiler/types"`},
},
}

148
queries/eager_load.go Normal file
View file

@ -0,0 +1,148 @@
package queries
import (
"database/sql"
"reflect"
"github.com/pkg/errors"
"github.com/vattle/sqlboiler/boil"
"github.com/vattle/sqlboiler/strmangle"
)
type loadRelationshipState struct {
exec boil.Executor
loaded map[string]struct{}
toLoad []string
}
func (l loadRelationshipState) hasLoaded(depth int) bool {
_, ok := l.loaded[l.buildKey(depth)]
return ok
}
func (l loadRelationshipState) setLoaded(depth int) {
l.loaded[l.buildKey(depth)] = struct{}{}
}
func (l loadRelationshipState) buildKey(depth int) string {
buf := strmangle.GetBuffer()
for i, piece := range l.toLoad[:depth+1] {
if i != 0 {
buf.WriteByte('.')
}
buf.WriteString(piece)
}
str := buf.String()
strmangle.PutBuffer(buf)
return str
}
// loadRelationships dynamically calls the template generated eager load
// functions of the form:
//
// func (t *TableR) LoadRelationshipName(exec Executor, singular bool, obj interface{})
//
// The arguments to this function are:
// - t is not considered here, and is always passed nil. The function exists on a loaded
// struct to avoid a circular dependency with boil, and the receiver is ignored.
// - exec is used to perform additional queries that might be required for loading the relationships.
// - singular is passed in to identify whether or not this was a single object
// or a slice that must be loaded into.
// - obj is the object or slice of objects, always of the type *obj or *[]*obj as per bind.
//
// It takes list of nested relationships to load.
func (l loadRelationshipState) loadRelationships(depth int, obj interface{}, bkind bindKind) error {
typ := reflect.TypeOf(obj).Elem()
if bkind == kindPtrSliceStruct {
typ = typ.Elem().Elem()
}
if !l.hasLoaded(depth) {
current := l.toLoad[depth]
ln, found := typ.FieldByName(loaderStructName)
// It's possible a Loaders struct doesn't exist on the struct.
if !found {
return errors.Errorf("attempted to load %s but no L struct was found", current)
}
// Attempt to find the LoadRelationshipName function
loadMethod, found := ln.Type.MethodByName(loadMethodPrefix + current)
if !found {
return errors.Errorf("could not find %s%s method for eager loading", loadMethodPrefix, current)
}
// Hack to allow nil executors
execArg := reflect.ValueOf(l.exec)
if !execArg.IsValid() {
execArg = reflect.ValueOf((*sql.DB)(nil))
}
val := reflect.ValueOf(obj).Elem()
if bkind == kindPtrSliceStruct {
val = val.Index(0).Elem()
}
methodArgs := []reflect.Value{
val.FieldByName(loaderStructName),
execArg,
reflect.ValueOf(bkind == kindStruct),
reflect.ValueOf(obj),
}
resp := loadMethod.Func.Call(methodArgs)
if intf := resp[0].Interface(); intf != nil {
return errors.Wrapf(intf.(error), "failed to eager load %s", current)
}
l.setLoaded(depth)
}
// Pull one off the queue, continue if there's still some to go
depth++
if depth >= len(l.toLoad) {
return nil
}
loadedObject := reflect.ValueOf(obj)
// If we eagerly loaded nothing
if loadedObject.IsNil() {
return nil
}
loadedObject = reflect.Indirect(loadedObject)
// If it's singular we can just immediately call without looping
if bkind == kindStruct {
return l.loadRelationshipsRecurse(depth, loadedObject)
}
// Loop over all eager loaded objects
ln := loadedObject.Len()
if ln == 0 {
return nil
}
for i := 0; i < ln; i++ {
iter := loadedObject.Index(i).Elem()
if err := l.loadRelationshipsRecurse(depth, iter); err != nil {
return err
}
}
return nil
}
// loadRelationshipsRecurse is a helper function for taking a reflect.Value and
// Basically calls loadRelationships with: obj.R.EagerLoadedObj, and whether it's a string or slice
func (l loadRelationshipState) loadRelationshipsRecurse(depth int, obj reflect.Value) error {
r := obj.FieldByName(relationshipStructName)
if !r.IsValid() || r.IsNil() {
return errors.Errorf("could not traverse into loaded %s relationship to load more things", l.toLoad[depth])
}
newObj := reflect.Indirect(r).FieldByName(l.toLoad[depth])
bkind := kindStruct
if reflect.Indirect(newObj).Kind() != reflect.Struct {
bkind = kindPtrSliceStruct
newObj = newObj.Addr()
}
return l.loadRelationships(depth, newObj.Interface(), bkind)
}

View file

@ -1,6 +1,10 @@
package boil
package queries
import "testing"
import (
"testing"
"github.com/vattle/sqlboiler/boil"
)
var loadFunctionCalled bool
var loadFunctionNestedCalled int
@ -32,12 +36,12 @@ type testNestedRSlice struct {
type testNestedLSlice struct {
}
func (testLStruct) LoadTestOne(exec Executor, singular bool, obj interface{}) error {
func (testLStruct) LoadTestOne(exec boil.Executor, singular bool, obj interface{}) error {
loadFunctionCalled = true
return nil
}
func (testNestedLStruct) LoadToEagerLoad(exec Executor, singular bool, obj interface{}) error {
func (testNestedLStruct) LoadToEagerLoad(exec boil.Executor, singular bool, obj interface{}) error {
switch x := obj.(type) {
case *testNestedStruct:
x.R = &testNestedRStruct{
@ -54,7 +58,7 @@ func (testNestedLStruct) LoadToEagerLoad(exec Executor, singular bool, obj inter
return nil
}
func (testNestedLSlice) LoadToEagerLoad(exec Executor, singular bool, obj interface{}) error {
func (testNestedLSlice) LoadToEagerLoad(exec boil.Executor, singular bool, obj interface{}) error {
switch x := obj.(type) {
case *testNestedSlice:

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"fmt"

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"reflect"

View file

@ -1,12 +1,12 @@
package qm
import "github.com/vattle/sqlboiler/boil"
import "github.com/vattle/sqlboiler/queries"
// QueryMod to modify the query object
type QueryMod func(q *boil.Query)
type QueryMod func(q *queries.Query)
// Apply the query mods to the Query object
func Apply(q *boil.Query, mods ...QueryMod) {
func Apply(q *queries.Query, mods ...QueryMod) {
for _, mod := range mods {
mod(q)
}
@ -14,8 +14,8 @@ func Apply(q *boil.Query, mods ...QueryMod) {
// SQL allows you to execute a plain SQL statement
func SQL(sql string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.SetSQL(q, sql, args...)
return func(q *queries.Query) {
queries.SetSQL(q, sql, args...)
}
}
@ -25,29 +25,29 @@ func SQL(sql string, args ...interface{}) QueryMod {
// Relationship name plurality is important, if your relationship is
// singular, you need to specify the singular form and vice versa.
func Load(relationships ...string) QueryMod {
return func(q *boil.Query) {
boil.SetLoad(q, relationships...)
return func(q *queries.Query) {
queries.SetLoad(q, relationships...)
}
}
// InnerJoin on another table
func InnerJoin(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendInnerJoin(q, clause, args...)
return func(q *queries.Query) {
queries.AppendInnerJoin(q, clause, args...)
}
}
// Select specific columns opposed to all columns
func Select(columns ...string) QueryMod {
return func(q *boil.Query) {
boil.AppendSelect(q, columns...)
return func(q *queries.Query) {
queries.AppendSelect(q, columns...)
}
}
// Where allows you to specify a where clause for your statement
func Where(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendWhere(q, clause, args...)
return func(q *queries.Query) {
queries.AppendWhere(q, clause, args...)
}
}
@ -55,24 +55,24 @@ func Where(clause string, args ...interface{}) QueryMod {
// And is a duplicate of the Where function, but allows for more natural looking
// query mod chains, for example: (Where("a=?"), And("b=?"), Or("c=?")))
func And(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendWhere(q, clause, args...)
return func(q *queries.Query) {
queries.AppendWhere(q, clause, args...)
}
}
// Or allows you to specify a where clause separated by an OR for your statement
func Or(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendWhere(q, clause, args...)
boil.SetLastWhereAsOr(q)
return func(q *queries.Query) {
queries.AppendWhere(q, clause, args...)
queries.SetLastWhereAsOr(q)
}
}
// WhereIn allows you to specify a "x IN (set)" clause for your where statement
// Example clauses: "column in ?", "(column1,column2) in ?"
func WhereIn(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendIn(q, clause, args...)
return func(q *queries.Query) {
queries.AppendIn(q, clause, args...)
}
}
@ -81,65 +81,65 @@ func WhereIn(clause string, args ...interface{}) QueryMod {
// allows for more natural looking query mod chains, for example:
// (WhereIn("column1 in ?"), AndIn("column2 in ?"), OrIn("column3 in ?"))
func AndIn(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendIn(q, clause, args...)
return func(q *queries.Query) {
queries.AppendIn(q, clause, args...)
}
}
// OrIn allows you to specify an IN clause separated by
// an OR for your where statement
func OrIn(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendIn(q, clause, args...)
boil.SetLastInAsOr(q)
return func(q *queries.Query) {
queries.AppendIn(q, clause, args...)
queries.SetLastInAsOr(q)
}
}
// GroupBy allows you to specify a group by clause for your statement
func GroupBy(clause string) QueryMod {
return func(q *boil.Query) {
boil.AppendGroupBy(q, clause)
return func(q *queries.Query) {
queries.AppendGroupBy(q, clause)
}
}
// OrderBy allows you to specify a order by clause for your statement
func OrderBy(clause string) QueryMod {
return func(q *boil.Query) {
boil.AppendOrderBy(q, clause)
return func(q *queries.Query) {
queries.AppendOrderBy(q, clause)
}
}
// Having allows you to specify a having clause for your statement
func Having(clause string, args ...interface{}) QueryMod {
return func(q *boil.Query) {
boil.AppendHaving(q, clause, args...)
return func(q *queries.Query) {
queries.AppendHaving(q, clause, args...)
}
}
// From allows to specify the table for your statement
func From(from string) QueryMod {
return func(q *boil.Query) {
boil.AppendFrom(q, from)
return func(q *queries.Query) {
queries.AppendFrom(q, from)
}
}
// Limit the number of returned rows
func Limit(limit int) QueryMod {
return func(q *boil.Query) {
boil.SetLimit(q, limit)
return func(q *queries.Query) {
queries.SetLimit(q, limit)
}
}
// Offset into the results
func Offset(offset int) QueryMod {
return func(q *boil.Query) {
boil.SetOffset(q, offset)
return func(q *queries.Query) {
queries.SetOffset(q, offset)
}
}
// For inserts a concurrency locking clause at the end of your statement
func For(clause string) QueryMod {
return func(q *boil.Query) {
boil.SetFor(q, clause)
return func(q *queries.Query) {
queries.SetFor(q, clause)
}
}

View file

@ -1,8 +1,10 @@
package boil
package queries
import (
"database/sql"
"fmt"
"github.com/vattle/sqlboiler/boil"
)
// joinKind is the type of join
@ -18,7 +20,7 @@ const (
// Query holds the state for the built up query
type Query struct {
executor Executor
executor boil.Executor
dialect *Dialect
plainSQL plainSQL
load []string
@ -81,7 +83,7 @@ type join struct {
}
// SQL makes a plainSQL query, usually for use with bind
func SQL(exec Executor, query string, args ...interface{}) *Query {
func SQL(exec boil.Executor, query string, args ...interface{}) *Query {
return &Query{
executor: exec,
plainSQL: plainSQL{
@ -91,17 +93,17 @@ func SQL(exec Executor, query string, args ...interface{}) *Query {
}
}
// SQLG makes a plainSQL query using the global Executor, usually for use with bind
// SQLG makes a plainSQL query using the global boil.Executor, usually for use with bind
func SQLG(query string, args ...interface{}) *Query {
return SQL(GetDB(), query, args...)
return SQL(boil.GetDB(), query, args...)
}
// Exec executes a query that does not need a row returned
func (q *Query) Exec() (sql.Result, error) {
qs, args := buildQuery(q)
if DebugMode {
fmt.Fprintln(DebugWriter, qs)
fmt.Fprintln(DebugWriter, args)
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, qs)
fmt.Fprintln(boil.DebugWriter, args)
}
return q.executor.Exec(qs, args...)
}
@ -109,9 +111,9 @@ func (q *Query) Exec() (sql.Result, error) {
// QueryRow executes the query for the One finisher and returns a row
func (q *Query) QueryRow() *sql.Row {
qs, args := buildQuery(q)
if DebugMode {
fmt.Fprintln(DebugWriter, qs)
fmt.Fprintln(DebugWriter, args)
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, qs)
fmt.Fprintln(boil.DebugWriter, args)
}
return q.executor.QueryRow(qs, args...)
}
@ -119,9 +121,9 @@ func (q *Query) QueryRow() *sql.Row {
// Query executes the query for the All finisher and returns multiple rows
func (q *Query) Query() (*sql.Rows, error) {
qs, args := buildQuery(q)
if DebugMode {
fmt.Fprintln(DebugWriter, qs)
fmt.Fprintln(DebugWriter, args)
if boil.DebugMode {
fmt.Fprintln(boil.DebugWriter, qs)
fmt.Fprintln(boil.DebugWriter, args)
}
return q.executor.Query(qs, args...)
}
@ -131,7 +133,7 @@ func (q *Query) Query() (*sql.Rows, error) {
func (q *Query) ExecP() sql.Result {
res, err := q.Exec()
if err != nil {
panic(WrapErr(err))
panic(boil.WrapErr(err))
}
return res
@ -142,19 +144,19 @@ func (q *Query) ExecP() sql.Result {
func (q *Query) QueryP() *sql.Rows {
rows, err := q.Query()
if err != nil {
panic(WrapErr(err))
panic(boil.WrapErr(err))
}
return rows
}
// SetExecutor on the query.
func SetExecutor(q *Query, exec Executor) {
func SetExecutor(q *Query, exec boil.Executor) {
q.executor = exec
}
// GetExecutor on the query.
func GetExecutor(q *Query) Executor {
func GetExecutor(q *Query) boil.Executor {
return q.executor
}

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"bytes"

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"bytes"

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"database/sql"

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"database/sql"
@ -8,6 +8,7 @@ import (
"sync"
"github.com/pkg/errors"
"github.com/vattle/sqlboiler/boil"
"github.com/vattle/sqlboiler/strmangle"
)
@ -40,7 +41,7 @@ const (
// It panics on error. See boil.Bind() documentation.
func (q *Query) BindP(obj interface{}) {
if err := q.Bind(obj); err != nil {
panic(WrapErr(err))
panic(boil.WrapErr(err))
}
}

View file

@ -1,4 +1,4 @@
package boil
package queries
import (
"database/sql/driver"

View file

@ -17,8 +17,8 @@ import (
"github.com/lib/pq/hstore"
"github.com/pkg/errors"
"github.com/satori/go.uuid"
"github.com/vattle/sqlboiler/boil/types"
"github.com/vattle/sqlboiler/strmangle"
"github.com/vattle/sqlboiler/types"
)
var (

View file

@ -15,7 +15,7 @@ import (
"github.com/pkg/errors"
"github.com/vattle/sqlboiler/bdb"
"github.com/vattle/sqlboiler/bdb/drivers"
"github.com/vattle/sqlboiler/boil"
"github.com/vattle/sqlboiler/queries"
"github.com/vattle/sqlboiler/strmangle"
)
@ -35,7 +35,7 @@ type State struct {
Driver bdb.Interface
Tables []bdb.Table
Dialect boil.Dialect
Dialect queries.Dialect
Templates *templateList
TestTemplates *templateList

View file

@ -8,7 +8,7 @@ import (
"text/template"
"github.com/vattle/sqlboiler/bdb"
"github.com/vattle/sqlboiler/boil"
"github.com/vattle/sqlboiler/queries"
"github.com/vattle/sqlboiler/strmangle"
)
@ -36,7 +36,7 @@ type templateData struct {
StringFuncs map[string]func(string) string
// Dialect controls quoting
Dialect boil.Dialect
Dialect queries.Dialect
LQ string
RQ string
}