func buildWhere(b *builder.Builder, table string, w Where, j []JoinParams) {
	first := true
	whereRec(b, table, w, j, &first)
}
buildWhere returns a WHERE statement
package dialect
import (
	"context"
	"fmt"
	"github.com/posener/orm"
	"github.com/posener/orm/dialect/builder"
	"github.com/posener/orm/dialect/mysql"
	"github.com/posener/orm/dialect/postgres"
	"github.com/posener/orm/dialect/sqlite3"
	"github.com/posener/orm/dialect/sqltypes"
	"github.com/posener/orm/load"
)
const (
	Mysql    = "mysql"
	Postgres = "postgres"
	Sqlite3  = "sqlite3"
)
type API interface {
	Name() string
	Create(orm.Conn, *CreateParams) ([]string, error)
	Insert(*InsertParams) (string, []interface{})
	Select(*SelectParams) (string, []interface{})
	Delete(*DeleteParams) (string, []interface{})
	Update(*UpdateParams) (string, []interface{})
	Drop(*DropParams) (string, []interface{})
}
type Dialect interface {
	Name() string
	GoTypeToColumnType(goType string, autoIncrement bool) *sqltypes.Type
	Translate(string) string
	ConvertValueCode(*load.Field) string
	Quote(string) string
	Var(int) string
}
var dialects = map[string]API{
	Mysql:    &dialect{name: Mysql, Dialect: new(mysql.Dialect)},
	Postgres: &dialect{name: Postgres, Dialect: new(postgres.Dialect)},
	Sqlite3:  &dialect{name: Sqlite3, Dialect: new(sqlite3.Dialect)},
}
func All() []API {
	var all []API
	for _, d := range dialects {
		all = append(all, d)
	}
	return all
}
func Get(name string) API {
	return dialects[name]
}
type dialect struct {
	Dialect
	name string
}
func (d *dialect) Create(conn orm.Conn, p *CreateParams) ([]string, error) {
	if p.Relations {
		return d.createRelationTables(conn, p)
	}
	return d.create(conn, p, p.Table, p.MarshaledTable)
}
func (d *dialect) create(conn orm.Conn, p *CreateParams, tableName, tableProperties string) ([]string, error) {
	table := new(Table)
	err := table.UnMarshal(tableProperties)
	if err != nil {
		return nil, fmt.Errorf("unmarshalling table properties: %s", err)
	}
	if p.AutoMigrate {
		stmts, ok, err := d.autoMigrate(p.Ctx, conn, tableName, table)
		if err != nil {
			return nil, fmt.Errorf("automigration: %s", err)
		}
		if ok {
			return stmts, nil
		}
	}
	b := builder.New(d, "CREATE TABLE")
	if p.IfNotExists {
		b.Append("IF NOT EXISTS")
	}
	b.Quote(tableName)
	b.Open()
	buildTable(b, d, table)
	b.Close()
	return []string{b.Statement()}, nil
}
func (d *dialect) createRelationTables(conn orm.Conn, p *CreateParams) ([]string, error) {
	var stmts []string
	for name, props := range p.MarshaledRelationTables {
		stmt, err := d.create(conn, p, name, props)
		if err != nil {
			return nil, fmt.Errorf("creating table %s: %s", name, err)
		}
		stmts = append(stmts, stmt...)
	}
	return stmts, nil
}
func (d *dialect) autoMigrate(ctx context.Context, conn orm.Conn, tableName string, want *Table) ([]string, bool, error) {
	got, err := d.loadTable(ctx, conn, tableName)
	if err != nil {
		return nil, false, err
	}
	if got == nil {
		return nil, false, nil
	}
	diff, err := got.Diff(want)
	if err != nil {
		return nil, false, fmt.Errorf("bad conditions: %s", err)
	}
	for len(diff.PrimaryKeys) > 0 {
		return nil, false, fmt.Errorf("not supported: add primary keys %s", diff.PrimaryKeys)
	}
	var stmts []string
	for _, col := range diff.Columns {
		b := builder.New(d, "ALTER TABLE")
		b.Quote(tableName)
		b.Append("ADD COLUMN")
		buildColumn(b, d, col)
		stmts = append(stmts, b.Statement())
	}
	for _, fk := range diff.ForeignKeys {
		b := builder.New(d, "ALTER TABLE")
		b.Quote(tableName)
		b.Append("ADD")
		buildForeignKey(b, fk)
		stmts = append(stmts, b.Statement())
	}
	return stmts, true, nil
}
func (d *dialect) Insert(p *InsertParams) (string, []interface{}) {
	b := builder.New(d, "INSERT INTO")
	b.Quote(p.Table)
	b.Open()
	for i, assignment := range p.Assignments {
		b.Append(d.Quote(assignment.Column))
		if i != len(p.Assignments)-1 {
			b.Comma()
		}
	}
	b.Close()
	b.Append("VALUES")
	b.Open()
	for i, arg := range p.Assignments.Args() {
		b.Var(arg)
		if i != len(p.Assignments.Args())-1 {
			b.Comma()
		}
	}
	b.Close()
	for i, col := range p.RetColumns {
		if i == 0 {
			b.Append("RETURNING")
		} else {
			b.Comma()
		}
		b.Quote(col)
	}
	return b.Statement(), b.Args()
}
func (d *dialect) Select(p *SelectParams) (string, []interface{}) {
	b := builder.New(d, "SELECT")
	buildSelectColumns(b, p)
	b.Append("FROM")
	b.Append(d.Quote(p.Table))
	buildJoin(b, p)
	buildWhere(b, p.Table, p.Where, p.Joins)
	buildGroupBy(b, p.Table, p)
	buildOrderBy(b, p.Table, p)
	buildPage(b, p.Page)
	return b.Statement(), b.Args()
}
func (d *dialect) Delete(p *DeleteParams) (string, []interface{}) {
	b := builder.New(d, "DELETE FROM")
	b.Append(d.Quote(p.Table))
	buildWhere(b, p.Table, p.Where, nil)
	return b.Statement(), b.Args()
}
func (d *dialect) Update(p *UpdateParams) (string, []interface{}) {
	b := builder.New(d, "UPDATE")
	b.Append(d.Quote(p.Table))
	b.Append("SET")
	for i, assign := range p.Assignments {
		b.Append(d.Quote(assign.Column))
		b.Append("=")
		b.Var(assign.ColumnValue)
		if i != len(p.Assignments)-1 {
			b.Comma()
		}
	}
	buildWhere(b, p.Table, p.Where, nil)
	return b.Statement(), b.Args()
}
func (d *dialect) Drop(p *DropParams) (string, []interface{}) {
	b := builder.New(d, "DROP TABLE")
	if p.IfExists {
		b.Append("IF EXISTS")
	}
	b.Append(d.Quote(p.Table))
	return b.Statement(), b.Args()
}
func buildTable(b *builder.Builder, d Dialect, t *Table) {
	for i, col := range t.Columns {
		buildColumn(b, d, col)
		if i != len(t.Columns)-1 {
			b.Comma()
		}
	}
	if len(t.PrimaryKeys) > 0 {
		b.Comma()
		b.Append("PRIMARY KEY")
		b.Open()
		buildQuoteSlice(b, t.PrimaryKeys...)
		b.Close()
	}
	if len(t.ForeignKeys) > 0 {
		b.Comma()
		for i, fk := range t.ForeignKeys {
			buildForeignKey(b, fk)
			if i != len(t.ForeignKeys)-1 {
				b.Comma()
			}
		}
	}
}
func buildColumn(b *builder.Builder, d Dialect, col Column) {
	b.Quote(col.Name)
	b.Append(d.GoTypeToColumnType(col.GoType, hasAutoIncrement(col.Options)).String())
	for _, opt := range col.Options {
		b.Append(d.Translate(opt))
	}
}
func buildForeignKey(b *builder.Builder, fk ForeignKey) {
	b.Append("FOREIGN KEY")
	b.Open()
	buildQuoteSlice(b, fk.Columns...)
	b.Close()
	b.Append("REFERENCES")
	b.Quote(fk.Table)
	b.Open()
	buildQuoteSlice(b, fk.ForeignColumns...)
	b.Close()
}
func hasAutoIncrement(options []string) bool {
	for _, opt := range options {
		if opt == "AUTO_INCREMENT" {
			return true
		}
	}
	return false
}
func buildSelectColumns(b *builder.Builder, p *SelectParams) {
	first := true
	columnRec(b, p.Table, p, &first)
	if p.Count {
		if !first {
			b.Comma()
		}
		b.Append("COUNT(*)")
	}
}
func columnRec(b *builder.Builder, table string, p *SelectParams, first *bool) {
	cols := p.SelectedColumns()
	for _, col := range cols {
		if !*first {
			b.Comma()
		}
		b.QuoteFullName(table, col)
		*first = false
	}
	for _, join := range p.Joins {
		columnRec(b, join.TableName(table), &join.SelectParams, first)
	}
}