Kill gorp (#19786)
* Kill gorp Gorp is dead. Long live Gorp. ```release-note NONE ```
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c3ec0a145b
Коммит
4da98cb51a
@@ -32,13 +32,10 @@ func (p *MyPlugin) MessageWillBePosted(_ *plugin.Context, _ *model.Post) (*model
|
||||
settings := p.API.GetUnsanitizedConfig().SqlSettings
|
||||
settings.Trace = model.NewBool(false)
|
||||
store := sqlstore.New(settings, nil)
|
||||
store.GetMaster().Db.Close()
|
||||
store.GetMasterX().Close()
|
||||
|
||||
for _, isMaster := range []bool{true, false} {
|
||||
// We replace the master DB with master and replica both just to make
|
||||
// gorp APIs work.
|
||||
handle := sql.OpenDB(driver.NewConnector(p.Driver, isMaster))
|
||||
store.GetMaster().Db = handle
|
||||
store.SetMasterX(handle)
|
||||
|
||||
wrapper := sqlstore.NewStoreTestWrapper(store)
|
||||
@@ -49,7 +46,7 @@ func (p *MyPlugin) MessageWillBePosted(_ *plugin.Context, _ *model.Post) (*model
|
||||
storetest.TestChannelStore(p.t, store, wrapper)
|
||||
storetest.TestBotStore(p.t, store, wrapper)
|
||||
|
||||
store.GetMaster().Db.Close()
|
||||
store.GetMasterX().Close()
|
||||
}
|
||||
|
||||
// Use the API to instantiate the driver
|
||||
|
||||
@@ -40,11 +40,11 @@ func NewDriverImpl(s *Server) *DriverImpl {
|
||||
}
|
||||
|
||||
func (d *DriverImpl) Conn(isMaster bool) (string, error) {
|
||||
dbFunc := d.s.sqlStore.GetMaster
|
||||
dbFunc := d.s.sqlStore.GetMasterX
|
||||
if !isMaster {
|
||||
dbFunc = d.s.sqlStore.GetReplica
|
||||
dbFunc = d.s.sqlStore.GetReplicaX
|
||||
}
|
||||
conn, err := dbFunc().Db.Conn(context.Background())
|
||||
conn, err := dbFunc().Conn(context.Background())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown()
|
||||
require.Same(t, s.sqlStore.GetMaster(), s.sqlStore.GetReplica())
|
||||
require.Same(t, s.sqlStore.GetMasterX(), s.sqlStore.GetReplicaX())
|
||||
require.Len(t, s.Config().SqlSettings.DataSourceReplicas, 1)
|
||||
})
|
||||
|
||||
@@ -103,7 +103,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown()
|
||||
require.NotSame(t, s.sqlStore.GetMaster(), s.sqlStore.GetReplica())
|
||||
require.NotSame(t, s.sqlStore.GetMasterX(), s.sqlStore.GetReplicaX())
|
||||
require.Len(t, s.Config().SqlSettings.DataSourceReplicas, 1)
|
||||
})
|
||||
|
||||
@@ -116,7 +116,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown()
|
||||
require.Same(t, s.sqlStore.GetMaster(), s.sqlStore.GetSearchReplica())
|
||||
require.Same(t, s.sqlStore.GetMasterX(), s.sqlStore.GetSearchReplicaX())
|
||||
require.Len(t, s.Config().SqlSettings.DataSourceSearchReplicas, 1)
|
||||
})
|
||||
|
||||
@@ -130,7 +130,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
||||
})
|
||||
require.NoError(t, err)
|
||||
defer s.Shutdown()
|
||||
require.NotSame(t, s.sqlStore.GetMaster(), s.sqlStore.GetSearchReplica())
|
||||
require.NotSame(t, s.sqlStore.GetMasterX(), s.sqlStore.GetSearchReplicaX())
|
||||
require.Len(t, s.Config().SqlSettings.DataSourceSearchReplicas, 1)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@@ -80,8 +79,7 @@ func getActualDatabaseConfig(t *testing.T) (string, *model.Config) {
|
||||
ID string `db:"id"`
|
||||
Value []byte `db:"value"`
|
||||
}
|
||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *mainHelper.GetSQLSettings().DriverName)
|
||||
err := db.Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||
err := mainHelper.GetSQLStore().GetMasterX().Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||
require.NoError(t, err)
|
||||
|
||||
var actualCfg *model.Config
|
||||
@@ -93,8 +91,7 @@ func getActualDatabaseConfig(t *testing.T) (string, *model.Config) {
|
||||
ID string `db:"Id"`
|
||||
Value []byte `db:"Value"`
|
||||
}
|
||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *mainHelper.GetSQLSettings().DriverName)
|
||||
err := db.Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||
err := mainHelper.GetSQLStore().GetMasterX().Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||
require.NoError(t, err)
|
||||
|
||||
var actualCfg *model.Config
|
||||
@@ -553,9 +550,7 @@ func TestDatabaseStoreSet(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
defer ds.Close()
|
||||
|
||||
sqlSettings := mainHelper.GetSQLSettings()
|
||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *sqlSettings.DriverName)
|
||||
_, err = db.Exec("DROP TABLE Configurations")
|
||||
_, err = mainHelper.GetSQLStore().GetMasterX().Exec("DROP TABLE Configurations")
|
||||
require.NoError(t, err)
|
||||
|
||||
newCfg := minimalConfig
|
||||
@@ -835,16 +830,15 @@ func TestDatabaseStoreLoad(t *testing.T) {
|
||||
cfgData, err := marshalConfig(invalidConfig)
|
||||
require.NoError(t, err)
|
||||
|
||||
sqlSettings := mainHelper.GetSQLSettings()
|
||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *sqlSettings.DriverName)
|
||||
truncateTables(t)
|
||||
id := model.NewId()
|
||||
_, err = db.NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:Id, :Value, :CreateAt, TRUE)", map[string]interface{}{
|
||||
"Id": id,
|
||||
"Value": cfgData,
|
||||
"CreateAt": model.GetMillis(),
|
||||
_, err = mainHelper.GetSQLStore().GetMasterX().NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:id, :value, :createat, TRUE)", map[string]interface{}{
|
||||
"id": id,
|
||||
"value": cfgData,
|
||||
"createat": model.GetMillis(),
|
||||
})
|
||||
require.NoError(t, err)
|
||||
t.Logf("%v\n", err)
|
||||
require.NoErrorf(t, err, "what is - %v", err)
|
||||
|
||||
err = ds.Load()
|
||||
if assert.Error(t, err) {
|
||||
|
||||
@@ -36,7 +36,7 @@ func truncateTable(t *testing.T, table string) {
|
||||
|
||||
switch *sqlSetting.DriverName {
|
||||
case model.DatabaseDriverMysql:
|
||||
_, err := sqlStore.GetMaster().Db.Exec(fmt.Sprintf("TRUNCATE TABLE %s", table))
|
||||
_, err := sqlStore.GetMasterX().Exec(fmt.Sprintf("TRUNCATE TABLE %s", table))
|
||||
if err != nil {
|
||||
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
||||
// Ignore if the Configurations table does not exist.
|
||||
@@ -48,7 +48,7 @@ func truncateTable(t *testing.T, table string) {
|
||||
require.NoError(t, err)
|
||||
|
||||
case model.DatabaseDriverPostgres:
|
||||
_, err := sqlStore.GetMaster().Db.Exec(fmt.Sprintf("TRUNCATE TABLE %s", table))
|
||||
_, err := sqlStore.GetMasterX().Exec(fmt.Sprintf("TRUNCATE TABLE %s", table))
|
||||
if err != nil {
|
||||
if driverErr, ok := err.(*pq.Error); ok {
|
||||
// Ignore if the Configurations table does not exist.
|
||||
|
||||
2
go.mod
2
go.mod
@@ -59,7 +59,6 @@ require (
|
||||
github.com/lib/pq v1.10.4
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404
|
||||
github.com/mattermost/gorp v1.6.2-0.20210714143452-8b50f5209a7f
|
||||
github.com/mattermost/gosaml2 v0.3.3
|
||||
github.com/mattermost/gziphandler v0.0.1
|
||||
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d
|
||||
@@ -67,6 +66,7 @@ require (
|
||||
github.com/mattermost/morph v0.0.0-20220222074146-cff3f12ff131
|
||||
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.18
|
||||
github.com/miekg/dns v1.1.46 // indirect
|
||||
|
||||
6
go.sum
6
go.sum
@@ -995,8 +995,6 @@ github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kN
|
||||
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
|
||||
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8=
|
||||
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
|
||||
github.com/mattermost/gorp v1.6.2-0.20210714143452-8b50f5209a7f h1:J47te5ubXIEbEaXi/nwStKQ/sLniXACgZ7LhK365YIY=
|
||||
github.com/mattermost/gorp v1.6.2-0.20210714143452-8b50f5209a7f/go.mod h1:QCQ3U0M9T/BlAdjKFJo0I1oe/YAgbyjNdhU8bpOLafk=
|
||||
github.com/mattermost/gosaml2 v0.3.3 h1:ysWrjp08tpWmo6rV2MQ88Eag/Ttjuj91fZsvibF4/Tg=
|
||||
github.com/mattermost/gosaml2 v0.3.3/go.mod h1:Z429EIOiEi9kbq6yHoApfzlcXpa6dzRDc6pO+Vy2Ksk=
|
||||
github.com/mattermost/gziphandler v0.0.1 h1:uXHcXF5agnQ6bXabvpiwwwZOlCYoa7mKHH0lxns/o8w=
|
||||
@@ -1149,7 +1147,6 @@ github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+
|
||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
@@ -1326,7 +1323,6 @@ github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8/go.mod h1:Z0q5wiB
|
||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/scylladb/termtables v0.0.0-20191203121021-c4c0b6d42ff4/go.mod h1:C1a7PQSMz9NShzorzCiG2fk9+xuCgLkPeCvMHYR2OWg=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
@@ -1530,8 +1526,6 @@ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX
|
||||
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
|
||||
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
|
||||
12
i18n/en.json
12
i18n/en.json
@@ -9191,18 +9191,6 @@
|
||||
"id": "sharedchannel.permalink.not_found",
|
||||
"translation": "This post contains permalinks to other channels which may not be visible to users in other sites."
|
||||
},
|
||||
{
|
||||
"id": "store.sql.convert_string_array",
|
||||
"translation": "FromDb: Unable to convert StringArray to *string"
|
||||
},
|
||||
{
|
||||
"id": "store.sql.convert_string_interface",
|
||||
"translation": "FromDb: Unable to convert StringInterface to *string"
|
||||
},
|
||||
{
|
||||
"id": "store.sql.convert_string_map",
|
||||
"translation": "FromDb: Unable to convert StringMap to *string"
|
||||
},
|
||||
{
|
||||
"id": "store.sql_bot.get.missing.app_error",
|
||||
"translation": "Bot does not exist."
|
||||
|
||||
@@ -6,17 +6,11 @@ package sqlstore
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/dyatlov/go-opengraph/opengraph"
|
||||
"github.com/mattermost/gorp"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/i18n"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type jsonArray []string
|
||||
@@ -68,85 +62,3 @@ func (t *TraceOnAdapter) Printf(format string, v ...interface{}) {
|
||||
type JSONSerializable interface {
|
||||
ToJSON() string
|
||||
}
|
||||
|
||||
type mattermConverter struct{}
|
||||
|
||||
func (me mattermConverter) ToDb(val interface{}) (interface{}, error) {
|
||||
switch t := val.(type) {
|
||||
case model.StringMap:
|
||||
return model.MapToJSON(t), nil
|
||||
case map[string]string:
|
||||
return model.MapToJSON(model.StringMap(t)), nil
|
||||
case model.StringArray:
|
||||
return model.ArrayToJSON(t), nil
|
||||
case model.StringInterface:
|
||||
return model.StringInterfaceToJSON(t), nil
|
||||
case map[string]interface{}:
|
||||
return model.StringInterfaceToJSON(model.StringInterface(t)), nil
|
||||
case JSONSerializable:
|
||||
return t.ToJSON(), nil
|
||||
case *opengraph.OpenGraph:
|
||||
return json.Marshal(t)
|
||||
case *model.PostImage:
|
||||
return json.Marshal(t)
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func (me mattermConverter) FromDb(target interface{}) (gorp.CustomScanner, bool) {
|
||||
switch target.(type) {
|
||||
case *model.StringMap:
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New(i18n.T("store.sql.convert_string_map"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
|
||||
case *map[string]string:
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New(i18n.T("store.sql.convert_string_map"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
|
||||
case *model.StringArray:
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New(i18n.T("store.sql.convert_string_array"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
|
||||
case *model.StringInterface:
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New(i18n.T("store.sql.convert_string_interface"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
|
||||
case *map[string]interface{}:
|
||||
binder := func(holder, target interface{}) error {
|
||||
s, ok := holder.(*string)
|
||||
if !ok {
|
||||
return errors.New(i18n.T("store.sql.convert_string_interface"))
|
||||
}
|
||||
b := []byte(*s)
|
||||
return json.Unmarshal(b, target)
|
||||
}
|
||||
return gorp.CustomScanner{Holder: new(string), Target: target, Binder: binder}, true
|
||||
}
|
||||
|
||||
return gorp.CustomScanner{}, false
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ package sqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/mattermost/gorp"
|
||||
)
|
||||
|
||||
// storeContextKey is the base type for all context keys for the store.
|
||||
@@ -35,14 +33,6 @@ func hasMaster(ctx context.Context) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// DBFromContext is a helper utility that returns the DB handle from a given context.
|
||||
func (ss *SqlStore) DBFromContext(ctx context.Context) *gorp.DbMap {
|
||||
if hasMaster(ctx) {
|
||||
return ss.GetMaster()
|
||||
}
|
||||
return ss.GetReplica()
|
||||
}
|
||||
|
||||
// DBXFromContext is a helper utility that returns the sqlx DB handle from a given context.
|
||||
func (ss *SqlStore) DBXFromContext(ctx context.Context) *sqlxDBWrapper {
|
||||
if hasMaster(ctx) {
|
||||
|
||||
@@ -58,22 +58,23 @@ func TestDeleteUnusedFeatures(t *testing.T) {
|
||||
ss.Preference().(*SqlPreferenceStore).deleteUnusedFeatures()
|
||||
|
||||
//make sure features with value "false" have actually been deleted from the database
|
||||
if val, err := ss.Preference().(*SqlPreferenceStore).GetReplica().SelectInt(`SELECT COUNT(*)
|
||||
var val int64
|
||||
if err := ss.Preference().(*SqlPreferenceStore).GetReplicaX().Get(&val, `SELECT COUNT(*)
|
||||
FROM Preferences
|
||||
WHERE Category = :Category
|
||||
AND Value = :Val
|
||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, map[string]interface{}{"Category": model.PreferenceCategoryAdvancedSettings, "Val": "false"}); err != nil {
|
||||
WHERE Category = ?
|
||||
AND Value = ?
|
||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, model.PreferenceCategoryAdvancedSettings, "false"); err != nil {
|
||||
require.NoError(t, err)
|
||||
} else if val != 0 {
|
||||
require.Fail(t, "Found %d features with value 'false', expected all to be deleted", val)
|
||||
}
|
||||
//
|
||||
// make sure features with value "true" remain saved
|
||||
if val, err := ss.Preference().(*SqlPreferenceStore).GetReplica().SelectInt(`SELECT COUNT(*)
|
||||
if err := ss.Preference().(*SqlPreferenceStore).GetReplicaX().Get(&val, `SELECT COUNT(*)
|
||||
FROM Preferences
|
||||
WHERE Category = :Category
|
||||
AND Value = :Val
|
||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, map[string]interface{}{"Category": model.PreferenceCategoryAdvancedSettings, "Val": "true"}); err != nil {
|
||||
WHERE Category = ?
|
||||
AND Value = ?
|
||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, model.PreferenceCategoryAdvancedSettings, "true"); err != nil {
|
||||
require.NoError(t, err)
|
||||
} else if val == 0 {
|
||||
require.Fail(t, "Found %d features with value 'true', expected to find at least %d features", val, 2)
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
"github.com/mattermost/gorp"
|
||||
"github.com/mattermost/mattermost-server/v6/model"
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
"github.com/mattermost/mattermost-server/v6/store/storetest"
|
||||
@@ -28,10 +27,6 @@ func NewStoreTestWrapper(orig *SqlStore) *StoreTestWrapper {
|
||||
return &StoreTestWrapper{orig}
|
||||
}
|
||||
|
||||
func (w *StoreTestWrapper) GetMaster() *gorp.DbMap {
|
||||
return w.orig.GetMaster()
|
||||
}
|
||||
|
||||
func (w *StoreTestWrapper) GetMasterX() storetest.SqlXExecutor {
|
||||
return w.orig.GetMasterX()
|
||||
}
|
||||
@@ -251,6 +246,18 @@ func (w *sqlxTxWrapper) Exec(query string, args ...interface{}) (sql.Result, err
|
||||
return w.ExecRaw(query, args...)
|
||||
}
|
||||
|
||||
func (w *sqlxTxWrapper) ExecNoTimeout(query string, args ...interface{}) (sql.Result, error) {
|
||||
query = w.Tx.Rebind(query)
|
||||
|
||||
if w.trace {
|
||||
defer func(then time.Time) {
|
||||
printArgs(query, time.Since(then), args)
|
||||
}(time.Now())
|
||||
}
|
||||
|
||||
return w.Tx.ExecContext(context.Background(), query, args...)
|
||||
}
|
||||
|
||||
// ExecRaw is like Exec but without any rebinding of params. You need to pass
|
||||
// the exact param types of your target database.
|
||||
func (w *sqlxTxWrapper) ExecRaw(query string, args ...interface{}) (sql.Result, error) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
_ "github.com/golang-migrate/migrate/v4/source/file"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/lib/pq"
|
||||
"github.com/mattermost/gorp"
|
||||
mbindata "github.com/mattermost/morph/sources/go_bindata"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
@@ -113,13 +112,10 @@ type SqlStore struct {
|
||||
rrCounter int64
|
||||
srCounter int64
|
||||
|
||||
master *gorp.DbMap
|
||||
masterX *sqlxDBWrapper
|
||||
|
||||
Replicas []*gorp.DbMap
|
||||
ReplicaXs []*sqlxDBWrapper
|
||||
|
||||
searchReplicas []*gorp.DbMap
|
||||
searchReplicaXs []*sqlxDBWrapper
|
||||
|
||||
replicaLagHandles []*dbsql.DB
|
||||
@@ -248,34 +244,6 @@ func setupConnection(connType string, dataSource string, settings *model.SqlSett
|
||||
return db
|
||||
}
|
||||
|
||||
func getDBMap(settings *model.SqlSettings, db *dbsql.DB) *gorp.DbMap {
|
||||
connectionTimeout := time.Duration(*settings.QueryTimeout) * time.Second
|
||||
var dbMap *gorp.DbMap
|
||||
switch *settings.DriverName {
|
||||
case model.DatabaseDriverMysql:
|
||||
dbMap = &gorp.DbMap{
|
||||
Db: db,
|
||||
TypeConverter: mattermConverter{},
|
||||
Dialect: gorp.MySQLDialect{Engine: "InnoDB", Encoding: "UTF8MB4"},
|
||||
QueryTimeout: connectionTimeout,
|
||||
}
|
||||
case model.DatabaseDriverPostgres:
|
||||
dbMap = &gorp.DbMap{
|
||||
Db: db,
|
||||
TypeConverter: mattermConverter{},
|
||||
Dialect: gorp.PostgresDialect{},
|
||||
QueryTimeout: connectionTimeout,
|
||||
}
|
||||
default:
|
||||
mlog.Fatal("Failed to create dialect specific driver")
|
||||
return nil
|
||||
}
|
||||
if settings.Trace != nil && *settings.Trace {
|
||||
dbMap.TraceOn("sql-trace:", &TraceOnAdapter{})
|
||||
}
|
||||
return dbMap
|
||||
}
|
||||
|
||||
func (ss *SqlStore) SetContext(context context.Context) {
|
||||
ss.context = context
|
||||
}
|
||||
@@ -300,7 +268,6 @@ func (ss *SqlStore) initConnection() {
|
||||
}
|
||||
|
||||
handle := setupConnection("master", dataSource, ss.settings)
|
||||
ss.master = getDBMap(ss.settings, handle)
|
||||
ss.masterX = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||
*ss.settings.Trace)
|
||||
@@ -309,11 +276,9 @@ func (ss *SqlStore) initConnection() {
|
||||
}
|
||||
|
||||
if len(ss.settings.DataSourceReplicas) > 0 {
|
||||
ss.Replicas = make([]*gorp.DbMap, len(ss.settings.DataSourceReplicas))
|
||||
ss.ReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceReplicas))
|
||||
for i, replica := range ss.settings.DataSourceReplicas {
|
||||
handle := setupConnection(fmt.Sprintf("replica-%v", i), replica, ss.settings)
|
||||
ss.Replicas[i] = getDBMap(ss.settings, handle)
|
||||
ss.ReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||
*ss.settings.Trace)
|
||||
@@ -324,11 +289,9 @@ func (ss *SqlStore) initConnection() {
|
||||
}
|
||||
|
||||
if len(ss.settings.DataSourceSearchReplicas) > 0 {
|
||||
ss.searchReplicas = make([]*gorp.DbMap, len(ss.settings.DataSourceSearchReplicas))
|
||||
ss.searchReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceSearchReplicas))
|
||||
for i, replica := range ss.settings.DataSourceSearchReplicas {
|
||||
handle := setupConnection(fmt.Sprintf("search-replica-%v", i), replica, ss.settings)
|
||||
ss.searchReplicas[i] = getDBMap(ss.settings, handle)
|
||||
ss.searchReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||
*ss.settings.Trace)
|
||||
@@ -386,10 +349,6 @@ func (ss *SqlStore) GetDbVersion(numerical bool) (string, error) {
|
||||
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetMaster() *gorp.DbMap {
|
||||
return ss.master
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetMasterX() *sqlxDBWrapper {
|
||||
return ss.masterX
|
||||
}
|
||||
@@ -403,22 +362,6 @@ func (ss *SqlStore) SetMasterX(db *sql.DB) {
|
||||
}
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetSearchReplica() *gorp.DbMap {
|
||||
ss.licenseMutex.RLock()
|
||||
license := ss.license
|
||||
ss.licenseMutex.RUnlock()
|
||||
if license == nil {
|
||||
return ss.GetMaster()
|
||||
}
|
||||
|
||||
if len(ss.settings.DataSourceSearchReplicas) == 0 {
|
||||
return ss.GetReplica()
|
||||
}
|
||||
|
||||
rrNum := atomic.AddInt64(&ss.srCounter, 1) % int64(len(ss.searchReplicas))
|
||||
return ss.searchReplicas[rrNum]
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetSearchReplicaX() *sqlxDBWrapper {
|
||||
ss.licenseMutex.RLock()
|
||||
license := ss.license
|
||||
@@ -435,18 +378,6 @@ func (ss *SqlStore) GetSearchReplicaX() *sqlxDBWrapper {
|
||||
return ss.searchReplicaXs[rrNum]
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetReplica() *gorp.DbMap {
|
||||
ss.licenseMutex.RLock()
|
||||
license := ss.license
|
||||
ss.licenseMutex.RUnlock()
|
||||
if len(ss.settings.DataSourceReplicas) == 0 || ss.lockedToMaster || license == nil {
|
||||
return ss.GetMaster()
|
||||
}
|
||||
|
||||
rrNum := atomic.AddInt64(&ss.rrCounter, 1) % int64(len(ss.Replicas))
|
||||
return ss.Replicas[rrNum]
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetReplicaX() *sqlxDBWrapper {
|
||||
ss.licenseMutex.RLock()
|
||||
license := ss.license
|
||||
@@ -455,7 +386,7 @@ func (ss *SqlStore) GetReplicaX() *sqlxDBWrapper {
|
||||
return ss.GetMasterX()
|
||||
}
|
||||
|
||||
rrNum := atomic.AddInt64(&ss.rrCounter, 1) % int64(len(ss.Replicas))
|
||||
rrNum := atomic.AddInt64(&ss.rrCounter, 1) % int64(len(ss.ReplicaXs))
|
||||
return ss.ReplicaXs[rrNum]
|
||||
}
|
||||
|
||||
@@ -507,8 +438,8 @@ func (ss *SqlStore) TotalReadDbConnections() int {
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, db := range ss.Replicas {
|
||||
count = count + db.Db.Stats().OpenConnections
|
||||
for _, db := range ss.ReplicaXs {
|
||||
count = count + db.Stats().OpenConnections
|
||||
}
|
||||
|
||||
return count
|
||||
@@ -520,8 +451,8 @@ func (ss *SqlStore) TotalSearchDbConnections() int {
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, db := range ss.searchReplicas {
|
||||
count = count + db.Db.Stats().OpenConnections
|
||||
for _, db := range ss.searchReplicaXs {
|
||||
count = count + db.Stats().OpenConnections
|
||||
}
|
||||
|
||||
return count
|
||||
@@ -748,10 +679,10 @@ func IsUniqueConstraintError(err error, indexName []string) bool {
|
||||
return unique && field
|
||||
}
|
||||
|
||||
func (ss *SqlStore) GetAllConns() []*gorp.DbMap {
|
||||
all := make([]*gorp.DbMap, len(ss.Replicas)+1)
|
||||
copy(all, ss.Replicas)
|
||||
all[len(ss.Replicas)] = ss.master
|
||||
func (ss *SqlStore) GetAllConns() []*sqlxDBWrapper {
|
||||
all := make([]*sqlxDBWrapper, len(ss.ReplicaXs)+1)
|
||||
copy(all, ss.ReplicaXs)
|
||||
all[len(ss.ReplicaXs)] = ss.masterX
|
||||
return all
|
||||
}
|
||||
|
||||
@@ -762,24 +693,24 @@ func (ss *SqlStore) RecycleDBConnections(d time.Duration) {
|
||||
originalDuration := time.Duration(*ss.settings.ConnMaxLifetimeMilliseconds) * time.Millisecond
|
||||
// Set the max lifetimes for all connections.
|
||||
for _, conn := range ss.GetAllConns() {
|
||||
conn.Db.SetConnMaxLifetime(d)
|
||||
conn.SetConnMaxLifetime(d)
|
||||
}
|
||||
// Wait for that period with an additional 2 seconds of scheduling delay.
|
||||
time.Sleep(d + 2*time.Second)
|
||||
// Reset max lifetime back to original value.
|
||||
for _, conn := range ss.GetAllConns() {
|
||||
conn.Db.SetConnMaxLifetime(originalDuration)
|
||||
conn.SetConnMaxLifetime(originalDuration)
|
||||
}
|
||||
}
|
||||
|
||||
func (ss *SqlStore) Close() {
|
||||
ss.master.Db.Close()
|
||||
for _, replica := range ss.Replicas {
|
||||
replica.Db.Close()
|
||||
ss.masterX.Close()
|
||||
for _, replica := range ss.ReplicaXs {
|
||||
replica.Close()
|
||||
}
|
||||
|
||||
for _, replica := range ss.searchReplicas {
|
||||
replica.Db.Close()
|
||||
for _, replica := range ss.searchReplicaXs {
|
||||
replica.Close()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import (
|
||||
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/lib/pq"
|
||||
"github.com/mattermost/gorp"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -186,12 +185,12 @@ func TestStoreLicenseRace(t *testing.T) {
|
||||
}()
|
||||
|
||||
go func() {
|
||||
store.GetReplica()
|
||||
store.GetReplicaX()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
go func() {
|
||||
store.GetSearchReplica()
|
||||
store.GetSearchReplicaX()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
@@ -276,14 +275,14 @@ func TestGetReplica(t *testing.T) {
|
||||
|
||||
store.UpdateLicense(&model.License{})
|
||||
|
||||
replicas := make(map[*gorp.DbMap]bool)
|
||||
replicas := make(map[*sqlxDBWrapper]bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
replicas[store.GetReplica()] = true
|
||||
replicas[store.GetReplicaX()] = true
|
||||
}
|
||||
|
||||
searchReplicas := make(map[*gorp.DbMap]bool)
|
||||
searchReplicas := make(map[*sqlxDBWrapper]bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
searchReplicas[store.GetSearchReplica()] = true
|
||||
searchReplicas[store.GetSearchReplicaX()] = true
|
||||
}
|
||||
|
||||
if testCase.DataSourceReplicaNum > 0 {
|
||||
@@ -291,13 +290,13 @@ func TestGetReplica(t *testing.T) {
|
||||
assert.Len(t, replicas, testCase.DataSourceReplicaNum)
|
||||
|
||||
for replica := range replicas {
|
||||
assert.NotSame(t, store.GetMaster(), replica)
|
||||
assert.NotSame(t, store.GetMasterX(), replica)
|
||||
}
|
||||
|
||||
} else if assert.Len(t, replicas, 1) {
|
||||
// Otherwise ensure the replicas contains only the master.
|
||||
for replica := range replicas {
|
||||
assert.Same(t, store.GetMaster(), replica)
|
||||
assert.Same(t, store.GetMasterX(), replica)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +305,7 @@ func TestGetReplica(t *testing.T) {
|
||||
assert.Len(t, searchReplicas, testCase.DataSourceSearchReplicaNum)
|
||||
|
||||
for searchReplica := range searchReplicas {
|
||||
assert.NotSame(t, store.GetMaster(), searchReplica)
|
||||
assert.NotSame(t, store.GetMasterX(), searchReplica)
|
||||
for replica := range replicas {
|
||||
assert.NotSame(t, searchReplica, replica)
|
||||
}
|
||||
@@ -319,7 +318,7 @@ func TestGetReplica(t *testing.T) {
|
||||
} else if testCase.DataSourceReplicaNum == 0 && assert.Len(t, searchReplicas, 1) {
|
||||
// Otherwise ensure the search replicas contains the master.
|
||||
for searchReplica := range searchReplicas {
|
||||
assert.Same(t, store.GetMaster(), searchReplica)
|
||||
assert.Same(t, store.GetMasterX(), searchReplica)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -344,14 +343,14 @@ func TestGetReplica(t *testing.T) {
|
||||
storetest.CleanupSqlSettings(settings)
|
||||
}()
|
||||
|
||||
replicas := make(map[*gorp.DbMap]bool)
|
||||
replicas := make(map[*sqlxDBWrapper]bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
replicas[store.GetReplica()] = true
|
||||
replicas[store.GetReplicaX()] = true
|
||||
}
|
||||
|
||||
searchReplicas := make(map[*gorp.DbMap]bool)
|
||||
searchReplicas := make(map[*sqlxDBWrapper]bool)
|
||||
for i := 0; i < 5; i++ {
|
||||
searchReplicas[store.GetSearchReplica()] = true
|
||||
searchReplicas[store.GetSearchReplicaX()] = true
|
||||
}
|
||||
|
||||
if testCase.DataSourceReplicaNum > 0 {
|
||||
@@ -359,13 +358,13 @@ func TestGetReplica(t *testing.T) {
|
||||
assert.Len(t, replicas, 1)
|
||||
|
||||
for replica := range replicas {
|
||||
assert.Same(t, store.GetMaster(), replica)
|
||||
assert.Same(t, store.GetMasterX(), replica)
|
||||
}
|
||||
|
||||
} else if assert.Len(t, replicas, 1) {
|
||||
// Otherwise ensure the replicas contains only the master.
|
||||
for replica := range replicas {
|
||||
assert.Same(t, store.GetMaster(), replica)
|
||||
assert.Same(t, store.GetMasterX(), replica)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,7 +373,7 @@ func TestGetReplica(t *testing.T) {
|
||||
assert.Len(t, searchReplicas, 1)
|
||||
|
||||
for searchReplica := range searchReplicas {
|
||||
assert.Same(t, store.GetMaster(), searchReplica)
|
||||
assert.Same(t, store.GetMasterX(), searchReplica)
|
||||
}
|
||||
|
||||
} else if testCase.DataSourceReplicaNum > 0 {
|
||||
@@ -385,7 +384,7 @@ func TestGetReplica(t *testing.T) {
|
||||
} else if assert.Len(t, searchReplicas, 1) {
|
||||
// Otherwise ensure the search replicas contains the master.
|
||||
for searchReplica := range searchReplicas {
|
||||
assert.Same(t, store.GetMaster(), searchReplica)
|
||||
assert.Same(t, store.GetMasterX(), searchReplica)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -755,10 +754,10 @@ func TestExecNoTimeout(t *testing.T) {
|
||||
StoreTest(t, func(t *testing.T, ss store.Store) {
|
||||
sqlStore := ss.(*SqlStore)
|
||||
var query string
|
||||
timeout := sqlStore.master.QueryTimeout
|
||||
sqlStore.master.QueryTimeout = 1
|
||||
timeout := sqlStore.masterX.queryTimeout
|
||||
sqlStore.masterX.queryTimeout = 1
|
||||
defer func() {
|
||||
sqlStore.master.QueryTimeout = timeout
|
||||
sqlStore.masterX.queryTimeout = timeout
|
||||
}()
|
||||
if sqlStore.DriverName() == model.DatabaseDriverMysql {
|
||||
query = `SELECT SLEEP(2);`
|
||||
|
||||
@@ -922,7 +922,7 @@ func (s SqlTeamStore) GetMember(ctx context.Context, teamId string, userId strin
|
||||
}
|
||||
|
||||
var dbMember teamMemberWithSchemeRoles
|
||||
err = s.DBFromContext(ctx).SelectOne(&dbMember, queryString, args...)
|
||||
err = s.DBXFromContext(ctx).Get(&dbMember, queryString, args...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, store.NewErrNotFound("TeamMember", fmt.Sprintf("teamId=%s, userId=%s", teamId, userId))
|
||||
@@ -1068,7 +1068,7 @@ func (s SqlTeamStore) GetTeamsForUser(ctx context.Context, userId string) ([]*mo
|
||||
}
|
||||
|
||||
dbMembers := teamMemberWithSchemeRolesList{}
|
||||
_, err = s.SqlStore.DBFromContext(ctx).Select(&dbMembers, queryString, args...)
|
||||
err = s.SqlStore.DBXFromContext(ctx).Select(&dbMembers, queryString, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId)
|
||||
}
|
||||
|
||||
@@ -282,27 +282,22 @@ func themeMigrationFailed(err error) {
|
||||
func upgradeDatabaseToVersion33(sqlStore *SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, Version320, Version330) {
|
||||
if sqlStore.DoesColumnExist("Users", "ThemeProps") {
|
||||
params := map[string]interface{}{
|
||||
"Category": model.PreferenceCategoryTheme,
|
||||
"Name": "",
|
||||
}
|
||||
|
||||
transaction, err := sqlStore.GetMaster().Begin()
|
||||
transaction, err := sqlStore.GetMasterX().Beginx()
|
||||
if err != nil {
|
||||
themeMigrationFailed(err)
|
||||
}
|
||||
defer finalizeTransaction(transaction)
|
||||
defer finalizeTransactionX(transaction)
|
||||
|
||||
// copy data across
|
||||
if _, err := transaction.ExecNoTimeout(
|
||||
`INSERT INTO
|
||||
Preferences(UserId, Category, Name, Value)
|
||||
SELECT
|
||||
Id, '`+model.PreferenceCategoryTheme+`', '', ThemeProps
|
||||
Id, '` + model.PreferenceCategoryTheme + `', '', ThemeProps
|
||||
FROM
|
||||
Users
|
||||
WHERE
|
||||
Users.ThemeProps != 'null'`, params); err != nil {
|
||||
Users.ThemeProps != 'null'`); err != nil {
|
||||
themeMigrationFailed(err)
|
||||
return
|
||||
}
|
||||
@@ -554,8 +549,8 @@ func upgradeDatabaseToVersion510(sqlStore *SqlStore) {
|
||||
func upgradeDatabaseToVersion511(sqlStore *SqlStore) {
|
||||
if shouldPerformUpgrade(sqlStore, Version5100, Version5110) {
|
||||
// Enforce all teams have an InviteID set
|
||||
var teams []*model.Team
|
||||
if _, err := sqlStore.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
|
||||
teams := []*model.Team{}
|
||||
if err := sqlStore.GetReplicaX().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
|
||||
mlog.Error("Error fetching Teams without InviteID", mlog.Err(err))
|
||||
} else {
|
||||
for _, team := range teams {
|
||||
@@ -701,7 +696,7 @@ func precheckMigrationToVersion528(sqlStore *SqlStore) error {
|
||||
}
|
||||
|
||||
var schemeIDWrong, typeWrong int
|
||||
row := sqlStore.GetMaster().Db.QueryRow(teamsQuery)
|
||||
row := sqlStore.GetMasterX().QueryRow(teamsQuery)
|
||||
if err = row.Scan(&schemeIDWrong, &typeWrong); err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
} else if err == nil && schemeIDWrong > 0 {
|
||||
|
||||
@@ -390,7 +390,7 @@ func (us SqlUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User
|
||||
}
|
||||
|
||||
users := []*model.User{}
|
||||
if _, err := us.SqlStore.DBFromContext(ctx).Select(&users, queryString, args...); err != nil {
|
||||
if err := us.SqlStore.DBXFromContext(ctx).Select(&users, queryString, args...); err != nil {
|
||||
return nil, errors.Wrap(err, "users_get_many_select")
|
||||
}
|
||||
|
||||
@@ -403,7 +403,7 @@ func (us SqlUserStore) Get(ctx context.Context, id string) (*model.User, error)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "users_get_tosql")
|
||||
}
|
||||
row := us.SqlStore.DBFromContext(ctx).Db.QueryRow(queryString, args...)
|
||||
row := us.SqlStore.DBXFromContext(ctx).QueryRow(queryString, args...)
|
||||
|
||||
var user model.User
|
||||
var props, notifyProps, timezone []byte
|
||||
@@ -774,7 +774,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID st
|
||||
}
|
||||
|
||||
users := []*model.User{}
|
||||
rows, err := us.SqlStore.DBFromContext(ctx).Db.Query(queryString, args...)
|
||||
rows, err := us.SqlStore.DBXFromContext(ctx).Query(queryString, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find Users")
|
||||
}
|
||||
@@ -998,7 +998,7 @@ func (us SqlUserStore) GetProfileByIds(ctx context.Context, userIds []string, op
|
||||
return nil, errors.Wrap(err, "get_profile_by_ids_tosql")
|
||||
}
|
||||
|
||||
if _, err := us.SqlStore.DBFromContext(ctx).Select(&users, queryString, args...); err != nil {
|
||||
if err := us.SqlStore.DBXFromContext(ctx).Select(&users, queryString, args...); err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find Users")
|
||||
}
|
||||
|
||||
@@ -1679,7 +1679,7 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
|
||||
OrderBy("u.CreateAt").
|
||||
Limit(uint64(limit)).
|
||||
ToSql()
|
||||
_, err := us.GetSearchReplica().Select(&users, usersQuery, args...)
|
||||
err := us.GetSearchReplicaX().Select(&users, usersQuery, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find Users")
|
||||
}
|
||||
@@ -1689,7 +1689,7 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
|
||||
userIds = append(userIds, user.Id)
|
||||
}
|
||||
|
||||
var channelMembers []*model.ChannelMember
|
||||
channelMembers := []*model.ChannelMember{}
|
||||
channelMembersQuery, args, _ := us.getQueryBuilder().
|
||||
Select(`
|
||||
cm.ChannelId,
|
||||
@@ -1709,18 +1709,18 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
|
||||
Join("Channels c ON cm.ChannelId = c.Id").
|
||||
Where(sq.Eq{"c.Type": model.ChannelTypeOpen, "cm.UserId": userIds}).
|
||||
ToSql()
|
||||
_, err = us.GetSearchReplica().Select(&channelMembers, channelMembersQuery, args...)
|
||||
err = us.GetSearchReplicaX().Select(&channelMembers, channelMembersQuery, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find ChannelMembers")
|
||||
}
|
||||
|
||||
var teamMembers []*model.TeamMember
|
||||
teamMembers := []*model.TeamMember{}
|
||||
teamMembersQuery, args, _ := us.getQueryBuilder().
|
||||
Select("TeamId, UserId, Roles, DeleteAt, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest, SchemeUser, SchemeAdmin").
|
||||
From("TeamMembers").
|
||||
Where(sq.Eq{"UserId": userIds, "DeleteAt": 0}).
|
||||
ToSql()
|
||||
_, err = us.GetSearchReplica().Select(&teamMembers, teamMembersQuery, args...)
|
||||
err = us.GetSearchReplicaX().Select(&teamMembers, teamMembersQuery, args...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to find TeamMembers")
|
||||
}
|
||||
|
||||
@@ -17,15 +17,7 @@ type SqlUserTermsOfServiceStore struct {
|
||||
}
|
||||
|
||||
func newSqlUserTermsOfServiceStore(sqlStore *SqlStore) store.UserTermsOfServiceStore {
|
||||
s := SqlUserTermsOfServiceStore{sqlStore}
|
||||
|
||||
for _, db := range sqlStore.GetAllConns() {
|
||||
table := db.AddTableWithName(model.UserTermsOfService{}, "UserTermsOfService").SetKeys(false, "UserId")
|
||||
table.ColMap("UserId").SetMaxSize(26)
|
||||
table.ColMap("TermsOfServiceId").SetMaxSize(26)
|
||||
}
|
||||
|
||||
return s
|
||||
return SqlUserTermsOfServiceStore{sqlStore}
|
||||
}
|
||||
|
||||
func (s SqlUserTermsOfServiceStore) GetByUser(userId string) (*model.UserTermsOfService, error) {
|
||||
|
||||
@@ -9,8 +9,6 @@ import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/mattermost/gorp"
|
||||
|
||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||
)
|
||||
|
||||
@@ -47,14 +45,6 @@ func MapStringsToQueryParams(list []string, paramPrefix string) (string, map[str
|
||||
return "(" + keys.String() + ")", params
|
||||
}
|
||||
|
||||
// finalizeTransaction ensures a transaction is closed after use, rolling back if not already committed.
|
||||
func finalizeTransaction(transaction *gorp.Transaction) {
|
||||
// Rollback returns sql.ErrTxDone if the transaction was already closed.
|
||||
if err := transaction.Rollback(); err != nil && err != sql.ErrTxDone {
|
||||
mlog.Error("Failed to rollback transaction", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
// finalizeTransactionX ensures a transaction is closed after use, rolling back if not already committed.
|
||||
func finalizeTransactionX(transaction *sqlxTxWrapper) {
|
||||
// Rollback returns sql.ErrTxDone if the transaction was already closed.
|
||||
|
||||
@@ -180,7 +180,7 @@ func (h *MainHelper) PreloadMigrations() {
|
||||
panic(fmt.Errorf("cannot read file: %v", err))
|
||||
}
|
||||
}
|
||||
handle := h.SQLStore.GetMaster()
|
||||
handle := h.SQLStore.GetMasterX()
|
||||
_, err = handle.Exec(string(buf))
|
||||
if err != nil {
|
||||
panic(errors.Wrap(err, "Error preloading migrations. Check if you have &multiStatements=true in your DSN if you are using MySQL. Or perhaps the schema changed? If yes, then update the warmup files accordingly"))
|
||||
@@ -271,7 +271,7 @@ func (h *MainHelper) SetReplicationLagForTesting(seconds int) error {
|
||||
}
|
||||
|
||||
func (h *MainHelper) execOnEachReplica(query string, args ...interface{}) error {
|
||||
for _, replica := range h.SQLStore.Replicas {
|
||||
for _, replica := range h.SQLStore.ReplicaXs {
|
||||
_, err := replica.Exec(query, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
10
vendor/github.com/mattermost/gorp/.gitignore
сгенерированный
поставляемый
10
vendor/github.com/mattermost/gorp/.gitignore
сгенерированный
поставляемый
@@ -1,10 +0,0 @@
|
||||
_test
|
||||
*.test
|
||||
_testmain.go
|
||||
_obj
|
||||
*~
|
||||
*.6
|
||||
6.out
|
||||
gorptest.bin
|
||||
tmp
|
||||
*.swp
|
||||
34
vendor/github.com/mattermost/gorp/CONTRIBUTING.md
сгенерированный
поставляемый
34
vendor/github.com/mattermost/gorp/CONTRIBUTING.md
сгенерированный
поставляемый
@@ -1,34 +0,0 @@
|
||||
# Contributions are very welcome!
|
||||
|
||||
## First: Create an Issue
|
||||
|
||||
Even if your fix is simple, we'd like to have an issue to relate to
|
||||
the PR. Discussion about the architecture and value can go on the
|
||||
issue, leaving PR comments exclusively for coding style.
|
||||
|
||||
## Second: Make Your PR
|
||||
|
||||
- Fork the `master` branch
|
||||
- Make your change
|
||||
- Make a PR against the `master` branch
|
||||
|
||||
You don't need to wait for comments on the issue before making your
|
||||
PR. If you do wait for comments, you'll have a better chance of
|
||||
getting your PR accepted the first time around, but it's not
|
||||
necessary.
|
||||
|
||||
## Third: Be Patient
|
||||
|
||||
- If your change breaks backward compatibility, this becomes
|
||||
especially true.
|
||||
|
||||
We all have lives and jobs, and many of us are no longer on projects
|
||||
that make use of `gorp`. We will get back to you, but it might take a
|
||||
while.
|
||||
|
||||
## Fourth: Consider Becoming a Maintainer
|
||||
|
||||
We really do need help. We will likely ask you for help after a good
|
||||
PR, but if we don't, please create an issue requesting maintainership.
|
||||
Considering how few of us are currently active, we are unlikely to
|
||||
refuse good help.
|
||||
22
vendor/github.com/mattermost/gorp/LICENSE
сгенерированный
поставляемый
22
vendor/github.com/mattermost/gorp/LICENSE
сгенерированный
поставляемый
@@ -1,22 +0,0 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) 2012 James Cooper <james@bitmechanic.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
24
vendor/github.com/mattermost/gorp/Makefile
сгенерированный
поставляемый
24
vendor/github.com/mattermost/gorp/Makefile
сгенерированный
поставляемый
@@ -1,24 +0,0 @@
|
||||
GOTESTFLAGS ?= -test.count=1
|
||||
|
||||
test-all: test-unit test-mymysql test-gomysql test-postgres test-sqlite
|
||||
|
||||
test-unit:
|
||||
echo "Running unit tests"
|
||||
ginkgo -r -race -randomizeAllSpecs -keepGoing -- -test.run TestGorp
|
||||
|
||||
test-mymysql:
|
||||
echo "Testing against mymysql"
|
||||
go test . $(GOTESTFLAGS) -dsn="tcp:localhost:3306*gorptest/gorptest/gorptest" -dialect="mysql"
|
||||
|
||||
test-gomysql:
|
||||
echo "Testing against gomysql"
|
||||
go test . $(GOTESTFLAGS) -dsn="gorptest:gorptest@tcp(localhost:3306)/gorptest" -dialect="gomysql"
|
||||
|
||||
test-postgres:
|
||||
echo "Testing against postgres"
|
||||
go test . $(GOTESTFLAGS) -dsn="host=localhost user=gorptest password=gorptest dbname=gorptest sslmode=disable" -dialect="postgres"
|
||||
|
||||
test-sqlite:
|
||||
echo "Testing against sqlite"
|
||||
go test . $(GOTESTFLAGS) -dsn="/tmp/gorptest.bin" -dialect="sqlite"
|
||||
rm -f /tmp/gorptest.bin
|
||||
805
vendor/github.com/mattermost/gorp/README.md
сгенерированный
поставляемый
805
vendor/github.com/mattermost/gorp/README.md
сгенерированный
поставляемый
@@ -1,805 +0,0 @@
|
||||
# Go Relational Persistence
|
||||
|
||||
[](http://travis-ci.org/go-gorp/gorp)
|
||||
[](https://coveralls.io/r/go-gorp/gorp)
|
||||
[](https://github.com/go-gorp/gorp/issues)
|
||||
[](https://godoc.org/gopkg.in/gorp.v1)
|
||||
[](https://godoc.org/gopkg.in/gorp.v2)
|
||||
[](https://godoc.org/github.com/go-gorp/gorp)
|
||||
|
||||
### Update 2016-11-13: Future versions
|
||||
|
||||
As many of the maintainers have become busy with other projects,
|
||||
progress toward the ever-elusive v2 has slowed to the point that we're
|
||||
only occasionally making progress outside of merging pull requests.
|
||||
In the interest of continuing to release, I'd like to lean toward a
|
||||
more maintainable path forward.
|
||||
|
||||
For the moment, I am releasing a v2 tag with the current feature set
|
||||
from master, as some of those features have been actively used and
|
||||
relied on by more than one project. Our next goal is to continue
|
||||
cleaning up the code base with non-breaking changes as much as
|
||||
possible, but if/when a breaking change is needed, we'll just release
|
||||
new versions. This allows us to continue development at whatever pace
|
||||
we're capable of, without delaying the release of features or refusing
|
||||
PRs.
|
||||
|
||||
## Introduction
|
||||
|
||||
I hesitate to call gorp an ORM. Go doesn't really have objects, at
|
||||
least not in the classic Smalltalk/Java sense. There goes the "O".
|
||||
gorp doesn't know anything about the relationships between your
|
||||
structs (at least not yet). So the "R" is questionable too (but I use
|
||||
it in the name because, well, it seemed more clever).
|
||||
|
||||
The "M" is alive and well. Given some Go structs and a database, gorp
|
||||
should remove a fair amount of boilerplate busy-work from your code.
|
||||
|
||||
I hope that gorp saves you time, minimizes the drudgery of getting
|
||||
data in and out of your database, and helps your code focus on
|
||||
algorithms, not infrastructure.
|
||||
|
||||
* Bind struct fields to table columns via API or tag
|
||||
* Support for embedded structs
|
||||
* Support for transactions
|
||||
* Forward engineer db schema from structs (great for unit tests)
|
||||
* Pre/post insert/update/delete hooks
|
||||
* Automatically generate insert/update/delete statements for a struct
|
||||
* Automatic binding of auto increment PKs back to struct after insert
|
||||
* Delete by primary key(s)
|
||||
* Select by primary key(s)
|
||||
* Optional trace sql logging
|
||||
* Bind arbitrary SQL queries to a struct
|
||||
* Bind slice to SELECT query results without type assertions
|
||||
* Use positional or named bind parameters in custom SELECT queries
|
||||
* Optional optimistic locking using a version column (for
|
||||
update/deletes)
|
||||
|
||||
## Installation
|
||||
|
||||
Use `go get` or your favorite vendoring tool, using whichever import
|
||||
path you'd like.
|
||||
|
||||
## Versioning
|
||||
|
||||
We use semantic version tags. Feel free to import through `gopkg.in`
|
||||
(e.g. `gopkg.in/gorp.v2`) to get the latest tag for a major version,
|
||||
or check out the tag using your favorite vendoring tool.
|
||||
|
||||
Development is not very active right now, but we have plans to
|
||||
restructure `gorp` as we continue to move toward a more extensible
|
||||
system. Whenever a breaking change is needed, the major version will
|
||||
be bumped.
|
||||
|
||||
The `master` branch is where all development is done, and breaking
|
||||
changes may happen from time to time. That said, if you want to live
|
||||
on the bleeding edge and are comfortable updating your code when we
|
||||
make a breaking change, you may use `github.com/go-gorp/gorp` as your
|
||||
import path.
|
||||
|
||||
Check the version tags to see what's available. We'll make a good
|
||||
faith effort to add badges for new versions, but we make no
|
||||
guarantees.
|
||||
|
||||
## Supported Go versions
|
||||
|
||||
This package is guaranteed to be compatible with the latest 2 major
|
||||
versions of Go.
|
||||
|
||||
Any earlier versions are only supported on a best effort basis and can
|
||||
be dropped any time. Go has a great compatibility promise. Upgrading
|
||||
your program to a newer version of Go should never really be a
|
||||
problem.
|
||||
|
||||
## Migration guide
|
||||
|
||||
#### Pre-v2 to v2
|
||||
Automatic mapping of the version column used in optimistic locking has
|
||||
been removed as it could cause problems if the type was not int. The
|
||||
version column must now explicitly be set with
|
||||
`tablemap.SetVersionCol()`.
|
||||
|
||||
## Help/Support
|
||||
|
||||
Use our [`gitter` channel](https://gitter.im/go-gorp/gorp). We used
|
||||
to use IRC, but with most of us being pulled in many directions, we
|
||||
often need the email notifications from `gitter` to yell at us to sign
|
||||
in.
|
||||
|
||||
## Quickstart
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"gopkg.in/gorp.v1"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
"log"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// initialize the DbMap
|
||||
dbmap := initDb()
|
||||
defer dbmap.Db.Close()
|
||||
|
||||
// delete any existing rows
|
||||
err := dbmap.TruncateTables()
|
||||
checkErr(err, "TruncateTables failed")
|
||||
|
||||
// create two posts
|
||||
p1 := newPost("Go 1.1 released!", "Lorem ipsum lorem ipsum")
|
||||
p2 := newPost("Go 1.2 released!", "Lorem ipsum lorem ipsum")
|
||||
|
||||
// insert rows - auto increment PKs will be set properly after the insert
|
||||
err = dbmap.Insert(&p1, &p2)
|
||||
checkErr(err, "Insert failed")
|
||||
|
||||
// use convenience SelectInt
|
||||
count, err := dbmap.SelectInt("select count(*) from posts")
|
||||
checkErr(err, "select count(*) failed")
|
||||
log.Println("Rows after inserting:", count)
|
||||
|
||||
// update a row
|
||||
p2.Title = "Go 1.2 is better than ever"
|
||||
count, err = dbmap.Update(&p2)
|
||||
checkErr(err, "Update failed")
|
||||
log.Println("Rows updated:", count)
|
||||
|
||||
// fetch one row - note use of "post_id" instead of "Id" since column is aliased
|
||||
//
|
||||
// Postgres users should use $1 instead of ? placeholders
|
||||
// See 'Known Issues' below
|
||||
//
|
||||
err = dbmap.SelectOne(&p2, "select * from posts where post_id=?", p2.Id)
|
||||
checkErr(err, "SelectOne failed")
|
||||
log.Println("p2 row:", p2)
|
||||
|
||||
// fetch all rows
|
||||
var posts []Post
|
||||
_, err = dbmap.Select(&posts, "select * from posts order by post_id")
|
||||
checkErr(err, "Select failed")
|
||||
log.Println("All rows:")
|
||||
for x, p := range posts {
|
||||
log.Printf(" %d: %v\n", x, p)
|
||||
}
|
||||
|
||||
// delete row by PK
|
||||
count, err = dbmap.Delete(&p1)
|
||||
checkErr(err, "Delete failed")
|
||||
log.Println("Rows deleted:", count)
|
||||
|
||||
// delete row manually via Exec
|
||||
_, err = dbmap.Exec("delete from posts where post_id=?", p2.Id)
|
||||
checkErr(err, "Exec failed")
|
||||
|
||||
// confirm count is zero
|
||||
count, err = dbmap.SelectInt("select count(*) from posts")
|
||||
checkErr(err, "select count(*) failed")
|
||||
log.Println("Row count - should be zero:", count)
|
||||
|
||||
log.Println("Done!")
|
||||
}
|
||||
|
||||
type Post struct {
|
||||
// db tag lets you specify the column name if it differs from the struct field
|
||||
Id int64 `db:"post_id"`
|
||||
Created int64
|
||||
Title string `db:",size:50"` // Column size set to 50
|
||||
Body string `db:"article_body,size:1024"` // Set both column name and size
|
||||
}
|
||||
|
||||
func newPost(title, body string) Post {
|
||||
return Post{
|
||||
Created: time.Now().UnixNano(),
|
||||
Title: title,
|
||||
Body: body,
|
||||
}
|
||||
}
|
||||
|
||||
func initDb() *gorp.DbMap {
|
||||
// connect to db using standard Go database/sql API
|
||||
// use whatever database/sql driver you wish
|
||||
db, err := sql.Open("sqlite3", "/tmp/post_db.bin")
|
||||
checkErr(err, "sql.Open failed")
|
||||
|
||||
// construct a gorp DbMap
|
||||
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.SqliteDialect{}}
|
||||
|
||||
// add a table, setting the table name to 'posts' and
|
||||
// specifying that the Id property is an auto incrementing PK
|
||||
dbmap.AddTableWithName(Post{}, "posts").SetKeys(true, "Id")
|
||||
|
||||
// create the table. in a production system you'd generally
|
||||
// use a migration tool, or create the tables via scripts
|
||||
err = dbmap.CreateTablesIfNotExists()
|
||||
checkErr(err, "Create tables failed")
|
||||
|
||||
return dbmap
|
||||
}
|
||||
|
||||
func checkErr(err error, msg string) {
|
||||
if err != nil {
|
||||
log.Fatalln(msg, err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Mapping structs to tables
|
||||
|
||||
First define some types:
|
||||
|
||||
```go
|
||||
type Invoice struct {
|
||||
Id int64
|
||||
Created int64
|
||||
Updated int64
|
||||
Memo string
|
||||
PersonId int64
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Id int64
|
||||
Created int64
|
||||
Updated int64
|
||||
FName string
|
||||
LName string
|
||||
}
|
||||
|
||||
// Example of using tags to alias fields to column names
|
||||
// The 'db' value is the column name
|
||||
//
|
||||
// A hyphen will cause gorp to skip this field, similar to the
|
||||
// Go json package.
|
||||
//
|
||||
// This is equivalent to using the ColMap methods:
|
||||
//
|
||||
// table := dbmap.AddTableWithName(Product{}, "product")
|
||||
// table.ColMap("Id").Rename("product_id")
|
||||
// table.ColMap("Price").Rename("unit_price")
|
||||
// table.ColMap("IgnoreMe").SetTransient(true)
|
||||
//
|
||||
// You can optionally declare the field to be a primary key and/or autoincrement
|
||||
//
|
||||
type Product struct {
|
||||
Id int64 `db:"product_id, primarykey, autoincrement"`
|
||||
Price int64 `db:"unit_price"`
|
||||
IgnoreMe string `db:"-"`
|
||||
}
|
||||
```
|
||||
|
||||
Then create a mapper, typically you'd do this one time at app startup:
|
||||
|
||||
```go
|
||||
// connect to db using standard Go database/sql API
|
||||
// use whatever database/sql driver you wish
|
||||
db, err := sql.Open("mymysql", "tcp:localhost:3306*mydb/myuser/mypassword")
|
||||
|
||||
// construct a gorp DbMap
|
||||
dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{"InnoDB", "UTF8"}}
|
||||
|
||||
// register the structs you wish to use with gorp
|
||||
// you can also use the shorter dbmap.AddTable() if you
|
||||
// don't want to override the table name
|
||||
//
|
||||
// SetKeys(true) means we have a auto increment primary key, which
|
||||
// will get automatically bound to your struct post-insert
|
||||
//
|
||||
t1 := dbmap.AddTableWithName(Invoice{}, "invoice_test").SetKeys(true, "Id")
|
||||
t2 := dbmap.AddTableWithName(Person{}, "person_test").SetKeys(true, "Id")
|
||||
t3 := dbmap.AddTableWithName(Product{}, "product_test").SetKeys(true, "Id")
|
||||
```
|
||||
|
||||
### Struct Embedding
|
||||
|
||||
gorp supports embedding structs. For example:
|
||||
|
||||
```go
|
||||
type Names struct {
|
||||
FirstName string
|
||||
LastName string
|
||||
}
|
||||
|
||||
type WithEmbeddedStruct struct {
|
||||
Id int64
|
||||
Names
|
||||
}
|
||||
|
||||
es := &WithEmbeddedStruct{-1, Names{FirstName: "Alice", LastName: "Smith"}}
|
||||
err := dbmap.Insert(es)
|
||||
```
|
||||
|
||||
See the `TestWithEmbeddedStruct` function in `gorp_test.go` for a full example.
|
||||
|
||||
### Create/Drop Tables ###
|
||||
|
||||
Automatically create / drop registered tables. This is useful for unit tests
|
||||
but is entirely optional. You can of course use gorp with tables created manually,
|
||||
or with a separate migration tool (like [goose](https://bitbucket.org/liamstask/goose) or [migrate](https://github.com/mattes/migrate)).
|
||||
|
||||
```go
|
||||
// create all registered tables
|
||||
dbmap.CreateTables()
|
||||
|
||||
// same as above, but uses "if not exists" clause to skip tables that are
|
||||
// already defined
|
||||
dbmap.CreateTablesIfNotExists()
|
||||
|
||||
// drop
|
||||
dbmap.DropTables()
|
||||
```
|
||||
|
||||
### SQL Logging
|
||||
|
||||
Optionally you can pass in a logger to trace all SQL statements.
|
||||
I recommend enabling this initially while you're getting the feel for what
|
||||
gorp is doing on your behalf.
|
||||
|
||||
Gorp defines a `GorpLogger` interface that Go's built in `log.Logger` satisfies.
|
||||
However, you can write your own `GorpLogger` implementation, or use a package such
|
||||
as `glog` if you want more control over how statements are logged.
|
||||
|
||||
```go
|
||||
// Will log all SQL statements + args as they are run
|
||||
// The first arg is a string prefix to prepend to all log messages
|
||||
dbmap.TraceOn("[gorp]", log.New(os.Stdout, "myapp:", log.Lmicroseconds))
|
||||
|
||||
// Turn off tracing
|
||||
dbmap.TraceOff()
|
||||
```
|
||||
|
||||
### Insert
|
||||
|
||||
```go
|
||||
// Must declare as pointers so optional callback hooks
|
||||
// can operate on your data, not copies
|
||||
inv1 := &Invoice{0, 100, 200, "first order", 0}
|
||||
inv2 := &Invoice{0, 100, 200, "second order", 0}
|
||||
|
||||
// Insert your rows
|
||||
err := dbmap.Insert(inv1, inv2)
|
||||
|
||||
// Because we called SetKeys(true) on Invoice, the Id field
|
||||
// will be populated after the Insert() automatically
|
||||
fmt.Printf("inv1.Id=%d inv2.Id=%d\n", inv1.Id, inv2.Id)
|
||||
```
|
||||
|
||||
### Update
|
||||
|
||||
Continuing the above example, use the `Update` method to modify an Invoice:
|
||||
|
||||
```go
|
||||
// count is the # of rows updated, which should be 1 in this example
|
||||
count, err := dbmap.Update(inv1)
|
||||
```
|
||||
|
||||
### Delete
|
||||
|
||||
If you have primary key(s) defined for a struct, you can use the `Delete`
|
||||
method to remove rows:
|
||||
|
||||
```go
|
||||
count, err := dbmap.Delete(inv1)
|
||||
```
|
||||
|
||||
### Select by Key
|
||||
|
||||
Use the `Get` method to fetch a single row by primary key. It returns
|
||||
nil if no row is found.
|
||||
|
||||
```go
|
||||
// fetch Invoice with Id=99
|
||||
obj, err := dbmap.Get(Invoice{}, 99)
|
||||
inv := obj.(*Invoice)
|
||||
```
|
||||
|
||||
### Ad Hoc SQL
|
||||
|
||||
#### SELECT
|
||||
|
||||
`Select()` and `SelectOne()` provide a simple way to bind arbitrary queries to a slice
|
||||
or a single struct.
|
||||
|
||||
```go
|
||||
// Select a slice - first return value is not needed when a slice pointer is passed to Select()
|
||||
var posts []Post
|
||||
_, err := dbmap.Select(&posts, "select * from post order by id")
|
||||
|
||||
// You can also use primitive types
|
||||
var ids []string
|
||||
_, err := dbmap.Select(&ids, "select id from post")
|
||||
|
||||
// Select a single row.
|
||||
// Returns an error if no row found, or if more than one row is found
|
||||
var post Post
|
||||
err := dbmap.SelectOne(&post, "select * from post where id=?", id)
|
||||
```
|
||||
|
||||
Want to do joins? Just write the SQL and the struct. gorp will bind them:
|
||||
|
||||
```go
|
||||
// Define a type for your join
|
||||
// It *must* contain all the columns in your SELECT statement
|
||||
//
|
||||
// The names here should match the aliased column names you specify
|
||||
// in your SQL - no additional binding work required. simple.
|
||||
//
|
||||
type InvoicePersonView struct {
|
||||
InvoiceId int64
|
||||
PersonId int64
|
||||
Memo string
|
||||
FName string
|
||||
}
|
||||
|
||||
// Create some rows
|
||||
p1 := &Person{0, 0, 0, "bob", "smith"}
|
||||
dbmap.Insert(p1)
|
||||
|
||||
// notice how we can wire up p1.Id to the invoice easily
|
||||
inv1 := &Invoice{0, 0, 0, "xmas order", p1.Id}
|
||||
dbmap.Insert(inv1)
|
||||
|
||||
// Run your query
|
||||
query := "select i.Id InvoiceId, p.Id PersonId, i.Memo, p.FName " +
|
||||
"from invoice_test i, person_test p " +
|
||||
"where i.PersonId = p.Id"
|
||||
|
||||
// pass a slice to Select()
|
||||
var list []InvoicePersonView
|
||||
_, err := dbmap.Select(&list, query)
|
||||
|
||||
// this should test true
|
||||
expected := InvoicePersonView{inv1.Id, p1.Id, inv1.Memo, p1.FName}
|
||||
if reflect.DeepEqual(list[0], expected) {
|
||||
fmt.Println("Woot! My join worked!")
|
||||
}
|
||||
```
|
||||
|
||||
#### SELECT string or int64
|
||||
|
||||
gorp provides a few convenience methods for selecting a single string or int64.
|
||||
|
||||
```go
|
||||
// select single int64 from db (use $1 instead of ? for postgresql)
|
||||
i64, err := dbmap.SelectInt("select count(*) from foo where blah=?", blahVal)
|
||||
|
||||
// select single string from db:
|
||||
s, err := dbmap.SelectStr("select name from foo where blah=?", blahVal)
|
||||
|
||||
```
|
||||
|
||||
#### Named bind parameters
|
||||
|
||||
You may use a map or struct to bind parameters by name. This is currently
|
||||
only supported in SELECT queries.
|
||||
|
||||
```go
|
||||
_, err := dbm.Select(&dest, "select * from Foo where name = :name and age = :age", map[string]interface{}{
|
||||
"name": "Rob",
|
||||
"age": 31,
|
||||
})
|
||||
```
|
||||
|
||||
#### UPDATE / DELETE
|
||||
|
||||
You can execute raw SQL if you wish. Particularly good for batch operations.
|
||||
|
||||
```go
|
||||
res, err := dbmap.Exec("delete from invoice_test where PersonId=?", 10)
|
||||
```
|
||||
|
||||
### Transactions
|
||||
|
||||
You can batch operations into a transaction:
|
||||
|
||||
```go
|
||||
func InsertInv(dbmap *DbMap, inv *Invoice, per *Person) error {
|
||||
// Start a new transaction
|
||||
trans, err := dbmap.Begin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
trans.Insert(per)
|
||||
inv.PersonId = per.Id
|
||||
trans.Insert(inv)
|
||||
|
||||
// if the commit is successful, a nil error is returned
|
||||
return trans.Commit()
|
||||
}
|
||||
```
|
||||
|
||||
### Hooks
|
||||
|
||||
Use hooks to update data before/after saving to the db. Good for timestamps:
|
||||
|
||||
```go
|
||||
// implement the PreInsert and PreUpdate hooks
|
||||
func (i *Invoice) PreInsert(s gorp.SqlExecutor) error {
|
||||
i.Created = time.Now().UnixNano()
|
||||
i.Updated = i.Created
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Invoice) PreUpdate(s gorp.SqlExecutor) error {
|
||||
i.Updated = time.Now().UnixNano()
|
||||
return nil
|
||||
}
|
||||
|
||||
// You can use the SqlExecutor to cascade additional SQL
|
||||
// Take care to avoid cycles. gorp won't prevent them.
|
||||
//
|
||||
// Here's an example of a cascading delete
|
||||
//
|
||||
func (p *Person) PreDelete(s gorp.SqlExecutor) error {
|
||||
query := "delete from invoice_test where PersonId=?"
|
||||
|
||||
_, err := s.Exec(query, p.Id)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
Full list of hooks that you can implement:
|
||||
|
||||
PostGet
|
||||
PreInsert
|
||||
PostInsert
|
||||
PreUpdate
|
||||
PostUpdate
|
||||
PreDelete
|
||||
PostDelete
|
||||
|
||||
All have the same signature. for example:
|
||||
|
||||
func (p *MyStruct) PostUpdate(s gorp.SqlExecutor) error
|
||||
|
||||
### Optimistic Locking
|
||||
|
||||
#### Note that this behaviour has changed in v2. See [Migration Guide](#migration-guide).
|
||||
|
||||
gorp provides a simple optimistic locking feature, similar to Java's
|
||||
JPA, that will raise an error if you try to update/delete a row whose
|
||||
`version` column has a value different than the one in memory. This
|
||||
provides a safe way to do "select then update" style operations
|
||||
without explicit read and write locks.
|
||||
|
||||
```go
|
||||
// Version is an auto-incremented number, managed by gorp
|
||||
// If this property is present on your struct, update
|
||||
// operations will be constrained
|
||||
//
|
||||
// For example, say we defined Person as:
|
||||
|
||||
type Person struct {
|
||||
Id int64
|
||||
Created int64
|
||||
Updated int64
|
||||
FName string
|
||||
LName string
|
||||
|
||||
// automatically used as the Version col
|
||||
// use table.SetVersionCol("columnName") to map a different
|
||||
// struct field as the version field
|
||||
Version int64
|
||||
}
|
||||
|
||||
p1 := &Person{0, 0, 0, "Bob", "Smith", 0}
|
||||
dbmap.Insert(p1) // Version is now 1
|
||||
|
||||
obj, err := dbmap.Get(Person{}, p1.Id)
|
||||
p2 := obj.(*Person)
|
||||
p2.LName = "Edwards"
|
||||
dbmap.Update(p2) // Version is now 2
|
||||
|
||||
p1.LName = "Howard"
|
||||
|
||||
// Raises error because p1.Version == 1, which is out of date
|
||||
count, err := dbmap.Update(p1)
|
||||
_, ok := err.(gorp.OptimisticLockError)
|
||||
if ok {
|
||||
// should reach this statement
|
||||
|
||||
// in a real app you might reload the row and retry, or
|
||||
// you might propegate this to the user, depending on the desired
|
||||
// semantics
|
||||
fmt.Printf("Tried to update row with stale data: %v\n", err)
|
||||
} else {
|
||||
// some other db error occurred - log or return up the stack
|
||||
fmt.Printf("Unknown db err: %v\n", err)
|
||||
}
|
||||
```
|
||||
### Adding INDEX(es) on column(s) beyond the primary key ###
|
||||
|
||||
Indexes are frequently critical for performance. Here is how to add
|
||||
them to your tables.
|
||||
|
||||
NB: SqlServer and Oracle need testing and possible adjustment to the
|
||||
CreateIndexSuffix() and DropIndexSuffix() methods to make AddIndex()
|
||||
work for them.
|
||||
|
||||
In the example below we put an index both on the Id field, and on the
|
||||
AcctId field.
|
||||
|
||||
```
|
||||
type Account struct {
|
||||
Id int64
|
||||
AcctId string // e.g. this might be a long uuid for portability
|
||||
}
|
||||
|
||||
// indexType (the 2nd param to AddIndex call) is "Btree" or "Hash" for MySQL.
|
||||
// demonstrate adding a second index on AcctId, and constrain that field to have unique values.
|
||||
dbm.AddTable(iptab.Account{}).SetKeys(true, "Id").AddIndex("AcctIdIndex", "Btree", []string{"AcctId"}).SetUnique(true)
|
||||
|
||||
err = dbm.CreateTablesIfNotExists()
|
||||
checkErr(err, "CreateTablesIfNotExists failed")
|
||||
|
||||
err = dbm.CreateIndex()
|
||||
checkErr(err, "CreateIndex failed")
|
||||
|
||||
```
|
||||
Check the effect of the CreateIndex() call in mysql:
|
||||
```
|
||||
$ mysql
|
||||
|
||||
MariaDB [test]> show create table Account;
|
||||
+---------+--------------------------+
|
||||
| Account | CREATE TABLE `Account` (
|
||||
`Id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`AcctId` varchar(255) DEFAULT NULL,
|
||||
PRIMARY KEY (`Id`),
|
||||
UNIQUE KEY `AcctIdIndex` (`AcctId`) USING BTREE <<<--- yes! index added.
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8
|
||||
+---------+--------------------------+
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Database Drivers
|
||||
|
||||
gorp uses the Go 1 `database/sql` package. A full list of compliant
|
||||
drivers is available here:
|
||||
|
||||
http://code.google.com/p/go-wiki/wiki/SQLDrivers
|
||||
|
||||
Sadly, SQL databases differ on various issues. gorp provides a Dialect
|
||||
interface that should be implemented per database vendor. Dialects
|
||||
are provided for:
|
||||
|
||||
* MySQL
|
||||
* PostgreSQL
|
||||
* sqlite3
|
||||
|
||||
Each of these three databases pass the test suite. See `gorp_test.go`
|
||||
for example DSNs for these three databases.
|
||||
|
||||
Support is also provided for:
|
||||
|
||||
* Oracle (contributed by @klaidliadon)
|
||||
* SQL Server (contributed by @qrawl) - use driver:
|
||||
github.com/denisenkom/go-mssqldb
|
||||
|
||||
Note that these databases are not covered by CI and I (@coopernurse)
|
||||
have no good way to test them locally. So please try them and send
|
||||
patches as needed, but expect a bit more unpredicability.
|
||||
|
||||
## Sqlite3 Extensions
|
||||
|
||||
In order to use sqlite3 extensions you need to first register a custom driver:
|
||||
|
||||
```go
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
// use whatever database/sql driver you wish
|
||||
sqlite "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func customDriver() (*sql.DB, error) {
|
||||
|
||||
// create custom driver with extensions defined
|
||||
sql.Register("sqlite3-custom", &sqlite.SQLiteDriver{
|
||||
Extensions: []string{
|
||||
"mod_spatialite",
|
||||
},
|
||||
})
|
||||
|
||||
// now you can then connect using the 'sqlite3-custom' driver instead of 'sqlite3'
|
||||
return sql.Open("sqlite3-custom", "/tmp/post_db.bin")
|
||||
}
|
||||
```
|
||||
|
||||
## Known Issues
|
||||
|
||||
### SQL placeholder portability
|
||||
|
||||
Different databases use different strings to indicate variable
|
||||
placeholders in prepared SQL statements. Unlike some database
|
||||
abstraction layers (such as JDBC), Go's `database/sql` does not
|
||||
standardize this.
|
||||
|
||||
SQL generated by gorp in the `Insert`, `Update`, `Delete`, and `Get`
|
||||
methods delegates to a Dialect implementation for each database, and
|
||||
will generate portable SQL.
|
||||
|
||||
Raw SQL strings passed to `Exec`, `Select`, `SelectOne`, `SelectInt`,
|
||||
etc will not be parsed. Consequently you may have portability issues
|
||||
if you write a query like this:
|
||||
|
||||
```go
|
||||
go // works on MySQL and Sqlite3, but not with Postgresql err :=
|
||||
dbmap.SelectOne(&val, "select * from foo where id = ?", 30) ```
|
||||
```
|
||||
|
||||
In `Select` and `SelectOne` you can use named parameters to work
|
||||
around this. The following is portable:
|
||||
|
||||
```go
|
||||
go err := dbmap.SelectOne(&val, "select * from foo where id = :id",
|
||||
map[string]interface{} { "id": 30})
|
||||
```
|
||||
|
||||
Additionally, when using Postgres as your database, you should utilize
|
||||
`$1` instead of `?` placeholders as utilizing `?` placeholders when
|
||||
querying Postgres will result in `pq: operator does not exist`
|
||||
errors. Alternatively, use `dbMap.Dialect.BindVar(varIdx)` to get the
|
||||
proper variable binding for your dialect.
|
||||
|
||||
### time.Time and time zones
|
||||
|
||||
gorp will pass `time.Time` fields through to the `database/sql`
|
||||
driver, but note that the behavior of this type varies across database
|
||||
drivers.
|
||||
|
||||
MySQL users should be especially cautious. See [this PR](https://github.com/ziutek/mymysql/pull/77)
|
||||
|
||||
To avoid any potential issues with timezone/DST, consider:
|
||||
|
||||
- Using an integer field for time data and storing UNIX time.
|
||||
- Using a custom time type that implements some SQL types:
|
||||
- [`"database/sql".Scanner`](https://golang.org/pkg/database/sql/#Scanner)
|
||||
- [`"database/sql/driver".Valuer`](https://golang.org/pkg/database/sql/driver/#Valuer)
|
||||
|
||||
## Running the tests
|
||||
|
||||
The included tests may be run against MySQL, Postgresql, or sqlite3.
|
||||
You must set two flags, dsn and dialect, in order to test the environment you want.
|
||||
If not flag is passed the tests are going to use the default ones which are:
|
||||
- DSN: `gorptest:gorptest@tcp(localhost:3306)/gorptest`
|
||||
- Dialect: `gomysql`
|
||||
|
||||
```bash
|
||||
# MySQL example:
|
||||
# run the tests
|
||||
go test -dsn="gorptest:gorptest@tcp(localhost:3306)/gorptest" -dialect="gomysql"
|
||||
|
||||
# run the tests and benchmarks
|
||||
go test -bench="Bench" -benchtime 10
|
||||
```
|
||||
|
||||
Valid `dialect` flag values are:
|
||||
|
||||
- [mysql](https://github.com/ziutek/mymysql)
|
||||
- [gomysql](https://github.com/Go-SQL-Driver/MySQL)
|
||||
- [postgres](https://github.com/lib/pq)
|
||||
- [sqlite](https://github.com/mattn/go-sqlite3)
|
||||
|
||||
## Performance
|
||||
|
||||
gorp uses reflection to construct SQL queries and bind parameters.
|
||||
See the BenchmarkNativeCrud vs BenchmarkGorpCrud in gorp_test.go for a
|
||||
simple perf test. On my MacBook Pro gorp is about 2-3% slower than
|
||||
hand written SQL.
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
* matthias-margush - column aliasing via tags
|
||||
* Rob Figueiredo - @robfig
|
||||
* Quinn Slack - @sqs
|
||||
103
vendor/github.com/mattermost/gorp/column.go
сгенерированный
поставляемый
103
vendor/github.com/mattermost/gorp/column.go
сгенерированный
поставляемый
@@ -1,103 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import "reflect"
|
||||
|
||||
// ColumnMap represents a mapping between a Go struct field and a single
|
||||
// column in a table.
|
||||
// Unique and MaxSize only inform the
|
||||
// CreateTables() function and are not used by Insert/Update/Delete/Get.
|
||||
type ColumnMap struct {
|
||||
// Column name in db table
|
||||
ColumnName string
|
||||
|
||||
// If true, this column is skipped in generated SQL statements
|
||||
Transient bool
|
||||
|
||||
// If true, " unique" is added to create table statements.
|
||||
// Not used elsewhere
|
||||
Unique bool
|
||||
|
||||
// If not nil, " default 'value'" is added to the create table statements.
|
||||
// Not used elsewhere
|
||||
DefaultConstraint *string
|
||||
|
||||
// Query used for getting generated id after insert
|
||||
GeneratedIdQuery string
|
||||
|
||||
// Passed to Dialect.ToSqlType() to assist in informing the
|
||||
// correct column type to map to in CreateTables()
|
||||
MaxSize int
|
||||
|
||||
DefaultValue string
|
||||
|
||||
// The column data type. If set it overrides the one converted from the Go type.
|
||||
DataType string
|
||||
|
||||
fieldName string
|
||||
gotype reflect.Type
|
||||
isPK bool
|
||||
isAutoIncr bool
|
||||
isNotNull bool
|
||||
}
|
||||
|
||||
// Rename allows you to specify the column name in the table
|
||||
//
|
||||
// Example: table.ColMap("Updated").Rename("date_updated")
|
||||
//
|
||||
func (c *ColumnMap) Rename(colname string) *ColumnMap {
|
||||
c.ColumnName = colname
|
||||
return c
|
||||
}
|
||||
|
||||
// SetTransient allows you to mark the column as transient. If true
|
||||
// this column will be skipped when SQL statements are generated
|
||||
func (c *ColumnMap) SetTransient(b bool) *ColumnMap {
|
||||
c.Transient = b
|
||||
return c
|
||||
}
|
||||
|
||||
// SetUnique adds "unique" to the create table statements for this
|
||||
// column, if b is true.
|
||||
func (c *ColumnMap) SetUnique(b bool) *ColumnMap {
|
||||
c.Unique = b
|
||||
return c
|
||||
}
|
||||
|
||||
// SetNotNull adds "not null" to the create table statements for this
|
||||
// column, if nn is true.
|
||||
func (c *ColumnMap) SetNotNull(nn bool) *ColumnMap {
|
||||
c.isNotNull = nn
|
||||
return c
|
||||
}
|
||||
|
||||
// SetMaxSize specifies the max length of values of this column. This is
|
||||
// passed to the dialect.ToSqlType() function, which can use the value
|
||||
// to alter the generated type for "create table" statements
|
||||
func (c *ColumnMap) SetMaxSize(size int) *ColumnMap {
|
||||
c.MaxSize = size
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDataType allows to specify a custom data type for the column.
|
||||
func (c *ColumnMap) SetDataType(dataType string) *ColumnMap {
|
||||
c.DataType = dataType
|
||||
return c
|
||||
}
|
||||
|
||||
// SetDefaultConstraint adds " default 'value'" to the create table statements for this
|
||||
// column, if value is not nil. Not used elsewhere
|
||||
func (c *ColumnMap) SetDefaultConstraint(value *string) *ColumnMap {
|
||||
c.DefaultConstraint = value
|
||||
return c
|
||||
}
|
||||
815
vendor/github.com/mattermost/gorp/db.go
сгенерированный
поставляемый
815
vendor/github.com/mattermost/gorp/db.go
сгенерированный
поставляемый
@@ -1,815 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// DbMap is the root gorp mapping object. Create one of these for each
|
||||
// database schema you wish to map. Each DbMap contains a list of
|
||||
// mapped tables.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// dialect := gorp.MySQLDialect{"InnoDB", "UTF8"}
|
||||
// dbmap := &gorp.DbMap{Db: db, Dialect: dialect}
|
||||
//
|
||||
type DbMap struct {
|
||||
// Db handle to use with this map
|
||||
Db *sql.DB
|
||||
|
||||
// Dialect implementation to use with this map
|
||||
Dialect Dialect
|
||||
|
||||
TypeConverter TypeConverter
|
||||
|
||||
QueryTimeout time.Duration
|
||||
|
||||
tables []*TableMap
|
||||
tablesDynamic map[string]*TableMap // tables that use same go-struct and different db table names
|
||||
logger GorpLogger
|
||||
logPrefix string
|
||||
}
|
||||
|
||||
func (m *DbMap) dynamicTableAdd(tableName string, tbl *TableMap) {
|
||||
if m.tablesDynamic == nil {
|
||||
m.tablesDynamic = make(map[string]*TableMap)
|
||||
}
|
||||
m.tablesDynamic[tableName] = tbl
|
||||
}
|
||||
|
||||
func (m *DbMap) dynamicTableFind(tableName string) (*TableMap, bool) {
|
||||
if m.tablesDynamic == nil {
|
||||
return nil, false
|
||||
}
|
||||
tbl, found := m.tablesDynamic[tableName]
|
||||
return tbl, found
|
||||
}
|
||||
|
||||
func (m *DbMap) dynamicTableMap() map[string]*TableMap {
|
||||
if m.tablesDynamic == nil {
|
||||
m.tablesDynamic = make(map[string]*TableMap)
|
||||
}
|
||||
return m.tablesDynamic
|
||||
}
|
||||
|
||||
func (m *DbMap) CreateIndex() error {
|
||||
|
||||
var err error
|
||||
dialect := reflect.TypeOf(m.Dialect)
|
||||
for _, table := range m.tables {
|
||||
for _, index := range table.indexes {
|
||||
err = m.createIndexImpl(dialect, table, index)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, table := range m.dynamicTableMap() {
|
||||
for _, index := range table.indexes {
|
||||
err = m.createIndexImpl(dialect, table, index)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *DbMap) createIndexImpl(dialect reflect.Type,
|
||||
table *TableMap,
|
||||
index *IndexMap) error {
|
||||
s := strings.Builder{}
|
||||
s.WriteString("create")
|
||||
if index.Unique {
|
||||
s.WriteString(" unique")
|
||||
}
|
||||
s.WriteString(" index")
|
||||
s.WriteString(fmt.Sprintf(" %s on %s", index.IndexName, table.TableName))
|
||||
if dname := dialect.Name(); dname == "PostgresDialect" && index.IndexType != "" {
|
||||
s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
|
||||
}
|
||||
s.WriteString(" (")
|
||||
for x, col := range index.columns {
|
||||
if x > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s.WriteString(m.Dialect.QuoteField(col))
|
||||
}
|
||||
s.WriteString(")")
|
||||
|
||||
if dname := dialect.Name(); dname == "MySQLDialect" && index.IndexType != "" {
|
||||
s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
|
||||
}
|
||||
s.WriteString(";")
|
||||
_, err := m.ExecNoTimeout(s.String())
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *TableMap) DropIndex(name string) error {
|
||||
|
||||
var err error
|
||||
dialect := reflect.TypeOf(t.dbmap.Dialect)
|
||||
for _, idx := range t.indexes {
|
||||
if idx.IndexName == name {
|
||||
s := strings.Builder{}
|
||||
s.WriteString(fmt.Sprintf("DROP INDEX %s", idx.IndexName))
|
||||
|
||||
if dname := dialect.Name(); dname == "MySQLDialect" {
|
||||
s.WriteString(fmt.Sprintf(" %s %s", t.dbmap.Dialect.DropIndexSuffix(), t.TableName))
|
||||
}
|
||||
s.WriteString(";")
|
||||
_, e := t.dbmap.ExecNoTimeout(s.String())
|
||||
if e != nil {
|
||||
err = e
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
t.ResetSql()
|
||||
return err
|
||||
}
|
||||
|
||||
// AddTable registers the given interface type with gorp. The table name
|
||||
// will be given the name of the TypeOf(i). You must call this function,
|
||||
// or AddTableWithName, for any struct type you wish to persist with
|
||||
// the given DbMap.
|
||||
//
|
||||
// This operation is idempotent. If i's type is already mapped, the
|
||||
// existing *TableMap is returned
|
||||
func (m *DbMap) AddTable(i interface{}) *TableMap {
|
||||
return m.AddTableWithName(i, "")
|
||||
}
|
||||
|
||||
// AddTableWithName has the same behavior as AddTable, but sets
|
||||
// table.TableName to name.
|
||||
func (m *DbMap) AddTableWithName(i interface{}, name string) *TableMap {
|
||||
return m.AddTableWithNameAndSchema(i, "", name)
|
||||
}
|
||||
|
||||
// AddTableWithNameAndSchema has the same behavior as AddTable, but sets
|
||||
// table.TableName to name.
|
||||
func (m *DbMap) AddTableWithNameAndSchema(i interface{}, schema string, name string) *TableMap {
|
||||
t := reflect.TypeOf(i)
|
||||
if name == "" {
|
||||
name = t.Name()
|
||||
}
|
||||
|
||||
// check if we have a table for this type already
|
||||
// if so, update the name and return the existing pointer
|
||||
for i := range m.tables {
|
||||
table := m.tables[i]
|
||||
if table.gotype == t {
|
||||
table.TableName = name
|
||||
return table
|
||||
}
|
||||
}
|
||||
|
||||
tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
|
||||
var primaryKey []*ColumnMap
|
||||
tmap.Columns, primaryKey = m.readStructColumns(t)
|
||||
m.tables = append(m.tables, tmap)
|
||||
if len(primaryKey) > 0 {
|
||||
tmap.keys = append(tmap.keys, primaryKey...)
|
||||
}
|
||||
|
||||
return tmap
|
||||
}
|
||||
|
||||
// AddTableDynamic registers the given interface type with gorp.
|
||||
// The table name will be dynamically determined at runtime by
|
||||
// using the GetTableName method on DynamicTable interface
|
||||
func (m *DbMap) AddTableDynamic(inp DynamicTable, schema string) *TableMap {
|
||||
|
||||
val := reflect.ValueOf(inp)
|
||||
elm := val.Elem()
|
||||
t := elm.Type()
|
||||
name := inp.TableName()
|
||||
if name == "" {
|
||||
panic("Missing table name in DynamicTable instance")
|
||||
}
|
||||
|
||||
// Check if there is another dynamic table with the same name
|
||||
if _, found := m.dynamicTableFind(name); found {
|
||||
panic(fmt.Sprintf("A table with the same name %v already exists", name))
|
||||
}
|
||||
|
||||
tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
|
||||
var primaryKey []*ColumnMap
|
||||
tmap.Columns, primaryKey = m.readStructColumns(t)
|
||||
if len(primaryKey) > 0 {
|
||||
tmap.keys = append(tmap.keys, primaryKey...)
|
||||
}
|
||||
|
||||
m.dynamicTableAdd(name, tmap)
|
||||
|
||||
return tmap
|
||||
}
|
||||
|
||||
func (m *DbMap) readStructColumns(t reflect.Type) (cols []*ColumnMap, primaryKey []*ColumnMap) {
|
||||
primaryKey = make([]*ColumnMap, 0)
|
||||
n := t.NumField()
|
||||
for i := 0; i < n; i++ {
|
||||
f := t.Field(i)
|
||||
if f.Anonymous && f.Type.Kind() == reflect.Struct {
|
||||
// Recursively add nested fields in embedded structs.
|
||||
subcols, subpk := m.readStructColumns(f.Type)
|
||||
// Don't append nested fields that have the same field
|
||||
// name as an already-mapped field.
|
||||
for _, subcol := range subcols {
|
||||
shouldAppend := true
|
||||
for _, col := range cols {
|
||||
if !subcol.Transient && subcol.fieldName == col.fieldName {
|
||||
shouldAppend = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if shouldAppend {
|
||||
cols = append(cols, subcol)
|
||||
}
|
||||
}
|
||||
if subpk != nil {
|
||||
primaryKey = append(primaryKey, subpk...)
|
||||
}
|
||||
} else {
|
||||
// Tag = Name { ',' Option }
|
||||
// Option = OptionKey [ ':' OptionValue ]
|
||||
cArguments := strings.Split(f.Tag.Get("db"), ",")
|
||||
columnName := cArguments[0]
|
||||
var maxSize int
|
||||
var defaultValue string
|
||||
var isAuto bool
|
||||
var isPK bool
|
||||
var isNotNull bool
|
||||
for _, argString := range cArguments[1:] {
|
||||
argString = strings.TrimSpace(argString)
|
||||
arg := strings.SplitN(argString, ":", 2)
|
||||
|
||||
// check mandatory/unexpected option values
|
||||
switch arg[0] {
|
||||
case "size", "default":
|
||||
// options requiring value
|
||||
if len(arg) == 1 {
|
||||
panic(fmt.Sprintf("missing option value for option %v on field %v", arg[0], f.Name))
|
||||
}
|
||||
default:
|
||||
// options where value is invalid (currently all other options)
|
||||
if len(arg) == 2 {
|
||||
panic(fmt.Sprintf("unexpected option value for option %v on field %v", arg[0], f.Name))
|
||||
}
|
||||
}
|
||||
|
||||
switch arg[0] {
|
||||
case "size":
|
||||
maxSize, _ = strconv.Atoi(arg[1])
|
||||
case "default":
|
||||
defaultValue = arg[1]
|
||||
case "primarykey":
|
||||
isPK = true
|
||||
case "autoincrement":
|
||||
isAuto = true
|
||||
case "notnull":
|
||||
isNotNull = true
|
||||
default:
|
||||
panic(fmt.Sprintf("Unrecognized tag option for field %v: %v", f.Name, arg))
|
||||
}
|
||||
}
|
||||
if columnName == "" {
|
||||
columnName = f.Name
|
||||
}
|
||||
|
||||
gotype := f.Type
|
||||
valueType := gotype
|
||||
if valueType.Kind() == reflect.Ptr {
|
||||
valueType = valueType.Elem()
|
||||
}
|
||||
value := reflect.New(valueType).Interface()
|
||||
if m.TypeConverter != nil {
|
||||
// Make a new pointer to a value of type gotype and
|
||||
// pass it to the TypeConverter's FromDb method to see
|
||||
// if a different type should be used for the column
|
||||
// type during table creation.
|
||||
scanner, useHolder := m.TypeConverter.FromDb(value)
|
||||
if useHolder {
|
||||
value = scanner.Holder
|
||||
gotype = reflect.TypeOf(value)
|
||||
}
|
||||
}
|
||||
if typer, ok := value.(SqlTyper); ok {
|
||||
gotype = reflect.TypeOf(typer.SqlType())
|
||||
} else if valuer, ok := value.(driver.Valuer); ok {
|
||||
// Only check for driver.Valuer if SqlTyper wasn't
|
||||
// found.
|
||||
v, err := valuer.Value()
|
||||
if err == nil && v != nil {
|
||||
gotype = reflect.TypeOf(v)
|
||||
}
|
||||
}
|
||||
cm := &ColumnMap{
|
||||
ColumnName: columnName,
|
||||
DefaultValue: defaultValue,
|
||||
Transient: columnName == "-",
|
||||
fieldName: f.Name,
|
||||
gotype: gotype,
|
||||
isPK: isPK,
|
||||
isAutoIncr: isAuto,
|
||||
isNotNull: isNotNull,
|
||||
MaxSize: maxSize,
|
||||
}
|
||||
if isPK {
|
||||
primaryKey = append(primaryKey, cm)
|
||||
}
|
||||
// Check for nested fields of the same field name and
|
||||
// override them.
|
||||
shouldAppend := true
|
||||
for index, col := range cols {
|
||||
if !col.Transient && col.fieldName == cm.fieldName {
|
||||
cols[index] = cm
|
||||
shouldAppend = false
|
||||
break
|
||||
}
|
||||
}
|
||||
if shouldAppend {
|
||||
cols = append(cols, cm)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CreateTables iterates through TableMaps registered to this DbMap and
|
||||
// executes "create table" statements against the database for each.
|
||||
//
|
||||
// This is particularly useful in unit tests where you want to create
|
||||
// and destroy the schema automatically.
|
||||
func (m *DbMap) CreateTables() error {
|
||||
return m.createTables(false)
|
||||
}
|
||||
|
||||
// CreateTablesIfNotExists is similar to CreateTables, but starts
|
||||
// each statement with "create table if not exists" so that existing
|
||||
// tables do not raise errors
|
||||
func (m *DbMap) CreateTablesIfNotExists() error {
|
||||
return m.createTables(true)
|
||||
}
|
||||
|
||||
func (m *DbMap) createTables(ifNotExists bool) error {
|
||||
var err error
|
||||
for i := range m.tables {
|
||||
table := m.tables[i]
|
||||
sql := table.SqlForCreate(ifNotExists)
|
||||
_, err = m.ExecNoTimeout(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, tbl := range m.dynamicTableMap() {
|
||||
sql := tbl.SqlForCreate(ifNotExists)
|
||||
_, err = m.ExecNoTimeout(sql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// DropTable drops an individual table.
|
||||
// Returns an error when the table does not exist.
|
||||
func (m *DbMap) DropTable(table interface{}) error {
|
||||
t := reflect.TypeOf(table)
|
||||
|
||||
tableName := ""
|
||||
if dyn, ok := table.(DynamicTable); ok {
|
||||
tableName = dyn.TableName()
|
||||
}
|
||||
|
||||
return m.dropTable(t, tableName, false)
|
||||
}
|
||||
|
||||
// DropTableIfExists drops an individual table when the table exists.
|
||||
func (m *DbMap) DropTableIfExists(table interface{}) error {
|
||||
t := reflect.TypeOf(table)
|
||||
|
||||
tableName := ""
|
||||
if dyn, ok := table.(DynamicTable); ok {
|
||||
tableName = dyn.TableName()
|
||||
}
|
||||
|
||||
return m.dropTable(t, tableName, true)
|
||||
}
|
||||
|
||||
// DropTables iterates through TableMaps registered to this DbMap and
|
||||
// executes "drop table" statements against the database for each.
|
||||
func (m *DbMap) DropTables() error {
|
||||
return m.dropTables(false)
|
||||
}
|
||||
|
||||
// DropTablesIfExists is the same as DropTables, but uses the "if exists" clause to
|
||||
// avoid errors for tables that do not exist.
|
||||
func (m *DbMap) DropTablesIfExists() error {
|
||||
return m.dropTables(true)
|
||||
}
|
||||
|
||||
// Goes through all the registered tables, dropping them one by one.
|
||||
// If an error is encountered, then it is returned and the rest of
|
||||
// the tables are not dropped.
|
||||
func (m *DbMap) dropTables(addIfExists bool) (err error) {
|
||||
for _, table := range m.tables {
|
||||
err = m.dropTableImpl(table, addIfExists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for _, table := range m.dynamicTableMap() {
|
||||
err = m.dropTableImpl(table, addIfExists)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Implementation of dropping a single table.
|
||||
func (m *DbMap) dropTable(t reflect.Type, name string, addIfExists bool) error {
|
||||
table := tableOrNil(m, t, name)
|
||||
if table == nil {
|
||||
return fmt.Errorf("table %s was not registered", table.TableName)
|
||||
}
|
||||
|
||||
return m.dropTableImpl(table, addIfExists)
|
||||
}
|
||||
|
||||
func (m *DbMap) dropTableImpl(table *TableMap, ifExists bool) (err error) {
|
||||
tableDrop := "drop table"
|
||||
if ifExists {
|
||||
tableDrop = m.Dialect.IfTableExists(tableDrop, table.SchemaName, table.TableName)
|
||||
}
|
||||
_, err = m.ExecNoTimeout(fmt.Sprintf("%s %s;", tableDrop, m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
|
||||
return err
|
||||
}
|
||||
|
||||
// TruncateTables iterates through TableMaps registered to this DbMap and
|
||||
// executes "truncate table" statements against the database for each, or in the case of
|
||||
// sqlite, a "delete from" with no "where" clause, which uses the truncate optimization
|
||||
// (http://www.sqlite.org/lang_delete.html)
|
||||
func (m *DbMap) TruncateTables() error {
|
||||
var err error
|
||||
for i := range m.tables {
|
||||
table := m.tables[i]
|
||||
_, e := m.ExecNoTimeout(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
|
||||
if e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
|
||||
for _, table := range m.dynamicTableMap() {
|
||||
_, e := m.ExecNoTimeout(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
|
||||
if e != nil {
|
||||
err = e
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert runs a SQL INSERT statement for each element in list. List
|
||||
// items must be pointers.
|
||||
//
|
||||
// Any interface whose TableMap has an auto-increment primary key will
|
||||
// have its last insert id bound to the PK field on the struct.
|
||||
//
|
||||
// The hook functions PreInsert() and/or PostInsert() will be executed
|
||||
// before/after the INSERT statement if the interface defines them.
|
||||
//
|
||||
// Panics if any interface in the list has not been registered with AddTable
|
||||
func (m *DbMap) Insert(list ...interface{}) error {
|
||||
return insert(m, m, list...)
|
||||
}
|
||||
|
||||
// Update runs a SQL UPDATE statement for each element in list. List
|
||||
// items must be pointers.
|
||||
//
|
||||
// The hook functions PreUpdate() and/or PostUpdate() will be executed
|
||||
// before/after the UPDATE statement if the interface defines them.
|
||||
//
|
||||
// Returns the number of rows updated.
|
||||
//
|
||||
// Returns an error if SetKeys has not been called on the TableMap
|
||||
// Panics if any interface in the list has not been registered with AddTable
|
||||
func (m *DbMap) Update(list ...interface{}) (int64, error) {
|
||||
return update(m, m, nil, list...)
|
||||
}
|
||||
|
||||
// UpdateColumns runs a SQL UPDATE statement for each element in list. List
|
||||
// items must be pointers.
|
||||
//
|
||||
// Only the columns accepted by filter are included in the UPDATE.
|
||||
//
|
||||
// The hook functions PreUpdate() and/or PostUpdate() will be executed
|
||||
// before/after the UPDATE statement if the interface defines them.
|
||||
//
|
||||
// Returns the number of rows updated.
|
||||
//
|
||||
// Returns an error if SetKeys has not been called on the TableMap
|
||||
// Panics if any interface in the list has not been registered with AddTable
|
||||
func (m *DbMap) UpdateColumns(filter ColumnFilter, list ...interface{}) (int64, error) {
|
||||
return update(m, m, filter, list...)
|
||||
}
|
||||
|
||||
// Delete runs a SQL DELETE statement for each element in list. List
|
||||
// items must be pointers.
|
||||
//
|
||||
// The hook functions PreDelete() and/or PostDelete() will be executed
|
||||
// before/after the DELETE statement if the interface defines them.
|
||||
//
|
||||
// Returns the number of rows deleted.
|
||||
//
|
||||
// Returns an error if SetKeys has not been called on the TableMap
|
||||
// Panics if any interface in the list has not been registered with AddTable
|
||||
func (m *DbMap) Delete(list ...interface{}) (int64, error) {
|
||||
return delete(m, m, list...)
|
||||
}
|
||||
|
||||
// Get runs a SQL SELECT to fetch a single row from the table based on the
|
||||
// primary key(s)
|
||||
//
|
||||
// i should be an empty value for the struct to load. keys should be
|
||||
// the primary key value(s) for the row to load. If multiple keys
|
||||
// exist on the table, the order should match the column order
|
||||
// specified in SetKeys() when the table mapping was defined.
|
||||
//
|
||||
// The hook function PostGet() will be executed after the SELECT
|
||||
// statement if the interface defines them.
|
||||
//
|
||||
// Returns a pointer to a struct that matches or nil if no row is found.
|
||||
//
|
||||
// Returns an error if SetKeys has not been called on the TableMap
|
||||
// Panics if any interface in the list has not been registered with AddTable
|
||||
func (m *DbMap) Get(i interface{}, keys ...interface{}) (interface{}, error) {
|
||||
return get(m, m, i, keys...)
|
||||
}
|
||||
|
||||
// Select runs an arbitrary SQL query, binding the columns in the result
|
||||
// to fields on the struct specified by i. args represent the bind
|
||||
// parameters for the SQL statement.
|
||||
//
|
||||
// Column names on the SELECT statement should be aliased to the field names
|
||||
// on the struct i. Returns an error if one or more columns in the result
|
||||
// do not match. It is OK if fields on i are not part of the SQL
|
||||
// statement.
|
||||
//
|
||||
// The hook function PostGet() will be executed after the SELECT
|
||||
// statement if the interface defines them.
|
||||
//
|
||||
// Values are returned in one of two ways:
|
||||
// 1. If i is a struct or a pointer to a struct, returns a slice of pointers to
|
||||
// matching rows of type i.
|
||||
// 2. If i is a pointer to a slice, the results will be appended to that slice
|
||||
// and nil returned.
|
||||
//
|
||||
// i does NOT need to be registered with AddTable()
|
||||
func (m *DbMap) Select(i interface{}, query string, args ...interface{}) ([]interface{}, error) {
|
||||
return hookedselect(m, m, i, query, args...)
|
||||
}
|
||||
|
||||
// Exec runs an arbitrary SQL statement. args represent the bind parameters.
|
||||
// This is equivalent to running: Exec() using database/sql
|
||||
// Times out based on the DbMap.QueryTimeout field
|
||||
func (m *DbMap) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
return exec(m, query, true, args...)
|
||||
}
|
||||
|
||||
// ExecNoTimeout is the same as Exec except it will not time out
|
||||
func (m *DbMap) ExecNoTimeout(query string, args ...interface{}) (sql.Result, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
return exec(m, query, false, args...)
|
||||
}
|
||||
|
||||
// SelectInt is a convenience wrapper around the gorp.SelectInt function
|
||||
func (m *DbMap) SelectInt(query string, args ...interface{}) (int64, error) {
|
||||
return SelectInt(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullInt is a convenience wrapper around the gorp.SelectNullInt function
|
||||
func (m *DbMap) SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error) {
|
||||
return SelectNullInt(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectFloat is a convenience wrapper around the gorp.SelectFloat function
|
||||
func (m *DbMap) SelectFloat(query string, args ...interface{}) (float64, error) {
|
||||
return SelectFloat(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullFloat is a convenience wrapper around the gorp.SelectNullFloat function
|
||||
func (m *DbMap) SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error) {
|
||||
return SelectNullFloat(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectStr is a convenience wrapper around the gorp.SelectStr function
|
||||
func (m *DbMap) SelectStr(query string, args ...interface{}) (string, error) {
|
||||
return SelectStr(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullStr is a convenience wrapper around the gorp.SelectNullStr function
|
||||
func (m *DbMap) SelectNullStr(query string, args ...interface{}) (sql.NullString, error) {
|
||||
return SelectNullStr(m, query, args...)
|
||||
}
|
||||
|
||||
// SelectOne is a convenience wrapper around the gorp.SelectOne function
|
||||
func (m *DbMap) SelectOne(holder interface{}, query string, args ...interface{}) error {
|
||||
return SelectOne(m, m, holder, query, args...)
|
||||
}
|
||||
|
||||
// Begin starts a gorp Transaction
|
||||
func (m *DbMap) Begin() (*Transaction, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, "begin;")
|
||||
}
|
||||
tx, err := m.Db.Begin()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Transaction{m, tx, false}, nil
|
||||
}
|
||||
|
||||
// Begin starts a gorp Transaction with a given context and opts.
|
||||
func (m *DbMap) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Transaction, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, "begin;")
|
||||
}
|
||||
tx, err := m.Db.BeginTx(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Transaction{m, tx, false}, nil
|
||||
}
|
||||
|
||||
// TableFor returns the *TableMap corresponding to the given Go Type
|
||||
// If no table is mapped to that type an error is returned.
|
||||
// If checkPK is true and the mapped table has no registered PKs, an error is returned.
|
||||
func (m *DbMap) TableFor(t reflect.Type, checkPK bool) (*TableMap, error) {
|
||||
table := tableOrNil(m, t, "")
|
||||
if table == nil {
|
||||
return nil, fmt.Errorf("no table found for type: %v", t.Name())
|
||||
}
|
||||
|
||||
if checkPK && len(table.keys) < 1 {
|
||||
e := fmt.Sprintf("gorp: no keys defined for table: %s",
|
||||
table.TableName)
|
||||
return nil, errors.New(e)
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// DynamicTableFor returns the *TableMap for the dynamic table corresponding
|
||||
// to the input tablename
|
||||
// If no table is mapped to that tablename an error is returned.
|
||||
// If checkPK is true and the mapped table has no registered PKs, an error is returned.
|
||||
func (m *DbMap) DynamicTableFor(tableName string, checkPK bool) (*TableMap, error) {
|
||||
table, found := m.dynamicTableFind(tableName)
|
||||
if !found {
|
||||
return nil, fmt.Errorf("gorp: no table found for name: %v", tableName)
|
||||
}
|
||||
|
||||
if checkPK && len(table.keys) < 1 {
|
||||
e := fmt.Sprintf("gorp: no keys defined for table: %s",
|
||||
table.TableName)
|
||||
return nil, errors.New(e)
|
||||
}
|
||||
|
||||
return table, nil
|
||||
}
|
||||
|
||||
// Prepare creates a prepared statement for later queries or executions.
|
||||
// Multiple queries or executions may be run concurrently from the returned statement.
|
||||
// This is equivalent to running: Prepare() using database/sql
|
||||
func (m *DbMap) Prepare(query string) (*sql.Stmt, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, nil)
|
||||
}
|
||||
return m.Db.Prepare(query)
|
||||
}
|
||||
|
||||
func tableOrNil(m *DbMap, t reflect.Type, name string) *TableMap {
|
||||
if name != "" {
|
||||
// Search by table name (dynamic tables)
|
||||
if table, found := m.dynamicTableFind(name); found {
|
||||
return table
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := range m.tables {
|
||||
table := m.tables[i]
|
||||
if table.gotype == t {
|
||||
return table
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DbMap) tableForPointer(ptr interface{}, checkPK bool) (*TableMap, reflect.Value, error) {
|
||||
ptrv := reflect.ValueOf(ptr)
|
||||
if ptrv.Kind() != reflect.Ptr {
|
||||
e := fmt.Sprintf("gorp: passed non-pointer: %v (kind=%v)", ptr,
|
||||
ptrv.Kind())
|
||||
return nil, reflect.Value{}, errors.New(e)
|
||||
}
|
||||
elem := ptrv.Elem()
|
||||
ifc := elem.Interface()
|
||||
var t *TableMap
|
||||
var err error
|
||||
tableName := ""
|
||||
if dyn, isDyn := ptr.(DynamicTable); isDyn {
|
||||
tableName = dyn.TableName()
|
||||
t, err = m.DynamicTableFor(tableName, checkPK)
|
||||
} else {
|
||||
etype := reflect.TypeOf(ifc)
|
||||
t, err = m.TableFor(etype, checkPK)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, reflect.Value{}, err
|
||||
}
|
||||
|
||||
return t, elem, nil
|
||||
}
|
||||
|
||||
func (m *DbMap) QueryRow(query string, args ...interface{}) *sql.Row {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
|
||||
return m.Db.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func (m *DbMap) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
|
||||
return m.Db.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (m *DbMap) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
|
||||
return m.Db.Query(query, args...)
|
||||
}
|
||||
|
||||
func (m *DbMap) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
||||
if m.logger != nil {
|
||||
now := time.Now()
|
||||
defer m.trace(now, query, args...)
|
||||
}
|
||||
|
||||
return m.Db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (m *DbMap) trace(started time.Time, query string, args ...interface{}) {
|
||||
if m.logger != nil {
|
||||
var margs = argsString(args...)
|
||||
m.logger.Printf("%s%s [%s] (%v)", m.logPrefix, query, margs, (time.Now().Sub(started)))
|
||||
}
|
||||
}
|
||||
114
vendor/github.com/mattermost/gorp/dialect.go
сгенерированный
поставляемый
114
vendor/github.com/mattermost/gorp/dialect.go
сгенерированный
поставляемый
@@ -1,114 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import "reflect"
|
||||
|
||||
// The Dialect interface encapsulates behaviors that differ across
|
||||
// SQL databases. At present the Dialect is only used by CreateTables()
|
||||
// but this could change in the future
|
||||
type Dialect interface {
|
||||
|
||||
// dialect name
|
||||
Name() string
|
||||
|
||||
// adds a suffix to any query, usually ";"
|
||||
QuerySuffix() string
|
||||
|
||||
// ToSqlType returns the SQL column type to use when creating a
|
||||
// table of the given Go Type. maxsize can be used to switch based on
|
||||
// size. For example, in MySQL []byte could map to BLOB, MEDIUMBLOB,
|
||||
// or LONGBLOB depending on the maxsize
|
||||
ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string
|
||||
|
||||
// string to append to primary key column definitions
|
||||
AutoIncrStr() string
|
||||
|
||||
// string to bind autoincrement columns to. Empty string will
|
||||
// remove reference to those columns in the INSERT statement.
|
||||
AutoIncrBindValue() string
|
||||
|
||||
AutoIncrInsertSuffix(col *ColumnMap) string
|
||||
|
||||
// string to append to "create table" statement for vendor specific
|
||||
// table attributes
|
||||
CreateTableSuffix() string
|
||||
|
||||
// string to append to "create index" statement
|
||||
CreateIndexSuffix() string
|
||||
|
||||
// string to append to "drop index" statement
|
||||
DropIndexSuffix() string
|
||||
|
||||
// string to truncate tables
|
||||
TruncateClause() string
|
||||
|
||||
// bind variable string to use when forming SQL statements
|
||||
// in many dbs it is "?", but Postgres appears to use $1
|
||||
//
|
||||
// i is a zero based index of the bind variable in this statement
|
||||
//
|
||||
BindVar(i int) string
|
||||
|
||||
// Handles quoting of a field name to ensure that it doesn't raise any
|
||||
// SQL parsing exceptions by using a reserved word as a field name.
|
||||
QuoteField(field string) string
|
||||
|
||||
// Handles building up of a schema.database string that is compatible with
|
||||
// the given dialect
|
||||
//
|
||||
// schema - The schema that <table> lives in
|
||||
// table - The table name
|
||||
QuotedTableForQuery(schema string, table string) string
|
||||
|
||||
// Existance clause for table creation / deletion
|
||||
IfSchemaNotExists(command, schema string) string
|
||||
IfTableExists(command, schema, table string) string
|
||||
IfTableNotExists(command, schema, table string) string
|
||||
}
|
||||
|
||||
// IntegerAutoIncrInserter is implemented by dialects that can perform
|
||||
// inserts with automatically incremented integer primary keys. If
|
||||
// the dialect can handle automatic assignment of more than just
|
||||
// integers, see TargetedAutoIncrInserter.
|
||||
type IntegerAutoIncrInserter interface {
|
||||
InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error)
|
||||
}
|
||||
|
||||
// TargetedAutoIncrInserter is implemented by dialects that can
|
||||
// perform automatic assignment of any primary key type (i.e. strings
|
||||
// for uuids, integers for serials, etc).
|
||||
type TargetedAutoIncrInserter interface {
|
||||
// InsertAutoIncrToTarget runs an insert operation and assigns the
|
||||
// automatically generated primary key directly to the passed in
|
||||
// target. The target should be a pointer to the primary key
|
||||
// field of the value being inserted.
|
||||
InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error
|
||||
}
|
||||
|
||||
// TargetQueryInserter is implemented by dialects that can perform
|
||||
// assignment of integer primary key type by executing a query
|
||||
// like "select sequence.currval from dual".
|
||||
type TargetQueryInserter interface {
|
||||
// TargetQueryInserter runs an insert operation and assigns the
|
||||
// automatically generated primary key retrived by the query
|
||||
// extracted from the GeneratedIdQuery field of the id column.
|
||||
InsertQueryToTarget(exec SqlExecutor, insertSql, idSql string, target interface{}, params ...interface{}) error
|
||||
}
|
||||
|
||||
func standardInsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
|
||||
res, err := exec.Exec(insertSql, params...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
173
vendor/github.com/mattermost/gorp/dialect_mysql.go
сгенерированный
поставляемый
173
vendor/github.com/mattermost/gorp/dialect_mysql.go
сгенерированный
поставляемый
@@ -1,173 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Implementation of Dialect for MySQL databases.
|
||||
type MySQLDialect struct {
|
||||
|
||||
// Engine is the storage engine to use "InnoDB" vs "MyISAM" for example
|
||||
Engine string
|
||||
|
||||
// Encoding is the character encoding to use for created tables
|
||||
Encoding string
|
||||
}
|
||||
|
||||
func (d MySQLDialect) Name() string { return "MySQLDialect" }
|
||||
|
||||
func (d MySQLDialect) QuerySuffix() string { return ";" }
|
||||
|
||||
func (d MySQLDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||
case reflect.Bool:
|
||||
return "boolean"
|
||||
case reflect.Int8:
|
||||
return "tinyint"
|
||||
case reflect.Uint8:
|
||||
return "tinyint unsigned"
|
||||
case reflect.Int16:
|
||||
return "smallint"
|
||||
case reflect.Uint16:
|
||||
return "smallint unsigned"
|
||||
case reflect.Int, reflect.Int32:
|
||||
return "int"
|
||||
case reflect.Uint, reflect.Uint32:
|
||||
return "int unsigned"
|
||||
case reflect.Int64:
|
||||
return "bigint"
|
||||
case reflect.Uint64:
|
||||
return "bigint unsigned"
|
||||
case reflect.Float64, reflect.Float32:
|
||||
return "double"
|
||||
case reflect.Slice:
|
||||
if val.Elem().Kind() == reflect.Uint8 {
|
||||
return "mediumblob"
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Name() {
|
||||
case "NullInt64":
|
||||
return "bigint"
|
||||
case "NullFloat64":
|
||||
return "double"
|
||||
case "NullBool":
|
||||
return "tinyint"
|
||||
case "Time":
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
/* == About varchar(N) ==
|
||||
* N is number of characters.
|
||||
* According to the documentation, 0 < N <= 65535.
|
||||
* But one utf-8 character takes 3 bytes and each row can
|
||||
* be only 65535 bytes. So there is no way to know exactly
|
||||
* how many chars a varchar column can actually store.
|
||||
* Text columns contribute only up to 12 bytes to the row
|
||||
* size as their contents are stored off-page.
|
||||
* Hence, we use a conservative maximum of 512 for varchar,
|
||||
* after which we switch to the text type.
|
||||
*/
|
||||
if maxsize == 0 {
|
||||
// Closer match for unbounded text
|
||||
return "longtext"
|
||||
} else if maxsize < 256 {
|
||||
return fmt.Sprintf("varchar(%d)", maxsize)
|
||||
} else {
|
||||
return "text"
|
||||
}
|
||||
}
|
||||
|
||||
// Returns auto_increment
|
||||
func (d MySQLDialect) AutoIncrStr() string {
|
||||
return "auto_increment"
|
||||
}
|
||||
|
||||
func (d MySQLDialect) AutoIncrBindValue() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
func (d MySQLDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Returns engine=%s charset=%s based on values stored on struct
|
||||
func (d MySQLDialect) CreateTableSuffix() string {
|
||||
if d.Engine == "" || d.Encoding == "" {
|
||||
msg := "gorp - undefined"
|
||||
|
||||
if d.Engine == "" {
|
||||
msg += " MySQLDialect.Engine"
|
||||
}
|
||||
if d.Engine == "" && d.Encoding == "" {
|
||||
msg += ","
|
||||
}
|
||||
if d.Encoding == "" {
|
||||
msg += " MySQLDialect.Encoding"
|
||||
}
|
||||
msg += ". Check that your MySQLDialect was correctly initialized when declared."
|
||||
panic(msg)
|
||||
}
|
||||
|
||||
return fmt.Sprintf(" engine=%s charset=%s", d.Engine, d.Encoding)
|
||||
}
|
||||
|
||||
func (m MySQLDialect) CreateIndexSuffix() string {
|
||||
return "using"
|
||||
}
|
||||
|
||||
func (m MySQLDialect) DropIndexSuffix() string {
|
||||
return "on"
|
||||
}
|
||||
|
||||
func (m MySQLDialect) TruncateClause() string {
|
||||
return "truncate"
|
||||
}
|
||||
|
||||
// Returns "?"
|
||||
func (d MySQLDialect) BindVar(i int) string {
|
||||
return "?"
|
||||
}
|
||||
|
||||
func (d MySQLDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
|
||||
return standardInsertAutoIncr(exec, insertSql, params...)
|
||||
}
|
||||
|
||||
func (d MySQLDialect) QuoteField(f string) string {
|
||||
return "`" + f + "`"
|
||||
}
|
||||
|
||||
func (d MySQLDialect) QuotedTableForQuery(schema string, table string) string {
|
||||
if strings.TrimSpace(schema) == "" {
|
||||
return d.QuoteField(table)
|
||||
}
|
||||
|
||||
return schema + "." + d.QuoteField(table)
|
||||
}
|
||||
|
||||
func (d MySQLDialect) IfSchemaNotExists(command, schema string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
|
||||
func (d MySQLDialect) IfTableExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if exists", command)
|
||||
}
|
||||
|
||||
func (d MySQLDialect) IfTableNotExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
148
vendor/github.com/mattermost/gorp/dialect_oracle.go
сгенерированный
поставляемый
148
vendor/github.com/mattermost/gorp/dialect_oracle.go
сгенерированный
поставляемый
@@ -1,148 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Implementation of Dialect for Oracle databases.
|
||||
type OracleDialect struct{}
|
||||
|
||||
func (d OracleDialect) Name() string { return "OracleDialect" }
|
||||
|
||||
func (d OracleDialect) QuerySuffix() string { return "" }
|
||||
|
||||
func (d OracleDialect) CreateIndexSuffix() string { return "" }
|
||||
|
||||
func (d OracleDialect) DropIndexSuffix() string { return "" }
|
||||
|
||||
func (d OracleDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||
case reflect.Bool:
|
||||
return "boolean"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
if isAutoIncr {
|
||||
return "serial"
|
||||
}
|
||||
return "integer"
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
if isAutoIncr {
|
||||
return "bigserial"
|
||||
}
|
||||
return "bigint"
|
||||
case reflect.Float64:
|
||||
return "double precision"
|
||||
case reflect.Float32:
|
||||
return "real"
|
||||
case reflect.Slice:
|
||||
if val.Elem().Kind() == reflect.Uint8 {
|
||||
return "bytea"
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Name() {
|
||||
case "NullInt64":
|
||||
return "bigint"
|
||||
case "NullFloat64":
|
||||
return "double precision"
|
||||
case "NullBool":
|
||||
return "boolean"
|
||||
case "NullTime", "Time":
|
||||
return "timestamp with time zone"
|
||||
}
|
||||
|
||||
if maxsize > 0 {
|
||||
return fmt.Sprintf("varchar(%d)", maxsize)
|
||||
} else {
|
||||
return "text"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns empty string
|
||||
func (d OracleDialect) AutoIncrStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d OracleDialect) AutoIncrBindValue() string {
|
||||
return "NULL"
|
||||
}
|
||||
|
||||
func (d OracleDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Returns suffix
|
||||
func (d OracleDialect) CreateTableSuffix() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d OracleDialect) TruncateClause() string {
|
||||
return "truncate"
|
||||
}
|
||||
|
||||
// Returns "$(i+1)"
|
||||
func (d OracleDialect) BindVar(i int) string {
|
||||
return fmt.Sprintf(":%d", i+1)
|
||||
}
|
||||
|
||||
// After executing the insert uses the ColMap IdQuery to get the generated id
|
||||
func (d OracleDialect) InsertQueryToTarget(exec SqlExecutor, insertSql, idSql string, target interface{}, params ...interface{}) error {
|
||||
_, err := exec.Exec(insertSql, params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
id, err := exec.SelectInt(idSql)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch target.(type) {
|
||||
case *int64:
|
||||
*(target.(*int64)) = id
|
||||
case *int32:
|
||||
*(target.(*int32)) = int32(id)
|
||||
case int:
|
||||
*(target.(*int)) = int(id)
|
||||
default:
|
||||
return fmt.Errorf("Id field can be int, int32 or int64")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d OracleDialect) QuoteField(f string) string {
|
||||
return `"` + strings.ToUpper(f) + `"`
|
||||
}
|
||||
|
||||
func (d OracleDialect) QuotedTableForQuery(schema string, table string) string {
|
||||
if strings.TrimSpace(schema) == "" {
|
||||
return d.QuoteField(table)
|
||||
}
|
||||
|
||||
return schema + "." + d.QuoteField(table)
|
||||
}
|
||||
|
||||
func (d OracleDialect) IfSchemaNotExists(command, schema string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
|
||||
func (d OracleDialect) IfTableExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if exists", command)
|
||||
}
|
||||
|
||||
func (d OracleDialect) IfTableNotExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
149
vendor/github.com/mattermost/gorp/dialect_postgres.go
сгенерированный
поставляемый
149
vendor/github.com/mattermost/gorp/dialect_postgres.go
сгенерированный
поставляемый
@@ -1,149 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type PostgresDialect struct {
|
||||
suffix string
|
||||
}
|
||||
|
||||
func (d PostgresDialect) Name() string { return "PostgresDialect" }
|
||||
|
||||
func (d PostgresDialect) QuerySuffix() string { return ";" }
|
||||
|
||||
func (d PostgresDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||
case reflect.Bool:
|
||||
return "boolean"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
|
||||
if isAutoIncr {
|
||||
return "serial"
|
||||
}
|
||||
return "integer"
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
if isAutoIncr {
|
||||
return "bigserial"
|
||||
}
|
||||
return "bigint"
|
||||
case reflect.Float64:
|
||||
return "double precision"
|
||||
case reflect.Float32:
|
||||
return "real"
|
||||
case reflect.Slice:
|
||||
if val.Elem().Kind() == reflect.Uint8 {
|
||||
return "bytea"
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Name() {
|
||||
case "NullInt64":
|
||||
return "bigint"
|
||||
case "NullFloat64":
|
||||
return "double precision"
|
||||
case "NullBool":
|
||||
return "boolean"
|
||||
case "Time", "NullTime":
|
||||
return "timestamp with time zone"
|
||||
}
|
||||
|
||||
if maxsize > 0 {
|
||||
return fmt.Sprintf("varchar(%d)", maxsize)
|
||||
} else {
|
||||
return "text"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Returns empty string
|
||||
func (d PostgresDialect) AutoIncrStr() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d PostgresDialect) AutoIncrBindValue() string {
|
||||
return "default"
|
||||
}
|
||||
|
||||
func (d PostgresDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||
return " returning " + d.QuoteField(col.ColumnName)
|
||||
}
|
||||
|
||||
// Returns suffix
|
||||
func (d PostgresDialect) CreateTableSuffix() string {
|
||||
return d.suffix
|
||||
}
|
||||
|
||||
func (d PostgresDialect) CreateIndexSuffix() string {
|
||||
return "using"
|
||||
}
|
||||
|
||||
func (d PostgresDialect) DropIndexSuffix() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d PostgresDialect) TruncateClause() string {
|
||||
return "truncate"
|
||||
}
|
||||
|
||||
// Returns "$(i+1)"
|
||||
func (d PostgresDialect) BindVar(i int) string {
|
||||
return fmt.Sprintf("$%d", i+1)
|
||||
}
|
||||
|
||||
func (d PostgresDialect) InsertAutoIncrToTarget(exec SqlExecutor, insertSql string, target interface{}, params ...interface{}) error {
|
||||
rows, err := exec.Query(insertSql, params...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return fmt.Errorf("No serial value returned for insert: %s Encountered error: %s", insertSql, rows.Err())
|
||||
}
|
||||
if err := rows.Scan(target); err != nil {
|
||||
return err
|
||||
}
|
||||
if rows.Next() {
|
||||
return fmt.Errorf("more than two serial value returned for insert: %s", insertSql)
|
||||
}
|
||||
return rows.Err()
|
||||
}
|
||||
|
||||
func (d PostgresDialect) QuoteField(f string) string {
|
||||
return `"` + strings.ToLower(f) + `"`
|
||||
}
|
||||
|
||||
func (d PostgresDialect) QuotedTableForQuery(schema string, table string) string {
|
||||
if strings.TrimSpace(schema) == "" {
|
||||
return d.QuoteField(table)
|
||||
}
|
||||
|
||||
return schema + "." + d.QuoteField(table)
|
||||
}
|
||||
|
||||
func (d PostgresDialect) IfSchemaNotExists(command, schema string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
|
||||
func (d PostgresDialect) IfTableExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if exists", command)
|
||||
}
|
||||
|
||||
func (d PostgresDialect) IfTableNotExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
121
vendor/github.com/mattermost/gorp/dialect_sqlite.go
сгенерированный
поставляемый
121
vendor/github.com/mattermost/gorp/dialect_sqlite.go
сгенерированный
поставляемый
@@ -1,121 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type SqliteDialect struct {
|
||||
suffix string
|
||||
}
|
||||
|
||||
func (d SqliteDialect) Name() string { return "SQLiteDialect" }
|
||||
|
||||
func (d SqliteDialect) QuerySuffix() string { return ";" }
|
||||
|
||||
func (d SqliteDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||
case reflect.Bool:
|
||||
return "integer"
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return "integer"
|
||||
case reflect.Float64, reflect.Float32:
|
||||
return "real"
|
||||
case reflect.Slice:
|
||||
if val.Elem().Kind() == reflect.Uint8 {
|
||||
return "blob"
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Name() {
|
||||
case "NullInt64":
|
||||
return "integer"
|
||||
case "NullFloat64":
|
||||
return "real"
|
||||
case "NullBool":
|
||||
return "integer"
|
||||
case "Time":
|
||||
return "datetime"
|
||||
}
|
||||
|
||||
if maxsize < 1 {
|
||||
maxsize = 255
|
||||
}
|
||||
return fmt.Sprintf("varchar(%d)", maxsize)
|
||||
}
|
||||
|
||||
// Returns autoincrement
|
||||
func (d SqliteDialect) AutoIncrStr() string {
|
||||
return "autoincrement"
|
||||
}
|
||||
|
||||
func (d SqliteDialect) AutoIncrBindValue() string {
|
||||
return "null"
|
||||
}
|
||||
|
||||
func (d SqliteDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Returns suffix
|
||||
func (d SqliteDialect) CreateTableSuffix() string {
|
||||
return d.suffix
|
||||
}
|
||||
|
||||
func (d SqliteDialect) CreateIndexSuffix() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d SqliteDialect) DropIndexSuffix() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// With sqlite, there technically isn't a TRUNCATE statement,
|
||||
// but a DELETE FROM uses a truncate optimization:
|
||||
// http://www.sqlite.org/lang_delete.html
|
||||
func (d SqliteDialect) TruncateClause() string {
|
||||
return "delete from"
|
||||
}
|
||||
|
||||
// Returns "?"
|
||||
func (d SqliteDialect) BindVar(i int) string {
|
||||
return "?"
|
||||
}
|
||||
|
||||
func (d SqliteDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
|
||||
return standardInsertAutoIncr(exec, insertSql, params...)
|
||||
}
|
||||
|
||||
func (d SqliteDialect) QuoteField(f string) string {
|
||||
return `"` + f + `"`
|
||||
}
|
||||
|
||||
// sqlite does not have schemas like PostgreSQL does, so just escape it like normal
|
||||
func (d SqliteDialect) QuotedTableForQuery(schema string, table string) string {
|
||||
return d.QuoteField(table)
|
||||
}
|
||||
|
||||
func (d SqliteDialect) IfSchemaNotExists(command, schema string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
|
||||
func (d SqliteDialect) IfTableExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if exists", command)
|
||||
}
|
||||
|
||||
func (d SqliteDialect) IfTableNotExists(command, schema, table string) string {
|
||||
return fmt.Sprintf("%s if not exists", command)
|
||||
}
|
||||
154
vendor/github.com/mattermost/gorp/dialect_sqlserver.go
сгенерированный
поставляемый
154
vendor/github.com/mattermost/gorp/dialect_sqlserver.go
сгенерированный
поставляемый
@@ -1,154 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Implementation of Dialect for Microsoft SQL Server databases.
|
||||
// Use gorp.SqlServerDialect{"2005"} for legacy datatypes.
|
||||
// Tested with driver: github.com/denisenkom/go-mssqldb
|
||||
|
||||
type SqlServerDialect struct {
|
||||
|
||||
// If set to "2005" legacy datatypes will be used
|
||||
Version string
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) Name() string { return "SQLServerDialect" }
|
||||
|
||||
func (d SqlServerDialect) ToSqlType(val reflect.Type, maxsize int, isAutoIncr bool) string {
|
||||
switch val.Kind() {
|
||||
case reflect.Ptr:
|
||||
return d.ToSqlType(val.Elem(), maxsize, isAutoIncr)
|
||||
case reflect.Bool:
|
||||
return "bit"
|
||||
case reflect.Int8:
|
||||
return "tinyint"
|
||||
case reflect.Uint8:
|
||||
return "smallint"
|
||||
case reflect.Int16:
|
||||
return "smallint"
|
||||
case reflect.Uint16:
|
||||
return "int"
|
||||
case reflect.Int, reflect.Int32:
|
||||
return "int"
|
||||
case reflect.Uint, reflect.Uint32:
|
||||
return "bigint"
|
||||
case reflect.Int64:
|
||||
return "bigint"
|
||||
case reflect.Uint64:
|
||||
return "numeric(20,0)"
|
||||
case reflect.Float32:
|
||||
return "float(24)"
|
||||
case reflect.Float64:
|
||||
return "float(53)"
|
||||
case reflect.Slice:
|
||||
if val.Elem().Kind() == reflect.Uint8 {
|
||||
return "varbinary"
|
||||
}
|
||||
}
|
||||
|
||||
switch val.Name() {
|
||||
case "NullInt64":
|
||||
return "bigint"
|
||||
case "NullFloat64":
|
||||
return "float(53)"
|
||||
case "NullBool":
|
||||
return "bit"
|
||||
case "NullTime", "Time":
|
||||
if d.Version == "2005" {
|
||||
return "datetime"
|
||||
}
|
||||
return "datetime2"
|
||||
}
|
||||
|
||||
if maxsize < 1 {
|
||||
if d.Version == "2005" {
|
||||
maxsize = 255
|
||||
} else {
|
||||
return fmt.Sprintf("nvarchar(max)")
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("nvarchar(%d)", maxsize)
|
||||
}
|
||||
|
||||
// Returns auto_increment
|
||||
func (d SqlServerDialect) AutoIncrStr() string {
|
||||
return "identity(0,1)"
|
||||
}
|
||||
|
||||
// Empty string removes autoincrement columns from the INSERT statements.
|
||||
func (d SqlServerDialect) AutoIncrBindValue() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) AutoIncrInsertSuffix(col *ColumnMap) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) CreateTableSuffix() string { return ";" }
|
||||
|
||||
func (d SqlServerDialect) TruncateClause() string {
|
||||
return "truncate table"
|
||||
}
|
||||
|
||||
// Returns "?"
|
||||
func (d SqlServerDialect) BindVar(i int) string {
|
||||
return "?"
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) InsertAutoIncr(exec SqlExecutor, insertSql string, params ...interface{}) (int64, error) {
|
||||
return standardInsertAutoIncr(exec, insertSql, params...)
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) QuoteField(f string) string {
|
||||
return "[" + strings.Replace(f, "]", "]]", -1) + "]"
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) QuotedTableForQuery(schema string, table string) string {
|
||||
if strings.TrimSpace(schema) == "" {
|
||||
return d.QuoteField(table)
|
||||
}
|
||||
return d.QuoteField(schema) + "." + d.QuoteField(table)
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) QuerySuffix() string { return ";" }
|
||||
|
||||
func (d SqlServerDialect) IfSchemaNotExists(command, schema string) string {
|
||||
s := fmt.Sprintf("if schema_id(N'%s') is null %s", schema, command)
|
||||
return s
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) IfTableExists(command, schema, table string) string {
|
||||
var schema_clause string
|
||||
if strings.TrimSpace(schema) != "" {
|
||||
schema_clause = fmt.Sprintf("%s.", d.QuoteField(schema))
|
||||
}
|
||||
s := fmt.Sprintf("if object_id('%s%s') is not null %s", schema_clause, d.QuoteField(table), command)
|
||||
return s
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) IfTableNotExists(command, schema, table string) string {
|
||||
var schema_clause string
|
||||
if strings.TrimSpace(schema) != "" {
|
||||
schema_clause = fmt.Sprintf("%s.", schema)
|
||||
}
|
||||
s := fmt.Sprintf("if object_id('%s%s') is null %s", schema_clause, table, command)
|
||||
return s
|
||||
}
|
||||
|
||||
func (d SqlServerDialect) CreateIndexSuffix() string { return "" }
|
||||
func (d SqlServerDialect) DropIndexSuffix() string { return "" }
|
||||
38
vendor/github.com/mattermost/gorp/errors.go
сгенерированный
поставляемый
38
vendor/github.com/mattermost/gorp/errors.go
сгенерированный
поставляемый
@@ -1,38 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// A non-fatal error, when a select query returns columns that do not exist
|
||||
// as fields in the struct it is being mapped to
|
||||
// TODO: discuss wether this needs an error. encoding/json silently ignores missing fields
|
||||
type NoFieldInTypeError struct {
|
||||
TypeName string
|
||||
MissingColNames []string
|
||||
}
|
||||
|
||||
func (err *NoFieldInTypeError) Error() string {
|
||||
return fmt.Sprintf("gorp: no fields %+v in type %s", err.MissingColNames, err.TypeName)
|
||||
}
|
||||
|
||||
// returns true if the error is non-fatal (ie, we shouldn't immediately return)
|
||||
func NonFatalError(err error) bool {
|
||||
switch err.(type) {
|
||||
case *NoFieldInTypeError:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
13
vendor/github.com/mattermost/gorp/go.mod
сгенерированный
поставляемый
13
vendor/github.com/mattermost/gorp/go.mod
сгенерированный
поставляемый
@@ -1,13 +0,0 @@
|
||||
module github.com/mattermost/gorp
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/go-sql-driver/mysql v1.5.0
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/onsi/ginkgo v1.13.0
|
||||
github.com/onsi/gomega v1.10.1
|
||||
github.com/ziutek/mymysql v1.5.4
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 // indirect
|
||||
)
|
||||
79
vendor/github.com/mattermost/gorp/go.sum
сгенерированный
поставляемый
79
vendor/github.com/mattermost/gorp/go.sum
сгенерированный
поставляемый
@@ -1,79 +0,0 @@
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.13.0 h1:M76yO2HkZASFjXL0HSoZJ1AYEmQxNJmY41Jx1zNUq1Y=
|
||||
github.com/onsi/ginkgo v1.13.0/go.mod h1:+REjRxOmWfHCjfv9TTWB1jD1Frx4XydAD3zm1lskyM0=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/sclevine/agouti v3.0.0+incompatible/go.mod h1:b4WX9W9L1sfQKXeJf1mUTLZKJ48R1S7H23Ji7oFO5Bw=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7 h1:AeiKBIuRw3UomYXSbLy0Mc2dDLfdtbT/IVn4keq83P0=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e h1:N7DeIrjYszNmSW409R3frPPwglRwMkXSBzwVbkOjLLA=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299 h1:DYfZAGf2WMFjMxbgTjaC+2HC7NkNAQs+6Q8b9WEB/F4=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80=
|
||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
608
vendor/github.com/mattermost/gorp/gorp.go
сгенерированный
поставляемый
608
vendor/github.com/mattermost/gorp/gorp.go
сгенерированный
поставляемый
@@ -1,608 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
//
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// OracleString (empty string is null)
|
||||
// TODO: move to dialect/oracle?, rename to String?
|
||||
type OracleString struct {
|
||||
sql.NullString
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (os *OracleString) Scan(value interface{}) error {
|
||||
if value == nil {
|
||||
os.String, os.Valid = "", false
|
||||
return nil
|
||||
}
|
||||
os.Valid = true
|
||||
return os.NullString.Scan(value)
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (os OracleString) Value() (driver.Value, error) {
|
||||
if !os.Valid || os.String == "" {
|
||||
return nil, nil
|
||||
}
|
||||
return os.String, nil
|
||||
}
|
||||
|
||||
// SqlTyper is a type that returns its database type. Most of the
|
||||
// time, the type can just use "database/sql/driver".Valuer; but when
|
||||
// it returns nil for its empty value, it needs to implement SqlTyper
|
||||
// to have its column type detected properly during table creation.
|
||||
type SqlTyper interface {
|
||||
SqlType() driver.Valuer
|
||||
}
|
||||
|
||||
// for fields that exists in DB table, but not exists in struct
|
||||
type dummyField struct{}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (nt *dummyField) Scan(value interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var zeroVal reflect.Value
|
||||
var versFieldConst = "[gorp_ver_field]"
|
||||
|
||||
// The TypeConverter interface provides a way to map a value of one
|
||||
// type to another type when persisting to, or loading from, a database.
|
||||
//
|
||||
// Example use cases: Implement type converter to convert bool types to "y"/"n" strings,
|
||||
// or serialize a struct member as a JSON blob.
|
||||
type TypeConverter interface {
|
||||
// ToDb converts val to another type. Called before INSERT/UPDATE operations
|
||||
ToDb(val interface{}) (interface{}, error)
|
||||
|
||||
// FromDb returns a CustomScanner appropriate for this type. This will be used
|
||||
// to hold values returned from SELECT queries.
|
||||
//
|
||||
// In particular the CustomScanner returned should implement a Binder
|
||||
// function appropriate for the Go type you wish to convert the db value to
|
||||
//
|
||||
// If bool==false, then no custom scanner will be used for this field.
|
||||
FromDb(target interface{}) (CustomScanner, bool)
|
||||
}
|
||||
|
||||
// Executor exposes the sql.DB and sql.Tx Exec function so that it can be used
|
||||
// on internal functions that convert named parameters for the Exec function.
|
||||
type executor interface {
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// SqlExecutor exposes gorp operations that can be run from Pre/Post
|
||||
// hooks. This hides whether the current operation that triggered the
|
||||
// hook is in a transaction.
|
||||
//
|
||||
// See the DbMap function docs for each of the functions below for more
|
||||
// information.
|
||||
type SqlExecutor interface {
|
||||
Get(i interface{}, keys ...interface{}) (interface{}, error)
|
||||
Insert(list ...interface{}) error
|
||||
Update(list ...interface{}) (int64, error)
|
||||
Delete(list ...interface{}) (int64, error)
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
ExecNoTimeout(query string, args ...interface{}) (sql.Result, error)
|
||||
Select(i interface{}, query string,
|
||||
args ...interface{}) ([]interface{}, error)
|
||||
SelectInt(query string, args ...interface{}) (int64, error)
|
||||
SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error)
|
||||
SelectFloat(query string, args ...interface{}) (float64, error)
|
||||
SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error)
|
||||
SelectStr(query string, args ...interface{}) (string, error)
|
||||
SelectNullStr(query string, args ...interface{}) (sql.NullString, error)
|
||||
SelectOne(holder interface{}, query string, args ...interface{}) error
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||
QueryRow(query string, args ...interface{}) *sql.Row
|
||||
QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row
|
||||
}
|
||||
|
||||
// DynamicTable allows the users of gorp to dynamically
|
||||
// use different database table names during runtime
|
||||
// while sharing the same golang struct for in-memory data
|
||||
type DynamicTable interface {
|
||||
TableName() string
|
||||
SetTableName(string)
|
||||
}
|
||||
|
||||
// Compile-time check that DbMap and Transaction implement the SqlExecutor
|
||||
// interface.
|
||||
var _, _ SqlExecutor = &DbMap{}, &Transaction{}
|
||||
|
||||
func argsString(args ...interface{}) string {
|
||||
var margs string
|
||||
for i, a := range args {
|
||||
var v interface{} = a
|
||||
if x, ok := v.(driver.Valuer); ok {
|
||||
y, err := x.Value()
|
||||
if err == nil {
|
||||
v = y
|
||||
}
|
||||
}
|
||||
switch v.(type) {
|
||||
case string:
|
||||
v = fmt.Sprintf("%q", v)
|
||||
default:
|
||||
v = fmt.Sprintf("%v", v)
|
||||
}
|
||||
margs += fmt.Sprintf("%d:%s", i+1, v)
|
||||
if i+1 < len(args) {
|
||||
margs += " "
|
||||
}
|
||||
}
|
||||
return margs
|
||||
}
|
||||
|
||||
// Calls the Exec function on the executor, but attempts to expand any eligible named
|
||||
// query arguments first.
|
||||
func exec(e SqlExecutor, query string, doTimeout bool, args ...interface{}) (sql.Result, error) {
|
||||
var dbMap *DbMap
|
||||
var executor executor
|
||||
switch m := e.(type) {
|
||||
case *DbMap:
|
||||
executor = m.Db
|
||||
dbMap = m
|
||||
case *Transaction:
|
||||
executor = m.tx
|
||||
dbMap = m.dbmap
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
query, args = maybeExpandNamedQuery(dbMap, query, args)
|
||||
}
|
||||
|
||||
if doTimeout {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dbMap.QueryTimeout)
|
||||
defer cancel()
|
||||
return executor.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
return executor.Exec(query, args...)
|
||||
}
|
||||
|
||||
// maybeExpandNamedQuery checks the given arg to see if it's eligible to be used
|
||||
// as input to a named query. If so, it rewrites the query to use
|
||||
// dialect-dependent bindvars and instantiates the corresponding slice of
|
||||
// parameters by extracting data from the map / struct.
|
||||
// If not, returns the input values unchanged.
|
||||
func maybeExpandNamedQuery(m *DbMap, query string, args []interface{}) (string, []interface{}) {
|
||||
var (
|
||||
arg = args[0]
|
||||
argval = reflect.ValueOf(arg)
|
||||
)
|
||||
if argval.Kind() == reflect.Ptr {
|
||||
argval = argval.Elem()
|
||||
}
|
||||
|
||||
if argval.Kind() == reflect.Map && argval.Type().Key().Kind() == reflect.String {
|
||||
return expandNamedQuery(m, query, func(key string) reflect.Value {
|
||||
return argval.MapIndex(reflect.ValueOf(key))
|
||||
})
|
||||
}
|
||||
if argval.Kind() != reflect.Struct {
|
||||
return query, args
|
||||
}
|
||||
if _, ok := arg.(time.Time); ok {
|
||||
// time.Time is driver.Value
|
||||
return query, args
|
||||
}
|
||||
if _, ok := arg.(driver.Valuer); ok {
|
||||
// driver.Valuer will be converted to driver.Value.
|
||||
return query, args
|
||||
}
|
||||
|
||||
return expandNamedQuery(m, query, argval.FieldByName)
|
||||
}
|
||||
|
||||
var keyRegexp = regexp.MustCompile(`:[[:word:]]+`)
|
||||
|
||||
// expandNamedQuery accepts a query with placeholders of the form ":key", and a
|
||||
// single arg of Kind Struct or Map[string]. It returns the query with the
|
||||
// dialect's placeholders, and a slice of args ready for positional insertion
|
||||
// into the query.
|
||||
func expandNamedQuery(m *DbMap, query string, keyGetter func(key string) reflect.Value) (string, []interface{}) {
|
||||
var (
|
||||
n int
|
||||
args []interface{}
|
||||
)
|
||||
return keyRegexp.ReplaceAllStringFunc(query, func(key string) string {
|
||||
val := keyGetter(key[1:])
|
||||
if !val.IsValid() {
|
||||
return key
|
||||
}
|
||||
args = append(args, val.Interface())
|
||||
newVar := m.Dialect.BindVar(n)
|
||||
n++
|
||||
return newVar
|
||||
}), args
|
||||
}
|
||||
|
||||
func columnToFieldIndex(m *DbMap, t reflect.Type, name string, cols []string) ([][]int, error) {
|
||||
colToFieldIndex := make([][]int, len(cols))
|
||||
|
||||
// check if type t is a mapped table - if so we'll
|
||||
// check the table for column aliasing below
|
||||
tableMapped := false
|
||||
table := tableOrNil(m, t, name)
|
||||
if table != nil {
|
||||
tableMapped = true
|
||||
}
|
||||
|
||||
// Loop over column names and find field in i to bind to
|
||||
// based on column name. all returned columns must match
|
||||
// a field in the i struct
|
||||
missingColNames := []string{}
|
||||
for x := range cols {
|
||||
colName := strings.ToLower(cols[x])
|
||||
field, found := t.FieldByNameFunc(func(fieldName string) bool {
|
||||
field, _ := t.FieldByName(fieldName)
|
||||
cArguments := strings.Split(field.Tag.Get("db"), ",")
|
||||
fieldName = cArguments[0]
|
||||
|
||||
if fieldName == "" || fieldName == "-" {
|
||||
fieldName = field.Name
|
||||
}
|
||||
if tableMapped {
|
||||
colMap := colMapOrNil(table, fieldName)
|
||||
if colMap != nil && colMap.ColumnName != "-" {
|
||||
fieldName = colMap.ColumnName
|
||||
}
|
||||
}
|
||||
return colName == strings.ToLower(fieldName)
|
||||
})
|
||||
if found {
|
||||
colToFieldIndex[x] = field.Index
|
||||
}
|
||||
if colToFieldIndex[x] == nil {
|
||||
missingColNames = append(missingColNames, colName)
|
||||
}
|
||||
}
|
||||
if len(missingColNames) > 0 {
|
||||
return colToFieldIndex, &NoFieldInTypeError{
|
||||
TypeName: t.Name(),
|
||||
MissingColNames: missingColNames,
|
||||
}
|
||||
}
|
||||
return colToFieldIndex, nil
|
||||
}
|
||||
|
||||
func fieldByName(val reflect.Value, fieldName string) *reflect.Value {
|
||||
// try to find field by exact match
|
||||
f := val.FieldByName(fieldName)
|
||||
|
||||
if f != zeroVal {
|
||||
return &f
|
||||
}
|
||||
|
||||
// try to find by case insensitive match - only the Postgres driver
|
||||
// seems to require this - in the case where columns are aliased in the sql
|
||||
fieldNameL := strings.ToLower(fieldName)
|
||||
fieldCount := val.NumField()
|
||||
t := val.Type()
|
||||
for i := 0; i < fieldCount; i++ {
|
||||
sf := t.Field(i)
|
||||
if strings.ToLower(sf.Name) == fieldNameL {
|
||||
f := val.Field(i)
|
||||
return &f
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// toSliceType returns the element type of the given object, if the object is a
|
||||
// "*[]*Element" or "*[]Element". If not, returns nil.
|
||||
// err is returned if the user was trying to pass a pointer-to-slice but failed.
|
||||
func toSliceType(i interface{}) (reflect.Type, error) {
|
||||
t := reflect.TypeOf(i)
|
||||
if t.Kind() != reflect.Ptr {
|
||||
// If it's a slice, return a more helpful error message
|
||||
if t.Kind() == reflect.Slice {
|
||||
return nil, fmt.Errorf("gorp: cannot SELECT into a non-pointer slice: %v", t)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
if t = t.Elem(); t.Kind() != reflect.Slice {
|
||||
return nil, nil
|
||||
}
|
||||
return t.Elem(), nil
|
||||
}
|
||||
|
||||
func toType(i interface{}) (reflect.Type, error) {
|
||||
t := reflect.TypeOf(i)
|
||||
|
||||
// If a Pointer to a type, follow
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("gorp: cannot SELECT into this type: %v", reflect.TypeOf(i))
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
type foundTable struct {
|
||||
table *TableMap
|
||||
dynName *string
|
||||
}
|
||||
|
||||
func tableFor(m *DbMap, t reflect.Type, i interface{}) (*foundTable, error) {
|
||||
if dyn, isDynamic := i.(DynamicTable); isDynamic {
|
||||
tableName := dyn.TableName()
|
||||
table, err := m.DynamicTableFor(tableName, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &foundTable{
|
||||
table: table,
|
||||
dynName: &tableName,
|
||||
}, nil
|
||||
}
|
||||
table, err := m.TableFor(t, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &foundTable{table: table}, nil
|
||||
}
|
||||
|
||||
func get(m *DbMap, exec SqlExecutor, i interface{},
|
||||
keys ...interface{}) (interface{}, error) {
|
||||
|
||||
t, err := toType(i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
foundTable, err := tableFor(m, t, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
table := foundTable.table
|
||||
|
||||
plan := table.bindGet()
|
||||
|
||||
v := reflect.New(t)
|
||||
if foundTable.dynName != nil {
|
||||
retDyn := v.Interface().(DynamicTable)
|
||||
retDyn.SetTableName(*foundTable.dynName)
|
||||
}
|
||||
|
||||
dest := make([]interface{}, len(plan.argFields))
|
||||
|
||||
conv := m.TypeConverter
|
||||
custScan := make([]CustomScanner, 0)
|
||||
|
||||
for x, fieldName := range plan.argFields {
|
||||
f := v.Elem().FieldByName(fieldName)
|
||||
target := f.Addr().Interface()
|
||||
if conv != nil {
|
||||
scanner, ok := conv.FromDb(target)
|
||||
if ok {
|
||||
target = scanner.Holder
|
||||
custScan = append(custScan, scanner)
|
||||
}
|
||||
}
|
||||
dest[x] = target
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), m.QueryTimeout)
|
||||
defer cancel()
|
||||
row := exec.QueryRowContext(ctx, plan.query, keys...)
|
||||
|
||||
err = row.Scan(dest...)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range custScan {
|
||||
err = c.Bind()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := v.Interface().(HasPostGet); ok {
|
||||
err := v.PostGet(exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return v.Interface(), nil
|
||||
}
|
||||
|
||||
func delete(m *DbMap, exec SqlExecutor, list ...interface{}) (int64, error) {
|
||||
count := int64(0)
|
||||
for _, ptr := range list {
|
||||
table, elem, err := m.tableForPointer(ptr, true)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
eval := elem.Addr().Interface()
|
||||
if v, ok := eval.(HasPreDelete); ok {
|
||||
err = v.PreDelete(exec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
bi, err := table.bindDelete(elem)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
res, err := exec.Exec(bi.query, bi.args...)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if rows == 0 && bi.existingVersion > 0 {
|
||||
return lockError(m, exec, table.TableName,
|
||||
bi.existingVersion, elem, bi.keys...)
|
||||
}
|
||||
|
||||
count += rows
|
||||
|
||||
if v, ok := eval.(HasPostDelete); ok {
|
||||
err := v.PostDelete(exec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func update(m *DbMap, exec SqlExecutor, colFilter ColumnFilter, list ...interface{}) (int64, error) {
|
||||
count := int64(0)
|
||||
for _, ptr := range list {
|
||||
table, elem, err := m.tableForPointer(ptr, true)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
eval := elem.Addr().Interface()
|
||||
if v, ok := eval.(HasPreUpdate); ok {
|
||||
err = v.PreUpdate(exec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
|
||||
bi, err := table.bindUpdate(elem, colFilter)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
res, err := exec.Exec(bi.query, bi.args...)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
if rows == 0 && bi.existingVersion > 0 {
|
||||
return lockError(m, exec, table.TableName,
|
||||
bi.existingVersion, elem, bi.keys...)
|
||||
}
|
||||
|
||||
if bi.versField != "" {
|
||||
elem.FieldByName(bi.versField).SetInt(bi.existingVersion + 1)
|
||||
}
|
||||
|
||||
count += rows
|
||||
|
||||
if v, ok := eval.(HasPostUpdate); ok {
|
||||
err = v.PostUpdate(exec)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return count, nil
|
||||
}
|
||||
|
||||
func insert(m *DbMap, exec SqlExecutor, list ...interface{}) error {
|
||||
for _, ptr := range list {
|
||||
table, elem, err := m.tableForPointer(ptr, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eval := elem.Addr().Interface()
|
||||
if v, ok := eval.(HasPreInsert); ok {
|
||||
err := v.PreInsert(exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
bi, err := table.bindInsert(elem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bi.autoIncrIdx > -1 {
|
||||
f := elem.FieldByName(bi.autoIncrFieldName)
|
||||
switch inserter := m.Dialect.(type) {
|
||||
case IntegerAutoIncrInserter:
|
||||
id, err := inserter.InsertAutoIncr(exec, bi.query, bi.args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k := f.Kind()
|
||||
if (k == reflect.Int) || (k == reflect.Int16) || (k == reflect.Int32) || (k == reflect.Int64) {
|
||||
f.SetInt(id)
|
||||
} else if (k == reflect.Uint) || (k == reflect.Uint16) || (k == reflect.Uint32) || (k == reflect.Uint64) {
|
||||
f.SetUint(uint64(id))
|
||||
} else {
|
||||
return fmt.Errorf("gorp: cannot set autoincrement value on non-Int field. SQL=%s autoIncrIdx=%d autoIncrFieldName=%s", bi.query, bi.autoIncrIdx, bi.autoIncrFieldName)
|
||||
}
|
||||
case TargetedAutoIncrInserter:
|
||||
err := inserter.InsertAutoIncrToTarget(exec, bi.query, f.Addr().Interface(), bi.args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case TargetQueryInserter:
|
||||
var idQuery = table.ColMap(bi.autoIncrFieldName).GeneratedIdQuery
|
||||
if idQuery == "" {
|
||||
return fmt.Errorf("gorp: cannot set %s value if its ColumnMap.GeneratedIdQuery is empty", bi.autoIncrFieldName)
|
||||
}
|
||||
err := inserter.InsertQueryToTarget(exec, bi.query, idQuery, f.Addr().Interface(), bi.args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("gorp: cannot use autoincrement fields on dialects that do not implement an autoincrementing interface")
|
||||
}
|
||||
} else {
|
||||
_, err := exec.Exec(bi.query, bi.args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := eval.(HasPostInsert); ok {
|
||||
err := v.PostInsert(exec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
49
vendor/github.com/mattermost/gorp/hooks.go
сгенерированный
поставляемый
49
vendor/github.com/mattermost/gorp/hooks.go
сгенерированный
поставляемый
@@ -1,49 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
//++ TODO v2-phase3: HasPostGet => PostGetter, HasPostDelete => PostDeleter, etc.
|
||||
|
||||
// PostUpdate() will be executed after the GET statement.
|
||||
type HasPostGet interface {
|
||||
PostGet(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PostUpdate() will be executed after the DELETE statement
|
||||
type HasPostDelete interface {
|
||||
PostDelete(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PostUpdate() will be executed after the UPDATE statement
|
||||
type HasPostUpdate interface {
|
||||
PostUpdate(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PostInsert() will be executed after the INSERT statement
|
||||
type HasPostInsert interface {
|
||||
PostInsert(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PreDelete() will be executed before the DELETE statement.
|
||||
type HasPreDelete interface {
|
||||
PreDelete(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PreUpdate() will be executed before UPDATE statement.
|
||||
type HasPreUpdate interface {
|
||||
PreUpdate(SqlExecutor) error
|
||||
}
|
||||
|
||||
// PreInsert() will be executed before INSERT statement.
|
||||
type HasPreInsert interface {
|
||||
PreInsert(SqlExecutor) error
|
||||
}
|
||||
56
vendor/github.com/mattermost/gorp/index.go
сгенерированный
поставляемый
56
vendor/github.com/mattermost/gorp/index.go
сгенерированный
поставляемый
@@ -1,56 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
// IndexMap represents a mapping between a Go struct field and a single
|
||||
// index in a table.
|
||||
// Unique and MaxSize only inform the
|
||||
// CreateTables() function and are not used by Insert/Update/Delete/Get.
|
||||
type IndexMap struct {
|
||||
// Index name in db table
|
||||
IndexName string
|
||||
|
||||
// If true, " unique" is added to create index statements.
|
||||
// Not used elsewhere
|
||||
Unique bool
|
||||
|
||||
// Index type supported by Dialect
|
||||
// Postgres: B-tree, Hash, GiST and GIN.
|
||||
// Mysql: Btree, Hash.
|
||||
// Sqlite: nil.
|
||||
IndexType string
|
||||
|
||||
// Columns name for single and multiple indexes
|
||||
columns []string
|
||||
}
|
||||
|
||||
// Rename allows you to specify the index name in the table
|
||||
//
|
||||
// Example: table.IndMap("customer_test_idx").Rename("customer_idx")
|
||||
//
|
||||
func (idx *IndexMap) Rename(indname string) *IndexMap {
|
||||
idx.IndexName = indname
|
||||
return idx
|
||||
}
|
||||
|
||||
// SetUnique adds "unique" to the create index statements for this
|
||||
// index, if b is true.
|
||||
func (idx *IndexMap) SetUnique(b bool) *IndexMap {
|
||||
idx.Unique = b
|
||||
return idx
|
||||
}
|
||||
|
||||
// SetIndexType specifies the index type supported by chousen SQL Dialect
|
||||
func (idx *IndexMap) SetIndexType(indtype string) *IndexMap {
|
||||
idx.IndexType = indtype
|
||||
return idx
|
||||
}
|
||||
63
vendor/github.com/mattermost/gorp/lockerror.go
сгенерированный
поставляемый
63
vendor/github.com/mattermost/gorp/lockerror.go
сгенерированный
поставляемый
@@ -1,63 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// OptimisticLockError is returned by Update() or Delete() if the
|
||||
// struct being modified has a Version field and the value is not equal to
|
||||
// the current value in the database
|
||||
type OptimisticLockError struct {
|
||||
// Table name where the lock error occurred
|
||||
TableName string
|
||||
|
||||
// Primary key values of the row being updated/deleted
|
||||
Keys []interface{}
|
||||
|
||||
// true if a row was found with those keys, indicating the
|
||||
// LocalVersion is stale. false if no value was found with those
|
||||
// keys, suggesting the row has been deleted since loaded, or
|
||||
// was never inserted to begin with
|
||||
RowExists bool
|
||||
|
||||
// Version value on the struct passed to Update/Delete. This value is
|
||||
// out of sync with the database.
|
||||
LocalVersion int64
|
||||
}
|
||||
|
||||
// Error returns a description of the cause of the lock error
|
||||
func (e OptimisticLockError) Error() string {
|
||||
if e.RowExists {
|
||||
return fmt.Sprintf("gorp: OptimisticLockError table=%s keys=%v out of date version=%d", e.TableName, e.Keys, e.LocalVersion)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("gorp: OptimisticLockError no row found for table=%s keys=%v", e.TableName, e.Keys)
|
||||
}
|
||||
|
||||
func lockError(m *DbMap, exec SqlExecutor, tableName string,
|
||||
existingVer int64, elem reflect.Value,
|
||||
keys ...interface{}) (int64, error) {
|
||||
|
||||
existing, err := get(m, exec, elem.Interface(), keys...)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
ole := OptimisticLockError{tableName, keys, true, existingVer}
|
||||
if existing == nil {
|
||||
ole.RowExists = false
|
||||
}
|
||||
return -1, ole
|
||||
}
|
||||
44
vendor/github.com/mattermost/gorp/logging.go
сгенерированный
поставляемый
44
vendor/github.com/mattermost/gorp/logging.go
сгенерированный
поставляемый
@@ -1,44 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import "fmt"
|
||||
|
||||
type GorpLogger interface {
|
||||
Printf(format string, v ...interface{})
|
||||
}
|
||||
|
||||
// TraceOn turns on SQL statement logging for this DbMap. After this is
|
||||
// called, all SQL statements will be sent to the logger. If prefix is
|
||||
// a non-empty string, it will be written to the front of all logged
|
||||
// strings, which can aid in filtering log lines.
|
||||
//
|
||||
// Use TraceOn if you want to spy on the SQL statements that gorp
|
||||
// generates.
|
||||
//
|
||||
// Note that the base log.Logger type satisfies GorpLogger, but adapters can
|
||||
// easily be written for other logging packages (e.g., the golang-sanctioned
|
||||
// glog framework).
|
||||
func (m *DbMap) TraceOn(prefix string, logger GorpLogger) {
|
||||
m.logger = logger
|
||||
if prefix == "" {
|
||||
m.logPrefix = prefix
|
||||
} else {
|
||||
m.logPrefix = fmt.Sprintf("%s ", prefix)
|
||||
}
|
||||
}
|
||||
|
||||
// TraceOff turns off tracing. It is idempotent.
|
||||
func (m *DbMap) TraceOff() {
|
||||
m.logger = nil
|
||||
m.logPrefix = ""
|
||||
}
|
||||
70
vendor/github.com/mattermost/gorp/nulltypes.go
сгенерированный
поставляемый
70
vendor/github.com/mattermost/gorp/nulltypes.go
сгенерированный
поставляемый
@@ -1,70 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A nullable Time value
|
||||
type NullTime struct {
|
||||
Time time.Time
|
||||
Valid bool // Valid is true if Time is not NULL
|
||||
}
|
||||
|
||||
// Scan implements the Scanner interface.
|
||||
func (nt *NullTime) Scan(value interface{}) error {
|
||||
switch t := value.(type) {
|
||||
case time.Time:
|
||||
nt.Time, nt.Valid = t, true
|
||||
case []byte:
|
||||
v := strToTime(string(t))
|
||||
if v != nil {
|
||||
nt.Valid = true
|
||||
nt.Time = *v
|
||||
}
|
||||
case string:
|
||||
v := strToTime(t)
|
||||
if v != nil {
|
||||
nt.Valid = true
|
||||
nt.Time = *v
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func strToTime(v string) *time.Time {
|
||||
for _, dtfmt := range []string{
|
||||
"2006-01-02 15:04:05.999999999",
|
||||
"2006-01-02T15:04:05.999999999",
|
||||
"2006-01-02 15:04:05",
|
||||
"2006-01-02T15:04:05",
|
||||
"2006-01-02 15:04",
|
||||
"2006-01-02T15:04",
|
||||
"2006-01-02",
|
||||
"2006-01-02 15:04:05-07:00",
|
||||
} {
|
||||
if t, err := time.Parse(dtfmt, v); err == nil {
|
||||
return &t
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value implements the driver Valuer interface.
|
||||
func (nt NullTime) Value() (driver.Value, error) {
|
||||
if !nt.Valid {
|
||||
return nil, nil
|
||||
}
|
||||
return nt.Time, nil
|
||||
}
|
||||
372
vendor/github.com/mattermost/gorp/select.go
сгенерированный
поставляемый
372
vendor/github.com/mattermost/gorp/select.go
сгенерированный
поставляемый
@@ -1,372 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// SelectInt executes the given query, which should be a SELECT statement for a single
|
||||
// integer column, and returns the value of the first row returned. If no rows are
|
||||
// found, zero is returned.
|
||||
func SelectInt(e SqlExecutor, query string, args ...interface{}) (int64, error) {
|
||||
var h int64
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return 0, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectNullInt executes the given query, which should be a SELECT statement for a single
|
||||
// integer column, and returns the value of the first row returned. If no rows are
|
||||
// found, the empty sql.NullInt64 value is returned.
|
||||
func SelectNullInt(e SqlExecutor, query string, args ...interface{}) (sql.NullInt64, error) {
|
||||
var h sql.NullInt64
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return h, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectFloat executes the given query, which should be a SELECT statement for a single
|
||||
// float column, and returns the value of the first row returned. If no rows are
|
||||
// found, zero is returned.
|
||||
func SelectFloat(e SqlExecutor, query string, args ...interface{}) (float64, error) {
|
||||
var h float64
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return 0, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectNullFloat executes the given query, which should be a SELECT statement for a single
|
||||
// float column, and returns the value of the first row returned. If no rows are
|
||||
// found, the empty sql.NullInt64 value is returned.
|
||||
func SelectNullFloat(e SqlExecutor, query string, args ...interface{}) (sql.NullFloat64, error) {
|
||||
var h sql.NullFloat64
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return h, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectStr executes the given query, which should be a SELECT statement for a single
|
||||
// char/varchar column, and returns the value of the first row returned. If no rows are
|
||||
// found, an empty string is returned.
|
||||
func SelectStr(e SqlExecutor, query string, args ...interface{}) (string, error) {
|
||||
var h string
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return "", err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectNullStr executes the given query, which should be a SELECT
|
||||
// statement for a single char/varchar column, and returns the value
|
||||
// of the first row returned. If no rows are found, the empty
|
||||
// sql.NullString is returned.
|
||||
func SelectNullStr(e SqlExecutor, query string, args ...interface{}) (sql.NullString, error) {
|
||||
var h sql.NullString
|
||||
err := selectVal(e, &h, query, args...)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return h, err
|
||||
}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// SelectOne executes the given query (which should be a SELECT statement)
|
||||
// and binds the result to holder, which must be a pointer.
|
||||
//
|
||||
// If no row is found, an error (sql.ErrNoRows specifically) will be returned
|
||||
//
|
||||
// If more than one row is found, an error will be returned.
|
||||
//
|
||||
func SelectOne(m *DbMap, e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
|
||||
t := reflect.TypeOf(holder)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
} else {
|
||||
return fmt.Errorf("gorp: SelectOne holder must be a pointer, but got: %t", holder)
|
||||
}
|
||||
|
||||
// Handle pointer to pointer
|
||||
isptr := false
|
||||
if t.Kind() == reflect.Ptr {
|
||||
isptr = true
|
||||
t = t.Elem()
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Struct {
|
||||
var nonFatalErr error
|
||||
|
||||
list, err := hookedselect(m, e, holder, query, args...)
|
||||
if err != nil {
|
||||
if !NonFatalError(err) { // FIXME: double negative, rename NonFatalError to FatalError
|
||||
return err
|
||||
}
|
||||
nonFatalErr = err
|
||||
}
|
||||
|
||||
dest := reflect.ValueOf(holder)
|
||||
if isptr {
|
||||
dest = dest.Elem()
|
||||
}
|
||||
|
||||
if list != nil && len(list) > 0 { // FIXME: invert if/else
|
||||
// check for multiple rows
|
||||
if len(list) > 1 {
|
||||
return fmt.Errorf("gorp: multiple rows returned for: %s - %v", query, args)
|
||||
}
|
||||
|
||||
// Initialize if nil
|
||||
if dest.IsNil() {
|
||||
dest.Set(reflect.New(t))
|
||||
}
|
||||
|
||||
// only one row found
|
||||
src := reflect.ValueOf(list[0])
|
||||
dest.Elem().Set(src.Elem())
|
||||
} else {
|
||||
// No rows found, return a proper error.
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
return nonFatalErr
|
||||
}
|
||||
|
||||
return selectVal(e, holder, query, args...)
|
||||
}
|
||||
|
||||
func selectVal(e SqlExecutor, holder interface{}, query string, args ...interface{}) error {
|
||||
var dbMap *DbMap
|
||||
switch m := e.(type) {
|
||||
case *DbMap:
|
||||
dbMap = m
|
||||
case *Transaction:
|
||||
dbMap = m.dbmap
|
||||
}
|
||||
|
||||
if len(args) == 1 {
|
||||
query, args = maybeExpandNamedQuery(dbMap, query, args)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), dbMap.QueryTimeout)
|
||||
defer cancel()
|
||||
rows, err := e.QueryContext(ctx, query, args...)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
if !rows.Next() {
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
return rows.Scan(holder)
|
||||
}
|
||||
|
||||
func hookedselect(m *DbMap, exec SqlExecutor, i interface{}, query string,
|
||||
args ...interface{}) ([]interface{}, error) {
|
||||
|
||||
list, err := rawselect(m, exec, i, query, args...)
|
||||
if err != nil {
|
||||
if !NonFatalError(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Determine where the results are: written to i, or returned in list
|
||||
if t, _ := toSliceType(i); t == nil {
|
||||
for _, v := range list {
|
||||
if v, ok := v.(HasPostGet); ok {
|
||||
err := v.PostGet(exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
resultsValue := reflect.Indirect(reflect.ValueOf(i))
|
||||
for i := 0; i < resultsValue.Len(); i++ {
|
||||
if v, ok := resultsValue.Index(i).Interface().(HasPostGet); ok {
|
||||
err := v.PostGet(exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func rawselect(m *DbMap, exec SqlExecutor, i interface{}, query string,
|
||||
args ...interface{}) ([]interface{}, error) {
|
||||
var (
|
||||
appendToSlice = false // Write results to i directly?
|
||||
intoStruct = true // Selecting into a struct?
|
||||
pointerElements = true // Are the slice elements pointers (vs values)?
|
||||
)
|
||||
|
||||
var nonFatalErr error
|
||||
|
||||
tableName := ""
|
||||
var dynObj DynamicTable
|
||||
isDynamic := false
|
||||
if dynObj, isDynamic = i.(DynamicTable); isDynamic {
|
||||
tableName = dynObj.TableName()
|
||||
}
|
||||
|
||||
// get type for i, verifying it's a supported destination
|
||||
t, err := toType(i)
|
||||
if err != nil {
|
||||
var err2 error
|
||||
if t, err2 = toSliceType(i); t == nil {
|
||||
if err2 != nil {
|
||||
return nil, err2
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
pointerElements = t.Kind() == reflect.Ptr
|
||||
if pointerElements {
|
||||
t = t.Elem()
|
||||
}
|
||||
appendToSlice = true
|
||||
intoStruct = t.Kind() == reflect.Struct
|
||||
}
|
||||
|
||||
// If the caller supplied a single struct/map argument, assume a "named
|
||||
// parameter" query. Extract the named arguments from the struct/map, create
|
||||
// the flat arg slice, and rewrite the query to use the dialect's placeholder.
|
||||
if len(args) == 1 {
|
||||
query, args = maybeExpandNamedQuery(m, query, args)
|
||||
}
|
||||
|
||||
// Run the query
|
||||
ctx, cancel := context.WithTimeout(context.Background(), m.QueryTimeout)
|
||||
defer cancel()
|
||||
rows, err := exec.QueryContext(ctx, query, args...)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// Fetch the column names as returned from db
|
||||
cols, err := rows.Columns()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !intoStruct && len(cols) > 1 {
|
||||
return nil, fmt.Errorf("gorp: select into non-struct slice requires 1 column, got %d", len(cols))
|
||||
}
|
||||
|
||||
var colToFieldIndex [][]int
|
||||
if intoStruct {
|
||||
colToFieldIndex, err = columnToFieldIndex(m, t, tableName, cols)
|
||||
if err != nil {
|
||||
if !NonFatalError(err) {
|
||||
return nil, err
|
||||
}
|
||||
nonFatalErr = err
|
||||
}
|
||||
}
|
||||
|
||||
conv := m.TypeConverter
|
||||
|
||||
// Add results to one of these two slices.
|
||||
var (
|
||||
list = make([]interface{}, 0)
|
||||
sliceValue = reflect.Indirect(reflect.ValueOf(i))
|
||||
)
|
||||
|
||||
for {
|
||||
if !rows.Next() {
|
||||
// if error occured return rawselect
|
||||
if rows.Err() != nil {
|
||||
return nil, rows.Err()
|
||||
}
|
||||
// time to exit from outer "for" loop
|
||||
break
|
||||
}
|
||||
v := reflect.New(t)
|
||||
|
||||
if isDynamic {
|
||||
v.Interface().(DynamicTable).SetTableName(tableName)
|
||||
}
|
||||
|
||||
dest := make([]interface{}, len(cols))
|
||||
|
||||
custScan := make([]CustomScanner, 0)
|
||||
|
||||
for x := range cols {
|
||||
f := v.Elem()
|
||||
if intoStruct {
|
||||
index := colToFieldIndex[x]
|
||||
if index == nil {
|
||||
// this field is not present in the struct, so create a dummy
|
||||
// value for rows.Scan to scan into
|
||||
var dummy dummyField
|
||||
dest[x] = &dummy
|
||||
continue
|
||||
}
|
||||
f = f.FieldByIndex(index)
|
||||
}
|
||||
target := f.Addr().Interface()
|
||||
if conv != nil {
|
||||
scanner, ok := conv.FromDb(target)
|
||||
if ok {
|
||||
target = scanner.Holder
|
||||
custScan = append(custScan, scanner)
|
||||
}
|
||||
}
|
||||
dest[x] = target
|
||||
}
|
||||
|
||||
err = rows.Scan(dest...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, c := range custScan {
|
||||
err = c.Bind()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if appendToSlice {
|
||||
if !pointerElements {
|
||||
v = v.Elem()
|
||||
}
|
||||
sliceValue.Set(reflect.Append(sliceValue, v))
|
||||
} else {
|
||||
list = append(list, v.Interface())
|
||||
}
|
||||
}
|
||||
|
||||
if appendToSlice && sliceValue.IsNil() {
|
||||
sliceValue.Set(reflect.MakeSlice(sliceValue.Type(), 0, 0))
|
||||
}
|
||||
|
||||
return list, nonFatalErr
|
||||
}
|
||||
271
vendor/github.com/mattermost/gorp/table.go
сгенерированный
поставляемый
271
vendor/github.com/mattermost/gorp/table.go
сгенерированный
поставляемый
@@ -1,271 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TableMap represents a mapping between a Go struct and a database table
|
||||
// Use dbmap.AddTable() or dbmap.AddTableWithName() to create these
|
||||
type TableMap struct {
|
||||
// Name of database table.
|
||||
TableName string
|
||||
SchemaName string
|
||||
gotype reflect.Type
|
||||
Columns []*ColumnMap
|
||||
keys []*ColumnMap
|
||||
indexes []*IndexMap
|
||||
uniqueTogether [][]string
|
||||
version *ColumnMap
|
||||
insertPlan bindPlan
|
||||
updatePlan bindPlan
|
||||
deletePlan bindPlan
|
||||
getPlan bindPlan
|
||||
dbmap *DbMap
|
||||
}
|
||||
|
||||
// ResetSql removes cached insert/update/select/delete SQL strings
|
||||
// associated with this TableMap. Call this if you've modified
|
||||
// any column names or the table name itself.
|
||||
func (t *TableMap) ResetSql() {
|
||||
t.insertPlan = bindPlan{}
|
||||
t.updatePlan = bindPlan{}
|
||||
t.deletePlan = bindPlan{}
|
||||
t.getPlan = bindPlan{}
|
||||
}
|
||||
|
||||
// SetKeys lets you specify the fields on a struct that map to primary
|
||||
// key columns on the table. If isAutoIncr is set, result.LastInsertId()
|
||||
// will be used after INSERT to bind the generated id to the Go struct.
|
||||
//
|
||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||
//
|
||||
// Panics if isAutoIncr is true, and fieldNames length != 1
|
||||
//
|
||||
func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
|
||||
if isAutoIncr && len(fieldNames) != 1 {
|
||||
panic(fmt.Sprintf(
|
||||
"gorp: SetKeys: fieldNames length must be 1 if key is auto-increment. (Saw %v fieldNames)",
|
||||
len(fieldNames)))
|
||||
}
|
||||
t.keys = make([]*ColumnMap, 0)
|
||||
for _, name := range fieldNames {
|
||||
colmap := t.ColMap(name)
|
||||
colmap.isPK = true
|
||||
colmap.isAutoIncr = isAutoIncr
|
||||
t.keys = append(t.keys, colmap)
|
||||
}
|
||||
t.ResetSql()
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// SetUniqueTogether lets you specify uniqueness constraints across multiple
|
||||
// columns on the table. Each call adds an additional constraint for the
|
||||
// specified columns.
|
||||
//
|
||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||
//
|
||||
// Panics if fieldNames length < 2.
|
||||
//
|
||||
func (t *TableMap) SetUniqueTogether(fieldNames ...string) *TableMap {
|
||||
if len(fieldNames) < 2 {
|
||||
panic(fmt.Sprintf(
|
||||
"gorp: SetUniqueTogether: must provide at least two fieldNames to set uniqueness constraint."))
|
||||
}
|
||||
|
||||
columns := make([]string, 0, len(fieldNames))
|
||||
for _, name := range fieldNames {
|
||||
columns = append(columns, name)
|
||||
}
|
||||
|
||||
alreadyExists := false
|
||||
checkDuplicates:
|
||||
for _, existingColumns := range t.uniqueTogether {
|
||||
if len(existingColumns) == len(columns) {
|
||||
for i := range columns {
|
||||
if existingColumns[i] != columns[i] {
|
||||
continue checkDuplicates
|
||||
}
|
||||
}
|
||||
|
||||
alreadyExists = true
|
||||
break checkDuplicates
|
||||
}
|
||||
}
|
||||
if !alreadyExists {
|
||||
t.uniqueTogether = append(t.uniqueTogether, columns)
|
||||
t.ResetSql()
|
||||
}
|
||||
|
||||
return t
|
||||
}
|
||||
|
||||
// ColMap returns the ColumnMap pointer matching the given struct field
|
||||
// name. It panics if the struct does not contain a field matching this
|
||||
// name.
|
||||
func (t *TableMap) ColMap(field string) *ColumnMap {
|
||||
col := colMapOrNil(t, field)
|
||||
if col == nil {
|
||||
e := fmt.Sprintf("No ColumnMap in table %s type %s with field %s",
|
||||
t.TableName, t.gotype.Name(), field)
|
||||
|
||||
panic(e)
|
||||
}
|
||||
return col
|
||||
}
|
||||
|
||||
func colMapOrNil(t *TableMap, field string) *ColumnMap {
|
||||
for _, col := range t.Columns {
|
||||
if col.fieldName == field || col.ColumnName == field {
|
||||
return col
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IdxMap returns the IndexMap pointer matching the given index name.
|
||||
func (t *TableMap) IdxMap(field string) *IndexMap {
|
||||
for _, idx := range t.indexes {
|
||||
if idx.IndexName == field {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddIndex registers the index with gorp for specified table with given parameters.
|
||||
// This operation is idempotent. If index is already mapped, the
|
||||
// existing *IndexMap is returned
|
||||
// Function will panic if one of the given for index columns does not exists
|
||||
//
|
||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||
//
|
||||
func (t *TableMap) AddIndex(name string, idxtype string, columns []string) *IndexMap {
|
||||
// check if we have a index with this name already
|
||||
for _, idx := range t.indexes {
|
||||
if idx.IndexName == name {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
for _, icol := range columns {
|
||||
if res := t.ColMap(icol); res == nil {
|
||||
e := fmt.Sprintf("No ColumnName in table %s to create index on", t.TableName)
|
||||
panic(e)
|
||||
}
|
||||
}
|
||||
|
||||
idx := &IndexMap{IndexName: name, Unique: false, IndexType: idxtype, columns: columns}
|
||||
t.indexes = append(t.indexes, idx)
|
||||
t.ResetSql()
|
||||
return idx
|
||||
}
|
||||
|
||||
// SetVersionCol sets the column to use as the Version field. By default
|
||||
// the "Version" field is used. Returns the column found, or panics
|
||||
// if the struct does not contain a field matching this name.
|
||||
//
|
||||
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
|
||||
func (t *TableMap) SetVersionCol(field string) *ColumnMap {
|
||||
c := t.ColMap(field)
|
||||
t.version = c
|
||||
t.ResetSql()
|
||||
return c
|
||||
}
|
||||
|
||||
// SqlForCreateTable gets a sequence of SQL commands that will create
|
||||
// the specified table and any associated schema
|
||||
func (t *TableMap) SqlForCreate(ifNotExists bool) string {
|
||||
s := strings.Builder{}
|
||||
dialect := t.dbmap.Dialect
|
||||
|
||||
if strings.TrimSpace(t.SchemaName) != "" {
|
||||
schemaCreate := "create schema"
|
||||
if ifNotExists {
|
||||
s.WriteString(dialect.IfSchemaNotExists(schemaCreate, t.SchemaName))
|
||||
} else {
|
||||
s.WriteString(schemaCreate)
|
||||
}
|
||||
s.WriteString(fmt.Sprintf(" %s;", t.SchemaName))
|
||||
}
|
||||
|
||||
tableCreate := "create table"
|
||||
if ifNotExists {
|
||||
s.WriteString(dialect.IfTableNotExists(tableCreate, t.SchemaName, t.TableName))
|
||||
} else {
|
||||
s.WriteString(tableCreate)
|
||||
}
|
||||
s.WriteString(fmt.Sprintf(" %s (", dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
|
||||
|
||||
x := 0
|
||||
for _, col := range t.Columns {
|
||||
if !col.Transient {
|
||||
if x > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
|
||||
stype := col.DataType
|
||||
if stype == "" {
|
||||
stype = dialect.ToSqlType(col.gotype, col.MaxSize, col.isAutoIncr)
|
||||
}
|
||||
|
||||
s.WriteString(fmt.Sprintf("%s %s", dialect.QuoteField(col.ColumnName), stype))
|
||||
|
||||
if col.isPK || col.isNotNull {
|
||||
s.WriteString(" not null")
|
||||
}
|
||||
if col.DefaultConstraint != nil {
|
||||
s.WriteString(fmt.Sprintf(" default '%s'", *col.DefaultConstraint))
|
||||
}
|
||||
if col.isPK && len(t.keys) == 1 {
|
||||
s.WriteString(" primary key")
|
||||
}
|
||||
if col.Unique {
|
||||
s.WriteString(" unique")
|
||||
}
|
||||
if col.isAutoIncr {
|
||||
s.WriteString(fmt.Sprintf(" %s", dialect.AutoIncrStr()))
|
||||
}
|
||||
|
||||
x++
|
||||
}
|
||||
}
|
||||
if len(t.keys) > 1 {
|
||||
s.WriteString(", primary key (")
|
||||
for x := range t.keys {
|
||||
if x > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s.WriteString(dialect.QuoteField(t.keys[x].ColumnName))
|
||||
}
|
||||
s.WriteString(")")
|
||||
}
|
||||
if len(t.uniqueTogether) > 0 {
|
||||
for _, columns := range t.uniqueTogether {
|
||||
s.WriteString(", unique (")
|
||||
for i, column := range columns {
|
||||
if i > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s.WriteString(dialect.QuoteField(column))
|
||||
}
|
||||
s.WriteString(")")
|
||||
}
|
||||
}
|
||||
s.WriteString(") ")
|
||||
s.WriteString(dialect.CreateTableSuffix())
|
||||
s.WriteString(dialect.QuerySuffix())
|
||||
return s.String()
|
||||
}
|
||||
312
vendor/github.com/mattermost/gorp/table_bindings.go
сгенерированный
поставляемый
312
vendor/github.com/mattermost/gorp/table_bindings.go
сгенерированный
поставляемый
@@ -1,312 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// CustomScanner binds a database column value to a Go type
|
||||
type CustomScanner struct {
|
||||
// After a row is scanned, Holder will contain the value from the database column.
|
||||
// Initialize the CustomScanner with the concrete Go type you wish the database
|
||||
// driver to scan the raw column into.
|
||||
Holder interface{}
|
||||
// Target typically holds a pointer to the target struct field to bind the Holder
|
||||
// value to.
|
||||
Target interface{}
|
||||
// Binder is a custom function that converts the holder value to the target type
|
||||
// and sets target accordingly. This function should return error if a problem
|
||||
// occurs converting the holder to the target.
|
||||
Binder func(holder interface{}, target interface{}) error
|
||||
}
|
||||
|
||||
// Used to filter columns when selectively updating
|
||||
type ColumnFilter func(*ColumnMap) bool
|
||||
|
||||
func acceptAllFilter(col *ColumnMap) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Bind is called automatically by gorp after Scan()
|
||||
func (me CustomScanner) Bind() error {
|
||||
return me.Binder(me.Holder, me.Target)
|
||||
}
|
||||
|
||||
type bindPlan struct {
|
||||
query string
|
||||
argFields []string
|
||||
keyFields []string
|
||||
versField string
|
||||
autoIncrIdx int
|
||||
autoIncrFieldName string
|
||||
once sync.Once
|
||||
}
|
||||
|
||||
func (plan *bindPlan) createBindInstance(elem reflect.Value, conv TypeConverter) (bindInstance, error) {
|
||||
bi := bindInstance{query: plan.query, autoIncrIdx: plan.autoIncrIdx, autoIncrFieldName: plan.autoIncrFieldName, versField: plan.versField}
|
||||
if plan.versField != "" {
|
||||
bi.existingVersion = elem.FieldByName(plan.versField).Int()
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
for i := 0; i < len(plan.argFields); i++ {
|
||||
k := plan.argFields[i]
|
||||
if k == versFieldConst {
|
||||
newVer := bi.existingVersion + 1
|
||||
bi.args = append(bi.args, newVer)
|
||||
if bi.existingVersion == 0 {
|
||||
elem.FieldByName(plan.versField).SetInt(int64(newVer))
|
||||
}
|
||||
} else {
|
||||
val := elem.FieldByName(k).Interface()
|
||||
if conv != nil {
|
||||
val, err = conv.ToDb(val)
|
||||
if err != nil {
|
||||
return bindInstance{}, err
|
||||
}
|
||||
}
|
||||
bi.args = append(bi.args, val)
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < len(plan.keyFields); i++ {
|
||||
k := plan.keyFields[i]
|
||||
val := elem.FieldByName(k).Interface()
|
||||
if conv != nil {
|
||||
val, err = conv.ToDb(val)
|
||||
if err != nil {
|
||||
return bindInstance{}, err
|
||||
}
|
||||
}
|
||||
bi.keys = append(bi.keys, val)
|
||||
}
|
||||
|
||||
return bi, nil
|
||||
}
|
||||
|
||||
type bindInstance struct {
|
||||
query string
|
||||
args []interface{}
|
||||
keys []interface{}
|
||||
existingVersion int64
|
||||
versField string
|
||||
autoIncrIdx int
|
||||
autoIncrFieldName string
|
||||
}
|
||||
|
||||
func (t *TableMap) bindInsert(elem reflect.Value) (bindInstance, error) {
|
||||
plan := &t.insertPlan
|
||||
plan.once.Do(func() {
|
||||
plan.autoIncrIdx = -1
|
||||
|
||||
s := strings.Builder{}
|
||||
s2 := strings.Builder{}
|
||||
s.WriteString(fmt.Sprintf("insert into %s (", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
|
||||
|
||||
x := 0
|
||||
first := true
|
||||
for y := range t.Columns {
|
||||
col := t.Columns[y]
|
||||
if !(col.isAutoIncr && t.dbmap.Dialect.AutoIncrBindValue() == "") {
|
||||
if !col.Transient {
|
||||
if !first {
|
||||
s.WriteString(",")
|
||||
s2.WriteString(",")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
|
||||
|
||||
if col.isAutoIncr {
|
||||
s2.WriteString(t.dbmap.Dialect.AutoIncrBindValue())
|
||||
plan.autoIncrIdx = y
|
||||
plan.autoIncrFieldName = col.fieldName
|
||||
} else {
|
||||
if col.DefaultValue == "" {
|
||||
s2.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
if col == t.version {
|
||||
plan.versField = col.fieldName
|
||||
plan.argFields = append(plan.argFields, versFieldConst)
|
||||
} else {
|
||||
plan.argFields = append(plan.argFields, col.fieldName)
|
||||
}
|
||||
x++
|
||||
} else {
|
||||
s2.WriteString(col.DefaultValue)
|
||||
}
|
||||
}
|
||||
first = false
|
||||
}
|
||||
} else {
|
||||
plan.autoIncrIdx = y
|
||||
plan.autoIncrFieldName = col.fieldName
|
||||
}
|
||||
}
|
||||
s.WriteString(") values (")
|
||||
s.WriteString(s2.String())
|
||||
s.WriteString(")")
|
||||
if plan.autoIncrIdx > -1 {
|
||||
s.WriteString(t.dbmap.Dialect.AutoIncrInsertSuffix(t.Columns[plan.autoIncrIdx]))
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuerySuffix())
|
||||
|
||||
plan.query = s.String()
|
||||
})
|
||||
|
||||
return plan.createBindInstance(elem, t.dbmap.TypeConverter)
|
||||
}
|
||||
|
||||
func (t *TableMap) bindUpdate(elem reflect.Value, colFilter ColumnFilter) (bindInstance, error) {
|
||||
if colFilter == nil {
|
||||
colFilter = acceptAllFilter
|
||||
}
|
||||
|
||||
plan := &t.updatePlan
|
||||
plan.once.Do(func() {
|
||||
s := strings.Builder{}
|
||||
s.WriteString(fmt.Sprintf("update %s set ", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
|
||||
x := 0
|
||||
|
||||
for y := range t.Columns {
|
||||
col := t.Columns[y]
|
||||
if !col.isAutoIncr && !col.Transient && colFilter(col) {
|
||||
if x > 0 {
|
||||
s.WriteString(", ")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
|
||||
if col == t.version {
|
||||
plan.versField = col.fieldName
|
||||
plan.argFields = append(plan.argFields, versFieldConst)
|
||||
} else {
|
||||
plan.argFields = append(plan.argFields, col.fieldName)
|
||||
}
|
||||
x++
|
||||
}
|
||||
}
|
||||
|
||||
s.WriteString(" where ")
|
||||
for y := range t.keys {
|
||||
col := t.keys[y]
|
||||
if y > 0 {
|
||||
s.WriteString(" and ")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
|
||||
plan.argFields = append(plan.argFields, col.fieldName)
|
||||
plan.keyFields = append(plan.keyFields, col.fieldName)
|
||||
x++
|
||||
}
|
||||
if plan.versField != "" {
|
||||
s.WriteString(" and ")
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(t.version.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
plan.argFields = append(plan.argFields, plan.versField)
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuerySuffix())
|
||||
|
||||
plan.query = s.String()
|
||||
})
|
||||
|
||||
return plan.createBindInstance(elem, t.dbmap.TypeConverter)
|
||||
}
|
||||
|
||||
func (t *TableMap) bindDelete(elem reflect.Value) (bindInstance, error) {
|
||||
plan := &t.deletePlan
|
||||
plan.once.Do(func() {
|
||||
s := strings.Builder{}
|
||||
s.WriteString(fmt.Sprintf("delete from %s", t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
|
||||
|
||||
for y := range t.Columns {
|
||||
col := t.Columns[y]
|
||||
if !col.Transient {
|
||||
if col == t.version {
|
||||
plan.versField = col.fieldName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.WriteString(" where ")
|
||||
for x := range t.keys {
|
||||
k := t.keys[x]
|
||||
if x > 0 {
|
||||
s.WriteString(" and ")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(k.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
|
||||
plan.keyFields = append(plan.keyFields, k.fieldName)
|
||||
plan.argFields = append(plan.argFields, k.fieldName)
|
||||
}
|
||||
if plan.versField != "" {
|
||||
s.WriteString(" and ")
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(t.version.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(len(plan.argFields)))
|
||||
|
||||
plan.argFields = append(plan.argFields, plan.versField)
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuerySuffix())
|
||||
|
||||
plan.query = s.String()
|
||||
})
|
||||
|
||||
return plan.createBindInstance(elem, t.dbmap.TypeConverter)
|
||||
}
|
||||
|
||||
func (t *TableMap) bindGet() *bindPlan {
|
||||
plan := &t.getPlan
|
||||
plan.once.Do(func() {
|
||||
s := strings.Builder{}
|
||||
s.WriteString("select ")
|
||||
|
||||
x := 0
|
||||
for _, col := range t.Columns {
|
||||
if !col.Transient {
|
||||
if x > 0 {
|
||||
s.WriteString(",")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
|
||||
plan.argFields = append(plan.argFields, col.fieldName)
|
||||
x++
|
||||
}
|
||||
}
|
||||
s.WriteString(" from ")
|
||||
s.WriteString(t.dbmap.Dialect.QuotedTableForQuery(t.SchemaName, t.TableName))
|
||||
s.WriteString(" where ")
|
||||
for x := range t.keys {
|
||||
col := t.keys[x]
|
||||
if x > 0 {
|
||||
s.WriteString(" and ")
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuoteField(col.ColumnName))
|
||||
s.WriteString("=")
|
||||
s.WriteString(t.dbmap.Dialect.BindVar(x))
|
||||
|
||||
plan.keyFields = append(plan.keyFields, col.fieldName)
|
||||
}
|
||||
s.WriteString(t.dbmap.Dialect.QuerySuffix())
|
||||
|
||||
plan.query = s.String()
|
||||
})
|
||||
|
||||
return plan
|
||||
}
|
||||
219
vendor/github.com/mattermost/gorp/transaction.go
сгенерированный
поставляемый
219
vendor/github.com/mattermost/gorp/transaction.go
сгенерированный
поставляемый
@@ -1,219 +0,0 @@
|
||||
// Copyright 2012 James Cooper. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package gorp provides a simple way to marshal Go structs to and from
|
||||
// SQL databases. It uses the database/sql package, and should work with any
|
||||
// compliant database/sql driver.
|
||||
//
|
||||
// Source code and project home:
|
||||
// https://github.com/go-gorp/gorp
|
||||
|
||||
package gorp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Transaction represents a database transaction.
|
||||
// Insert/Update/Delete/Get/Exec operations will be run in the context
|
||||
// of that transaction. Transactions should be terminated with
|
||||
// a call to Commit() or Rollback()
|
||||
type Transaction struct {
|
||||
dbmap *DbMap
|
||||
tx *sql.Tx
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Insert has the same behavior as DbMap.Insert(), but runs in a transaction.
|
||||
func (t *Transaction) Insert(list ...interface{}) error {
|
||||
return insert(t.dbmap, t, list...)
|
||||
}
|
||||
|
||||
// Update had the same behavior as DbMap.Update(), but runs in a transaction.
|
||||
func (t *Transaction) Update(list ...interface{}) (int64, error) {
|
||||
return update(t.dbmap, t, nil, list...)
|
||||
}
|
||||
|
||||
// UpdateColumns had the same behavior as DbMap.UpdateColumns(), but runs in a transaction.
|
||||
func (t *Transaction) UpdateColumns(filter ColumnFilter, list ...interface{}) (int64, error) {
|
||||
return update(t.dbmap, t, filter, list...)
|
||||
}
|
||||
|
||||
// Delete has the same behavior as DbMap.Delete(), but runs in a transaction.
|
||||
func (t *Transaction) Delete(list ...interface{}) (int64, error) {
|
||||
return delete(t.dbmap, t, list...)
|
||||
}
|
||||
|
||||
// Get has the same behavior as DbMap.Get(), but runs in a transaction.
|
||||
func (t *Transaction) Get(i interface{}, keys ...interface{}) (interface{}, error) {
|
||||
return get(t.dbmap, t, i, keys...)
|
||||
}
|
||||
|
||||
// Select has the same behavior as DbMap.Select(), but runs in a transaction.
|
||||
func (t *Transaction) Select(i interface{}, query string, args ...interface{}) ([]interface{}, error) {
|
||||
return hookedselect(t.dbmap, t, i, query, args...)
|
||||
}
|
||||
|
||||
// Exec has the same behavior as DbMap.Exec(), but runs in a transaction.
|
||||
func (t *Transaction) Exec(query string, args ...interface{}) (sql.Result, error) {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return exec(t, query, true, args...)
|
||||
}
|
||||
|
||||
// ExecNoTimeout has the same behavior as DbMap.ExecNoTimeout(), but runs in a transaction.
|
||||
func (t *Transaction) ExecNoTimeout(query string, args ...interface{}) (sql.Result, error) {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return exec(t, query, false, args...)
|
||||
}
|
||||
|
||||
// SelectInt is a convenience wrapper around the gorp.SelectInt function.
|
||||
func (t *Transaction) SelectInt(query string, args ...interface{}) (int64, error) {
|
||||
return SelectInt(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullInt is a convenience wrapper around the gorp.SelectNullInt function.
|
||||
func (t *Transaction) SelectNullInt(query string, args ...interface{}) (sql.NullInt64, error) {
|
||||
return SelectNullInt(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectFloat is a convenience wrapper around the gorp.SelectFloat function.
|
||||
func (t *Transaction) SelectFloat(query string, args ...interface{}) (float64, error) {
|
||||
return SelectFloat(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullFloat is a convenience wrapper around the gorp.SelectNullFloat function.
|
||||
func (t *Transaction) SelectNullFloat(query string, args ...interface{}) (sql.NullFloat64, error) {
|
||||
return SelectNullFloat(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectStr is a convenience wrapper around the gorp.SelectStr function.
|
||||
func (t *Transaction) SelectStr(query string, args ...interface{}) (string, error) {
|
||||
return SelectStr(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectNullStr is a convenience wrapper around the gorp.SelectNullStr function.
|
||||
func (t *Transaction) SelectNullStr(query string, args ...interface{}) (sql.NullString, error) {
|
||||
return SelectNullStr(t, query, args...)
|
||||
}
|
||||
|
||||
// SelectOne is a convenience wrapper around the gorp.SelectOne function.
|
||||
func (t *Transaction) SelectOne(holder interface{}, query string, args ...interface{}) error {
|
||||
return SelectOne(t.dbmap, t, holder, query, args...)
|
||||
}
|
||||
|
||||
// Commit commits the underlying database transaction.
|
||||
func (t *Transaction) Commit() error {
|
||||
if !t.closed {
|
||||
t.closed = true
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, "commit;")
|
||||
}
|
||||
return t.tx.Commit()
|
||||
}
|
||||
|
||||
return sql.ErrTxDone
|
||||
}
|
||||
|
||||
// Rollback rolls back the underlying database transaction.
|
||||
func (t *Transaction) Rollback() error {
|
||||
if !t.closed {
|
||||
t.closed = true
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, "rollback;")
|
||||
}
|
||||
return t.tx.Rollback()
|
||||
}
|
||||
|
||||
return sql.ErrTxDone
|
||||
}
|
||||
|
||||
// Savepoint creates a savepoint with the given name. The name is interpolated
|
||||
// directly into the SQL SAVEPOINT statement, so you must sanitize it if it is
|
||||
// derived from user input.
|
||||
func (t *Transaction) Savepoint(name string) error {
|
||||
query := "savepoint " + t.dbmap.Dialect.QuoteField(name)
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, nil)
|
||||
}
|
||||
_, err := t.tx.Exec(query)
|
||||
return err
|
||||
}
|
||||
|
||||
// RollbackToSavepoint rolls back to the savepoint with the given name. The
|
||||
// name is interpolated directly into the SQL SAVEPOINT statement, so you must
|
||||
// sanitize it if it is derived from user input.
|
||||
func (t *Transaction) RollbackToSavepoint(savepoint string) error {
|
||||
query := "rollback to savepoint " + t.dbmap.Dialect.QuoteField(savepoint)
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, nil)
|
||||
}
|
||||
_, err := t.tx.Exec(query)
|
||||
return err
|
||||
}
|
||||
|
||||
// ReleaseSavepint releases the savepoint with the given name. The name is
|
||||
// interpolated directly into the SQL SAVEPOINT statement, so you must sanitize
|
||||
// it if it is derived from user input.
|
||||
func (t *Transaction) ReleaseSavepoint(savepoint string) error {
|
||||
query := "release savepoint " + t.dbmap.Dialect.QuoteField(savepoint)
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, nil)
|
||||
}
|
||||
_, err := t.tx.Exec(query)
|
||||
return err
|
||||
}
|
||||
|
||||
// Prepare has the same behavior as DbMap.Prepare(), but runs in a transaction.
|
||||
func (t *Transaction) Prepare(query string) (*sql.Stmt, error) {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, nil)
|
||||
}
|
||||
return t.tx.Prepare(query)
|
||||
}
|
||||
|
||||
func (t *Transaction) QueryRow(query string, args ...interface{}) *sql.Row {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return t.tx.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func (t *Transaction) QueryRowContext(ctx context.Context, query string, args ...interface{}) *sql.Row {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return t.tx.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
func (t *Transaction) Query(query string, args ...interface{}) (*sql.Rows, error) {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return t.tx.Query(query, args...)
|
||||
}
|
||||
|
||||
func (t *Transaction) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
|
||||
if t.dbmap.logger != nil {
|
||||
now := time.Now()
|
||||
defer t.dbmap.trace(now, query, args...)
|
||||
}
|
||||
return t.tx.QueryContext(ctx, query, args...)
|
||||
}
|
||||
5
vendor/modules.txt
поставляемый
5
vendor/modules.txt
поставляемый
@@ -387,9 +387,6 @@ github.com/mattermost/go-i18n/i18n
|
||||
github.com/mattermost/go-i18n/i18n/bundle
|
||||
github.com/mattermost/go-i18n/i18n/language
|
||||
github.com/mattermost/go-i18n/i18n/translation
|
||||
# github.com/mattermost/gorp v1.6.2-0.20210714143452-8b50f5209a7f
|
||||
## explicit
|
||||
github.com/mattermost/gorp
|
||||
# github.com/mattermost/gosaml2 v0.3.3
|
||||
## explicit
|
||||
github.com/mattermost/gosaml2
|
||||
@@ -429,6 +426,8 @@ github.com/mattn/go-isatty
|
||||
# github.com/mattn/go-runewidth v0.0.13
|
||||
## explicit
|
||||
github.com/mattn/go-runewidth
|
||||
# github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
## explicit
|
||||
# github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369
|
||||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||
# github.com/mholt/archiver/v3 v3.5.1
|
||||
|
||||
Ссылка в новой задаче
Block a user