Skip to content

Commit

Permalink
Merge pull request #36 from flycash/select
Browse files Browse the repository at this point in the history
Feat: Support updater
  • Loading branch information
flycash authored Oct 3, 2021
2 parents a95f39b + db41227 commit 939cf25
Show file tree
Hide file tree
Showing 11 changed files with 444 additions and 65 deletions.
3 changes: 2 additions & 1 deletion .CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@
- [Metadata API](https://github.com/gotomicro/eql/pull/16)
- [tagMetaRegistry: default implementation of MetaRegistry](https://github.com/gotomicro/eql/pull/25)
- [Refactor: move Insert function into db.file](https://github.com/gotomicro/eql/pull/28)
- [Selector implementation, except WHERE and HAVING](https://github.com/gotomicro/eql/pull/32)
- [Selector implementation, excluding WHERE and HAVING clauses](https://github.com/gotomicro/eql/pull/32)
- [Updater implementation, excluding WHERE clause](https://github.com/gotomicro/eql/pull/36)
29 changes: 17 additions & 12 deletions assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,27 @@ type Assignable interface {
assign()
}

type Assignment struct {
Column string
Value ValueExpr
}
type Assignment binaryExpr

// 实现注意:
// 1. value 是 ValueExpr
// 2. value 不是 ValueExpr,这时候看做是一个普通的值
func Assign(column string, value interface{}) *Assignment {
panic("implement me")
func Assign(column string, value interface{}) Assignment {
var expr Expr
switch v := value.(type) {
case Expr:
expr = v
default:
expr = valueExpr{val: v}
}
return Assignment{left: C(column), op: opEQ, right: expr}
}

func (a *Assignment) assign() {
func (a Assignment) assign() {
panic("implement me")
}

type ValueExpr interface {
value()
type valueExpr struct {
val interface{}
}

func (valueExpr) expr() (string, error){
return "", nil
}
63 changes: 62 additions & 1 deletion builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@

package eql

import "strings"
import (
"errors"
"github.com/gotomicro/eql/internal"
"strings"
)

// QueryBuilder is used to build a query
type QueryBuilder interface {
Expand Down Expand Up @@ -61,4 +65,61 @@ func (b *builder) parameter(arg interface{}) {
}
b.buffer.WriteByte('?')
b.args = append(b.args, arg)
}

func (b *builder) buildExpr(expr Expr) error {
switch e := expr.(type) {
case RawExpr:
b.buffer.WriteString(string(e))
case Column:
cm, ok := b.meta.fieldMap[e.name]
if !ok {
return internal.NewInvalidColumnError(e.name)
}
b.quote(cm.columnName)
case valueExpr:
b.parameter(e.val)
case MathExpr:
if err := b.buildBinaryExpr(binaryExpr(e)); err != nil {
return err
}
case binaryExpr:
if err := b.buildBinaryExpr(e); err != nil {
return err
}
default:
return errors.New("unsupported expr")
}
return nil
}

func (b *builder) buildBinaryExpr(e binaryExpr) error {
err := b.buildBinarySubExpr(e.left)
if err != nil {
return err
}
b.buffer.WriteString(string(e.op))
return b.buildBinarySubExpr(e.right)
}

func (b *builder) buildBinarySubExpr(subExpr Expr) error {
switch r := subExpr.(type) {
case MathExpr:
b.buffer.WriteByte('(')
if err := b.buildBinaryExpr(binaryExpr(r)); err != nil {
return err
}
b.buffer.WriteByte(')')
case binaryExpr:
b.buffer.WriteByte('(')
if err := b.buildBinaryExpr(r); err != nil {
return err
}
b.buffer.WriteByte(')')
default:
if err := b.buildExpr(r); err != nil {
return err
}
}
return nil
}
25 changes: 21 additions & 4 deletions column.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,20 @@ func (c Column) As(alias string) Selectable {
}
}

func (Column) Inc(val interface{}) MathExpr {
panic("implement me")
func (c Column) Add(val interface{}) MathExpr {
return MathExpr{
left: c,
op: opAdd,
right: valueOf(val),
}
}

func (Column) Times(val interface{}) MathExpr {
panic("implement me")
func (c Column) Multi(val interface{}) MathExpr {
return MathExpr{
left: c,
op: opMulti,
right: valueOf(val),
}
}

func (Column) assign() {
Expand Down Expand Up @@ -73,3 +81,12 @@ func Columns(cs...string) columns {
}
}

func valueOf(val interface{}) Expr {
switch v := val.(type) {
case Expr:
return v
default:
return valueExpr{val: val}
}
}

94 changes: 83 additions & 11 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,27 @@

package eql

import "strings"
import (
"reflect"
"strings"
)

// DBOption configure DB
type DBOption func(db *DB)

// DB represents a database
type DB struct {
metaRegistry MetaRegistry
dialect Dialect
dialect Dialect
nullAssertFunc NullAssertFunc
}

// New returns DB. It's the entry of EQL
func New(opts ...DBOption) *DB {
db := &DB{
metaRegistry: defaultMetaRegistry,
dialect: mysql,
metaRegistry: defaultMetaRegistry,
dialect: mysql,
nullAssertFunc: NilAsNullFunc,
}
for _, o := range opts {
o(db)
Expand All @@ -40,11 +45,7 @@ func New(opts ...DBOption) *DB {
// Select starts a select query. If columns are empty, all columns will be fetched
func (db *DB) Select(columns ...Selectable) *Selector {
return &Selector{
builder: builder{
registry: db.metaRegistry,
dialect: db.dialect,
buffer: &strings.Builder{},
},
builder: db.builder(),
columns: columns,
}
}
Expand All @@ -54,11 +55,82 @@ func (*DB) Delete() *Deleter {
panic("implement me")
}

func (*DB) Update(table interface{}) *Updater {
panic("implement me")
func (db *DB) Update(table interface{}) *Updater {
return &Updater{
builder: db.builder(),
table: table,
nullAssertFunc: db.nullAssertFunc,
}
}

// Insert generate Inserter to builder insert query
func (db *DB) Insert() *Inserter {
return &Inserter{}
}

func (db *DB) builder() builder {
return builder{
registry: db.metaRegistry,
dialect: db.dialect,
buffer: &strings.Builder{},
}
}

func WithNullAssertFunc(nullable NullAssertFunc) DBOption {
return func(db *DB) {
db.nullAssertFunc = nullable
}
}

// NullAssertFunc determined if the value is NULL.
// As we know, there is a gap between NULL and nil
// There are two kinds of nullAssertFunc
// 1. nil = NULL, see NilAsNullFunc
// 2. zero value = NULL, see ZeroAsNullFunc
type NullAssertFunc func(val interface{}) bool

// NilAsNullFunc use the strict definition of "nullAssertFunc"
// if and only if the val is nil, indicates value is null
func NilAsNullFunc(val interface{}) bool {
return val == nil
}

// ZeroAsNullFunc means "zero value = null"
func ZeroAsNullFunc(val interface{}) bool {
if val == nil{
return true
}
switch v := val.(type) {
case int:
return v == 0
case int8:
return v == 0
case int16:
return v == 0
case int32:
return v == 0
case int64:
return v == 0
case uint:
return v == 0
case uint8:
return v == 0
case uint16:
return v == 0
case uint32:
return v == 0
case uint64:
return v == 0
case float32:
return v == 0
case float64:
return v == 0
case bool:
return v
case string:
return v == ""
default:
valRef := reflect.ValueOf(val)
return valRef.IsZero()
}
}
51 changes: 51 additions & 0 deletions db_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2021 gotomicro
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package eql

import (
"github.com/stretchr/testify/assert"
"testing"
)

func TestStrictNullableFunc(t *testing.T) {
str := "Hello"
assert.False(t, NilAsNullFunc(str))
str = ""
assert.False(t, NilAsNullFunc(str))
var err error
assert.True(t, NilAsNullFunc(err))

var i int
assert.False(t, NilAsNullFunc(i))
}

func TestZeroAsNullableFunc(t *testing.T) {
assert.True(t, ZeroAsNullFunc(0))
assert.True(t, ZeroAsNullFunc(int8(0)))
assert.True(t, ZeroAsNullFunc(int16(0)))
assert.True(t, ZeroAsNullFunc(int32(0)))
assert.True(t, ZeroAsNullFunc(int64(0)))
assert.True(t, ZeroAsNullFunc(uint(0)))
assert.True(t, ZeroAsNullFunc(uint8(0)))
assert.True(t, ZeroAsNullFunc(uint16(0)))
assert.True(t, ZeroAsNullFunc(uint32(0)))
assert.True(t, ZeroAsNullFunc(uint64(0)))
assert.True(t, ZeroAsNullFunc(float32(0)))
assert.True(t, ZeroAsNullFunc(float64(0)))
assert.True(t, ZeroAsNullFunc(""))
var err error
assert.True(t, ZeroAsNullFunc(err))
}

Loading

0 comments on commit 939cf25

Please sign in to comment.