add documents on all exported functions and interfaces

This commit is contained in:
lqs 2020-07-07 17:07:14 +08:00
parent 23f58d61a0
commit 7fea9e30a0
14 changed files with 89 additions and 34 deletions

View File

@ -2,12 +2,14 @@ package sqlingo
import "strings" import "strings"
// CaseExpression indicates the status in a CASE statement
type CaseExpression interface { type CaseExpression interface {
WhenThen(when BooleanExpression, then interface{}) CaseExpression WhenThen(when BooleanExpression, then interface{}) CaseExpression
Else(value interface{}) CaseExpressionWithElse Else(value interface{}) CaseExpressionWithElse
End() Expression End() Expression
} }
// CaseExpressionWithElse indicates the status in CASE ... ELSE ... statement
type CaseExpressionWithElse interface { type CaseExpressionWithElse interface {
End() Expression End() Expression
} }
@ -23,6 +25,7 @@ type whenThen struct {
then interface{} then interface{}
} }
// Case initiates a CASE statement
func Case() CaseExpression { func Case() CaseExpression {
return caseStatus{} return caseStatus{}
} }

View File

@ -6,11 +6,13 @@ import (
"strings" "strings"
) )
// Model is the interface of generated model struct
type Model interface { type Model interface {
GetTable() Table GetTable() Table
GetValues() []interface{} GetValues() []interface{}
} }
// Assignment is an assignment statement
type Assignment interface { type Assignment interface {
GetSQL(scope scope) (string, error) GetSQL(scope scope) (string, error)
} }

View File

@ -7,6 +7,7 @@ import (
"strconv" "strconv"
) )
// Cursor is the interface of a row cursor.
type Cursor interface { type Cursor interface {
Next() bool Next() bool
Scan(dest ...interface{}) error Scan(dest ...interface{}) error

View File

@ -6,24 +6,42 @@ import (
"time" "time"
) )
// Database is the interface of a database with underlying sql.DB object.
type Database interface { type Database interface {
// Get the underlying sql.DB object of the database
GetDB() *sql.DB GetDB() *sql.DB
BeginTx(ctx context.Context, opts *sql.TxOptions, f func(tx Transaction) error) error BeginTx(ctx context.Context, opts *sql.TxOptions, f func(tx Transaction) error) error
// Executes a query and return the cursor
Query(sql string) (Cursor, error) Query(sql string) (Cursor, error)
// Executes a query with context and return the cursor
QueryContext(ctx context.Context, sqlString string) (Cursor, error) QueryContext(ctx context.Context, sqlString string) (Cursor, error)
// Executes a statement
Execute(sql string) (sql.Result, error) Execute(sql string) (sql.Result, error)
// Executes a statement with context
ExecuteContext(ctx context.Context, sql string) (sql.Result, error) ExecuteContext(ctx context.Context, sql string) (sql.Result, error)
// Set the logger function
SetLogger(logger func(sql string, durationNano int64)) SetLogger(logger func(sql string, durationNano int64))
// Set the retry policy function.
// The retry policy function returns true if needs retry.
SetRetryPolicy(retryPolicy func(err error) bool) SetRetryPolicy(retryPolicy func(err error) bool)
// enable or disable caller info
EnableCallerInfo(enableCallerInfo bool) EnableCallerInfo(enableCallerInfo bool)
// Set a interceptor function
SetInterceptor(interceptor InterceptorFunc) SetInterceptor(interceptor InterceptorFunc)
// Initiate a SELECT statement
Select(fields ...interface{}) selectWithFields Select(fields ...interface{}) selectWithFields
// Initiate a SELECT DISTINCT statement
SelectDistinct(fields ...interface{}) selectWithFields SelectDistinct(fields ...interface{}) selectWithFields
// Initiate a SELECT * FROM statement
SelectFrom(tables ...Table) selectWithTables SelectFrom(tables ...Table) selectWithTables
// Initiate a INSERT INTO statement
InsertInto(table Table) insertWithTable InsertInto(table Table) insertWithTable
// Initiate a REPLACE INTO statement
ReplaceInto(table Table) insertWithTable ReplaceInto(table Table) insertWithTable
// Initiate a UPDATE statement
Update(table Table) updateWithSet Update(table Table) updateWithSet
// Initiate a DELETE FROM statement
DeleteFrom(table Table) deleteWithTable DeleteFrom(table Table) deleteWithTable
} }
@ -58,6 +76,7 @@ func (d *database) SetInterceptor(interceptor InterceptorFunc) {
d.interceptor = interceptor d.interceptor = interceptor
} }
// Open a database, similar to sql.Open
func Open(driverName string, dataSourceName string) (db Database, err error) { func Open(driverName string, dataSourceName string) (db Database, err error) {
var sqlDB *sql.DB var sqlDB *sql.DB
if dataSourceName != "" { if dataSourceName != "" {
@ -80,9 +99,8 @@ func (d database) GetDB() *sql.DB {
func (d database) getTxOrDB() txOrDB { func (d database) getTxOrDB() txOrDB {
if d.tx != nil { if d.tx != nil {
return d.tx return d.tx
} else {
return d.db
} }
return d.db
} }
func (d database) Query(sqlString string) (Cursor, error) { func (d database) Query(sqlString string) (Cursor, error) {
@ -118,6 +136,9 @@ func (d database) queryContextOnce(ctx context.Context, sqlStringWithCallerInfo
interceptor := d.interceptor interceptor := d.interceptor
var rows *sql.Rows var rows *sql.Rows
invoker := func(ctx context.Context, sql string) (err error) { invoker := func(ctx context.Context, sql string) (err error) {
if ctx == nil {
ctx = context.Background()
}
rows, err = d.getTxOrDB().QueryContext(ctx, sql) rows, err = d.getTxOrDB().QueryContext(ctx, sql)
return return
} }

View File

@ -6,15 +6,23 @@ import (
"strconv" "strconv"
) )
// Expression is the interface of a SQL expression.
type Expression interface { type Expression interface {
// get the SQL string
GetSQL(scope scope) (string, error) GetSQL(scope scope) (string, error)
getOperatorPriority() int getOperatorPriority() int
// <> operator
NotEquals(other interface{}) BooleanExpression NotEquals(other interface{}) BooleanExpression
// == operator
Equals(other interface{}) BooleanExpression Equals(other interface{}) BooleanExpression
// < operator
LessThan(other interface{}) BooleanExpression LessThan(other interface{}) BooleanExpression
// <= operator
LessThanOrEquals(other interface{}) BooleanExpression LessThanOrEquals(other interface{}) BooleanExpression
// > operator
GreaterThan(other interface{}) BooleanExpression GreaterThan(other interface{}) BooleanExpression
// >= operator
GreaterThanOrEquals(other interface{}) BooleanExpression GreaterThanOrEquals(other interface{}) BooleanExpression
IsNull() BooleanExpression IsNull() BooleanExpression
@ -29,10 +37,12 @@ type Expression interface {
IfNull(altValue interface{}) Expression IfNull(altValue interface{}) Expression
} }
// Alias is the interface of an table/column alias.
type Alias interface { type Alias interface {
GetSQL(scope scope) (string, error) GetSQL(scope scope) (string, error)
} }
// BooleanExpression is the interface of a SQL expression with boolean value.
type BooleanExpression interface { type BooleanExpression interface {
Expression Expression
And(other interface{}) BooleanExpression And(other interface{}) BooleanExpression
@ -40,6 +50,7 @@ type BooleanExpression interface {
Not() BooleanExpression Not() BooleanExpression
} }
// NumberExpression is the interface of a SQL expression with number value.
type NumberExpression interface { type NumberExpression interface {
Expression Expression
Add(other interface{}) NumberExpression Add(other interface{}) NumberExpression
@ -55,6 +66,7 @@ type NumberExpression interface {
Max() UnknownExpression Max() UnknownExpression
} }
// StringExpression is the interface of a SQL expression with string value.
type StringExpression interface { type StringExpression interface {
Expression Expression
Min() UnknownExpression Min() UnknownExpression
@ -63,6 +75,7 @@ type StringExpression interface {
Contains(substring string) BooleanExpression Contains(substring string) BooleanExpression
} }
// UnknownExpression is the interface of a SQL expression with unknown value.
type UnknownExpression interface { type UnknownExpression interface {
Expression Expression
And(other interface{}) BooleanExpression And(other interface{}) BooleanExpression
@ -116,6 +129,7 @@ func falseExpression() expression {
} }
} }
// Raw create a raw SQL statement
func Raw(sql string) UnknownExpression { func Raw(sql string) UnknownExpression {
return expression{ return expression{
sql: sql, sql: sql,
@ -123,6 +137,7 @@ func Raw(sql string) UnknownExpression {
} }
} }
// And creates an expression with AND operator.
func And(expressions ...BooleanExpression) (result BooleanExpression) { func And(expressions ...BooleanExpression) (result BooleanExpression) {
if len(expressions) == 0 { if len(expressions) == 0 {
result = trueExpression() result = trueExpression()
@ -138,6 +153,7 @@ func And(expressions ...BooleanExpression) (result BooleanExpression) {
return return
} }
// Or creates an expression with OR operator.
func Or(expressions ...BooleanExpression) (result BooleanExpression) { func Or(expressions ...BooleanExpression) (result BooleanExpression) {
if len(expressions) == 0 { if len(expressions) == 0 {
result = falseExpression() result = falseExpression()
@ -490,20 +506,20 @@ func (e expression) NotIn(values ...interface{}) BooleanExpression {
return expression{builder: builder, priority: 11} return expression{builder: builder, priority: 11}
} }
type JoinerFunc = func(exprSql, valuesSql string) string type joinerFunc = func(exprSql, valuesSql string) string
type BooleanFunc = func(other interface{}) BooleanExpression type booleanFunc = func(other interface{}) BooleanExpression
type BuilderFunc = func(scope scope) (string, error) type builderFunc = func(scope scope) (string, error)
func (e expression) getBuilder(single BooleanFunc, joiner JoinerFunc, values ...interface{}) BuilderFunc { func (e expression) getBuilder(single booleanFunc, joiner joinerFunc, values ...interface{}) builderFunc {
return func(scope scope) (string, error) { return func(scope scope) (string, error) {
var valuesSql string var valuesSql string
var err error var err error
if len(values) == 1 { if len(values) == 1 {
value := values[0] value := values[0]
if select_, ok := value.(toSelectFinal); ok { if selectStatus, ok := value.(toSelectFinal); ok {
// IN subquery // IN subquery
valuesSql, err = select_.GetSQL() valuesSql, err = selectStatus.GetSQL()
if err != nil { if err != nil {
return "", err return "", err
} }

View File

@ -2,18 +2,22 @@ package sqlingo
import "strings" import "strings"
// Field is the interface of a generated field.
type Field interface { type Field interface {
Expression Expression
} }
// NumberField is the interface of a generated field of number type.
type NumberField interface { type NumberField interface {
NumberExpression NumberExpression
} }
// BooleanField is the interface of a generated field of boolean type.
type BooleanField interface { type BooleanField interface {
BooleanExpression BooleanExpression
} }
// StringField is the interface of a generated field of string type.
type StringField interface { type StringField interface {
StringExpression StringExpression
} }
@ -41,21 +45,24 @@ func newFieldExpression(tableName string, fieldName string) expression {
} }
} }
// NewNumberField creates a reference to a number field. It should only be called from generated code.
func NewNumberField(tableName string, fieldName string) NumberField { func NewNumberField(tableName string, fieldName string) NumberField {
return newFieldExpression(tableName, fieldName) return newFieldExpression(tableName, fieldName)
} }
// NewBooleanField creates a reference to a boolean field. It should only be called from generated code.
func NewBooleanField(tableName string, fieldName string) BooleanField { func NewBooleanField(tableName string, fieldName string) BooleanField {
return newFieldExpression(tableName, fieldName) return newFieldExpression(tableName, fieldName)
} }
// NewStringField creates a reference to a string field. It should only be called from generated code.
func NewStringField(tableName string, fieldName string) StringField { func NewStringField(tableName string, fieldName string) StringField {
return newFieldExpression(tableName, fieldName) return newFieldExpression(tableName, fieldName)
} }
type FieldList []Field type fieldList []Field
func (fields FieldList) GetSQL(scope scope) (string, error) { func (fields fieldList) GetSQL(scope scope) (string, error) {
isSingleTable := len(scope.Tables) == 1 && scope.lastJoin == nil isSingleTable := len(scope.Tables) == 1 && scope.lastJoin == nil
var sb strings.Builder var sb strings.Builder
if len(fields) == 0 { if len(fields) == 0 {

View File

@ -37,7 +37,7 @@ func TestField(t *testing.T) {
assertValue(t, NewBooleanField("t1", "f1").Equals(true), "`t1`.`f1` = 1") assertValue(t, NewBooleanField("t1", "f1").Equals(true), "`t1`.`f1` = 1")
assertValue(t, NewStringField("t1", "f1").Equals("x"), "`t1`.`f1` = 'x'") assertValue(t, NewStringField("t1", "f1").Equals("x"), "`t1`.`f1` = 'x'")
sql, _ := FieldList{}.GetSQL(scope{ sql, _ := fieldList{}.GetSQL(scope{
Tables: []Table{ Tables: []Table{
&dummyTable{}, &dummyTable{},
}, },
@ -46,7 +46,7 @@ func TestField(t *testing.T) {
t.Error(sql) t.Error(sql)
} }
sql, _ = FieldList{}.GetSQL(scope{ sql, _ = fieldList{}.GetSQL(scope{
Tables: []Table{ Tables: []Table{
&dummyTable{}, &dummyTable{},
&dummyTable{}, &dummyTable{},
@ -56,7 +56,7 @@ func TestField(t *testing.T) {
t.Error(sql) t.Error(sql)
} }
if _, err := (FieldList{ if _, err := (fieldList{
expression{builder: func(scope scope) (string, error) { expression{builder: func(scope scope) (string, error) {
return "", errors.New("error") return "", errors.New("error")
}}, }},

View File

@ -10,26 +10,32 @@ func function(name string, args ...interface{}) expression {
}} }}
} }
// Function creates an expression of the call to specified function.
func Function(name string, args ...interface{}) Expression { func Function(name string, args ...interface{}) Expression {
return function(name, args...) return function(name, args...)
} }
// Concat creates an expression of CONCAT function.
func Concat(args ...interface{}) StringExpression { func Concat(args ...interface{}) StringExpression {
return function("CONCAT", args...) return function("CONCAT", args...)
} }
// Count creates an expression of COUNT aggregator.
func Count(arg interface{}) NumberExpression { func Count(arg interface{}) NumberExpression {
return function("COUNT", arg) return function("COUNT", arg)
} }
// If creates an expression of IF function.
func If(predicate Expression, trueValue interface{}, falseValue interface{}) (result Expression) { func If(predicate Expression, trueValue interface{}, falseValue interface{}) (result Expression) {
return function("IF", predicate, trueValue, falseValue) return function("IF", predicate, trueValue, falseValue)
} }
// Length creates an expression of LENGTH function.
func Length(arg interface{}) NumberExpression { func Length(arg interface{}) NumberExpression {
return function("LENGTH", arg) return function("LENGTH", arg)
} }
// Sum creates an expression of SUM aggregator.
func Sum(arg interface{}) NumberExpression { func Sum(arg interface{}) NumberExpression {
return function("SUM", arg) return function("SUM", arg)
} }

View File

@ -4,7 +4,10 @@ import (
"context" "context"
) )
// InvokerFunc is the function type of the actual invoker. It should be called in an interceptor.
type InvokerFunc = func(ctx context.Context, sql string) error type InvokerFunc = func(ctx context.Context, sql string) error
// InterceptorFunc is the function type of an interceptor. An interceptor should implement this function to fulfill it's purpose.
type InterceptorFunc = func(ctx context.Context, sql string, invoker InvokerFunc) error type InterceptorFunc = func(ctx context.Context, sql string, invoker InvokerFunc) error
// TODO: add some common interceptors // TODO: add some common interceptors

View File

@ -1,5 +1,6 @@
package sqlingo package sqlingo
// OrderBy indicates the ORDER BY column and the status of descending order.
type OrderBy interface { type OrderBy interface {
GetSQL(scope scope) (string, error) GetSQL(scope scope) (string, error)
} }

View File

@ -1,7 +1,7 @@
package sqlingo package sqlingo
import ( import (
. "context" "context"
"errors" "errors"
"reflect" "reflect"
"strconv" "strconv"
@ -101,7 +101,7 @@ type selectWithLock interface {
} }
type toSelectWithContext interface { type toSelectWithContext interface {
WithContext(ctx Context) toSelectFinal WithContext(ctx context.Context) toSelectFinal
} }
type toSelectFinal interface { type toSelectFinal interface {
@ -123,14 +123,14 @@ type join struct {
type selectStatus struct { type selectStatus struct {
scope scope scope scope
distinct bool distinct bool
fields FieldList fields fieldList
where BooleanExpression where BooleanExpression
orderBys []OrderBy orderBys []OrderBy
groupBys []Expression groupBys []Expression
having BooleanExpression having BooleanExpression
limit *int limit *int
offset int offset int
ctx Context ctx context.Context
lock string lock string
} }
@ -263,8 +263,8 @@ func (s selectStatus) ForUpdate() selectWithLock {
func (s selectStatus) asDerivedTable(name string) Table { func (s selectStatus) asDerivedTable(name string) Table {
return derivedTable{ return derivedTable{
name: name, name: name,
select_: s, selectStatus: s,
} }
} }
@ -364,26 +364,18 @@ func (s selectStatus) GetSQL() (string, error) {
return sb.String(), nil return sb.String(), nil
} }
func (s selectStatus) WithContext(ctx Context) toSelectFinal { func (s selectStatus) WithContext(ctx context.Context) toSelectFinal {
s.ctx = ctx s.ctx = ctx
return s return s
} }
func (s selectStatus) getContext() Context {
if s.ctx != nil {
return s.ctx
} else {
return Background()
}
}
func (s selectStatus) FetchCursor() (Cursor, error) { func (s selectStatus) FetchCursor() (Cursor, error) {
sqlString, err := s.GetSQL() sqlString, err := s.GetSQL()
if err != nil { if err != nil {
return nil, err return nil, err
} }
cursor, err := s.scope.Database.QueryContext(s.getContext(), sqlString) cursor, err := s.scope.Database.QueryContext(s.ctx, sqlString)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,5 +1,6 @@
package sqlingo package sqlingo
// Table is the interface of a generated table.
type Table interface { type Table interface {
GetName() string GetName() string
GetSQL(scope scope) string GetSQL(scope scope) string
@ -27,13 +28,14 @@ func (t table) getOperatorPriority() int {
return 0 return 0
} }
// NewTable creates a reference to a table. It should only be called from generated code.
func NewTable(name string) Table { func NewTable(name string) Table {
return table{name: name, sqlDialects: quoteIdentifier(name)} return table{name: name, sqlDialects: quoteIdentifier(name)}
} }
type derivedTable struct { type derivedTable struct {
name string name string
select_ selectStatus selectStatus selectStatus
} }
func (t derivedTable) GetFieldByName(name string) Field { func (t derivedTable) GetFieldByName(name string) Field {
@ -53,10 +55,10 @@ func (t derivedTable) GetName() string {
} }
func (t derivedTable) GetSQL(scope scope) string { func (t derivedTable) GetSQL(scope scope) string {
sql, _ := t.select_.GetSQL() sql, _ := t.selectStatus.GetSQL()
return "(" + sql + ") AS " + t.name return "(" + sql + ") AS " + t.name
} }
func (t derivedTable) GetFields() []Field { func (t derivedTable) GetFields() []Field {
return t.select_.fields return t.selectStatus.fields
} }

View File

@ -12,7 +12,7 @@ func TestTable(t *testing.T) {
func TestDerivedTable(t *testing.T) { func TestDerivedTable(t *testing.T) {
dummyFields := []Field{NewNumberField("table", "field")} dummyFields := []Field{NewNumberField("table", "field")}
dt := derivedTable{ dt := derivedTable{
select_: selectStatus{ selectStatus: selectStatus{
fields: dummyFields, fields: dummyFields,
}, },
} }

View File

@ -5,6 +5,7 @@ import (
"database/sql" "database/sql"
) )
// Transaction is the interface of a transaction with underlying sql.Tx object.
type Transaction interface { type Transaction interface {
GetDB() *sql.DB GetDB() *sql.DB
GetTx() *sql.Tx GetTx() *sql.Tx