diff --git a/sqlbuilder/alias.go b/sqlbuilder/alias.go index 52258f2..4dd9b8b 100644 --- a/sqlbuilder/alias.go +++ b/sqlbuilder/alias.go @@ -14,7 +14,7 @@ func NewAlias(expression Expression, alias string) *Alias { func (a *Alias) serializeForProjection(statement statementType, out *queryData) error { - err := a.expression.serializeForProjection(statement, out) + err := a.expression.serialize(statement, out) if err != nil { return err diff --git a/sqlbuilder/bool_expression_test.go b/sqlbuilder/bool_expression_test.go index fc84c9b..19e1d3c 100644 --- a/sqlbuilder/bool_expression_test.go +++ b/sqlbuilder/bool_expression_test.go @@ -46,8 +46,9 @@ func TestBinaryBoolExpression(t *testing.T) { boolExpression := Int(2).EQ(Int(3)) assertClauseSerialize(t, boolExpression, "($1 = $2)", int64(2), int64(3)) + assertProjectionSerialize(t, boolExpression, "$1 = $2", int64(2), int64(3)) assertProjectionSerialize(t, boolExpression.AS("alias_eq_expression"), - `$1 = $2 AS "alias_eq_expression"`, int64(2), int64(3)) + `($1 = $2) AS "alias_eq_expression"`, int64(2), int64(3)) assertClauseSerialize(t, boolExpression.AND(Int(4).EQ(Int(5))), "(($1 = $2) AND ($3 = $4))", int64(2), int64(3), int64(4), int64(5)) assertClauseSerialize(t, boolExpression.OR(Int(4).EQ(Int(5))), diff --git a/sqlbuilder/clause.go b/sqlbuilder/clause.go index 87e5857..75ab789 100644 --- a/sqlbuilder/clause.go +++ b/sqlbuilder/clause.go @@ -58,7 +58,7 @@ func (q *queryData) decreaseIdent() { q.ident -= defaultIdent } -func (q *queryData) writeProjection(statement statementType, projections []projection) error { +func (q *queryData) writeProjections(statement statementType, projections []projection) error { q.increaseIdent() err := serializeProjectionList(statement, projections, q) q.decreaseIdent() diff --git a/sqlbuilder/column.go b/sqlbuilder/column.go index bd5b14a..3fdb173 100644 --- a/sqlbuilder/column.go +++ b/sqlbuilder/column.go @@ -10,11 +10,7 @@ type column interface { Name() string TableName() string - // Internal function for tracking tableName that a column belongs to - // for the purpose of serialization setTableName(table string) - defaultAlias() string - defaultAliasProjection() projection } type Column interface { @@ -61,10 +57,6 @@ func (c *columnImpl) defaultAlias() string { return c.name } -func (c *columnImpl) defaultAliasProjection() projection { - return c.AS(c.defaultAlias()) -} - func (c *columnImpl) serializeAsOrderBy(statement statementType, out *queryData) error { if statement == set_statement { // set Statement (UNION, EXCEPT ...) can reference only select projections in order by clause @@ -84,6 +76,18 @@ func (c *columnImpl) serializeAsOrderBy(statement statementType, out *queryData) return c.serialize(statement, out) } +func (c columnImpl) serializeForProjection(statement statementType, out *queryData) error { + err := c.serialize(statement, out) + + if err != nil { + return err + } + + out.writeString(`AS "` + c.defaultAlias() + `"`) + + return nil +} + func (c columnImpl) serialize(statement statementType, out *queryData, options ...serializeOption) error { columnRef := "" diff --git a/sqlbuilder/column_test.go b/sqlbuilder/column_test.go index 971919d..f5d9ef2 100644 --- a/sqlbuilder/column_test.go +++ b/sqlbuilder/column_test.go @@ -9,6 +9,6 @@ func TestColumn(t *testing.T) { assertClauseSerialize(t, column, "col") column.setTableName("table1") assertClauseSerialize(t, column, "table1.col") - assertProjectionSerialize(t, column.defaultAliasProjection(), `table1.col AS "table1.col"`) + assertProjectionSerialize(t, column, `table1.col AS "table1.col"`) assertProjectionSerialize(t, column.AS("alias1"), `table1.col AS "alias1"`) } diff --git a/sqlbuilder/column_types_test.go b/sqlbuilder/column_types_test.go index f6affb6..be106f6 100644 --- a/sqlbuilder/column_types_test.go +++ b/sqlbuilder/column_types_test.go @@ -10,24 +10,24 @@ func TestNewBoolColumn(t *testing.T) { boolColumn := BoolColumn("colBool").From(subQuery) assertClauseSerialize(t, boolColumn, "sub_query.colBool") assertClauseSerialize(t, boolColumn.EQ(Bool(true)), "(sub_query.colBool = $1)", true) - assertProjectionSerialize(t, boolColumn.defaultAliasProjection(), `sub_query.colBool AS "sub_query.colBool"`) + assertProjectionSerialize(t, boolColumn, `sub_query.colBool AS "sub_query.colBool"`) boolColumn2 := table1ColBool.From(subQuery) assertClauseSerialize(t, boolColumn2, `sub_query."table1.colBool"`) assertClauseSerialize(t, boolColumn2.EQ(Bool(true)), `(sub_query."table1.colBool" = $1)`, true) - assertProjectionSerialize(t, boolColumn2.defaultAliasProjection(), `sub_query."table1.colBool" AS "sub_query.table1.colBool"`) + assertProjectionSerialize(t, boolColumn2, `sub_query."table1.colBool" AS "sub_query.table1.colBool"`) } func TestNewIntColumn(t *testing.T) { intColumn := IntegerColumn("colInt").From(subQuery) assertClauseSerialize(t, intColumn, "sub_query.colInt") assertClauseSerialize(t, intColumn.EQ(Int(12)), "(sub_query.colInt = $1)", int64(12)) - assertProjectionSerialize(t, intColumn.defaultAliasProjection(), `sub_query.colInt AS "sub_query.colInt"`) + assertProjectionSerialize(t, intColumn, `sub_query.colInt AS "sub_query.colInt"`) intColumn2 := table1ColInt.From(subQuery) assertClauseSerialize(t, intColumn2, `sub_query."table1.colInt"`) assertClauseSerialize(t, intColumn2.EQ(Int(14)), `(sub_query."table1.colInt" = $1)`, int64(14)) - assertProjectionSerialize(t, intColumn2.defaultAliasProjection(), `sub_query."table1.colInt" AS "sub_query.table1.colInt"`) + assertProjectionSerialize(t, intColumn2, `sub_query."table1.colInt" AS "sub_query.table1.colInt"`) } @@ -35,11 +35,11 @@ func TestNewFloatColumnColumn(t *testing.T) { floatColumn := FloatColumn("colFloat").From(subQuery) assertClauseSerialize(t, floatColumn, "sub_query.colFloat") assertClauseSerialize(t, floatColumn.EQ(Float(1.11)), "(sub_query.colFloat = $1)", float64(1.11)) - assertProjectionSerialize(t, floatColumn.defaultAliasProjection(), `sub_query.colFloat AS "sub_query.colFloat"`) + assertProjectionSerialize(t, floatColumn, `sub_query.colFloat AS "sub_query.colFloat"`) floatColumn2 := table1ColFloat.From(subQuery) assertClauseSerialize(t, floatColumn2, `sub_query."table1.colFloat"`) assertClauseSerialize(t, floatColumn2.EQ(Float(2.22)), `(sub_query."table1.colFloat" = $1)`, float64(2.22)) - assertProjectionSerialize(t, floatColumn2.defaultAliasProjection(), `sub_query."table1.colFloat" AS "sub_query.table1.colFloat"`) + assertProjectionSerialize(t, floatColumn2, `sub_query."table1.colFloat" AS "sub_query.table1.colFloat"`) } diff --git a/sqlbuilder/insert_statement.go b/sqlbuilder/insert_statement.go index efbef19..24f9964 100644 --- a/sqlbuilder/insert_statement.go +++ b/sqlbuilder/insert_statement.go @@ -106,7 +106,8 @@ func (i *insertStatementImpl) VALUES_MAPPING(data interface{}) InsertStatement { } func (i *insertStatementImpl) RETURNING(projections ...projection) InsertStatement { - i.returning = defaultProjectionAliasing(projections) + //i.returning = defaultProjectionAliasing(projections) + i.returning = projections return i } @@ -206,7 +207,7 @@ func (s *insertStatementImpl) Sql() (sql string, args []interface{}, err error) queryData.nextLine() queryData.writeString("RETURNING") - err = queryData.writeProjection(insert_statement, s.returning) + err = queryData.writeProjections(insert_statement, s.returning) if err != nil { return diff --git a/sqlbuilder/projection.go b/sqlbuilder/projection.go index d111c9f..f64746c 100644 --- a/sqlbuilder/projection.go +++ b/sqlbuilder/projection.go @@ -11,27 +11,13 @@ type ColumnList []Column func (cl ColumnList) isProjectionType() {} func (cl ColumnList) serializeForProjection(statement statementType, out *queryData) error { - for i, column := range cl { - err := column.serializeForProjection(statement, out) + projections := columnListToProjectionList(cl) - if err != nil { - return err - } + err := serializeProjectionList(statement, projections, out) - if i != len(cl)-1 { - out.writeString(", ") - } + if err != nil { + return err } + return nil } - -func (cl ColumnList) DefaultAlias() []projection { - newColumnList := []projection{} - - for _, column := range cl { - newColumn := column.defaultAliasProjection() - newColumnList = append(newColumnList, newColumn) - } - - return newColumnList -} diff --git a/sqlbuilder/select_statement.go b/sqlbuilder/select_statement.go index d236bf8..34088f7 100644 --- a/sqlbuilder/select_statement.go +++ b/sqlbuilder/select_statement.go @@ -49,26 +49,10 @@ type selectStatementImpl struct { forUpdate bool } -func defaultProjectionAliasing(projections []projection) []projection { - aliasedProjections := []projection{} - - for _, projection := range projections { - if column, ok := projection.(Column); ok { - aliasedProjections = append(aliasedProjections, column.defaultAliasProjection()) - } else if columnList, ok := projection.(ColumnList); ok { - aliasedProjections = append(aliasedProjections, columnList.DefaultAlias()...) - } else { - aliasedProjections = append(aliasedProjections, projection) - } - } - - return aliasedProjections -} - func newSelectStatement(table ReadableTable, projections []projection) SelectStatement { newSelect := &selectStatementImpl{ table: table, - projections: defaultProjectionAliasing(projections), + projections: projections, limit: -1, offset: -1, forUpdate: false, @@ -117,11 +101,11 @@ func (s *selectStatementImpl) serializeImpl(out *queryData) error { out.writeString("DISTINCT") } - if s.projections == nil || len(s.projections) == 0 { - return errors.New("No column selected for projection.") + if len(s.projections) == 0 { + return errors.New("no column selected for projection") } - err := out.writeProjection(select_statement, s.projections) + err := out.writeProjections(select_statement, s.projections) if err != nil { return err diff --git a/sqlbuilder/update_statement.go b/sqlbuilder/update_statement.go index c0f6c08..d148a75 100644 --- a/sqlbuilder/update_statement.go +++ b/sqlbuilder/update_statement.go @@ -48,7 +48,7 @@ func (u *updateStatementImpl) WHERE(expression BoolExpression) UpdateStatement { } func (u *updateStatementImpl) RETURNING(projections ...projection) UpdateStatement { - u.returning = defaultProjectionAliasing(projections) + u.returning = projections return u } diff --git a/sqlbuilder/utils.go b/sqlbuilder/utils.go index ee2745e..cd11681 100644 --- a/sqlbuilder/utils.go +++ b/sqlbuilder/utils.go @@ -87,7 +87,7 @@ func serializeProjectionList(statement statementType, projections []projection, } if col == nil { - return errors.New("projection Expression is nil.") + return errors.New("projection Expression is nil") } if err := col.serializeForProjection(statement, out); err != nil { @@ -118,15 +118,15 @@ func isNil(v interface{}) bool { return v == nil || (reflect.ValueOf(v).Kind() == reflect.Ptr && reflect.ValueOf(v).IsNil()) } -//func stringExpressionListToExpressionList(stringExpressions []StringExpression) []Expression{ -// var ret []Expression -// -// for _, strExp := range stringExpressions { -// ret = append(ret, strExp) -// } -// -// return ret -//} +func columnListToProjectionList(columns []Column) []projection { + var ret []projection + + for _, column := range columns { + ret = append(ret, column) + } + + return ret +} func Query(statement Statement, db execution.Db, destination interface{}) error { query, args, err := statement.Sql()