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"
// CaseExpression indicates the status in a CASE statement
type CaseExpression interface {
WhenThen(when BooleanExpression, then interface{}) CaseExpression
Else(value interface{}) CaseExpressionWithElse
End() Expression
}
// CaseExpressionWithElse indicates the status in CASE ... ELSE ... statement
type CaseExpressionWithElse interface {
End() Expression
}
@ -23,6 +25,7 @@ type whenThen struct {
then interface{}
}
// Case initiates a CASE statement
func Case() CaseExpression {
return caseStatus{}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -2,18 +2,22 @@ package sqlingo
import "strings"
// Field is the interface of a generated field.
type Field interface {
Expression
}
// NumberField is the interface of a generated field of number type.
type NumberField interface {
NumberExpression
}
// BooleanField is the interface of a generated field of boolean type.
type BooleanField interface {
BooleanExpression
}
// StringField is the interface of a generated field of string type.
type StringField interface {
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 {
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 {
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 {
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
var sb strings.Builder
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, NewStringField("t1", "f1").Equals("x"), "`t1`.`f1` = 'x'")
sql, _ := FieldList{}.GetSQL(scope{
sql, _ := fieldList{}.GetSQL(scope{
Tables: []Table{
&dummyTable{},
},
@ -46,7 +46,7 @@ func TestField(t *testing.T) {
t.Error(sql)
}
sql, _ = FieldList{}.GetSQL(scope{
sql, _ = fieldList{}.GetSQL(scope{
Tables: []Table{
&dummyTable{},
&dummyTable{},
@ -56,7 +56,7 @@ func TestField(t *testing.T) {
t.Error(sql)
}
if _, err := (FieldList{
if _, err := (fieldList{
expression{builder: func(scope scope) (string, 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 {
return function(name, args...)
}
// Concat creates an expression of CONCAT function.
func Concat(args ...interface{}) StringExpression {
return function("CONCAT", args...)
}
// Count creates an expression of COUNT aggregator.
func Count(arg interface{}) NumberExpression {
return function("COUNT", arg)
}
// If creates an expression of IF function.
func If(predicate Expression, trueValue interface{}, falseValue interface{}) (result Expression) {
return function("IF", predicate, trueValue, falseValue)
}
// Length creates an expression of LENGTH function.
func Length(arg interface{}) NumberExpression {
return function("LENGTH", arg)
}
// Sum creates an expression of SUM aggregator.
func Sum(arg interface{}) NumberExpression {
return function("SUM", arg)
}

View File

@ -4,7 +4,10 @@ import (
"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
// 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
// TODO: add some common interceptors

View File

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

View File

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

View File

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

View File

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