func (q *BaseQuery) ToSql() (string, []interface{}, error) {
	_, builder := q.compile()
	return builder.ToSql()
}
ToSql returns the SQL generated by the query, the query arguments, and
any error returned during the compile process.
package kallax
import (
	"errors"
	"fmt"
	"github.com/Masterminds/squirrel"
)
var (
	ErrManyToManyNotSupported = errors.New("kallax: many to many relationships are not supported")
)
type Query interface {
	compile() ([]string, squirrel.SelectBuilder)
	getRelationships() []Relationship
	isReadOnly() bool
	Schema() Schema
	GetOffset() uint64
	GetLimit() uint64
	GetBatchSize() uint64
}
type columnSet []SchemaField
func (cs columnSet) contains(col SchemaField) bool {
	for _, c := range cs {
		if c.String() == col.String() {
			return true
		}
	}
	return false
}
func (cs *columnSet) add(cols ...SchemaField) {
	for _, col := range cols {
		cs.addCol(col)
	}
}
func (cs *columnSet) addCol(col SchemaField) {
	if !cs.contains(col) {
		*cs = append(*cs, col)
	}
}
func (cs *columnSet) remove(cols ...SchemaField) {
	var newSet = make(columnSet, 0, len(*cs))
	toRemove := columnSet(cols)
	for _, col := range *cs {
		if !toRemove.contains(col) {
			newSet = append(newSet, col)
		}
	}
	*cs = newSet
}
func (cs columnSet) copy() []SchemaField {
	var result = make(columnSet, len(cs))
	for i, col := range cs {
		result[i] = col
	}
	return result
}
type BaseQuery struct {
	schema          Schema
	columns         columnSet
	excludedColumns columnSet
	relationColumns []string
	relationships   []Relationship
	builder         squirrel.SelectBuilder
	selectChanged bool
	batchSize     uint64
	offset        uint64
	limit         uint64
}
func NewBaseQuery(schema Schema) *BaseQuery {
	return &BaseQuery{
		builder: squirrel.StatementBuilder.
			PlaceholderFormat(squirrel.Dollar).
			Select().
			From(schema.Table() + " " + schema.Alias()),
		columns:   columnSet(schema.Columns()),
		batchSize: 50,
		schema:    schema,
	}
}
func (q *BaseQuery) Schema() Schema {
	return q.schema
}
func (q *BaseQuery) isReadOnly() bool {
	return q.selectChanged
}
func (q *BaseQuery) Select(columns ...SchemaField) {
	if !q.selectChanged {
		q.columns = columnSet{}
		q.selectChanged = true
	}
	q.excludedColumns.remove(columns...)
	q.columns.add(columns...)
}
func (q *BaseQuery) SelectNot(columns ...SchemaField) {
	q.excludedColumns.add(columns...)
}
func (q *BaseQuery) Copy() *BaseQuery {
	return &BaseQuery{
		builder:         q.builder,
		columns:         q.columns.copy(),
		excludedColumns: q.excludedColumns.copy(),
		relationColumns: q.relationColumns[:],
		relationships:   q.relationships[:],
		selectChanged:   q.selectChanged,
		batchSize:       q.GetBatchSize(),
		limit:           q.GetLimit(),
		offset:          q.GetOffset(),
		schema:          q.schema,
	}
}
func (q *BaseQuery) getRelationships() []Relationship {
	return q.relationships
}
func (q *BaseQuery) selectedColumns() []SchemaField {
	var result = make([]SchemaField, 0, len(q.columns))
	for _, col := range q.columns {
		if !q.excludedColumns.contains(col) {
			result = append(result, col)
		}
	}
	return result
}
func (q *BaseQuery) AddRelation(schema Schema, field string, typ RelationshipType, filter Condition) error {
	if typ == ManyToMany {
		return ErrManyToManyNotSupported
	}
	fk, ok := q.schema.ForeignKey(field)
	if !ok {
		return fmt.Errorf(
			"kallax: cannot find foreign key to join tables %s and %s",
			q.schema.Table(), schema.Table(),
		)
	}
	schema = schema.WithAlias(field)
	if typ == OneToOne {
		q.join(schema, fk)
	}
	q.relationships = append(q.relationships, Relationship{typ, field, schema, filter})
	return nil
}
func (q *BaseQuery) join(schema Schema, fk *ForeignKey) {
	fkCol := fk.QualifiedName(schema)
	idCol := q.schema.ID().QualifiedName(q.schema)
	if fk.Inverse {
		fkCol = schema.ID().QualifiedName(schema)
		idCol = fk.QualifiedName(q.schema)
	}
	q.builder = q.builder.LeftJoin(fmt.Sprintf(
		"%s %s ON (%s = %s)",
		schema.Table(),
		schema.Alias(),
		fkCol,
		idCol,
	))
	for _, col := range schema.Columns() {
		q.relationColumns = append(
			q.relationColumns,
			col.QualifiedName(schema),
		)
	}
}
func (q *BaseQuery) Order(cols ...ColumnOrder) {
	var c = make([]string, len(cols))
	for i, v := range cols {
		c[i] = v.ToSql(q.schema)
	}
	q.builder = q.builder.OrderBy(c...)
}
func (q *BaseQuery) BatchSize(size uint64) {
	q.batchSize = size
}
func (q *BaseQuery) GetBatchSize() uint64 {
	return q.batchSize
}
func (q *BaseQuery) Limit(n uint64) {
	q.limit = n
}
func (q *BaseQuery) GetLimit() uint64 {
	return q.limit
}
func (q *BaseQuery) Offset(n uint64) {
	q.offset = n
}
func (q *BaseQuery) GetOffset() uint64 {
	return q.offset
}
func (q *BaseQuery) Where(cond Condition) {
	q.builder = q.builder.Where(cond(q.schema))
}
func (q *BaseQuery) compile() ([]string, squirrel.SelectBuilder) {
	columns := q.selectedColumns()
	var (
		qualifiedColumns = make([]string, len(columns))
		columnNames      = make([]string, len(columns))
	)
	for i := range columns {
		qualifiedColumns[i] = columns[i].QualifiedName(q.schema)
		columnNames[i] = columns[i].String()
	}
	return columnNames, q.builder.Columns(
		append(qualifiedColumns, q.relationColumns...)...,
	)
}
func (q *BaseQuery) String() string {
	_, builder := q.compile()
	sql, _, _ := builder.ToSql()
	return sql
}