diff --git a/cmd/gf/go.mod b/cmd/gf/go.mod index 94ef8f12a..ca9f97fe7 100644 --- a/cmd/gf/go.mod +++ b/cmd/gf/go.mod @@ -8,6 +8,7 @@ require ( github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.0.0-rc2 github.com/gogf/gf/v2 v2.0.0 github.com/olekukonko/tablewriter v0.0.5 + github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 // indirect ) replace ( diff --git a/cmd/gf/go.sum b/cmd/gf/go.sum index 063d63012..4e6605816 100644 --- a/cmd/gf/go.sum +++ b/cmd/gf/go.sum @@ -75,6 +75,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ= +github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI= diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go index 94b92a8d9..7c433517b 100644 --- a/database/gdb/gdb_model.go +++ b/database/gdb/gdb_model.go @@ -17,38 +17,39 @@ import ( // Model is core struct implementing the DAO for ORM. type Model struct { - db DB // Underlying DB interface. - tx *TX // Underlying TX interface. - rawSql string // rawSql is the raw SQL string which marks a raw SQL based Model not a table based Model. - schema string // Custom database schema. - linkType int // Mark for operation on master or slave. - tablesInit string // Table names when model initialization. - tables string // Operation table names, which can be more than one table names and aliases, like: "user", "user u", "user u, user_detail ud". - fields string // Operation fields, multiple fields joined using char ','. - fieldsEx string // Excluded operation fields, multiple fields joined using char ','. - withArray []interface{} // Arguments for With feature. - withAll bool // Enable model association operations on all objects that have "with" tag in the struct. - extraArgs []interface{} // Extra custom arguments for sql, which are prepended to the arguments before sql committed to underlying driver. - whereHolder []ModelWhereHolder // Condition strings for where operation. - groupBy string // Used for "group by" statement. - orderBy string // Used for "order by" statement. - having []interface{} // Used for "having..." statement. - start int // Used for "select ... start, limit ..." statement. - limit int // Used for "select ... start, limit ..." statement. - option int // Option for extra operation features. - offset int // Offset statement for some databases grammar. - data interface{} // Data for operation, which can be type of map/[]map/struct/*struct/string, etc. - batch int // Batch number for batch Insert/Replace/Save operations. - filter bool // Filter data and where key-value pairs according to the fields of the table. - distinct string // Force the query to only return distinct results. - lockInfo string // Lock for update or in shared lock. - cacheEnabled bool // Enable sql result cache feature, which is mainly for indicating cache duration(especially 0) usage. - cacheOption CacheOption // Cache option for query statement. - hook HookHandler // Hook functions for model hook feature. - unscoped bool // Disables soft deleting features when select/delete operations. - safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model. - onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement. - onDuplicateEx interface{} // onDuplicateEx is used for excluding some columns ON "DUPLICATE KEY UPDATE" statement. + db DB // Underlying DB interface. + tx *TX // Underlying TX interface. + rawSql string // rawSql is the raw SQL string which marks a raw SQL based Model not a table based Model. + schema string // Custom database schema. + linkType int // Mark for operation on master or slave. + tablesInit string // Table names when model initialization. + tables string // Operation table names, which can be more than one table names and aliases, like: "user", "user u", "user u, user_detail ud". + fields string // Operation fields, multiple fields joined using char ','. + fieldsEx string // Excluded operation fields, multiple fields joined using char ','. + withArray []interface{} // Arguments for With feature. + withAll bool // Enable model association operations on all objects that have "with" tag in the struct. + extraArgs []interface{} // Extra custom arguments for sql, which are prepended to the arguments before sql committed to underlying driver. + whereHolder []ModelWhereHolder // Condition strings for where operation. + groupBy string // Used for "group by" statement. + orderBy string // Used for "order by" statement. + having []interface{} // Used for "having..." statement. + start int // Used for "select ... start, limit ..." statement. + limit int // Used for "select ... start, limit ..." statement. + option int // Option for extra operation features. + offset int // Offset statement for some databases grammar. + data interface{} // Data for operation, which can be type of map/[]map/struct/*struct/string, etc. + batch int // Batch number for batch Insert/Replace/Save operations. + filter bool // Filter data and where key-value pairs according to the fields of the table. + distinct string // Force the query to only return distinct results. + lockInfo string // Lock for update or in shared lock. + cacheEnabled bool // Enable sql result cache feature, which is mainly for indicating cache duration(especially 0) usage. + cacheOption CacheOption // Cache option for query statement. + hookHandler HookHandler // Hook functions for model hook feature. + shardingHandler ShardingHandler // Custom sharding handler for sharding feature. + unscoped bool // Disables soft deleting features when select/delete operations. + safe bool // If true, it clones and returns a new model object whenever operation done; or else it changes the attribute of current model. + onDuplicate interface{} // onDuplicate is used for ON "DUPLICATE KEY UPDATE" statement. + onDuplicateEx interface{} // onDuplicateEx is used for excluding some columns ON "DUPLICATE KEY UPDATE" statement. } // ModelHandler is a function that handles given Model and returns a new Model that is custom modified. diff --git a/database/gdb/gdb_model_delete.go b/database/gdb/gdb_model_delete.go index 8b27cd945..8ba960519 100644 --- a/database/gdb/gdb_model_delete.go +++ b/database/gdb/gdb_model_delete.go @@ -40,7 +40,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) { db: m.db, link: m.getLink(true), }, - handler: m.hook.Update, + handler: m.hookHandler.Update, }, Table: m.tables, Data: fmt.Sprintf(`%s=?`, m.db.GetCore().QuoteString(fieldNameDelete)), @@ -63,7 +63,7 @@ func (m *Model) Delete(where ...interface{}) (result sql.Result, err error) { db: m.db, link: m.getLink(true), }, - handler: m.hook.Delete, + handler: m.hookHandler.Delete, }, Table: m.tables, Condition: conditionStr, diff --git a/database/gdb/gdb_model_hook.go b/database/gdb/gdb_model_hook.go index fac0f4a7c..ee94eb525 100644 --- a/database/gdb/gdb_model_hook.go +++ b/database/gdb/gdb_model_hook.go @@ -143,6 +143,6 @@ func (h *HookDeleteInput) Next(ctx context.Context) (result sql.Result, err erro // Hook sets the hook functions for current model. func (m *Model) Hook(hook HookHandler) *Model { model := m.getModel() - model.hook = hook + model.hookHandler = hook return model } diff --git a/database/gdb/gdb_model_insert.go b/database/gdb/gdb_model_insert.go index 4013ca7f7..077845b3e 100644 --- a/database/gdb/gdb_model_insert.go +++ b/database/gdb/gdb_model_insert.go @@ -317,7 +317,7 @@ func (m *Model) doInsertWithOption(insertOption int) (result sql.Result, err err db: m.db, link: m.getLink(true), }, - handler: m.hook.Insert, + handler: m.hookHandler.Insert, }, Table: m.tables, Data: list, diff --git a/database/gdb/gdb_model_select.go b/database/gdb/gdb_model_select.go index 05049639c..e9e57c4ed 100644 --- a/database/gdb/gdb_model_select.go +++ b/database/gdb/gdb_model_select.go @@ -539,7 +539,7 @@ func (m *Model) doGetAllBySql(sql string, args ...interface{}) (result Result, e db: m.db, link: m.getLink(false), }, - handler: m.hook.Select, + handler: m.hookHandler.Select, }, Table: m.tables, Sql: sql, diff --git a/database/gdb/gdb_model_sharding.go b/database/gdb/gdb_model_sharding.go new file mode 100644 index 000000000..1e07971cc --- /dev/null +++ b/database/gdb/gdb_model_sharding.go @@ -0,0 +1,80 @@ +// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. +// +// This Source Code Form is subject to the terms of the MIT License. +// If a copy of the MIT was not distributed with this file, +// You can obtain one at https://github.com/gogf/gf. + +package gdb + +import ( + "context" + "reflect" + + "github.com/gogf/gf/v2/container/gvar" + "github.com/gogf/gf/v2/errors/gerror" +) + +// ShardingInput is input parameters for custom sharding handler. +type ShardingInput struct { + Table string // Current operation table name. + Schema string // Current operation schema, usually empty string which means uses default schema from configuration. + Data map[string]Value // Accurate key-value pairs from SELECT/INSERT/UPDATE/DELETE statement. +} + +// ShardingOutput is output parameters for custom sharding handler. +type ShardingOutput struct { + Table string // New table name for current operation. Use empty string for no changes of table name. + Schema string // New schema name for current operation. Use empty string for using default schema from configuration. +} + +type ShardingHandler func(ctx context.Context, in ShardingInput) (out *ShardingOutput, err error) + +type callShardingHandlerInput struct { + Table string + InsertData List + UpdateData interface{} + Condition string + Sql string +} + +func (m *Model) callShardingHandler(ctx context.Context, in callShardingHandlerInput) (out *ShardingOutput, err error) { + if m.shardingHandler == nil { + return &ShardingOutput{}, nil + } + return +} + +func (m *Model) shardingDataFromInsertData(data List) (shardingData map[string]Value, err error) { + if len(data) == 0 { + return nil, nil + } + shardingData = make(map[string]Value) + // If given batch data(in batch insert scenario), it uses the first data. + for k, v := range data[0] { + shardingData[k] = gvar.New(v) + } + return shardingData, nil +} + +func (m *Model) shardingDataFromUpdateData(data interface{}) (shardingData map[string]Value, err error) { + shardingData = make(map[string]Value) + switch value := data.(type) { + case map[string]interface{}: + for k, v := range value { + shardingData[k] = gvar.New(v) + } + case string: + + default: + return nil, gerror.Newf(`unsupported data of type "%s" for sharding`, reflect.TypeOf(data)) + } + return +} + +func (m *Model) shardingDataFromSql(sql string, args []interface{}) (shardingData map[string]Value, err error) { + return +} + +func (m *Model) shardingDataFromCondition(condition string) (shardingData map[string]Value, err error) { + return +} diff --git a/database/gdb/gdb_model_update.go b/database/gdb/gdb_model_update.go index 4ac93bffc..5f9c6cb2d 100644 --- a/database/gdb/gdb_model_update.go +++ b/database/gdb/gdb_model_update.go @@ -82,7 +82,7 @@ func (m *Model) Update(dataAndWhere ...interface{}) (result sql.Result, err erro db: m.db, link: m.getLink(true), }, - handler: m.hook.Update, + handler: m.hookHandler.Update, }, Table: m.tables, Data: newData,