Column types refactoring.

This commit is contained in:
zer0sub 2019-03-31 14:07:58 +02:00
parent 38007810c1
commit 033ab1d0da
19 changed files with 746 additions and 396 deletions

View file

@ -20,9 +20,9 @@ func NewAlias(expression Expression, alias string) *Alias {
}
}
func (a *Alias) SerializeSql(out *bytes.Buffer) error {
func (a *Alias) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
err := a.expression.SerializeSql(out)
err := a.expression.SerializeSql(out, ALIASED)
if err != nil {
return err

View file

@ -11,6 +11,11 @@ import (
type BoolExpression interface {
Expression
Eq(expression BoolExpression) BoolExpression
NotEq(expression BoolExpression) BoolExpression
GtEq(rhs Expression) BoolExpression
LtEq(rhs Expression) BoolExpression
And(expression BoolExpression) BoolExpression
Or(expression BoolExpression) BoolExpression
IsTrue() BoolExpression
@ -21,6 +26,22 @@ type boolInterfaceImpl struct {
parent BoolExpression
}
func (b *boolInterfaceImpl) Eq(expression BoolExpression) BoolExpression {
return Eq(b.parent, expression)
}
func (b *boolInterfaceImpl) NotEq(expression BoolExpression) BoolExpression {
return Neq(b.parent, expression)
}
func (b *boolInterfaceImpl) GtEq(rhs Expression) BoolExpression {
return Gte(b.parent, rhs)
}
func (b *boolInterfaceImpl) LtEq(rhs Expression) BoolExpression {
return Lte(b.parent, rhs)
}
func (b *boolInterfaceImpl) And(expression BoolExpression) BoolExpression {
return And(b.parent, expression)
}
@ -42,7 +63,7 @@ type boolLiteralExpression struct {
literalExpression
}
func NewBoolLiteralExpression(value bool) BoolExpression {
func newBoolLiteralExpression(value bool) BoolExpression {
boolLiteralExpression := boolLiteralExpression{}
sqlValue, err := sqltypes.BuildValue(value)
@ -57,15 +78,17 @@ func NewBoolLiteralExpression(value bool) BoolExpression {
//---------------------------------------------------//
type binaryBoolExpression struct {
expressionInterfaceImpl
boolInterfaceImpl
binaryExpression
}
func NewBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpression {
func newBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpression {
boolExpression := binaryBoolExpression{}
boolExpression.binaryExpression = *NewBinaryExpression(lhs, rhs, operator, &boolExpression)
boolExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
boolExpression.expressionInterfaceImpl.parent = &boolExpression
boolExpression.boolInterfaceImpl.parent = &boolExpression
return &boolExpression
@ -73,15 +96,17 @@ func NewBinaryBoolExpression(lhs, rhs Expression, operator []byte) BoolExpressio
//---------------------------------------------------//
type prefixBoolExpression struct {
expressionInterfaceImpl
boolInterfaceImpl
prefixExpression
}
func NewPrefixBoolExpression(expression Expression, operator []byte) BoolExpression {
func newPrefixBoolExpression(expression Expression, operator []byte) BoolExpression {
boolExpression := prefixBoolExpression{}
boolExpression.prefixExpression = *NewPrefixExpression(expression, operator, &boolExpression)
boolExpression.prefixExpression = newPrefixExpression(expression, operator)
boolExpression.expressionInterfaceImpl.parent = &boolExpression
boolExpression.boolInterfaceImpl.parent = &boolExpression
return &boolExpression
@ -89,6 +114,7 @@ func NewPrefixBoolExpression(expression Expression, operator []byte) BoolExpress
//---------------------------------------------------//
type conjunctBoolExpression struct {
expressionInterfaceImpl
boolInterfaceImpl
conjunctExpression
@ -103,8 +129,8 @@ func NewConjunctBoolExpression(operator []byte, expressions ...BoolExpression) B
},
}
//boolExpression.expressionInterfaceImpl.parent = &boolExpression
//boolExpression.boolInterfaceImpl.parent = &boolExpression
boolExpression.expressionInterfaceImpl.parent = &boolExpression
boolExpression.boolInterfaceImpl.parent = &boolExpression
return &boolExpression
}
@ -120,7 +146,7 @@ type inExpression struct {
err error
}
func (c *inExpression) SerializeSql(out *bytes.Buffer) error {
func (c *inExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
if c.err != nil {
return errors.Wrap(c.err, "Invalid IN expression")
}
@ -159,9 +185,9 @@ func (c *inExpression) SerializeSql(out *bytes.Buffer) error {
func Eq(lhs, rhs Expression) BoolExpression {
lit, ok := rhs.(*literalExpression)
if ok && sqltypes.Value(lit.value).IsNull() {
return NewBinaryBoolExpression(lhs, rhs, []byte(" IS "))
return newBinaryBoolExpression(lhs, rhs, []byte(" IS "))
}
return NewBinaryBoolExpression(lhs, rhs, []byte(" = "))
return newBinaryBoolExpression(lhs, rhs, []byte(" = "))
}
// Returns a representation of "a=b", where b is a literal
@ -173,9 +199,9 @@ func EqL(lhs Expression, val interface{}) BoolExpression {
func Neq(lhs, rhs Expression) BoolExpression {
lit, ok := rhs.(*literalExpression)
if ok && sqltypes.Value(lit.value).IsNull() {
return NewBinaryBoolExpression(lhs, rhs, []byte(" IS NOT "))
return newBinaryBoolExpression(lhs, rhs, []byte(" IS NOT "))
}
return NewBinaryBoolExpression(lhs, rhs, []byte("!="))
return newBinaryBoolExpression(lhs, rhs, []byte("!="))
}
// Returns a representation of "a!=b", where b is a literal
@ -185,7 +211,7 @@ func NeqL(lhs Expression, val interface{}) BoolExpression {
// Returns a representation of "a<b"
func Lt(lhs Expression, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte("<"))
return newBinaryBoolExpression(lhs, rhs, []byte("<"))
}
// Returns a representation of "a<b", where b is a literal
@ -195,7 +221,7 @@ func LtL(lhs Expression, val interface{}) BoolExpression {
// Returns a representation of "a<=b"
func Lte(lhs, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte("<="))
return newBinaryBoolExpression(lhs, rhs, []byte("<="))
}
// Returns a representation of "a<=b", where b is a literal
@ -205,7 +231,7 @@ func LteL(lhs Expression, val interface{}) BoolExpression {
// Returns a representation of "a>b"
func Gt(lhs, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte(">"))
return newBinaryBoolExpression(lhs, rhs, []byte(">"))
}
// Returns a representation of "a>b", where b is a literal
@ -215,7 +241,7 @@ func GtL(lhs Expression, val interface{}) BoolExpression {
// Returns a representation of "a>=b"
func Gte(lhs, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte(">="))
return newBinaryBoolExpression(lhs, rhs, []byte(">="))
}
// Returns a representation of "a>=b", where b is a literal
@ -225,11 +251,11 @@ func GteL(lhs Expression, val interface{}) BoolExpression {
// Returns a representation of "not expr"
func Not(expr BoolExpression) BoolExpression {
return NewPrefixBoolExpression(expr, []byte(" NOT "))
return newPrefixBoolExpression(expr, []byte(" NOT "))
}
func IsTrue(expr BoolExpression) BoolExpression {
return NewPrefixBoolExpression(expr, []byte(" IS TRUE "))
return newPrefixBoolExpression(expr, []byte(" IS TRUE "))
}
// Returns a representation of "c[0] AND ... AND c[n-1]" for c in clauses
@ -243,7 +269,7 @@ func Or(expressions ...BoolExpression) BoolExpression {
}
func Like(lhs, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte(" LIKE "))
return newBinaryBoolExpression(lhs, rhs, []byte(" LIKE "))
}
func LikeL(lhs Expression, val string) BoolExpression {
@ -251,7 +277,7 @@ func LikeL(lhs Expression, val string) BoolExpression {
}
func Regexp(lhs, rhs Expression) BoolExpression {
return NewBinaryBoolExpression(lhs, rhs, []byte(" REGEXP "))
return newBinaryBoolExpression(lhs, rhs, []byte(" REGEXP "))
}
func RegexpL(lhs Expression, val string) BoolExpression {

View file

@ -97,7 +97,7 @@ func TestUnaryIsTrueExpression(t *testing.T) {
}
func TestBoolLiteral(t *testing.T) {
literal := NewBoolLiteralExpression(true)
literal := newBoolLiteralExpression(true)
out := bytes.Buffer{}
err := literal.SerializeSql(&out)

View file

@ -2,6 +2,22 @@ package sqlbuilder
import "bytes"
type serializeOption int
const (
ALIASED = iota
FOR_PROJECTION
)
type Clause interface {
SerializeSql(out *bytes.Buffer) error
SerializeSql(out *bytes.Buffer, options ...serializeOption) error
}
func contains(s []serializeOption, e serializeOption) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}

View file

@ -6,8 +6,6 @@ import (
"bytes"
"regexp"
"strings"
"github.com/dropbox/godropbox/errors"
)
// XXX: Maybe add UIntColumn
@ -15,31 +13,29 @@ import (
// Representation of a tableName for query generation
type Column interface {
Expression
isProjectionInterface
Name() string
TableName() string
// Serialization for use in column lists
SerializeSqlForColumnList(out *bytes.Buffer) error
// Internal function for tracking tableName that a column belongs to
// for the purpose of serialization
setTableName(table string) error
Eq(rhs Expression) BoolExpression
Neq(rhs Expression) BoolExpression
Gte(rhs Expression) BoolExpression
GteLiteral(rhs interface{}) BoolExpression
Lte(rhs Expression) BoolExpression
LteLiteral(rhs interface{}) BoolExpression
Asc() OrderByClause
Desc() OrderByClause
}
type columnInterfaceImpl struct {
parent Column
}
func (c *columnInterfaceImpl) Asc() OrderByClause {
return &orderByClause{expression: c.parent, ascent: true}
}
func (c *columnInterfaceImpl) Desc() OrderByClause {
return &orderByClause{expression: c.parent, ascent: false}
}
type NullableColumn bool
const (
@ -47,10 +43,10 @@ const (
NotNullable NullableColumn = false
)
// A column that can be refer to outside of the projection list
type NonAliasColumn interface {
Column
}
//// A column that can be refer to outside of the projection list
//type NonAliasColumn interface {
// Column
//}
type Collation string
@ -70,19 +66,25 @@ const (
// The base type for real materialized columns.
type baseColumn struct {
expressionInterfaceImpl
isProjection
columnInterfaceImpl
name string
nullable NullableColumn
tableName string
alias string
}
//func (c *baseColumn) As(alias string) Projection {
// newBaseColumn := *c
// newBaseColumn.alias = alias
//
// return &newBaseColumn
//}
func newBaseColumn(name string, nullable NullableColumn, tableName string, parent Column) baseColumn {
bc := baseColumn{
name: name,
nullable: nullable,
tableName: tableName,
}
bc.expressionInterfaceImpl.parent = parent
bc.columnInterfaceImpl.parent = parent
return bc
}
func (c *baseColumn) Name() string {
return c.name
@ -97,20 +99,7 @@ func (c *baseColumn) setTableName(table string) error {
return nil
}
func (c *baseColumn) SerializeSqlForColumnList(out *bytes.Buffer) error {
c.SerializeSql(out)
if c.alias != "" {
_, _ = out.WriteString(" AS \"" + c.alias + "\"")
} else if c.tableName != "" {
_, _ = out.WriteString(" AS \"" + c.tableName + "." + c.name + "\"")
}
return nil
}
func (c baseColumn) SerializeSql(out *bytes.Buffer) error {
func (c baseColumn) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
if c.tableName != "" {
_, _ = out.WriteString(c.tableName)
_, _ = out.WriteString(".")
@ -125,190 +114,163 @@ func (c baseColumn) SerializeSql(out *bytes.Buffer) error {
out.WriteString("\"")
}
if contains(options, FOR_PROJECTION) && !contains(options, ALIASED) && c.tableName != "" {
_, _ = out.WriteString(" AS \"" + c.tableName + "." + c.name + "\"")
}
return nil
}
func (c *baseColumn) Eq(rhs Expression) BoolExpression {
return Eq(c, rhs)
}
//
//type bytesColumn struct {
// baseColumn
//}
//
//// Representation of VARBINARY/BLOB columns
//// This function will panic if name is not valid
//func BytesColumn(name string, nullable NullableColumn) Column {
// if !validIdentifierName(name) {
// panic("Invalid column name in bytes column")
// }
// bc := &bytesColumn{}
// bc.name = name
// bc.nullable = nullable
// return bc
//}
//
//type stringColumn struct {
// baseColumn
// charset Charset
// collation Collation
//}
//
//// Representation of VARCHAR/TEXT columns
//// This function will panic if name is not valid
//func StrColumn(
// name string,
// charset Charset,
// collation Collation,
// nullable NullableColumn) Column {
//
// if !validIdentifierName(name) {
// panic("Invalid column name in str column")
// }
// sc := &stringColumn{charset: charset, collation: collation}
// sc.name = name
// sc.nullable = nullable
// return sc
//}
//
//type dateTimeColumn struct {
// baseColumn
//}
//
//// Representation of DateTime columns
//// This function will panic if name is not valid
//func DateTimeColumn(name string, nullable NullableColumn) Column {
// if !validIdentifierName(name) {
// panic("Invalid column name in datetime column")
// }
// dc := &dateTimeColumn{}
// dc.name = name
// dc.nullable = nullable
// return dc
//}
func (c *baseColumn) Neq(rhs Expression) BoolExpression {
return Neq(c, rhs)
}
//type IntegerColumn struct {
// baseColumn
//}
//
//// Representation of any integer column
//// This function will panic if name is not valid
//func IntColumn(name string, nullable NullableColumn) *IntegerColumn {
// if !validIdentifierName(name) {
// panic("Invalid column name in int column")
// }
// ic := &IntegerColumn{}
// ic.name = name
// ic.nullable = nullable
// return ic
//}
func (c *baseColumn) Gte(rhs Expression) BoolExpression {
return Gte(c, rhs)
}
func (c *baseColumn) GteLiteral(rhs interface{}) BoolExpression {
return Gte(c, Literal(rhs))
}
func (c *baseColumn) Lte(rhs Expression) BoolExpression {
return Lte(c, rhs)
}
func (c *baseColumn) LteLiteral(literal interface{}) BoolExpression {
return Lte(c, Literal(literal))
}
func (c *baseColumn) Asc() OrderByClause {
return Asc(c)
}
func (c *baseColumn) Desc() OrderByClause {
return Desc(c)
}
type bytesColumn struct {
baseColumn
}
// Representation of VARBINARY/BLOB columns
// This function will panic if name is not valid
func BytesColumn(name string, nullable NullableColumn) NonAliasColumn {
if !validIdentifierName(name) {
panic("Invalid column name in bytes column")
}
bc := &bytesColumn{}
bc.name = name
bc.nullable = nullable
return bc
}
type stringColumn struct {
baseColumn
charset Charset
collation Collation
}
// Representation of VARCHAR/TEXT columns
// This function will panic if name is not valid
func StrColumn(
name string,
charset Charset,
collation Collation,
nullable NullableColumn) NonAliasColumn {
if !validIdentifierName(name) {
panic("Invalid column name in str column")
}
sc := &stringColumn{charset: charset, collation: collation}
sc.name = name
sc.nullable = nullable
return sc
}
type dateTimeColumn struct {
baseColumn
}
// Representation of DateTime columns
// This function will panic if name is not valid
func DateTimeColumn(name string, nullable NullableColumn) NonAliasColumn {
if !validIdentifierName(name) {
panic("Invalid column name in datetime column")
}
dc := &dateTimeColumn{}
dc.name = name
dc.nullable = nullable
return dc
}
type IntegerColumn struct {
baseColumn
}
// Representation of any integer column
// This function will panic if name is not valid
func IntColumn(name string, nullable NullableColumn) *IntegerColumn {
if !validIdentifierName(name) {
panic("Invalid column name in int column")
}
ic := &IntegerColumn{}
ic.name = name
ic.nullable = nullable
return ic
}
type doubleColumn struct {
baseColumn
}
// Representation of any double column
// This function will panic if name is not valid
func DoubleColumn(name string, nullable NullableColumn) NonAliasColumn {
if !validIdentifierName(name) {
panic("Invalid column name in int column")
}
ic := &doubleColumn{}
ic.name = name
ic.nullable = nullable
return ic
}
type booleanColumn struct {
baseColumn
// XXX: Maybe allow isBoolExpression (for now, not included because
// the deferred lookup equivalent can never be isBoolExpression)
}
//type doubleColumn struct {
// baseColumn
//}
//
//// Representation of any double column
//// This function will panic if name is not valid
//func DoubleColumn(name string, nullable NullableColumn) Column {
// if !validIdentifierName(name) {
// panic("Invalid column name in int column")
// }
// ic := &doubleColumn{}
// ic.name = name
// ic.nullable = nullable
// return ic
//}
//
//type booleanColumn struct {
// baseColumn
//
// // XXX: Maybe allow isBoolExpression (for now, not included because
// // the deferred lookup equivalent can never be isBoolExpression)
//}
// Representation of TINYINT used as a bool
// This function will panic if name is not valid
func BoolColumn(name string, nullable NullableColumn) NonAliasColumn {
if !validIdentifierName(name) {
panic("Invalid column name in bool column")
}
bc := &booleanColumn{}
bc.name = name
bc.nullable = nullable
return bc
}
//func NewBoolColumn(name string, nullable NullableColumn) Column {
// if !validIdentifierName(name) {
// panic("Invalid column name in bool column")
// }
// bc := &booleanColumn{}
// bc.name = name
// bc.nullable = nullable
// return bc
//}
//
//type aliasColumn struct {
// baseColumn
// expression Expression
//}
//
//func (c *aliasColumn) SerializeSql(out *bytes.Buffer) error {
// _ = out.WriteByte('`')
// _, _ = out.WriteString(c.name)
// _ = out.WriteByte('`')
// return nil
//}
//
//func (c *aliasColumn) SerializeSqlForColumnList(out *bytes.Buffer) error {
// if !validIdentifierName(c.name) {
// return errors.Newf(
// "Invalid alias name `%s`. Generated sql: %s",
// c.name,
// out.String())
// }
// if c.expression == nil {
// return errors.Newf(
// "Cannot alias a nil expression. Generated sql: %s",
// out.String())
// }
//
// _ = out.WriteByte('(')
// if c.expression == nil {
// return errors.Newf("nil alias clause. Generate sql: %s", out.String())
// }
// if err := c.expression.SerializeSql(out); err != nil {
// return err
// }
// _, _ = out.WriteString(") AS \"")
// _, _ = out.WriteString(c.name)
// _ = out.WriteByte('"')
// return nil
//}
type aliasColumn struct {
baseColumn
expression Expression
}
func (c *aliasColumn) SerializeSql(out *bytes.Buffer) error {
_ = out.WriteByte('`')
_, _ = out.WriteString(c.name)
_ = out.WriteByte('`')
return nil
}
func (c *aliasColumn) SerializeSqlForColumnList(out *bytes.Buffer) error {
if !validIdentifierName(c.name) {
return errors.Newf(
"Invalid alias name `%s`. Generated sql: %s",
c.name,
out.String())
}
if c.expression == nil {
return errors.Newf(
"Cannot alias a nil expression. Generated sql: %s",
out.String())
}
_ = out.WriteByte('(')
if c.expression == nil {
return errors.Newf("nil alias clause. Generate sql: %s", out.String())
}
if err := c.expression.SerializeSql(out); err != nil {
return err
}
_, _ = out.WriteString(") AS \"")
_, _ = out.WriteString(c.name)
_ = out.WriteByte('"')
return nil
}
func (c *aliasColumn) setTableName(table string) error {
return errors.Newf(
"Alias column '%s' should never have setTableName called on it",
c.name)
}
//func (c *aliasColumn) setTableName(table string) error {
// return errors.Newf(
// "Alias column '%s' should never have setTableName called on it",
// c.name)
//}
// Representation of aliased clauses (expression AS name)
//func Alias(name string, c Expression) Column {

View file

@ -0,0 +1,65 @@
package sqlbuilder
//------------------------------------------------------//
type BoolColumn struct {
boolInterfaceImpl
baseColumn
}
func NewBoolColumn(name string, nullable NullableColumn) *BoolColumn {
if !validIdentifierName(name) {
panic("Invalid column name in bool column")
}
boolColumn := &BoolColumn{}
boolColumn.baseColumn = newBaseColumn(name, nullable, "", boolColumn)
boolColumn.boolInterfaceImpl.parent = boolColumn
return boolColumn
}
//------------------------------------------------------//
type NumericColumn struct {
numericInterfaceImpl
baseColumn
}
func NewNumericColumn(name string, nullable NullableColumn) *NumericColumn {
if !validIdentifierName(name) {
panic("Invalid column name")
}
numericColumn := &NumericColumn{}
numericColumn.numericInterfaceImpl.parent = numericColumn
numericColumn.baseColumn = newBaseColumn(name, nullable, "", numericColumn)
return numericColumn
}
//------------------------------------------------------//
type IntegerColumn struct {
numericInterfaceImpl
integerInterfaceImpl
baseColumn
}
// Representation of any integer column
// This function will panic if name is not valid
func NewIntegerColumn(name string, nullable NullableColumn) *IntegerColumn {
if !validIdentifierName(name) {
panic("Invalid column name")
}
integerColumn := &IntegerColumn{}
integerColumn.numericInterfaceImpl.parent = integerColumn
integerColumn.integerInterfaceImpl.parent = integerColumn
integerColumn.baseColumn = newBaseColumn(name, nullable, "", integerColumn)
return integerColumn
}

View file

@ -0,0 +1,97 @@
package sqlbuilder
import (
"bytes"
"gotest.tools/assert"
"testing"
)
func TestNewBoolColumn(t *testing.T) {
boolColumn := NewBoolColumn("col", Nullable)
out := bytes.Buffer{}
err := boolColumn.SerializeSql(&out)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = boolColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = boolColumn.setTableName("table1")
assert.NilError(t, err)
err = boolColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "table1.col"`)
out.Reset()
err = boolColumn.setTableName("table1")
assert.NilError(t, err)
aliasedBoolColumn := boolColumn.As("alias1")
err = aliasedBoolColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "alias1"`)
}
func TestNewIntColumn(t *testing.T) {
integerColumn := NewIntegerColumn("col", Nullable)
out := bytes.Buffer{}
err := integerColumn.SerializeSql(&out)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = integerColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = integerColumn.setTableName("table1")
assert.NilError(t, err)
err = integerColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "table1.col"`)
out.Reset()
err = integerColumn.setTableName("table1")
assert.NilError(t, err)
aliasedBoolColumn := integerColumn.As("alias1")
err = aliasedBoolColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "alias1"`)
}
func TestNewNumericColumnColumn(t *testing.T) {
numericColumn := NewNumericColumn("col", Nullable)
out := bytes.Buffer{}
err := numericColumn.SerializeSql(&out)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = numericColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), "col")
out.Reset()
err = numericColumn.setTableName("table1")
assert.NilError(t, err)
err = numericColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "table1.col"`)
out.Reset()
err = numericColumn.setTableName("table1")
assert.NilError(t, err)
aliasedBoolColumn := numericColumn.As("alias1")
err = aliasedBoolColumn.SerializeSql(&out, FOR_PROJECTION)
assert.NilError(t, err)
assert.Equal(t, out.String(), `table1.col AS "alias1"`)
}

View file

@ -12,7 +12,7 @@ type Expression interface {
As(alias string) Clause
IsDistinct(expression Expression) BoolExpression
IsNull(expression Expression) BoolExpression
IsNull() BoolExpression
}
type expressionInterfaceImpl struct {
@ -27,31 +27,27 @@ func (e *expressionInterfaceImpl) IsDistinct(expression Expression) BoolExpressi
return nil
}
func (e *expressionInterfaceImpl) IsNull(expression Expression) BoolExpression {
func (e *expressionInterfaceImpl) IsNull() BoolExpression {
return nil
}
// Representation of binary operations (e.g. comparisons, arithmetic)
type binaryExpression struct {
expressionInterfaceImpl
lhs, rhs Expression
operator []byte
}
func NewBinaryExpression(lhs, rhs Expression, operator []byte, parent ...Expression) *binaryExpression {
func newBinaryExpression(lhs, rhs Expression, operator []byte, parent ...Expression) binaryExpression {
binaryExpression := binaryExpression{
lhs: lhs,
rhs: rhs,
operator: operator,
}
if len(parent) > 0 {
binaryExpression.parent = parent[0]
return binaryExpression
}
return &binaryExpression
}
func (c *binaryExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (c *binaryExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
if c.lhs == nil {
return errors.Newf("nil lhs. Generated sql: %s", out.String())
}
@ -73,25 +69,20 @@ func (c *binaryExpression) SerializeSql(out *bytes.Buffer) (err error) {
// A not expression which negates a expression value
type prefixExpression struct {
expressionInterfaceImpl
expression Expression
operator []byte
}
func NewPrefixExpression(expression Expression, operator []byte, parent ...Expression) *prefixExpression {
func newPrefixExpression(expression Expression, operator []byte) prefixExpression {
prefixExpression := prefixExpression{
expression: expression,
operator: operator,
}
if len(parent) > 0 {
prefixExpression.parent = parent[0]
return prefixExpression
}
return &prefixExpression
}
func (p *prefixExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (p *prefixExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
_, _ = out.Write(p.operator)
if p.expression == nil {
@ -106,12 +97,11 @@ func (p *prefixExpression) SerializeSql(out *bytes.Buffer) (err error) {
// Representation of n-ary conjunctions (AND/OR)
type conjunctExpression struct {
expressionInterfaceImpl
expressions []BoolExpression
conjunction []byte
}
func (conj *conjunctExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (conj *conjunctExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
if len(conj.expressions) == 0 {
return errors.Newf(
"Empty conjunction. Generated sql: %s",
@ -154,7 +144,38 @@ func NewLiteralExpression(value sqltypes.Value) *literalExpression {
return &exp
}
func (c literalExpression) SerializeSql(out *bytes.Buffer) error {
func (c literalExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
sqltypes.Value(c.value).EncodeSql(out)
return nil
}
//------------------------------------------------------//
// Dummy type for select *
type ColumnList []Column
func (cl ColumnList) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
for i, column := range cl {
err := column.SerializeSql(out)
if err != nil {
return err
}
if i != len(cl)-1 {
out.WriteString(", ")
}
}
return nil
}
func (e ColumnList) As(alias string) Clause {
panic("Invalid usage")
}
func (e ColumnList) IsDistinct(expression Expression) BoolExpression {
panic("Invalid usage")
}
func (e ColumnList) IsNull(expression Expression) BoolExpression {
panic("Invalid usage")
}

View file

@ -17,7 +17,7 @@ type orderByClause struct {
ascent bool
}
func (o *orderByClause) SerializeSql(out *bytes.Buffer) error {
func (o *orderByClause) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
if o.expression == nil {
return errors.Newf(
"nil order by clause. Generated sql: %s",
@ -82,7 +82,7 @@ type arithmeticExpression struct {
operator []byte
}
func (arith *arithmeticExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (arith *arithmeticExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
if len(arith.expressions) == 0 {
return errors.Newf(
"Empty arithmetic expression. Generated sql: %s",
@ -115,7 +115,7 @@ type tupleExpression struct {
elements listClause
}
func (tuple *tupleExpression) SerializeSql(out *bytes.Buffer) error {
func (tuple *tupleExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
if len(tuple.elements.clauses) < 1 {
return errors.Newf("Tuples must include at least one element")
}
@ -141,7 +141,7 @@ type listClause struct {
includeParentheses bool
}
func (list *listClause) SerializeSql(out *bytes.Buffer) error {
func (list *listClause) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
if list.includeParentheses {
_ = out.WriteByte('(')
}
@ -162,7 +162,7 @@ type funcExpression struct {
args *listClause
}
func (c *funcExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (c *funcExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
if !validIdentifierName(c.funcName) {
return errors.Newf(
"Invalid function name: %s. Generated sql: %s",
@ -205,7 +205,7 @@ type intervalExpression struct {
var intervalSep = ":"
func (c *intervalExpression) SerializeSql(out *bytes.Buffer) (err error) {
func (c *intervalExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) {
hours := c.duration / time.Hour
minutes := (c.duration % time.Hour) / time.Minute
sec := (c.duration % time.Minute) / time.Second
@ -336,7 +336,7 @@ type ifExpression struct {
falseExpression Expression
}
func (exp *ifExpression) SerializeSql(out *bytes.Buffer) error {
func (exp *ifExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
_, _ = out.WriteString("IF(")
_ = exp.conditional.SerializeSql(out)
_, _ = out.WriteString(",")

View file

@ -3,15 +3,13 @@ package sqlbuilder
import "bytes"
type FuncExpression struct {
isProjection
name string
expression Expression
alias string
}
func (f *FuncExpression) As(alias string) Projection {
func (f *FuncExpression) As(alias string) Clause {
newFuncExpression := *f
newFuncExpression.alias = alias
@ -19,7 +17,7 @@ func (f *FuncExpression) As(alias string) Projection {
return &newFuncExpression
}
func (f *FuncExpression) SerializeSql(out *bytes.Buffer) error {
func (f *FuncExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
out.WriteString(f.name)
out.WriteString("(")
err := f.expression.SerializeSql(out)
@ -37,9 +35,9 @@ func (f *FuncExpression) SerializeSql(out *bytes.Buffer) error {
return nil
}
func (f *FuncExpression) SerializeSqlForColumnList(out *bytes.Buffer) error {
return f.SerializeSql(out)
}
//func (f *FuncExpression) SerializeSqlForColumnList(out *bytes.Buffer) error {
// return f.SerializeSql(out)
//}
func MAX(expression Expression) *FuncExpression {
return &FuncExpression{

View file

@ -0,0 +1,82 @@
package sqlbuilder
type IntegerExpression interface {
NumericExpression
//AddInt(value int) IntegerExpression
//AddInt64(value int) IntegerExpression
BitAnd(expression IntegerExpression) IntegerExpression
BitOr(expression IntegerExpression) IntegerExpression
BitXor(expression IntegerExpression) IntegerExpression
BitNot() IntegerExpression
}
type integerInterfaceImpl struct {
parent IntegerExpression
}
//func (i *integerInterfaceImpl) AddInt(expression IntegerExpression) IntegerExpression {
// return NewBinaryIntegerExpression(i.parent, expression, " & ")
//}
//
//func (i *integerInterfaceImpl) AddInt64(expression IntegerExpression) IntegerExpression {
// return NewBinaryIntegerExpression(i.parent, expression, " & ")
//}
func (i *integerInterfaceImpl) BitAnd(expression IntegerExpression) IntegerExpression {
return NewBinaryIntegerExpression(i.parent, expression, " & ")
}
func (i *integerInterfaceImpl) BitOr(expression IntegerExpression) IntegerExpression {
return NewBinaryIntegerExpression(i.parent, expression, " | ")
}
func (i *integerInterfaceImpl) BitXor(expression IntegerExpression) IntegerExpression {
return NewBinaryIntegerExpression(i.parent, expression, " # ")
}
func (i *integerInterfaceImpl) BitNot() IntegerExpression {
return NewPrefixIntegerExpression(i.parent, " ~")
}
//---------------------------------------------------//
type binaryIntegerExpression struct {
expressionInterfaceImpl
numericInterfaceImpl
integerInterfaceImpl
binaryExpression
}
func NewBinaryIntegerExpression(lhs, rhs IntegerExpression, operator string) IntegerExpression {
integerExpression := binaryIntegerExpression{}
integerExpression.expressionInterfaceImpl.parent = &integerExpression
integerExpression.numericInterfaceImpl.parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression
integerExpression.binaryExpression = newBinaryExpression(lhs, rhs, []byte(operator))
return &integerExpression
}
//---------------------------------------------------//
type prefixIntegerExpression struct {
expressionInterfaceImpl
numericInterfaceImpl
integerInterfaceImpl
prefixExpression
}
func NewPrefixIntegerExpression(expression IntegerExpression, operator string) IntegerExpression {
integerExpression := prefixIntegerExpression{}
integerExpression.prefixExpression = newPrefixExpression(expression, []byte(operator))
integerExpression.expressionInterfaceImpl.parent = &integerExpression
integerExpression.numericInterfaceImpl.parent = &integerExpression
integerExpression.integerInterfaceImpl.parent = &integerExpression
return &integerExpression
}

View file

@ -0,0 +1,94 @@
package sqlbuilder
import (
"github.com/dropbox/godropbox/database/sqltypes"
"github.com/pkg/errors"
)
type NumericExpression interface {
Expression
Eq(expression NumericExpression) BoolExpression
NotEq(expression NumericExpression) BoolExpression
GtEq(rhs NumericExpression) BoolExpression
LtEq(rhs NumericExpression) BoolExpression
Add(expression NumericExpression) NumericExpression
Sub(expression NumericExpression) NumericExpression
Mul(expression NumericExpression) NumericExpression
Div(expression NumericExpression) NumericExpression
}
type numericInterfaceImpl struct {
parent NumericExpression
}
func (n *numericInterfaceImpl) Eq(expression NumericExpression) BoolExpression {
return Eq(n.parent, expression)
}
func (n *numericInterfaceImpl) NotEq(expression NumericExpression) BoolExpression {
return Neq(n.parent, expression)
}
func (n *numericInterfaceImpl) GtEq(expression NumericExpression) BoolExpression {
return Gte(n.parent, expression)
}
func (n *numericInterfaceImpl) LtEq(expression NumericExpression) BoolExpression {
return Lte(n.parent, expression)
}
func (n *numericInterfaceImpl) Add(expression NumericExpression) NumericExpression {
return newBinaryNumericExpression(n.parent, expression, []byte(" + "))
}
func (n *numericInterfaceImpl) Sub(expression NumericExpression) NumericExpression {
return newBinaryNumericExpression(n.parent, expression, []byte(" - "))
}
func (n *numericInterfaceImpl) Mul(expression NumericExpression) NumericExpression {
return newBinaryNumericExpression(n.parent, expression, []byte(" * "))
}
func (n *numericInterfaceImpl) Div(expression NumericExpression) NumericExpression {
return newBinaryNumericExpression(n.parent, expression, []byte(" / "))
}
//---------------------------------------------------//
type numericLiteral struct {
numericInterfaceImpl
literalExpression
}
func NewNumericLiteral(value interface{}) NumericExpression {
numericLiteral := numericLiteral{}
sqlValue, err := sqltypes.BuildValue(value)
if err != nil {
panic(errors.Wrap(err, "Invalid literal value"))
}
numericLiteral.literalExpression = *NewLiteralExpression(sqlValue)
numericLiteral.numericInterfaceImpl.parent = &numericLiteral
return &numericLiteral
}
//---------------------------------------------------//
type binaryNumericExpression struct {
expressionInterfaceImpl
numericInterfaceImpl
binaryExpression
}
func newBinaryNumericExpression(lhs, rhs Expression, operator []byte) NumericExpression {
numericExpression := binaryNumericExpression{}
numericExpression.binaryExpression = newBinaryExpression(lhs, rhs, operator)
numericExpression.expressionInterfaceImpl.parent = &numericExpression
numericExpression.numericInterfaceImpl.parent = &numericExpression
return &numericExpression
}

View file

@ -36,7 +36,7 @@ type selectStatementImpl struct {
expressionInterfaceImpl
table ReadableTable
projections []Projection
projections []Expression
where BoolExpression
group *listClause
having BoolExpression
@ -50,7 +50,7 @@ type selectStatementImpl struct {
func newSelectStatement(
table ReadableTable,
projections []Projection) SelectStatement {
projections []Expression) SelectStatement {
return &selectStatementImpl{
table: table,
@ -63,7 +63,7 @@ func newSelectStatement(
}
}
func (s *selectStatementImpl) SerializeSql(out *bytes.Buffer) error {
func (s *selectStatementImpl) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
str, err := s.String()
if err != nil {
@ -210,7 +210,7 @@ func (q *selectStatementImpl) String() (sql string, err error) {
"nil column selected. Generated sql: %s",
buf.String())
}
if err = col.SerializeSqlForColumnList(buf); err != nil {
if err = col.SerializeSql(buf, FOR_PROJECTION); err != nil {
return
}
}

View file

@ -4,22 +4,22 @@ import "bytes"
type SelectStatementTable struct {
statement SelectStatement
columns []NonAliasColumn
columns []Column
alias string
}
func (s *SelectStatementTable) Columns() []NonAliasColumn {
func (s *SelectStatementTable) Columns() []Column {
return s.columns
}
func (s *SelectStatementTable) Column(name string) NonAliasColumn {
func (s *SelectStatementTable) Column(name string) Column {
return &baseColumn{
name: name,
tableName: s.alias,
}
}
func (s *SelectStatementTable) ColumnFrom(column NonAliasColumn) NonAliasColumn {
func (s *SelectStatementTable) ColumnFrom(column Column) Column {
return &baseColumn{
name: column.TableName() + "." + column.Name(),
tableName: s.alias,
@ -43,7 +43,7 @@ func (s *SelectStatementTable) SerializeSql(out *bytes.Buffer) error {
}
// Generates a select query on the current tableName.
func (s *SelectStatementTable) Select(projections ...Projection) SelectStatement {
func (s *SelectStatementTable) Select(projections ...Expression) SelectStatement {
return newSelectStatement(s, projections)
}
@ -52,9 +52,9 @@ func (s *SelectStatementTable) InnerJoinOn(table ReadableTable, onCondition Bool
return InnerJoinOn(s, table, onCondition)
}
func (s *SelectStatementTable) InnerJoinUsing(table ReadableTable, col1 Column, col2 Column) ReadableTable {
return InnerJoinOn(s, table, col1.Eq(col2))
}
//func (s *SelectStatementTable) InnerJoinUsing(table ReadableTable, col1 Column, col2 Column) ReadableTable {
// return InnerJoinOn(s, table, col1.Eq(col2))
//}
// Creates a left join tableName expression using onCondition.
func (s *SelectStatementTable) LeftJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable {
@ -66,8 +66,8 @@ func (s *SelectStatementTable) RightJoinOn(table ReadableTable, onCondition Bool
return RightJoinOn(s, table, onCondition)
}
func (s *SelectStatementTable) FullJoin(table ReadableTable, col1 Column, col2 Column) ReadableTable {
return FullJoin(s, table, col1.Eq(col2))
func (s *SelectStatementTable) FullJoin(table ReadableTable, onCondition BoolExpression) ReadableTable {
return FullJoin(s, table, onCondition)
}
func (s *SelectStatementTable) CrossJoin(table ReadableTable) ReadableTable {

View file

@ -20,7 +20,7 @@ type InsertStatement interface {
// Add a row of values to the insert statement.
Add(row ...Expression) InsertStatement
AddOnDuplicateKeyUpdate(col NonAliasColumn, expr Expression) InsertStatement
AddOnDuplicateKeyUpdate(col Column, expr Expression) InsertStatement
Comment(comment string) InsertStatement
IgnoreDuplicates(ignore bool) InsertStatement
}
@ -48,7 +48,7 @@ type UnionStatement interface {
type UpdateStatement interface {
Statement
Set(column NonAliasColumn, expression Expression) UpdateStatement
Set(column Column, expression Expression) UpdateStatement
Where(expression BoolExpression) UpdateStatement
OrderBy(clauses ...OrderByClause) UpdateStatement
Limit(limit int64) UpdateStatement
@ -178,7 +178,7 @@ func (us *unionStatementImpl) String() (sql string, err error) {
}
// Union statements in MySQL require that the same number of columns in each subquery
var projections []Projection
var projections []Expression
for _, statement := range us.selects {
// do a type assertion to get at the underlying struct
@ -267,7 +267,7 @@ func (us *unionStatementImpl) String() (sql string, err error) {
func newInsertStatement(
t WritableTable,
columns ...NonAliasColumn) InsertStatement {
columns ...Column) InsertStatement {
return &insertStatementImpl{
table: t,
@ -278,13 +278,13 @@ func newInsertStatement(
}
type columnAssignment struct {
col NonAliasColumn
col Column
expr Expression
}
type insertStatementImpl struct {
table WritableTable
columns []NonAliasColumn
columns []Column
rows [][]Expression
onDuplicateKeyUpdates []columnAssignment
comment string
@ -303,7 +303,7 @@ func (s *insertStatementImpl) Add(
}
func (s *insertStatementImpl) AddOnDuplicateKeyUpdate(
col NonAliasColumn,
col Column,
expr Expression) InsertStatement {
s.onDuplicateKeyUpdates = append(
@ -361,7 +361,7 @@ func (s *insertStatementImpl) String() (sql string, err error) {
buf.String())
}
if err = col.SerializeSqlForColumnList(buf); err != nil {
if err = col.SerializeSql(buf, FOR_PROJECTION); err != nil {
return
}
}
@ -413,12 +413,11 @@ func (s *insertStatementImpl) String() (sql string, err error) {
if colExpr.col == nil {
return "", errors.Newf(
("nil column in on duplicate key update list. " +
"Generated sql: %s"),
"nil column in on duplicate key update list. "+"Generated sql: %s",
buf.String())
}
if err = colExpr.col.SerializeSqlForColumnList(buf); err != nil {
if err = colExpr.col.SerializeSql(buf, FOR_PROJECTION); err != nil {
return
}
@ -426,8 +425,7 @@ func (s *insertStatementImpl) String() (sql string, err error) {
if colExpr.expr == nil {
return "", errors.Newf(
("nil expression in on duplicate key update list. " +
"Generated sql: %s"),
"nil expression in on duplicate key update list. "+"Generated sql: %s",
buf.String())
}
@ -447,14 +445,14 @@ func (s *insertStatementImpl) String() (sql string, err error) {
func newUpdateStatement(table WritableTable) UpdateStatement {
return &updateStatementImpl{
table: table,
updateValues: make(map[NonAliasColumn]Expression),
updateValues: make(map[Column]Expression),
limit: -1,
}
}
type updateStatementImpl struct {
table WritableTable
updateValues map[NonAliasColumn]Expression
updateValues map[Column]Expression
where BoolExpression
order *listClause
limit int64
@ -466,7 +464,7 @@ func (u *updateStatementImpl) Execute(db *sql.DB, data interface{}) error {
}
func (u *updateStatementImpl) Set(
column NonAliasColumn,
column Column,
expression Expression) UpdateStatement {
u.updateValues[column] = expression

View file

@ -12,22 +12,21 @@ import (
// are not supported.
type ReadableTable interface {
// Returns the list of columns that are in the current tableName expression.
Columns() []NonAliasColumn
Columns() []Column
Column(name string) NonAliasColumn
Column(name string) Column
// Generates the sql string for the current tableName expression. Note: the
// generated string may not be a valid/executable sql statement.
// The database is the name of the database the tableName is on
SerializeSql(out *bytes.Buffer) error
// Generates a select query on the current tableName.
Select(projections ...Projection) SelectStatement
Select(projections ...Expression) SelectStatement
// Creates a inner join tableName expression using onCondition.
InnerJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
InnerJoinUsing(table ReadableTable, col1 Column, col2 Column) ReadableTable
//InnerJoinUsing(table ReadableTable, col1 Column, col2 Column) ReadableTable
// Creates a left join tableName expression using onCondition.
LeftJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
@ -35,7 +34,7 @@ type ReadableTable interface {
// Creates a right join tableName expression using onCondition.
RightJoinOn(table ReadableTable, onCondition BoolExpression) ReadableTable
FullJoin(table ReadableTable, col1 Column, col2 Column) ReadableTable
FullJoin(table ReadableTable, onCondition BoolExpression) ReadableTable
CrossJoin(table ReadableTable) ReadableTable
}
@ -43,21 +42,21 @@ type ReadableTable interface {
// The sql tableName write interface.
type WritableTable interface {
// Returns the list of columns that are in the tableName.
Columns() []NonAliasColumn
Columns() []Column
// Generates the sql string for the current tableName expression. Note: the
// generated string may not be a valid/executable sql statement.
// The database is the name of the database the tableName is on
SerializeSql(out *bytes.Buffer) error
Insert(columns ...NonAliasColumn) InsertStatement
Insert(columns ...Column) InsertStatement
Update() UpdateStatement
Delete() DeleteStatement
}
// Defines a physical tableName in the database that is both readable and writable.
// This function will panic if name is not valid
func NewTable(schemaName, name string, columns ...NonAliasColumn) *Table {
func NewTable(schemaName, name string, columns ...Column) *Table {
if !validIdentifierName(name) {
panic("Invalid tableName name")
}
@ -66,7 +65,7 @@ func NewTable(schemaName, name string, columns ...NonAliasColumn) *Table {
schemaName: schemaName,
name: name,
columns: columns,
columnLookup: make(map[string]NonAliasColumn),
columnLookup: make(map[string]Column),
}
for _, c := range columns {
err := c.setTableName(name)
@ -87,21 +86,21 @@ type Table struct {
schemaName string
name string
alias string
columns []NonAliasColumn
columnLookup map[string]NonAliasColumn
columns []Column
columnLookup map[string]Column
// If not empty, the name of the index to force
forcedIndex string
}
// Returns the specified column, or errors if it doesn't exist in the tableName
func (t *Table) getColumn(name string) (NonAliasColumn, error) {
func (t *Table) getColumn(name string) (Column, error) {
if c, ok := t.columnLookup[name]; ok {
return c, nil
}
return nil, errors.Newf("No such column '%s' in tableName '%s'", name, t.name)
}
func (t *Table) Column(name string) NonAliasColumn {
func (t *Table) Column(name string) Column {
return &baseColumn{
name: name,
nullable: NotNullable,
@ -109,9 +108,9 @@ func (t *Table) Column(name string) NonAliasColumn {
}
}
// Returns all columns for a tableName as a slice of projections
func (t *Table) Projections() []Projection {
result := make([]Projection, 0)
// Returns all expresssion for a tableName as a slice of projections
func (t *Table) Projections() []Expression {
result := make([]Expression, 0)
for _, col := range t.columns {
col.Asc()
@ -142,7 +141,7 @@ func (t *Table) SchemaName() string {
}
// Returns a list of the tableName's columns
func (t *Table) Columns() []NonAliasColumn {
func (t *Table) Columns() []Column {
return t.columns
}
@ -182,7 +181,7 @@ func (t *Table) SerializeSql(out *bytes.Buffer) error {
}
// Generates a select query on the current tableName.
func (t *Table) Select(projections ...Projection) SelectStatement {
func (t *Table) Select(projections ...Expression) SelectStatement {
return newSelectStatement(t, projections)
}
@ -194,13 +193,13 @@ func (t *Table) InnerJoinOn(
return InnerJoinOn(t, table, onCondition)
}
func (t *Table) InnerJoinUsing(
table ReadableTable,
col1 Column,
col2 Column) ReadableTable {
return InnerJoinOn(t, table, col1.Eq(col2))
}
//func (t *Table) InnerJoinUsing(
// table ReadableTable,
// col1 Column,
// col2 Column) ReadableTable {
//
// return InnerJoinOn(t, table, col1.Eq(col2))
//}
// Creates a left join tableName expression using onCondition.
func (t *Table) LeftJoinOn(
@ -218,15 +217,15 @@ func (t *Table) RightJoinOn(
return RightJoinOn(t, table, onCondition)
}
func (t *Table) FullJoin(table ReadableTable, col1, col2 Column) ReadableTable {
return FullJoin(t, table, col1.Eq(col2))
func (t *Table) FullJoin(table ReadableTable, onCondition BoolExpression) ReadableTable {
return FullJoin(t, table, onCondition)
}
func (t *Table) CrossJoin(table ReadableTable) ReadableTable {
return CrossJoin(t, table)
}
func (t *Table) Insert(columns ...NonAliasColumn) InsertStatement {
func (t *Table) Insert(columns ...Column) InsertStatement {
return newInsertStatement(t, columns...)
}
@ -309,15 +308,15 @@ func CrossJoin(
return newJoinTable(lhs, rhs, CROSS_JOIN, nil)
}
func (t *joinTable) Columns() []NonAliasColumn {
columns := make([]NonAliasColumn, 0)
func (t *joinTable) Columns() []Column {
columns := make([]Column, 0)
columns = append(columns, t.lhs.Columns()...)
columns = append(columns, t.rhs.Columns()...)
return columns
}
func (t *joinTable) Column(name string) NonAliasColumn {
func (t *joinTable) Column(name string) Column {
panic("Not implemented")
}
@ -364,7 +363,7 @@ func (t *joinTable) SerializeSql(out *bytes.Buffer) (err error) {
return nil
}
func (t *joinTable) Select(projections ...Projection) SelectStatement {
func (t *joinTable) Select(projections ...Expression) SelectStatement {
return newSelectStatement(t, projections)
}
@ -375,14 +374,6 @@ func (t *joinTable) InnerJoinOn(
return InnerJoinOn(t, table, onCondition)
}
func (t *joinTable) InnerJoinUsing(
table ReadableTable,
col1 Column,
col2 Column) ReadableTable {
return InnerJoinOn(t, table, col1.Eq(col2))
}
func (t *joinTable) LeftJoinOn(
table ReadableTable,
onCondition BoolExpression) ReadableTable {
@ -390,8 +381,8 @@ func (t *joinTable) LeftJoinOn(
return LeftJoinOn(t, table, onCondition)
}
func (t *joinTable) FullJoin(table ReadableTable, col1 Column, col2 Column) ReadableTable {
return FullJoin(t, table, col1.Eq(col2))
func (t *joinTable) FullJoin(table ReadableTable, onCondition BoolExpression) ReadableTable {
return FullJoin(t, table, onCondition)
}
func (t *joinTable) CrossJoin(table ReadableTable) ReadableTable {

View file

@ -1,3 +1,5 @@
// +build disabled
package sqlbuilder
var table1Col1 = IntColumn("col1", Nullable)

View file

@ -1,9 +1,5 @@
package sqlbuilder
import (
"bytes"
)
// A clause that can be used in order by
type OrderByClause interface {
Clause
@ -11,43 +7,43 @@ type OrderByClause interface {
}
// A clause that is selectable.
type Projection interface {
Clause
isProjectionInterface
//type Projection interface {
// Clause
// isProjectionInterface
//
// SerializeSqlForColumnList(out *bytes.Buffer) error
//}
SerializeSqlForColumnList(out *bytes.Buffer) error
}
//type ColumnList []Column
//
//func (cl ColumnList) SerializeSql(out *bytes.Buffer, options ...serializeOption) error {
// for i, column := range cl {
// column.SerializeSql(out)
//
// if i != len(cl)-1 {
// out.WriteString(", ")
// }
// }
// return nil
//}
//
//func (cl ColumnList) isProjectionType() {
//}
//
//func (cl ColumnList) As(name string) Clause {
// panic("Unallowed operation ")
//}
type ColumnList []NonAliasColumn
func (cl ColumnList) SerializeSql(out *bytes.Buffer) error {
for i, column := range cl {
column.SerializeSql(out)
if i != len(cl)-1 {
out.WriteString(", ")
}
}
return nil
}
func (cl ColumnList) isProjectionType() {
}
func (cl ColumnList) As(name string) Projection {
panic("Unallowed operation ")
}
func (cl ColumnList) SerializeSqlForColumnList(out *bytes.Buffer) error {
for i, column := range cl {
column.SerializeSqlForColumnList(out)
if i != len(cl)-1 {
out.WriteString(", ")
}
}
return nil
}
//func (cl ColumnList) SerializeSqlForColumnList(out *bytes.Buffer) error {
// for i, column := range cl {
// column.SerializeSqlForColumnList(out)
//
// if i != len(cl)-1 {
// out.WriteString(", ")
// }
// }
// return nil
//}
//
// Boiler plates ...
@ -63,12 +59,13 @@ type isOrderByClause struct {
func (o *isOrderByClause) isOrderByClauseType() {
}
type isProjectionInterface interface {
isProjectionType()
}
type isProjection struct {
}
func (p *isProjection) isProjectionType() {
}
//
//type isProjectionInterface interface {
// isProjectionType()
//}
//
//type isProjection struct {
//}
//
//func (p *isProjection) isProjectionType() {
//}

1
sqlbuilder/utils.go Normal file
View file

@ -0,0 +1 @@
package sqlbuilder