refactor Session, remove Value & lower SQL & SQLVars

This commit is contained in:
gzdaijie
2020-02-25 01:37:39 +08:00
parent 80954cc02f
commit 5713ae0787
10 changed files with 204 additions and 71 deletions
+13 -16
View File
@@ -2,18 +2,15 @@ package session
import (
"database/sql"
"strings"
"geeorm/log"
)
// Session keep a pointer to sql.DB and provides all execution of all
// kind of database operations.
type Session struct {
db *sql.DB
SQL strings.Builder
SQLVars []interface{}
db *sql.DB
sql string
sqlVars []interface{}
}
// New creates a instance of Session
@@ -21,10 +18,10 @@ func New(db *sql.DB) *Session {
return &Session{db: db}
}
// Exec raw SQL with SQLVars
// Exec raw sql with sqlVars
func (s *Session) Exec() (result sql.Result, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if result, err = s.db.Exec(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if result, err = s.db.Exec(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
@@ -32,22 +29,22 @@ func (s *Session) Exec() (result sql.Result, err error) {
// QueryRow gets a record from db
func (s *Session) QueryRow() *sql.Row {
log.Info(s.SQL.String(), s.SQLVars)
return s.db.QueryRow(s.SQL.String(), s.SQLVars...)
log.Info(s.sql, s.sqlVars)
return s.db.QueryRow(s.sql, s.sqlVars...)
}
// QueryRows gets a list of records from db
func (s *Session) QueryRows() (rows *sql.Rows, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if rows, err = s.db.Query(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if rows, err = s.db.Query(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
}
// Raw appends SQL and SQLVars
// Raw appends sql and sqlVars
func (s *Session) Raw(sql string, values ...interface{}) *Session {
s.SQL.WriteString(sql)
s.SQLVars = append(s.SQLVars, values...)
s.sql += sql
s.sqlVars = append(s.sqlVars, values...)
return s
}
@@ -2,8 +2,6 @@ package session
import (
"database/sql"
"strings"
"geeorm/dialect"
"geeorm/log"
"geeorm/schema"
@@ -15,10 +13,8 @@ type Session struct {
db *sql.DB
dialect dialect.Dialect
refTable *schema.Schema
Value interface{}
SQL strings.Builder
SQLVars []interface{}
sql string
sqlVars []interface{}
}
// New creates a instance of Session
@@ -29,10 +25,10 @@ func New(db *sql.DB, dialect dialect.Dialect) *Session {
}
}
// Exec raw SQL with SQLVars
// Exec raw sql with sqlVars
func (s *Session) Exec() (result sql.Result, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if result, err = s.db.Exec(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if result, err = s.db.Exec(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
@@ -40,22 +36,22 @@ func (s *Session) Exec() (result sql.Result, err error) {
// QueryRow gets a record from db
func (s *Session) QueryRow() *sql.Row {
log.Info(s.SQL.String(), s.SQLVars)
return s.db.QueryRow(s.SQL.String(), s.SQLVars...)
log.Info(s.sql, s.sqlVars)
return s.db.QueryRow(s.sql, s.sqlVars...)
}
// QueryRows gets a list of records from db
func (s *Session) QueryRows() (rows *sql.Rows, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if rows, err = s.db.Query(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if rows, err = s.db.Query(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
}
// Raw appends SQL and SQLVars
// Raw appends sql and sqlVars
func (s *Session) Raw(sql string, values ...interface{}) *Session {
s.SQL.WriteString(sql)
s.SQLVars = append(s.SQLVars, values...)
s.sql += sql
s.sqlVars = append(s.sqlVars, values...)
return s
}
@@ -2,7 +2,6 @@ package session
import (
"database/sql"
"geeorm/log"
"os"
"testing"
@@ -18,7 +17,6 @@ var (
func setup() {
TestDB, _ = sql.Open("sqlite3", "gee.db")
TestDial, _ = dialect.GetDialect("sqlite3")
log.SetLevel(log.ErrorLevel)
}
func teardown() {
+46
View File
@@ -0,0 +1,46 @@
package clause
import (
"strings"
)
// Clause contains SQL conditions
type Clause struct {
sql map[Type]string
sqlVars map[Type][]interface{}
}
// Type is the type of Clause
type Type int
// Support types for Clause
const (
INSERT Type = 0
VALUES Type = 1
SELECT Type = 2
LIMIT Type = 3
)
// Set adds a sub clause of specific type
func (c *Clause) Set(name Type, vars ...interface{}) {
if c.sql == nil {
c.sql = make(map[Type]string)
c.sqlVars = make(map[Type][]interface{})
}
sql, vars := generators[name](vars...)
c.sql[name] = sql
c.sqlVars[name] = vars
}
// Build generate the final SQL and SQLVars
func (c *Clause) Build(orders []Type) (string, []interface{}) {
var sqls []string
var vars []interface{}
for _, order := range orders {
if sql, ok := c.sql[order]; ok {
sqls = append(sqls, sql)
vars = append(vars, c.sqlVars[order]...)
}
}
return strings.Join(sqls, " "), vars
}
+32
View File
@@ -0,0 +1,32 @@
package clause
import (
"reflect"
"testing"
)
func TestClause_Set(t *testing.T) {
var clause Clause
clause.Set(INSERT, "User", "Name,Age")
sql := clause.sql[INSERT]
vars := clause.sqlVars[INSERT]
t.Log(sql, vars)
if sql != "INSERT INTO User (Name,Age)" || len(vars) != 0 {
t.Fatal("failed to get clause")
}
}
func TestClause_Build(t *testing.T) {
var clause Clause
clause.Set(LIMIT, 3)
clause.Set(SELECT, "User", "*")
orders := []Type{SELECT, LIMIT}
sql, vars := clause.Build(orders)
t.Log(sql, vars)
if sql != "SELECT * FROM User LIMIT ?" {
t.Fatal("failed to build SQL")
}
if !reflect.DeepEqual(vars, []interface{}{3}) {
t.Fatal("failed to build SQLVars")
}
}
+68
View File
@@ -0,0 +1,68 @@
package clause
import (
"fmt"
"log"
"strings"
)
type generator func(values ...interface{}) (string, []interface{})
var generators map[Type]generator
func init() {
generators = make(map[Type]generator)
generators[INSERT] = _insert
generators[VALUES] = _values
generators[SELECT] = _select
generators[LIMIT] = _limit
}
func genBindVars(num int) string {
var vars []string
for i := 0; i < num; i++ {
vars = append(vars, "?")
}
return strings.Join(vars, ", ")
}
func _insert(values ...interface{}) (string, []interface{}) {
// INSERT INTO $tableName ($fields)
tableName := values[0]
fields := values[1]
return fmt.Sprintf("INSERT INTO %s (%v)", tableName, fields), []interface{}{}
}
func _values(values ...interface{}) (string, []interface{}) {
// VALUES ($v1), (&v2), ...
var bindStr string
var sql strings.Builder
var vars []interface{}
sql.WriteString("VALUES ")
for i, value := range values {
v := value.([]interface{})
if bindStr == "" {
bindStr = genBindVars(len(v))
}
sql.WriteString(fmt.Sprintf("(%v)", bindStr))
if i+1 != len(values) {
sql.WriteString(", ")
}
vars = append(vars, v...)
}
return sql.String(), vars
}
func _select(values ...interface{}) (string, []interface{}) {
// SELECT $fields FROM $tableName
tableName := values[0]
fields := values[1]
return fmt.Sprintf("SELECT %v FROM %s", fields, tableName), []interface{}{}
}
func _limit(values ...interface{}) (string, []interface{}) {
// LIMIT $num
log.Println(values...)
return "LIMIT ?", values
}
@@ -19,7 +19,6 @@ type Schema struct {
PrimaryField *Field
Fields []*Field
FieldNames []string
BindVars []string
}
// Values return the values of dest's member variables
@@ -52,7 +51,6 @@ func Parse(dest interface{}, d dialect.Dialect) *Schema {
}
schema.Fields = append(schema.Fields, field)
schema.FieldNames = append(schema.FieldNames, p.Name)
schema.BindVars = append(schema.BindVars, "?")
}
}
return schema
@@ -66,4 +64,4 @@ func (field *Field) String() string {
// String returns readable string
func (schema *Schema) String() string {
return fmt.Sprintf("TABLE %s %v", schema.TableName, schema.Fields)
}
}
+14 -16
View File
@@ -2,8 +2,7 @@ package session
import (
"database/sql"
"strings"
"geeorm/clause"
"geeorm/dialect"
"geeorm/log"
"geeorm/schema"
@@ -15,10 +14,9 @@ type Session struct {
db *sql.DB
dialect dialect.Dialect
refTable *schema.Schema
Value interface{}
SQL strings.Builder
SQLVars []interface{}
clause clause.Clause
sql string
sqlVars []interface{}
}
// New creates a instance of Session
@@ -29,10 +27,10 @@ func New(db *sql.DB, dialect dialect.Dialect) *Session {
}
}
// Exec raw SQL with SQLVars
// Exec raw sql with sqlVars
func (s *Session) Exec() (result sql.Result, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if result, err = s.db.Exec(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if result, err = s.db.Exec(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
@@ -40,22 +38,22 @@ func (s *Session) Exec() (result sql.Result, err error) {
// QueryRow gets a record from db
func (s *Session) QueryRow() *sql.Row {
log.Info(s.SQL.String(), s.SQLVars)
return s.db.QueryRow(s.SQL.String(), s.SQLVars...)
log.Info(s.sql, s.sqlVars)
return s.db.QueryRow(s.sql, s.sqlVars...)
}
// QueryRows gets a list of records from db
func (s *Session) QueryRows() (rows *sql.Rows, err error) {
log.Info(s.SQL.String(), s.SQLVars)
if rows, err = s.db.Query(s.SQL.String(), s.SQLVars...); err != nil {
log.Info(s.sql, s.sqlVars)
if rows, err = s.db.Query(s.sql, s.sqlVars...); err != nil {
log.Error(err)
}
return
}
// Raw appends SQL and SQLVars
// Raw appends sql and sqlVars
func (s *Session) Raw(sql string, values ...interface{}) *Session {
s.SQL.WriteString(sql)
s.SQLVars = append(s.SQLVars, values...)
s.sql += sql
s.sqlVars = append(s.sqlVars, values...)
return s
}
@@ -2,7 +2,6 @@ package session
import (
"database/sql"
"geeorm/log"
"os"
"testing"
@@ -18,7 +17,6 @@ var (
func setup() {
TestDB, _ = sql.Open("sqlite3", "gee.db")
TestDial, _ = dialect.GetDialect("sqlite3")
log.SetLevel(log.ErrorLevel)
}
func teardown() {
@@ -1,7 +1,7 @@
package session
import (
"fmt"
"geeorm/clause"
"reflect"
"strings"
)
@@ -9,23 +9,20 @@ import (
// Create one or more records in database
func (s *Session) Create(values ...interface{}) (int64, error) {
var flag bool
for i, value := range values {
recordValues := make([]interface{}, 0)
for _, value := range values {
table := s.RefTable(value)
filedSQL := strings.Join(table.FieldNames, ", ")
bindVarSQL := strings.Join(table.BindVars, ", ")
if !flag {
s.Raw(fmt.Sprintf("INSERT INTO %s (%v) VALUES ", table.TableName, filedSQL))
flag = true
fieldSQL := strings.Join(table.FieldNames, ", ")
s.clause.Set(clause.INSERT, table.TableName, fieldSQL)
}
s.Raw(fmt.Sprintf("(%v)", bindVarSQL), table.Values(value)...)
if i == len(values)-1 {
s.Raw(";")
} else {
s.Raw(",")
}
recordValues = append(recordValues, table.Values(value))
}
result, err := s.Exec()
s.clause.Set(clause.VALUES, recordValues...)
sql, vars := s.clause.Build([]clause.Type{clause.INSERT, clause.VALUES})
result, err := s.Raw(sql, vars...).Exec()
if err != nil {
return 0, err
}
@@ -38,8 +35,12 @@ func (s *Session) First(value interface{}) error {
table := s.RefTable(value)
fieldSQL := strings.Join(table.FieldNames, ", ")
selectSQL := fmt.Sprintf("SELECT %v FROM %s LIMIT 1", fieldSQL, table.TableName)
row := s.Raw(selectSQL).QueryRow()
s.clause.Set(clause.SELECT, table.TableName, fieldSQL)
s.clause.Set(clause.LIMIT, 1)
sql, vars := s.clause.Build([]clause.Type{clause.SELECT, clause.LIMIT})
row := s.Raw(sql, vars...).QueryRow()
dest := reflect.ValueOf(value).Elem()
var values []interface{}
@@ -57,8 +58,9 @@ func (s *Session) Find(values interface{}) error {
table := s.RefTable(reflect.New(destType).Elem().Interface())
fieldSQL := strings.Join(table.FieldNames, ", ")
selectSQL := fmt.Sprintf("SELECT %v FROM %s", fieldSQL, table.TableName)
rows, err := s.Raw(selectSQL).QueryRows()
s.clause.Set(clause.SELECT, table.TableName, fieldSQL)
sql, vars := s.clause.Build([]clause.Type{clause.SELECT})
rows, err := s.Raw(sql, vars...).QueryRows()
if err != nil {
return err
}