Skip to content

Commit

Permalink
internal/value: 抽象 Value 接口与基于反射的实现
Browse files Browse the repository at this point in the history
- 将元数据抽象挪到 internal/model 包
- 将方言抽象挪到 intenal/dialect 包
- 抽象了 Value 接口并且提供了基于反射的实现
  • Loading branch information
flycash committed May 16, 2022
1 parent 1dc491e commit be36c9d
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 172 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.17
go-version: 1.18

- name: Build
run: go build -v ./...
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

简单的 ORM 框架。

> 注意:这是一个全中文的仓库。这意味着注释、文档和错误信息,都会是中文的。介意的用户可以选择 GORM,这也是一个杰出的 ORM 仓库
请使用 Go 1.18 以上版本。

> 注意:这是一个全中文的仓库。这意味着注释、文档和错误信息,都会是中文。介意的用户可以选择别的 ORM 仓库,但是不必来反馈说希望提供英文版本,我们是不会提供的。我们缺乏足够的英文水平良好的开发者,这也是为何我选择将这个项目做成全中文的原因。
## SQL 2003 标准
理论上来说,我们计划支持 [SQL 2003 standard](https://ronsavage.github.io/SQL/sql-2003-2.bnf.html#query%20specification). 不过据我们所知,并不是所有的数据库都支持全部的 SQL 2003 标准,所以用户还是需要进一步检查目标数据库的语法。
Expand Down
26 changes: 14 additions & 12 deletions builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ package eorm

import (
"errors"
"github.com/gotomicro/eorm/internal"
dialect2 "github.com/gotomicro/eorm/internal/dialect"
error2 "github.com/gotomicro/eorm/internal/error"
"github.com/gotomicro/eorm/internal/model"
"github.com/valyala/bytebufferpool"
)

Expand All @@ -32,21 +34,21 @@ type Query struct {
}

type builder struct {
registry MetaRegistry
dialect Dialect
registry model.MetaRegistry
dialect dialect2.Dialect
// Use bytebufferpool to reduce memory allocation.
// After using buffer, it must be put back in bytebufferpool.
// Call bytebufferpool.Get() to get a buffer, call bytebufferpool.Put() to put buffer back to bytebufferpool.
buffer *bytebufferpool.ByteBuffer
meta *TableMeta
meta *model.TableMeta
args []interface{}
aliases map[string]struct{}
}

func (b *builder) quote(val string) {
_ = b.buffer.WriteByte(b.dialect.quote)
_ = b.buffer.WriteByte(b.dialect.Quote)
_, _ = b.buffer.WriteString(val)
_ = b.buffer.WriteByte(b.dialect.quote)
_ = b.buffer.WriteByte(b.dialect.Quote)
}

func (b *builder) space() {
Expand Down Expand Up @@ -81,11 +83,11 @@ func (b *builder) buildExpr(expr Expr) error {
b.quote(e.name)
return nil
}
cm, ok := b.meta.fieldMap[e.name]
cm, ok := b.meta.FieldMap[e.name]
if !ok {
return internal.NewInvalidColumnError(e.name)
return error2.NewInvalidColumnError(e.name)
}
b.quote(cm.columnName)
b.quote(cm.ColumnName)
}
case Aggregate:
if err := b.buildHavingAggregate(e); err != nil {
Expand Down Expand Up @@ -123,11 +125,11 @@ func (b *builder) buildPredicates(predicates []Predicate) error {
func (b *builder) buildHavingAggregate(aggregate Aggregate) error {
_, _ = b.buffer.WriteString(aggregate.fn)
_ = b.buffer.WriteByte('(')
cMeta, ok := b.meta.fieldMap[aggregate.arg]
cMeta, ok := b.meta.FieldMap[aggregate.arg]
if !ok {
return internal.NewInvalidColumnError(aggregate.arg)
return error2.NewInvalidColumnError(aggregate.arg)
}
b.quote(cMeta.columnName)
b.quote(cMeta.ColumnName)
_ = b.buffer.WriteByte(')')
return nil
}
Expand Down
14 changes: 8 additions & 6 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
package eorm

import (
"github.com/gotomicro/eorm/internal/dialect"
"github.com/gotomicro/eorm/internal/model"
"github.com/valyala/bytebufferpool"
)

Expand All @@ -23,16 +25,16 @@ type DBOption func(db *DB)

// DB represents a database
type DB struct {
metaRegistry MetaRegistry
dialect Dialect
metaRegistry model.MetaRegistry
dialect dialect.Dialect
}

// NewDB returns DB.
// By default, it will create an instance of MetaRegistry and use MySQL as the dialect
func NewDB(opts ...DBOption) *DB {
db := &DB{
metaRegistry: &tagMetaRegistry{},
dialect: MySQL,
metaRegistry: model.NewMetaRegistry(),
dialect: dialect.MySQL,
}
for _, o := range opts {
o(db)
Expand All @@ -41,14 +43,14 @@ func NewDB(opts ...DBOption) *DB {
}

// DBWithMetaRegistry specify the MetaRegistry
func DBWithMetaRegistry(registry MetaRegistry) DBOption {
func DBWithMetaRegistry(registry model.MetaRegistry) DBOption {
return func(db *DB) {
db.metaRegistry = registry
}
}

// DBWithDialect specify dialect
func DBWithDialect(dialect Dialect) DBOption {
func DBWithDialect(dialect dialect.Dialect) DBOption {
return func(db *DB) {
db.dialect = dialect
}
Expand Down
10 changes: 6 additions & 4 deletions db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,21 @@ package eorm

import (
"fmt"
"github.com/gotomicro/eorm/internal/dialect"
"github.com/gotomicro/eorm/internal/model"
)

func ExampleNew() {
// case1 without DBOption
db := NewDB()
fmt.Printf("case1 dialect: %s\n", db.dialect.name)
fmt.Printf("case1 dialect: %s\n", db.dialect.Name)

// case2 use DBOption
db = NewDB(DBWithDialect(SQLite))
fmt.Printf("case2 dialect: %s\n", db.dialect.name)
db = NewDB(DBWithDialect(dialect.SQLite))
fmt.Printf("case2 dialect: %s\n", db.dialect.Name)

// case3 share registry among DB
registry := NewTagMetaRegistry()
registry := model.NewTagMetaRegistry()
db1 := NewDB(DBWithMetaRegistry(registry))
db2 := NewDB(DBWithMetaRegistry(registry))
fmt.Printf("case3 same registry: %v", db1.metaRegistry == db2.metaRegistry)
Expand Down
2 changes: 1 addition & 1 deletion delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func (d *Deleter) Build() (*Query, error) {
return nil, err
}

d.quote(d.meta.tableName)
d.quote(d.meta.TableName)
if len(d.where) > 0 {
_, err = d.buffer.WriteString(" WHERE ")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/gotomicro/eorm

go 1.17
go 1.18

require (
github.com/stretchr/testify v1.7.0
Expand Down
21 changes: 11 additions & 10 deletions insert.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package eorm
import (
"errors"
"fmt"
"github.com/gotomicro/eorm/internal/model"
"reflect"
)

Expand All @@ -42,7 +43,7 @@ func (i *Inserter) Build() (*Query, error) {
if err != nil {
return &Query{}, err
}
i.quote(i.meta.tableName)
i.quote(i.meta.TableName)
i.buffer.WriteString("(")
fields, err := i.buildColumns()
if err != nil {
Expand All @@ -54,9 +55,9 @@ func (i *Inserter) Build() (*Query, error) {
i.buffer.WriteString("(")
refVal := reflect.ValueOf(value).Elem()
for j, v := range fields {
field := refVal.FieldByName(v.fieldName)
field := refVal.FieldByName(v.FieldName)
if !field.IsValid() {
return &Query{}, fmt.Errorf("invalid column %s", v.fieldName)
return &Query{}, fmt.Errorf("invalid column %s", v.FieldName)
}
val := field.Interface()
i.parameter(val)
Expand Down Expand Up @@ -101,24 +102,24 @@ func (i *Inserter) OnConflict(cs ...string) *PgSQLUpserter {
panic("implement me")
}

func (i *Inserter) buildColumns() ([]*ColumnMeta, error) {
cs := i.meta.columns
func (i *Inserter) buildColumns() ([]*model.ColumnMeta, error) {
cs := i.meta.Columns
if len(i.columns) != 0 {
cs = make([]*ColumnMeta, 0, len(i.columns))
cs = make([]*model.ColumnMeta, 0, len(i.columns))
for index, value := range i.columns {
v, isOk := i.meta.fieldMap[value]
v, isOk := i.meta.FieldMap[value]
if !isOk {
return cs, fmt.Errorf("invalid column %s", value)
}
i.quote(v.columnName)
i.quote(v.ColumnName)
if index != len(i.columns)-1 {
i.comma()
}
cs = append(cs, v)
}
} else {
for index, value := range i.meta.columns {
i.quote(value.columnName)
for index, value := range i.meta.Columns {
i.quote(value.ColumnName)
if index != len(cs)-1 {
i.comma()
}
Expand Down
14 changes: 7 additions & 7 deletions dialect.go → internal/dialect/dialect.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package eorm
package dialect

// Dialect specify config or behavior of special SQL dialects
type Dialect struct {
name string
Name string
// in MYSQL, it's "`"
quote byte
Quote byte
}

var (
MySQL = Dialect{
name: "MySQL",
quote: '`',
Name: "MySQL",
Quote: '`',
}
SQLite = Dialect{
name: "SQLite",
quote: '`',
Name: "SQLite",
Quote: '`',
}
)
9 changes: 6 additions & 3 deletions internal/error.go → internal/error/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package internal
package error

import (
"errors"
"fmt"
)

var errValueNotSet = errors.New("value unset")
var (
errValueNotSet = errors.New("value unset")
)


// NewInvalidColumnError returns an error represents invalid field name
// TODO(do we need errors pkg?)
func NewInvalidColumnError(field string) error {
return fmt.Errorf("eql: invalid column name %s, " +
return fmt.Errorf("eorm: invalid column name %s, " +
"it must be a valid field name of structure", field)
}

Expand Down
Loading

0 comments on commit be36c9d

Please sign in to comment.