package sqlbuilder import ( "bytes" "github.com/dropbox/godropbox/database/sqltypes" "github.com/dropbox/godropbox/errors" ) // An expression type Expression interface { Clause Projection As(alias string) Projection IsDistinct(expression Expression) BoolExpression IsNull() BoolExpression Asc() OrderByClause Desc() OrderByClause } type expressionInterfaceImpl struct { parent Expression } func (e *expressionInterfaceImpl) As(alias string) Projection { return NewAlias(e.parent, alias) } func (e *expressionInterfaceImpl) IsDistinct(expression Expression) BoolExpression { return nil } func (e *expressionInterfaceImpl) IsNull() BoolExpression { return nil } func (e *expressionInterfaceImpl) Asc() OrderByClause { return &orderByClause{expression: e.parent, ascent: true} } func (e *expressionInterfaceImpl) Desc() OrderByClause { return &orderByClause{expression: e.parent, ascent: false} } func (e *expressionInterfaceImpl) SerializeForProjection(out *bytes.Buffer) error { return e.parent.SerializeSql(out, FOR_PROJECTION) } // Representation of binary operations (e.g. comparisons, arithmetic) type binaryExpression struct { lhs, rhs Expression operator []byte } func newBinaryExpression(lhs, rhs Expression, operator []byte, parent ...Expression) binaryExpression { binaryExpression := binaryExpression{ lhs: lhs, rhs: rhs, operator: operator, } return binaryExpression } 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()) } if err = c.lhs.SerializeSql(out); err != nil { return } _, _ = out.Write(c.operator) if c.rhs == nil { return errors.Newf("nil rhs. Generated sql: %s", out.String()) } if err = c.rhs.SerializeSql(out); err != nil { return } return nil } // A not expression which negates a expression value type prefixExpression struct { expression Expression operator []byte } func newPrefixExpression(expression Expression, operator []byte) prefixExpression { prefixExpression := prefixExpression{ expression: expression, operator: operator, } return prefixExpression } func (p *prefixExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) { _, _ = out.Write(p.operator) if p.expression == nil { return errors.Newf("nil prefix expression. Generated sql: %s", out.String()) } if err = p.expression.SerializeSql(out); err != nil { return } return nil } // Representation of n-ary conjunctions (AND/OR) type conjunctExpression struct { expressions []BoolExpression conjunction []byte } func (conj *conjunctExpression) SerializeSql(out *bytes.Buffer, options ...serializeOption) (err error) { if len(conj.expressions) == 0 { return errors.Newf( "Empty conjunction. Generated sql: %s", out.String()) } clauses := make([]Clause, len(conj.expressions), len(conj.expressions)) for i, expr := range conj.expressions { clauses[i] = expr } useParentheses := len(clauses) > 1 if useParentheses { _ = out.WriteByte('(') } if err = serializeClauses(clauses, conj.conjunction, out); err != nil { return } if useParentheses { _ = out.WriteByte(')') } return nil } //-------------------------------------------------------------- // Representation of an escaped literal type literalExpression struct { expressionInterfaceImpl value sqltypes.Value } func NewLiteralExpression(value sqltypes.Value) *literalExpression { exp := literalExpression{value: value} exp.expressionInterfaceImpl.parent = &exp return &exp } 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") //}