Rename of types and errors.

This commit is contained in:
go-jet 2019-07-08 13:00:44 +02:00
parent 18bbf1b5fb
commit 63f2d04651
30 changed files with 142 additions and 238 deletions

View file

@ -247,7 +247,7 @@ jsonText, _ := json.MarshalIndent(dest, "", "\t")
fmt.Println(string(jsonText)) fmt.Println(string(jsonText))
``` ```
```json ```js
[ [
{ {
"ActorID": 1, "ActorID": 1,
@ -319,7 +319,8 @@ fmt.Println(string(jsonText))
} }
] ]
}, },
...(125 more items) //...(125 more items)
]
``` ```
What if we also want to have list of films per category and actors per category, where films are longer than 180 minutes, film language is 'English' What if we also want to have list of films per category and actors per category, where films are longer than 180 minutes, film language is 'English'
@ -340,7 +341,7 @@ handleError(err)
<details> <details>
<summary>Click to see dest2 json</summary> <summary>Click to see dest2 json</summary>
```json ```js
[ [
{ {
"CategoryID": 8, "CategoryID": 8,
@ -423,7 +424,8 @@ handleError(err)
} }
] ]
}, },
... //...
]
``` ```
</details> </details>

View file

@ -5,7 +5,7 @@ import (
) )
func TestBoolExpressionEQ(t *testing.T) { func TestBoolExpressionEQ(t *testing.T) {
assertClauseSerializeErr(t, table1ColBool.EQ(nil), "nil rhs") assertClauseSerializeErr(t, table1ColBool.EQ(nil), "jet: nil rhs")
assertClauseSerialize(t, table1ColBool.EQ(table2ColBool), "(table1.col_bool = table2.col_bool)") assertClauseSerialize(t, table1ColBool.EQ(table2ColBool), "(table1.col_bool = table2.col_bool)")
assertClauseSerialize(t, table1ColBool.EQ(Bool(true)), "(table1.col_bool = $1)", true) assertClauseSerialize(t, table1ColBool.EQ(Bool(true)), "(table1.col_bool = $1)", true)
} }

View file

@ -39,13 +39,13 @@ func (d *deleteStatementImpl) RETURNING(projections ...projection) DeleteStateme
func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error { func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
if d == nil { if d == nil {
return errors.New("delete statement is nil") return errors.New("jet: delete statement is nil")
} }
out.newLine() out.newLine()
out.writeString("DELETE FROM") out.writeString("DELETE FROM")
if d.table == nil { if d.table == nil {
return errors.New("nil tableName") return errors.New("jet: nil tableName")
} }
if err := d.table.serialize(delete_statement, out); err != nil { if err := d.table.serialize(delete_statement, out); err != nil {
@ -53,7 +53,7 @@ func (d *deleteStatementImpl) serializeImpl(out *sqlBuilder) error {
} }
if d.where == nil { if d.where == nil {
return errors.New("deleting without a WHERE clause") return errors.New("jet: deleting without a WHERE clause")
} }
if err := out.writeWhere(delete_statement, d.where); err != nil { if err := out.writeWhere(delete_statement, d.where); err != nil {

View file

@ -5,8 +5,8 @@ import (
) )
func TestDeleteUnconditionally(t *testing.T) { func TestDeleteUnconditionally(t *testing.T) {
assertStatementErr(t, table1.DELETE(), `deleting without a WHERE clause`) assertStatementErr(t, table1.DELETE(), `jet: deleting without a WHERE clause`)
assertStatementErr(t, table1.DELETE().WHERE(nil), `deleting without a WHERE clause`) assertStatementErr(t, table1.DELETE().WHERE(nil), `jet: deleting without a WHERE clause`)
} }
func TestDeleteWithWhere(t *testing.T) { func TestDeleteWithWhere(t *testing.T) {

View file

@ -17,12 +17,12 @@ import (
func Query(db DB, context context.Context, query string, args []interface{}, destinationPtr interface{}) error { func Query(db DB, context context.Context, query string, args []interface{}, destinationPtr interface{}) error {
if destinationPtr == nil { if destinationPtr == nil {
return errors.New("Destination is nil. ") return errors.New("jet: Destination is nil.")
} }
destinationPtrType := reflect.TypeOf(destinationPtr) destinationPtrType := reflect.TypeOf(destinationPtr)
if destinationPtrType.Kind() != reflect.Ptr { if destinationPtrType.Kind() != reflect.Ptr {
return errors.New("Destination has to be a pointer to slice or pointer to struct. ") return errors.New("jet: Destination has to be a pointer to slice or pointer to struct")
} }
if destinationPtrType.Elem().Kind() == reflect.Slice { if destinationPtrType.Elem().Kind() == reflect.Slice {
@ -51,22 +51,22 @@ func Query(db DB, context context.Context, query string, args []interface{}, des
} }
return nil return nil
} else { } else {
return errors.New("Unsupported destination type. ") return errors.New("jet: unsupported destination type")
} }
} }
func queryToSlice(db DB, ctx context.Context, query string, args []interface{}, slicePtr interface{}) error { func queryToSlice(db DB, ctx context.Context, query string, args []interface{}, slicePtr interface{}) error {
if db == nil { if db == nil {
return errors.New("db is nil") return errors.New("jet: db is nil")
} }
if slicePtr == nil { if slicePtr == nil {
return errors.New("Destination is nil. ") return errors.New("jet: Destination is nil. ")
} }
destinationType := reflect.TypeOf(slicePtr) destinationType := reflect.TypeOf(slicePtr)
if destinationType.Kind() != reflect.Ptr && destinationType.Elem().Kind() != reflect.Slice { if destinationType.Kind() != reflect.Ptr && destinationType.Elem().Kind() != reflect.Slice {
return errors.New("Destination has to be a pointer to slice. ") return errors.New("jet: Destination has to be a pointer to slice. ")
} }
if ctx == nil { if ctx == nil {
@ -157,7 +157,7 @@ func mapRowToSlice(scanContext *scanContext, groupKey string, slicePtrValue refl
} }
if sliceElemType.Kind() != reflect.Struct { if sliceElemType.Kind() != reflect.Struct {
return false, errors.New("Unsupported dest type: " + structField.Name + " " + structField.Type.String()) return false, errors.New("jet: Unsupported dest type: " + structField.Name + " " + structField.Type.String())
} }
structGroupKey := scanContext.getGroupKey(sliceElemType, structField) structGroupKey := scanContext.getGroupKey(sliceElemType, structField)
@ -229,7 +229,7 @@ func appendElemToSlice(slicePtrValue reflect.Value, objPtrValue reflect.Value) e
} }
if !newElemValue.Type().AssignableTo(sliceElemType) { if !newElemValue.Type().AssignableTo(sliceElemType) {
return fmt.Errorf("Scan: can't append %s to %s slice ", newElemValue.Type().String(), sliceValue.Type().String()) return fmt.Errorf("jet: can't append %s to %s slice ", newElemValue.Type().String(), sliceValue.Type().String())
} }
sliceValue.Set(reflect.Append(sliceValue, newElemValue)) sliceValue.Set(reflect.Append(sliceValue, newElemValue))
@ -247,7 +247,7 @@ func newElemPtrValueForSlice(slicePtrValue reflect.Value) reflect.Value {
func mapRowToDestinationPtr(scanContext *scanContext, groupKey string, destPtrValue reflect.Value, structField *reflect.StructField) (updated bool, err error) { func mapRowToDestinationPtr(scanContext *scanContext, groupKey string, destPtrValue reflect.Value, structField *reflect.StructField) (updated bool, err error) {
if destPtrValue.Kind() != reflect.Ptr { if destPtrValue.Kind() != reflect.Ptr {
return false, errors.New("Internal error. ") return false, errors.New("jet: Internal error. ")
} }
destValueKind := destPtrValue.Elem().Kind() destValueKind := destPtrValue.Elem().Kind()
@ -257,7 +257,7 @@ func mapRowToDestinationPtr(scanContext *scanContext, groupKey string, destPtrVa
} else if destValueKind == reflect.Slice { } else if destValueKind == reflect.Slice {
return mapRowToSlice(scanContext, groupKey, destPtrValue, structField) return mapRowToSlice(scanContext, groupKey, destPtrValue, structField)
} else { } else {
return false, errors.New("Unsupported dest type: " + structField.Name + " " + structField.Type.String()) return false, errors.New("jet: Unsupported dest type: " + structField.Name + " " + structField.Type.String())
} }
} }
@ -274,7 +274,7 @@ func mapRowToDestinationValue(scanContext *scanContext, groupKey string, dest re
destPtrValue = dest destPtrValue = dest
} }
} else { } else {
return false, errors.New("Internal error. ") return false, errors.New("jet: Internal error. ")
} }
updated, err = mapRowToDestinationPtr(scanContext, groupKey, destPtrValue, structField) updated, err = mapRowToDestinationPtr(scanContext, groupKey, destPtrValue, structField)
@ -337,7 +337,7 @@ func mapRowToStruct(scanContext *scanContext, groupKey string, structPtrValue re
err = setReflectValue(reflect.ValueOf(cellValue), fieldValue) err = setReflectValue(reflect.ValueOf(cellValue), fieldValue)
if err != nil { if err != nil {
err = fmt.Errorf("Scan: %s, at struct field: %s %s of type %s. ", err.Error(), field.Name, field.Type.String(), structType.String()) err = fmt.Errorf("%s, at struct field: %s %s of type %s. ", err.Error(), field.Name, field.Type.String(), structType.String())
return return
} }
} }
@ -456,7 +456,7 @@ func setReflectValue(source, destination reflect.Value) error {
} }
if !sourceElem.Type().AssignableTo(destination.Type()) { if !sourceElem.Type().AssignableTo(destination.Type()) {
return errors.New("can't set " + sourceElem.Type().String() + " to " + destination.Type().String()) return errors.New("jet: can't set " + sourceElem.Type().String() + " to " + destination.Type().String())
} }
destination.Set(sourceElem) destination.Set(sourceElem)

View file

@ -96,13 +96,13 @@ func newBinaryExpression(lhs, rhs Expression, operator string) binaryOpExpressio
func (c *binaryOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (c *binaryOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if c == nil { if c == nil {
return errors.New("binary Expression is nil") return errors.New("jet: binary Expression is nil")
} }
if c.lhs == nil { if c.lhs == nil {
return errors.New("nil lhs") return errors.New("jet: nil lhs")
} }
if c.rhs == nil { if c.rhs == nil {
return errors.New("nil rhs") return errors.New("jet: nil rhs")
} }
wrap := !contains(options, noWrap) wrap := !contains(options, noWrap)
@ -145,13 +145,13 @@ func newPrefixExpression(expression Expression, operator string) prefixOpExpress
func (p *prefixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (p *prefixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if p == nil { if p == nil {
return errors.New("Prefix Expression is nil.") return errors.New("jet: Prefix Expression is nil.")
} }
out.writeString(p.operator + " ") out.writeString(p.operator + " ")
if p.expression == nil { if p.expression == nil {
return errors.New("nil prefix Expression.") return errors.New("jet: nil prefix Expression.")
} }
if err := p.expression.serialize(statement, out); err != nil { if err := p.expression.serialize(statement, out); err != nil {
return err return err
@ -177,11 +177,11 @@ func newPostfixOpExpression(expression Expression, operator string) postfixOpExp
func (p *postfixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (p *postfixOpExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if p == nil { if p == nil {
return errors.New("Postifx operator Expression is nil.") return errors.New("jet: Postifx operator Expression is nil.")
} }
if p.expression == nil { if p.expression == nil {
return errors.New("nil prefix Expression.") return errors.New("jet: nil prefix Expression.")
} }
if err := p.expression.serialize(statement, out); err != nil { if err := p.expression.serialize(statement, out); err != nil {
return err return err

View file

@ -1,51 +0,0 @@
package jet
import (
"strconv"
"time"
)
type intervalExpression struct {
expressionInterfaceImpl
duration time.Duration
}
const intervalSep = ":"
func (c *intervalExpression) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
out.writeString("INTERVAL '")
duration := c.duration
if duration < 0 {
duration = -duration
out.writeString("-")
}
hours := duration / time.Hour
minutes := (duration % time.Hour) / time.Minute
sec := (duration % time.Minute) / time.Second
msec := (duration % time.Second) / time.Microsecond
out.writeString(strconv.FormatInt(int64(hours), 10))
out.writeString(intervalSep)
out.writeString(strconv.FormatInt(int64(minutes), 10))
out.writeString(intervalSep)
out.writeString(strconv.FormatInt(int64(sec), 10))
out.writeString(intervalSep)
out.writeString(strconv.FormatInt(int64(msec), 10))
out.writeString("' HOUR_MICROSECOND")
return nil
}
//// Interval returns a representation of duration
//func Interval(duration time.Duration) expressions {
// intervalExp := &intervalExpression{
// duration: duration,
// }
//
// intervalExp.expressionInterfaceImpl.parent = intervalExp
//
// return intervalExp
//}

View file

@ -1,76 +0,0 @@
// +build disabled
package jet
import (
"bytes"
"time"
gc "gopkg.in/check.v1"
)
func (s *ExprSuite) TestInterval(c *gc.C) {
testTable := []struct {
interval time.Duration
expected string
expectedErr error
}{
{
interval: 50 * time.Microsecond,
expected: "INTERVAL '0:0:0:50' HOUR_MICROSECOND",
},
{
interval: -50 * time.Microsecond,
expected: "INTERVAL '-0:0:0:50' HOUR_MICROSECOND",
},
{
interval: 50*time.Microsecond + 50*time.Second,
expected: "INTERVAL '0:0:50:50' HOUR_MICROSECOND",
},
{
interval: 50*time.Microsecond +
50*time.Second +
50*time.Minute,
expected: "INTERVAL '0:50:50:50' HOUR_MICROSECOND",
},
{
interval: 50*time.Microsecond +
50*time.Second +
50*time.Minute +
50*time.Hour,
expected: "INTERVAL '50:50:50:50' HOUR_MICROSECOND",
},
{
interval: 50 * time.Hour,
expected: "INTERVAL '50:0:0:0' HOUR_MICROSECOND",
},
{
interval: 50*time.Hour + 50*time.Minute,
expected: "INTERVAL '50:50:0:0' HOUR_MICROSECOND",
},
{
interval: 50*time.Hour + 50*time.Minute + 50*time.Second,
expected: "INTERVAL '50:50:50:0' HOUR_MICROSECOND",
},
{
interval: 0,
expected: "INTERVAL '0:0:0:0' HOUR_MICROSECOND",
},
{
interval: 50 * time.Nanosecond,
expected: "INTERVAL '0:0:0:0' HOUR_MICROSECOND",
},
}
buf := &bytes.Buffer{}
for i, tt := range testTable {
buf.Reset()
err := Interval(tt.interval).Serialize(buf)
c.Assert(err, gc.Equals, tt.expectedErr,
gc.Commentf("experiment #%d", i))
if err == nil {
c.Assert(buf.String(), gc.Equals, tt.expected,
gc.Commentf("experiment #%d", i))
}
}
}

View file

@ -46,7 +46,7 @@ func (e *expressionTableImpl) AllColumns() ProjectionList {
func (e *expressionTableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (e *expressionTableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if e == nil { if e == nil {
return errors.New("Expression table is nil. ") return errors.New("jet: Expression table is nil. ")
} }
err := e.expression.serialize(statement, out) err := e.expression.serialize(statement, out)

View file

@ -7,7 +7,7 @@ import (
func TestExpressionIS_NULL(t *testing.T) { func TestExpressionIS_NULL(t *testing.T) {
assertClauseSerialize(t, table2Col3.IS_NULL(), "table2.col3 IS NULL") assertClauseSerialize(t, table2Col3.IS_NULL(), "table2.col3 IS NULL")
assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NULL(), "(table2.col3 + table2.col3) IS NULL") assertClauseSerialize(t, table2Col3.ADD(table2Col3).IS_NULL(), "(table2.col3 + table2.col3) IS NULL")
assertClauseSerializeErr(t, table2Col3.ADD(nil), "nil rhs") assertClauseSerializeErr(t, table2Col3.ADD(nil), "jet: nil rhs")
} }
func TestExpressionIS_NOT_NULL(t *testing.T) { func TestExpressionIS_NOT_NULL(t *testing.T) {

View file

@ -27,7 +27,7 @@ func newFunc(name string, expressions []Expression, parent Expression) *funcExpr
func (f *funcExpressionImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (f *funcExpressionImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if f == nil { if f == nil {
return errors.New("Function expressions is nil. ") return errors.New("jet: Function expressions is nil. ")
} }
addBrackets := !f.noBrackets || len(f.expressions) > 0 addBrackets := !f.noBrackets || len(f.expressions) > 0

View file

@ -103,7 +103,7 @@ const (
func (e *{{ToGoIdentifier $.Name}}) Scan(value interface{}) error { func (e *{{ToGoIdentifier $.Name}}) Scan(value interface{}) error {
if v, ok := value.(string); !ok { if v, ok := value.(string); !ok {
return errors.New("Invalid data for {{ToGoIdentifier $.Name}} enum") return errors.New("jet: Invalid data for {{ToGoIdentifier $.Name}} enum")
} else { } else {
switch string(v) { switch string(v) {
{{- range $index, $element := .Values}} {{- range $index, $element := .Values}}
@ -111,7 +111,7 @@ func (e *{{ToGoIdentifier $.Name}}) Scan(value interface{}) error {
*e = {{ToGoIdentifier $.Name}}_{{ToGoIdentifier $element}} *e = {{ToGoIdentifier $.Name}}_{{ToGoIdentifier $element}}
{{- end}} {{- end}}
default: default:
return errors.New("Inavlid data " + string(v) + "for {{ToGoIdentifier $.Name}} enum") return errors.New("jet: Inavlid data " + string(v) + "for {{ToGoIdentifier $.Name}} enum")
} }
return nil return nil

View file

@ -82,7 +82,7 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
queryData.writeString("INSERT INTO") queryData.writeString("INSERT INTO")
if isNil(i.table) { if isNil(i.table) {
return "", nil, errors.New("table is nil") return "", nil, errors.New("jet: table is nil")
} }
err = i.table.serialize(insert_statement, queryData) err = i.table.serialize(insert_statement, queryData)
@ -104,11 +104,11 @@ func (i *insertStatementImpl) Sql() (sql string, args []interface{}, err error)
} }
if len(i.rows) == 0 && i.query == nil { if len(i.rows) == 0 && i.query == nil {
return "", nil, errors.New("no row values or query specified") return "", nil, errors.New("jet: no row values or query specified")
} }
if len(i.rows) > 0 && i.query != nil { if len(i.rows) > 0 && i.query != nil {
return "", nil, errors.New("only row values or query has to be specified") return "", nil, errors.New("jet: only row values or query has to be specified")
} }
if len(i.rows) > 0 { if len(i.rows) > 0 {

View file

@ -7,8 +7,8 @@ import (
) )
func TestInvalidInsert(t *testing.T) { func TestInvalidInsert(t *testing.T) {
assertStatementErr(t, table1.INSERT(table1Col1), "no row values or query specified") assertStatementErr(t, table1.INSERT(table1Col1), "jet: no row values or query specified")
assertStatementErr(t, table1.INSERT(nil).VALUES(1), "nil column in columns list") assertStatementErr(t, table1.INSERT(nil).VALUES(1), "jet: nil column in columns list")
} }
func TestInsertNilValue(t *testing.T) { func TestInsertNilValue(t *testing.T) {

View file

@ -55,11 +55,11 @@ func (l *lockStatementImpl) DebugSql() (query string, err error) {
func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) { func (l *lockStatementImpl) Sql() (query string, args []interface{}, err error) {
if l == nil { if l == nil {
return "", nil, errors.New("nil Statement.") return "", nil, errors.New("jet: nil Statement.")
} }
if len(l.tables) == 0 { if len(l.tables) == 0 {
return "", nil, errors.New("There is no table selected to be locked. ") return "", nil, errors.New("jet: There is no table selected to be locked. ")
} }
out := &sqlBuilder{} out := &sqlBuilder{}

View file

@ -102,7 +102,7 @@ func (c *caseOperatorImpl) ELSE(els Expression) CaseOperatorExpression {
func (c *caseOperatorImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (c *caseOperatorImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if c == nil { if c == nil {
return errors.New("Case Expression is nil. ") return errors.New("jet: Case Expression is nil. ")
} }
out.writeString("(CASE") out.writeString("(CASE")
@ -116,11 +116,11 @@ func (c *caseOperatorImpl) serialize(statement statementType, out *sqlBuilder, o
} }
if len(c.when) == 0 || len(c.then) == 0 { if len(c.when) == 0 || len(c.then) == 0 {
return errors.New("Invalid case Statement. There should be at least one when/then Expression pair. ") return errors.New("jet: Invalid case Statement. There should be at least one when/then Expression pair. ")
} }
if len(c.when) != len(c.then) { if len(c.when) != len(c.then) {
return errors.New("When and then Expression count mismatch. ") return errors.New("jet: When and then Expression count mismatch. ")
} }
for i, when := range c.when { for i, when := range c.when {

View file

@ -13,7 +13,7 @@ type orderByClauseImpl struct {
func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error { func (o *orderByClauseImpl) serializeForOrderBy(statement statementType, out *sqlBuilder) error {
if o.expression == nil { if o.expression == nil {
return errors.New("nil orderBy by clause.") return errors.New("jet: nil orderBy by clause.")
} }
if err := o.expression.serializeForOrderBy(statement, out); err != nil { if err := o.expression.serializeForOrderBy(statement, out); err != nil {

View file

@ -155,7 +155,7 @@ func (s *selectStatementImpl) projections() []projection {
func (s *selectStatementImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (s *selectStatementImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if s == nil { if s == nil {
return errors.New("Select expression is nil. ") return errors.New("jet: Select expression is nil. ")
} }
out.writeString("(") out.writeString("(")
@ -175,7 +175,7 @@ func (s *selectStatementImpl) serialize(statement statementType, out *sqlBuilder
func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error { func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
if s == nil { if s == nil {
return errors.New("Select expression is nil. ") return errors.New("jet: Select expression is nil. ")
} }
out.newLine() out.newLine()
@ -186,7 +186,7 @@ func (s *selectStatementImpl) serializeImpl(out *sqlBuilder) error {
} }
if len(s.projectionList) == 0 { if len(s.projectionList) == 0 {
return errors.New("no column selected for projection") return errors.New("jet: no column selected for projection")
} }
err := out.writeProjections(select_statement, s.projectionList) err := out.writeProjections(select_statement, s.projectionList)

View file

@ -3,7 +3,7 @@ package jet
import "testing" import "testing"
func TestInvalidSelect(t *testing.T) { func TestInvalidSelect(t *testing.T) {
assertStatementErr(t, SELECT(nil), "projection is nil") assertStatementErr(t, SELECT(nil), "jet: projection is nil")
} }
func TestSelectColumnList(t *testing.T) { func TestSelectColumnList(t *testing.T) {

View file

@ -71,7 +71,7 @@ func (s *setStatementImpl) projections() []projection {
func (s *setStatementImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (s *setStatementImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if s == nil { if s == nil {
return errors.New("Set expression is nil. ") return errors.New("jet: Set expression is nil. ")
} }
wrap := s.orderBy != nil || s.limit >= 0 || s.offset >= 0 wrap := s.orderBy != nil || s.limit >= 0 || s.offset >= 0
@ -98,11 +98,11 @@ func (s *setStatementImpl) serialize(statement statementType, out *sqlBuilder, o
func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error { func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
if s == nil { if s == nil {
return errors.New("Set expression is nil. ") return errors.New("jet: Set expression is nil. ")
} }
if len(s.selects) < 2 { if len(s.selects) < 2 {
return errors.New("UNION Statement must have at least two SELECT statements.") return errors.New("jet: UNION Statement must have at least two SELECT statements.")
} }
out.newLine() out.newLine()
@ -121,7 +121,7 @@ func (s *setStatementImpl) serializeImpl(out *sqlBuilder) error {
} }
if selectStmt == nil { if selectStmt == nil {
return errors.New("select statement is nil") return errors.New("jet: select statement is nil")
} }
err := selectStmt.serialize(set_statement, out) err := selectStmt.serialize(set_statement, out)

View file

@ -37,7 +37,7 @@ func TestUnionNilSelect(t *testing.T) {
SELECT(table1Col1). SELECT(table1Col1).
UNION(nil) UNION(nil)
assertStatementErr(t, unionStmt, "select statement is nil") assertStatementErr(t, unionStmt, "jet: select statement is nil")
} }
func TestUnionThreeSelect1(t *testing.T) { func TestUnionThreeSelect1(t *testing.T) {

View file

@ -170,7 +170,7 @@ func (t *tableImpl) columns() []column {
func (t *tableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error { func (t *tableImpl) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) error {
if t == nil { if t == nil {
return errors.New("tableImpl is nil. ") return errors.New("jet: tableImpl is nil. ")
} }
out.writeIdentifier(t.schemaName) out.writeIdentifier(t.schemaName)
@ -237,11 +237,11 @@ func (t *joinTable) columns() []column {
func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) (err error) { func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options ...serializeOption) (err error) {
if t == nil { if t == nil {
return errors.New("Join table is nil. ") return errors.New("jet: Join table is nil. ")
} }
if isNil(t.lhs) { if isNil(t.lhs) {
return errors.New("left hand side of join operation is nil table") return errors.New("jet: left hand side of join operation is nil table")
} }
if err = t.lhs.serialize(statement, out); err != nil { if err = t.lhs.serialize(statement, out); err != nil {
@ -264,7 +264,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
} }
if isNil(t.rhs) { if isNil(t.rhs) {
return errors.New("right hand side of join operation is nil table") return errors.New("jet: right hand side of join operation is nil table")
} }
if err = t.rhs.serialize(statement, out); err != nil { if err = t.rhs.serialize(statement, out); err != nil {
@ -272,7 +272,7 @@ func (t *joinTable) serialize(statement statementType, out *sqlBuilder, options
} }
if t.onCondition == nil && t.join_type != crossJoin { if t.onCondition == nil && t.join_type != crossJoin {
return errors.New("join condition is nil") return errors.New("jet: join condition is nil")
} }
if t.onCondition != nil { if t.onCondition != nil {

View file

@ -6,9 +6,9 @@ import (
func TestJoinNilInputs(t *testing.T) { func TestJoinNilInputs(t *testing.T) {
assertClauseSerializeErr(t, table2.INNER_JOIN(nil, table1ColBool.EQ(table2ColBool)), assertClauseSerializeErr(t, table2.INNER_JOIN(nil, table1ColBool.EQ(table2ColBool)),
"right hand side of join operation is nil table") "jet: right hand side of join operation is nil table")
assertClauseSerializeErr(t, table2.INNER_JOIN(table1, nil), assertClauseSerializeErr(t, table2.INNER_JOIN(table1, nil),
"join condition is nil") "jet: join condition is nil")
} }
func TestINNER_JOIN(t *testing.T) { func TestINNER_JOIN(t *testing.T) {

View file

@ -21,31 +21,31 @@ func TestScanToInvalidDestination(t *testing.T) {
t.Run("nil dest", func(t *testing.T) { t.Run("nil dest", func(t *testing.T) {
err := query.Query(db, nil) err := query.Query(db, nil)
assert.Error(t, err, "Destination is nil. ") assert.Error(t, err, "jet: Destination is nil.")
}) })
t.Run("struct dest", func(t *testing.T) { t.Run("struct dest", func(t *testing.T) {
err := query.Query(db, struct{}{}) err := query.Query(db, struct{}{})
assert.Error(t, err, "Destination has to be a pointer to slice or pointer to struct. ") assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
}) })
t.Run("slice dest", func(t *testing.T) { t.Run("slice dest", func(t *testing.T) {
err := query.Query(db, []struct{}{}) err := query.Query(db, []struct{}{})
assert.Error(t, err, "Destination has to be a pointer to slice or pointer to struct. ") assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
}) })
t.Run("slice of pointers to pointer dest", func(t *testing.T) { t.Run("slice of pointers to pointer dest", func(t *testing.T) {
err := query.Query(db, []**struct{}{}) err := query.Query(db, []**struct{}{})
assert.Error(t, err, "Destination has to be a pointer to slice or pointer to struct. ") assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
}) })
t.Run("map dest", func(t *testing.T) { t.Run("map dest", func(t *testing.T) {
err := query.Query(db, []map[string]string{}) err := query.Query(db, []map[string]string{})
assert.Error(t, err, "Destination has to be a pointer to slice or pointer to struct. ") assert.Error(t, err, "jet: Destination has to be a pointer to slice or pointer to struct")
}) })
} }
@ -129,7 +129,7 @@ func TestScanToStruct(t *testing.T) {
err := query.Query(db, &dest) err := query.Query(db, &dest)
assert.Error(t, err, "Unsupported dest type: Inventory **model.Inventory") assert.Error(t, err, "jet: Unsupported dest type: Inventory **model.Inventory")
}) })
t.Run("invalid dest 2", func(t *testing.T) { t.Run("invalid dest 2", func(t *testing.T) {
@ -139,7 +139,7 @@ func TestScanToStruct(t *testing.T) {
err := query.Query(db, &dest) err := query.Query(db, &dest)
assert.Error(t, err, "Unsupported dest type: Inventory ***model.Inventory") assert.Error(t, err, "jet: Unsupported dest type: Inventory ***model.Inventory")
}) })
t.Run("custom struct", func(t *testing.T) { t.Run("custom struct", func(t *testing.T) {
@ -170,7 +170,7 @@ func TestScanToStruct(t *testing.T) {
err := query.Query(db, &dest) err := query.Query(db, &dest)
assert.Error(t, err, `Scan: can't set int32 to int, at struct field: InventoryID int of type tests.Inventory. `) assert.Error(t, err, `jet: can't set int32 to int, at struct field: InventoryID int of type tests.Inventory. `)
fmt.Println(err) fmt.Println(err)
}) })
@ -431,7 +431,7 @@ func TestScanToSlice(t *testing.T) {
var dest []int var dest []int
err := query.Query(db, &dest) err := query.Query(db, &dest)
assert.Error(t, err, `Scan: can't append int32 to []int slice `) assert.Error(t, err, `jet: can't append int32 to []int slice `)
}) })
}) })
@ -678,7 +678,7 @@ func TestScanToSlice(t *testing.T) {
err := query.Query(db, &dest) err := query.Query(db, &dest)
assert.Error(t, err, "Unsupported dest type: Cities []**struct { *model.City }") assert.Error(t, err, "jet: Unsupported dest type: Cities []**struct { *model.City }")
}) })
} }

View file

@ -861,14 +861,14 @@ FROM dvds.film
WHERE film.rental_rate = ( WHERE film.rental_rate = (
SELECT MAX(film.rental_rate) SELECT MAX(film.rental_rate)
FROM dvds.film FROM dvds.film
)::double precision )
ORDER BY film.film_id ASC; ORDER BY film.film_id ASC;
` `
maxFilmRentalRate := CAST( maxFilmRentalRate := FloatExp(
Film. Film.
SELECT(MAXf(Film.RentalRate)), SELECT(MAXf(Film.RentalRate)),
).AS_DOUBLE() )
query := Film. query := Film.
SELECT(Film.AllColumns). SELECT(Film.AllColumns).

View file

@ -62,7 +62,7 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
out.writeString("UPDATE") out.writeString("UPDATE")
if isNil(u.table) { if isNil(u.table) {
return "", nil, errors.New("table to update is nil") return "", nil, errors.New("jet: table to update is nil")
} }
if err = u.table.serialize(update_statement, out); err != nil { if err = u.table.serialize(update_statement, out); err != nil {
@ -70,11 +70,11 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
} }
if len(u.columns) == 0 { if len(u.columns) == 0 {
return "", nil, errors.New("no columns selected") return "", nil, errors.New("jet: no columns selected")
} }
if len(u.row) == 0 { if len(u.row) == 0 {
return "", nil, errors.New("no values to updated") return "", nil, errors.New("jet: no values to updated")
} }
out.newLine() out.newLine()
@ -111,7 +111,7 @@ func (u *updateStatementImpl) Sql() (sql string, args []interface{}, err error)
} }
if u.where == nil { if u.where == nil {
return "", nil, errors.New("WHERE clause not set") return "", nil, errors.New("jet: WHERE clause not set")
} }
if err = out.writeWhere(update_statement, u.where); err != nil { if err = out.writeWhere(update_statement, u.where); err != nil {

View file

@ -71,6 +71,6 @@ RETURNING table1.col1 AS "table1.col1";
} }
func TestInvalidInputs(t *testing.T) { func TestInvalidInputs(t *testing.T) {
assertStatementErr(t, table1.UPDATE(table1ColInt).SET(1, 2), "WHERE clause not set") assertStatementErr(t, table1.UPDATE(table1ColInt).SET(1, 2), "jet: WHERE clause not set")
assertStatementErr(t, table1.UPDATE(nil).SET(1, 2), "nil column in columns list") assertStatementErr(t, table1.UPDATE(nil).SET(1, 2), "jet: nil column in columns list")
} }

View file

@ -32,7 +32,7 @@ func serializeGroupByClauseList(statement statementType, clauses []groupByClause
} }
if c == nil { if c == nil {
return errors.New("nil clause.") return errors.New("jet: nil clause.")
} }
if err = c.serializeForGroupBy(statement, out); err != nil { if err = c.serializeForGroupBy(statement, out); err != nil {
@ -51,7 +51,7 @@ func serializeClauseList(statement statementType, clauses []clause, out *sqlBuil
} }
if c == nil { if c == nil {
return errors.New("nil clause.") return errors.New("jet: nil clause.")
} }
if err = c.serialize(statement, out); err != nil { if err = c.serialize(statement, out); err != nil {
@ -87,7 +87,7 @@ func serializeProjectionList(statement statementType, projections []projection,
} }
if col == nil { if col == nil {
return errors.New("projection is nil") return errors.New("jet: projection is nil")
} }
if err := col.serializeForProjection(statement, out); err != nil { if err := col.serializeForProjection(statement, out); err != nil {
@ -105,7 +105,7 @@ func serializeColumnNames(columns []column, out *sqlBuilder) error {
} }
if col == nil { if col == nil {
return errors.New("nil column in columns list") return errors.New("jet: nil column in columns list")
} }
out.writeString(col.Name()) out.writeString(col.Name())

View file

@ -13,7 +13,7 @@ Jet sql builder supports following expression types:
_This list might be extended with feature Jet releases._ _This list might be extended with feature Jet releases._
### Literal type ### Literal Types
For every expression type there is a method to create one expression literal type . For every expression type there is a method to create one expression literal type .
Literal type examples: Literal type examples:
@ -32,7 +32,7 @@ jet.NULL
jet.STAR (alias for *) jet.STAR (alias for *)
``` ```
### Column types ### Column Types
Every sql builder table column belongs to one expression type. There are following column types: Every sql builder table column belongs to one expression type. There are following column types:
``` ```
jet.ColumnBool jet.ColumnBool
@ -62,7 +62,7 @@ jet.Int(11).LIKE(jet.Float(22.2)) // integer expressions doesn't have LIKE
``` ```
## Comparision operators ## Comparision Operators
Jet supports following comparison operators for all expression types: Jet supports following comparison operators for all expression types:
@ -80,7 +80,7 @@ Jet supports following comparison operators for all expression types:
*Left-hand side and right-hand side of operators have to be of the same type* *Left-hand side and right-hand side of operators have to be of the same type*
## Arithmetic operators ## Arithmetic Operators
Following arithmetic operators are supported for integer and float expressions. Following arithmetic operators are supported for integer and float expressions.
If the first argument is float expression, second argument can be integer or float expression. If the first argument is float expression, second argument can be integer or float expression.
@ -96,7 +96,7 @@ If the first argument is integer expression second argument can only be integer
| POW | jet.Float(10.01).POW(table.Film.Length) | 10.01 ^ film.length | | POW | jet.Float(10.01).POW(table.Film.Length) | 10.01 ^ film.length |
## Bit operators ## Bit Operators
Following operators are only available on integer expressions: Following operators are only available on integer expressions:
@ -110,7 +110,7 @@ Following operators are only available on integer expressions:
| BIT_SHIFT_RIGHT | jet.Int(11).BIT_SHIFT_RIGHT(table.Film.Length) | 11 >> film.length | | BIT_SHIFT_RIGHT | jet.Int(11).BIT_SHIFT_RIGHT(table.Film.Length) | 11 >> film.length |
## Logical operators ## Logical Operators
Following operators are only available on boolean expressions: Following operators are only available on boolean expressions:
@ -124,7 +124,7 @@ Following operators are only available on boolean expressions:
| IS_NOT_UNKNOWN | table.Staff.Active.IS_NOT_UNKNOWN() | staff.active IS NOT UNKNOWN | | IS_NOT_UNKNOWN | table.Staff.Active.IS_NOT_UNKNOWN() | staff.active IS NOT UNKNOWN |
## String operators ## String Operators
Following operators are only available on string expressions: Following operators are only available on string expressions:
@ -137,27 +137,56 @@ Following operators are only available on string expressions:
| NOT_SIMILAR_TO | table.Film.Name.NOT_SIMILAR_TO(String("%Wind%")) | staff.active NOT SIMILAR TO %Wind% | | NOT_SIMILAR_TO | table.Film.Name.NOT_SIMILAR_TO(String("%Wind%")) | staff.active NOT SIMILAR TO %Wind% |
## SQL Cast operators ## SQL Cast Operators
Cast operators allow expressions to be casted to some other database type. Cast operators allow expressions to be casted to some other database type.
SQL builder expression type changes accordingly to database type. SQL builder expression type changes accordingly to database type.
| Method | Example | Generated sql | | Method | Example | Generated sql |
| ------------------------------ | -------------------------------------------|---------------------------- | | ------------------------------ | ----------------------------------------------- | --------------------------------------------- |
| TO_BOOL | table.Film.Description.TO_BOOL() | film.description::boolean | | CAST(exp).AS_BOOL() | CAST(table.Film.Description).AS_BOOL() | film.description::boolean |
| TO_SMALLINT | table.Film.Description.TO_SMALLINT() | film.description::smallint | | CAST(exp).AS_SMALLINT() | CAST(table.Film.Description).AS_SMALLINT() | film.description::smallint |
| TO_INTEGER | table.Film.Description.TO_INTEGER() | film.description::integer | | CAST(exp).AS_INTEGER() | CAST(table.Film.Description).AS_INTEGER() | film.description::integer |
| TO_BIGINT | table.Film.Description.TO_BIGINT() | film.description::bigint | | CAST(exp).AS_BIGINT() | CAST(table.Film.Description).AS_BIGINT() | film.description::bigint |
| TO_NUMERIC | table.Film.Description.TO_NUMERIC(10, 6) | film.description::numeric(10,6) | | CAST(exp).AS_NUMERIC() | CAST(table.Film.Description).AS_NUMERIC(10, 6) | film.description::numeric(10,6) |
| TO_REAL | table.Film.Description.TO_REAL() | film.description::real | | CAST(exp).AS_REAL() | CAST(table.Film.Description).AS_REAL() | film.description::real |
| TO_DOUBLE | table.Film.Description.TO_DOUBLE() | film.description::double | | CAST(exp).AS_DOUBLE() | CAST(table.Film.Description).AS_DOUBLE() | film.description::double |
| TO_TEXT | table.Film.Description.TO_TEXT() | film.description::text | | CAST(exp).AS_TEXT() | CAST(table.Film.Description).AS_TEXT() | film.description::text |
| TO_DATE | table.Film.Description.TO_DATE() | film.description::date | | CAST(exp).AS_DATE() | CAST(table.Film.Description).AS_DATE() | film.description::date |
| TO_TIME | table.Film.Description.TO_TIME() | film.description::time | | CAST(exp).AS_TIME() | CAST(table.Film.Description).AS_TIME() | film.description::time without time zone |
| TO_TIMEZ | table.Film.Description.TO_TIMEZ() | film.description::timez | | CAST(exp).AS_TIMEZ() | CAST(table.Film.Description).AS_TIMEZ() | film.description::time with time zone |
| TO_TIMESTAMP | table.Film.Description.TO_TIMESTAMP() | film.description::timestamp | | CAST(exp).AS_TIMESTAMP() | CAST(table.Film.Description).AS_TIMESTAMP() | film.description::timestamp without time zone |
| TO_TIMESTAMPZ | table.Film.Description.TO_TIMESTAMPZ() | film.description::timestampz | | CAST(exp).AS_TIMESTAMPZ() | CAST(table.Film.Description).AS_TIMESTAMPZ() | film.description::timestamp with time zone |
## SQL builder cast ## SQL Builder Cast Wrapper
TODO: For some expressions sql builder can't deduce expression type directly. For instance scalar sub-query:
```
( SELECT(MAXf(Film.RentalRate)).
FROM(Film) ).LT(Float(11.1))
```
This expression would not compile, because sub-query, although calculates one scalar float value, it is not a float expression.
To fix this sub-query can be cast to some float type, or just wrapped as float expression:
```
FloatExp( SELECT(MAXf(Film.RentalRate)).
FROM(Film) ).LT(Float(11.1))
```
There are wrappers for all supported types:
```
- BoolExp(exp)
- IntExp(exp)
- FloatExp(exp)
- StringExp(exp)
- DateExp(exp)
- TimeExp(exp)
- TimezExp(exp)
- TimestampExp(exp)
- TimestampzExp(exp)
```
**Cast wrapper does NOT inject cast operator to generated SQL.**
## RAW Operator
There is a RAW operator expression, that accepts raw sql as a string. It can be used for any unsupported functions, operators or expressions.
For example:
```RAW("current_database()")``` _can be cast or wrapped, as needed._

View file

@ -113,7 +113,7 @@ const (
func (e *MpaaRating) Scan(value interface{}) error { func (e *MpaaRating) Scan(value interface{}) error {
if v, ok := value.(string); !ok { if v, ok := value.(string); !ok {
return errors.New("Invalid data for MpaaRating enum") return errors.New("jet: Invalid data for MpaaRating enum")
} else { } else {
switch string(v) { switch string(v) {
case "G": case "G":