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 := p.API.GetUnsanitizedConfig().SqlSettings
|
||||||
settings.Trace = model.NewBool(false)
|
settings.Trace = model.NewBool(false)
|
||||||
store := sqlstore.New(settings, nil)
|
store := sqlstore.New(settings, nil)
|
||||||
store.GetMaster().Db.Close()
|
store.GetMasterX().Close()
|
||||||
|
|
||||||
for _, isMaster := range []bool{true, false} {
|
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))
|
handle := sql.OpenDB(driver.NewConnector(p.Driver, isMaster))
|
||||||
store.GetMaster().Db = handle
|
|
||||||
store.SetMasterX(handle)
|
store.SetMasterX(handle)
|
||||||
|
|
||||||
wrapper := sqlstore.NewStoreTestWrapper(store)
|
wrapper := sqlstore.NewStoreTestWrapper(store)
|
||||||
@@ -49,7 +46,7 @@ func (p *MyPlugin) MessageWillBePosted(_ *plugin.Context, _ *model.Post) (*model
|
|||||||
storetest.TestChannelStore(p.t, store, wrapper)
|
storetest.TestChannelStore(p.t, store, wrapper)
|
||||||
storetest.TestBotStore(p.t, store, wrapper)
|
storetest.TestBotStore(p.t, store, wrapper)
|
||||||
|
|
||||||
store.GetMaster().Db.Close()
|
store.GetMasterX().Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the API to instantiate the driver
|
// Use the API to instantiate the driver
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ func NewDriverImpl(s *Server) *DriverImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DriverImpl) Conn(isMaster bool) (string, error) {
|
func (d *DriverImpl) Conn(isMaster bool) (string, error) {
|
||||||
dbFunc := d.s.sqlStore.GetMaster
|
dbFunc := d.s.sqlStore.GetMasterX
|
||||||
if !isMaster {
|
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer s.Shutdown()
|
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)
|
require.Len(t, s.Config().SqlSettings.DataSourceReplicas, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -103,7 +103,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer s.Shutdown()
|
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)
|
require.Len(t, s.Config().SqlSettings.DataSourceReplicas, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -116,7 +116,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer s.Shutdown()
|
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)
|
require.Len(t, s.Config().SqlSettings.DataSourceSearchReplicas, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ func TestReadReplicaDisabledBasedOnLicense(t *testing.T) {
|
|||||||
})
|
})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer s.Shutdown()
|
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)
|
require.Len(t, s.Config().SqlSettings.DataSourceSearchReplicas, 1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
@@ -80,8 +79,7 @@ func getActualDatabaseConfig(t *testing.T) (string, *model.Config) {
|
|||||||
ID string `db:"id"`
|
ID string `db:"id"`
|
||||||
Value []byte `db:"value"`
|
Value []byte `db:"value"`
|
||||||
}
|
}
|
||||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *mainHelper.GetSQLSettings().DriverName)
|
err := mainHelper.GetSQLStore().GetMasterX().Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||||
err := db.Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var actualCfg *model.Config
|
var actualCfg *model.Config
|
||||||
@@ -93,8 +91,7 @@ func getActualDatabaseConfig(t *testing.T) (string, *model.Config) {
|
|||||||
ID string `db:"Id"`
|
ID string `db:"Id"`
|
||||||
Value []byte `db:"Value"`
|
Value []byte `db:"Value"`
|
||||||
}
|
}
|
||||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *mainHelper.GetSQLSettings().DriverName)
|
err := mainHelper.GetSQLStore().GetMasterX().Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
||||||
err := db.Get(&actual, "SELECT Id, Value FROM Configurations WHERE Active")
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var actualCfg *model.Config
|
var actualCfg *model.Config
|
||||||
@@ -553,9 +550,7 @@ func TestDatabaseStoreSet(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer ds.Close()
|
defer ds.Close()
|
||||||
|
|
||||||
sqlSettings := mainHelper.GetSQLSettings()
|
_, err = mainHelper.GetSQLStore().GetMasterX().Exec("DROP TABLE Configurations")
|
||||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *sqlSettings.DriverName)
|
|
||||||
_, err = db.Exec("DROP TABLE Configurations")
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
newCfg := minimalConfig
|
newCfg := minimalConfig
|
||||||
@@ -835,16 +830,15 @@ func TestDatabaseStoreLoad(t *testing.T) {
|
|||||||
cfgData, err := marshalConfig(invalidConfig)
|
cfgData, err := marshalConfig(invalidConfig)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
sqlSettings := mainHelper.GetSQLSettings()
|
|
||||||
db := sqlx.NewDb(mainHelper.GetSQLStore().GetMaster().Db, *sqlSettings.DriverName)
|
|
||||||
truncateTables(t)
|
truncateTables(t)
|
||||||
id := model.NewId()
|
id := model.NewId()
|
||||||
_, err = db.NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:Id, :Value, :CreateAt, TRUE)", map[string]interface{}{
|
_, err = mainHelper.GetSQLStore().GetMasterX().NamedExec("INSERT INTO Configurations (Id, Value, CreateAt, Active) VALUES(:id, :value, :createat, TRUE)", map[string]interface{}{
|
||||||
"Id": id,
|
"id": id,
|
||||||
"Value": cfgData,
|
"value": cfgData,
|
||||||
"CreateAt": model.GetMillis(),
|
"createat": model.GetMillis(),
|
||||||
})
|
})
|
||||||
require.NoError(t, err)
|
t.Logf("%v\n", err)
|
||||||
|
require.NoErrorf(t, err, "what is - %v", err)
|
||||||
|
|
||||||
err = ds.Load()
|
err = ds.Load()
|
||||||
if assert.Error(t, err) {
|
if assert.Error(t, err) {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ func truncateTable(t *testing.T, table string) {
|
|||||||
|
|
||||||
switch *sqlSetting.DriverName {
|
switch *sqlSetting.DriverName {
|
||||||
case model.DatabaseDriverMysql:
|
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 err != nil {
|
||||||
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
if driverErr, ok := err.(*mysql.MySQLError); ok {
|
||||||
// Ignore if the Configurations table does not exist.
|
// Ignore if the Configurations table does not exist.
|
||||||
@@ -48,7 +48,7 @@ func truncateTable(t *testing.T, table string) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
case model.DatabaseDriverPostgres:
|
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 err != nil {
|
||||||
if driverErr, ok := err.(*pq.Error); ok {
|
if driverErr, ok := err.(*pq.Error); ok {
|
||||||
// Ignore if the Configurations table does not exist.
|
// 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/lib/pq v1.10.4
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404
|
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/gosaml2 v0.3.3
|
||||||
github.com/mattermost/gziphandler v0.0.1
|
github.com/mattermost/gziphandler v0.0.1
|
||||||
github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d
|
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/morph v0.0.0-20220222074146-cff3f12ff131
|
||||||
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
|
github.com/mattermost/rsc v0.0.0-20160330161541-bbaefb05eaa0
|
||||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
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/mholt/archiver/v3 v3.5.1
|
||||||
github.com/microcosm-cc/bluemonday v1.0.18
|
github.com/microcosm-cc/bluemonday v1.0.18
|
||||||
github.com/miekg/dns v1.1.46 // indirect
|
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/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 h1:Khvh6waxG1cHc4Cz5ef9n3XVCxRWpAKUtqg9PJl5+y8=
|
||||||
github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404/go.mod h1:RyS7FDNQlzF1PsjbJWHRI35exqaKGSO9qD4iv8QjE34=
|
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 h1:ysWrjp08tpWmo6rV2MQ88Eag/Ttjuj91fZsvibF4/Tg=
|
||||||
github.com/mattermost/gosaml2 v0.3.3/go.mod h1:Z429EIOiEi9kbq6yHoApfzlcXpa6dzRDc6pO+Vy2Ksk=
|
github.com/mattermost/gosaml2 v0.3.3/go.mod h1:Z429EIOiEi9kbq6yHoApfzlcXpa6dzRDc6pO+Vy2Ksk=
|
||||||
github.com/mattermost/gziphandler v0.0.1 h1:uXHcXF5agnQ6bXabvpiwwwZOlCYoa7mKHH0lxns/o8w=
|
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.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.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
|
||||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
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.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 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
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/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/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/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/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 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
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/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/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/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=
|
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.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.3/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",
|
"id": "sharedchannel.permalink.not_found",
|
||||||
"translation": "This post contains permalinks to other channels which may not be visible to users in other sites."
|
"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",
|
"id": "store.sql_bot.get.missing.app_error",
|
||||||
"translation": "Bot does not exist."
|
"translation": "Bot does not exist."
|
||||||
|
|||||||
@@ -6,17 +6,11 @@ package sqlstore
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"database/sql/driver"
|
"database/sql/driver"
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
"github.com/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type jsonArray []string
|
type jsonArray []string
|
||||||
@@ -68,85 +62,3 @@ func (t *TraceOnAdapter) Printf(format string, v ...interface{}) {
|
|||||||
type JSONSerializable interface {
|
type JSONSerializable interface {
|
||||||
ToJSON() string
|
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 (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/mattermost/gorp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// storeContextKey is the base type for all context keys for the store.
|
// storeContextKey is the base type for all context keys for the store.
|
||||||
@@ -35,14 +33,6 @@ func hasMaster(ctx context.Context) bool {
|
|||||||
return false
|
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.
|
// DBXFromContext is a helper utility that returns the sqlx DB handle from a given context.
|
||||||
func (ss *SqlStore) DBXFromContext(ctx context.Context) *sqlxDBWrapper {
|
func (ss *SqlStore) DBXFromContext(ctx context.Context) *sqlxDBWrapper {
|
||||||
if hasMaster(ctx) {
|
if hasMaster(ctx) {
|
||||||
|
|||||||
@@ -58,22 +58,23 @@ func TestDeleteUnusedFeatures(t *testing.T) {
|
|||||||
ss.Preference().(*SqlPreferenceStore).deleteUnusedFeatures()
|
ss.Preference().(*SqlPreferenceStore).deleteUnusedFeatures()
|
||||||
|
|
||||||
//make sure features with value "false" have actually been deleted from the database
|
//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
|
FROM Preferences
|
||||||
WHERE Category = :Category
|
WHERE Category = ?
|
||||||
AND Value = :Val
|
AND Value = ?
|
||||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, map[string]interface{}{"Category": model.PreferenceCategoryAdvancedSettings, "Val": "false"}); err != nil {
|
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, model.PreferenceCategoryAdvancedSettings, "false"); err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
} else if val != 0 {
|
} else if val != 0 {
|
||||||
require.Fail(t, "Found %d features with value 'false', expected all to be deleted", val)
|
require.Fail(t, "Found %d features with value 'false', expected all to be deleted", val)
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
// make sure features with value "true" remain saved
|
// 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
|
FROM Preferences
|
||||||
WHERE Category = :Category
|
WHERE Category = ?
|
||||||
AND Value = :Val
|
AND Value = ?
|
||||||
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, map[string]interface{}{"Category": model.PreferenceCategoryAdvancedSettings, "Val": "true"}); err != nil {
|
AND Name LIKE '`+store.FeatureTogglePrefix+`%'`, model.PreferenceCategoryAdvancedSettings, "true"); err != nil {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
} else if val == 0 {
|
} else if val == 0 {
|
||||||
require.Fail(t, "Found %d features with value 'true', expected to find at least %d features", val, 2)
|
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/jmoiron/sqlx"
|
||||||
|
|
||||||
"github.com/mattermost/gorp"
|
|
||||||
"github.com/mattermost/mattermost-server/v6/model"
|
"github.com/mattermost/mattermost-server/v6/model"
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
||||||
"github.com/mattermost/mattermost-server/v6/store/storetest"
|
"github.com/mattermost/mattermost-server/v6/store/storetest"
|
||||||
@@ -28,10 +27,6 @@ func NewStoreTestWrapper(orig *SqlStore) *StoreTestWrapper {
|
|||||||
return &StoreTestWrapper{orig}
|
return &StoreTestWrapper{orig}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *StoreTestWrapper) GetMaster() *gorp.DbMap {
|
|
||||||
return w.orig.GetMaster()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *StoreTestWrapper) GetMasterX() storetest.SqlXExecutor {
|
func (w *StoreTestWrapper) GetMasterX() storetest.SqlXExecutor {
|
||||||
return w.orig.GetMasterX()
|
return w.orig.GetMasterX()
|
||||||
}
|
}
|
||||||
@@ -251,6 +246,18 @@ func (w *sqlxTxWrapper) Exec(query string, args ...interface{}) (sql.Result, err
|
|||||||
return w.ExecRaw(query, args...)
|
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
|
// ExecRaw is like Exec but without any rebinding of params. You need to pass
|
||||||
// the exact param types of your target database.
|
// the exact param types of your target database.
|
||||||
func (w *sqlxTxWrapper) ExecRaw(query string, args ...interface{}) (sql.Result, error) {
|
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/golang-migrate/migrate/v4/source/file"
|
||||||
"github.com/jmoiron/sqlx"
|
"github.com/jmoiron/sqlx"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/mattermost/gorp"
|
|
||||||
mbindata "github.com/mattermost/morph/sources/go_bindata"
|
mbindata "github.com/mattermost/morph/sources/go_bindata"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
@@ -113,13 +112,10 @@ type SqlStore struct {
|
|||||||
rrCounter int64
|
rrCounter int64
|
||||||
srCounter int64
|
srCounter int64
|
||||||
|
|
||||||
master *gorp.DbMap
|
|
||||||
masterX *sqlxDBWrapper
|
masterX *sqlxDBWrapper
|
||||||
|
|
||||||
Replicas []*gorp.DbMap
|
|
||||||
ReplicaXs []*sqlxDBWrapper
|
ReplicaXs []*sqlxDBWrapper
|
||||||
|
|
||||||
searchReplicas []*gorp.DbMap
|
|
||||||
searchReplicaXs []*sqlxDBWrapper
|
searchReplicaXs []*sqlxDBWrapper
|
||||||
|
|
||||||
replicaLagHandles []*dbsql.DB
|
replicaLagHandles []*dbsql.DB
|
||||||
@@ -248,34 +244,6 @@ func setupConnection(connType string, dataSource string, settings *model.SqlSett
|
|||||||
return db
|
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) {
|
func (ss *SqlStore) SetContext(context context.Context) {
|
||||||
ss.context = context
|
ss.context = context
|
||||||
}
|
}
|
||||||
@@ -300,7 +268,6 @@ func (ss *SqlStore) initConnection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle := setupConnection("master", dataSource, ss.settings)
|
handle := setupConnection("master", dataSource, ss.settings)
|
||||||
ss.master = getDBMap(ss.settings, handle)
|
|
||||||
ss.masterX = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
ss.masterX = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||||
*ss.settings.Trace)
|
*ss.settings.Trace)
|
||||||
@@ -309,11 +276,9 @@ func (ss *SqlStore) initConnection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(ss.settings.DataSourceReplicas) > 0 {
|
if len(ss.settings.DataSourceReplicas) > 0 {
|
||||||
ss.Replicas = make([]*gorp.DbMap, len(ss.settings.DataSourceReplicas))
|
|
||||||
ss.ReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceReplicas))
|
ss.ReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceReplicas))
|
||||||
for i, replica := range ss.settings.DataSourceReplicas {
|
for i, replica := range ss.settings.DataSourceReplicas {
|
||||||
handle := setupConnection(fmt.Sprintf("replica-%v", i), replica, ss.settings)
|
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()),
|
ss.ReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||||
*ss.settings.Trace)
|
*ss.settings.Trace)
|
||||||
@@ -324,11 +289,9 @@ func (ss *SqlStore) initConnection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(ss.settings.DataSourceSearchReplicas) > 0 {
|
if len(ss.settings.DataSourceSearchReplicas) > 0 {
|
||||||
ss.searchReplicas = make([]*gorp.DbMap, len(ss.settings.DataSourceSearchReplicas))
|
|
||||||
ss.searchReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceSearchReplicas))
|
ss.searchReplicaXs = make([]*sqlxDBWrapper, len(ss.settings.DataSourceSearchReplicas))
|
||||||
for i, replica := range ss.settings.DataSourceSearchReplicas {
|
for i, replica := range ss.settings.DataSourceSearchReplicas {
|
||||||
handle := setupConnection(fmt.Sprintf("search-replica-%v", i), replica, ss.settings)
|
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()),
|
ss.searchReplicaXs[i] = newSqlxDBWrapper(sqlx.NewDb(handle, ss.DriverName()),
|
||||||
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
time.Duration(*ss.settings.QueryTimeout)*time.Second,
|
||||||
*ss.settings.Trace)
|
*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 {
|
func (ss *SqlStore) GetMasterX() *sqlxDBWrapper {
|
||||||
return ss.masterX
|
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 {
|
func (ss *SqlStore) GetSearchReplicaX() *sqlxDBWrapper {
|
||||||
ss.licenseMutex.RLock()
|
ss.licenseMutex.RLock()
|
||||||
license := ss.license
|
license := ss.license
|
||||||
@@ -435,18 +378,6 @@ func (ss *SqlStore) GetSearchReplicaX() *sqlxDBWrapper {
|
|||||||
return ss.searchReplicaXs[rrNum]
|
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 {
|
func (ss *SqlStore) GetReplicaX() *sqlxDBWrapper {
|
||||||
ss.licenseMutex.RLock()
|
ss.licenseMutex.RLock()
|
||||||
license := ss.license
|
license := ss.license
|
||||||
@@ -455,7 +386,7 @@ func (ss *SqlStore) GetReplicaX() *sqlxDBWrapper {
|
|||||||
return ss.GetMasterX()
|
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]
|
return ss.ReplicaXs[rrNum]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,8 +438,8 @@ func (ss *SqlStore) TotalReadDbConnections() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for _, db := range ss.Replicas {
|
for _, db := range ss.ReplicaXs {
|
||||||
count = count + db.Db.Stats().OpenConnections
|
count = count + db.Stats().OpenConnections
|
||||||
}
|
}
|
||||||
|
|
||||||
return count
|
return count
|
||||||
@@ -520,8 +451,8 @@ func (ss *SqlStore) TotalSearchDbConnections() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count := 0
|
count := 0
|
||||||
for _, db := range ss.searchReplicas {
|
for _, db := range ss.searchReplicaXs {
|
||||||
count = count + db.Db.Stats().OpenConnections
|
count = count + db.Stats().OpenConnections
|
||||||
}
|
}
|
||||||
|
|
||||||
return count
|
return count
|
||||||
@@ -748,10 +679,10 @@ func IsUniqueConstraintError(err error, indexName []string) bool {
|
|||||||
return unique && field
|
return unique && field
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SqlStore) GetAllConns() []*gorp.DbMap {
|
func (ss *SqlStore) GetAllConns() []*sqlxDBWrapper {
|
||||||
all := make([]*gorp.DbMap, len(ss.Replicas)+1)
|
all := make([]*sqlxDBWrapper, len(ss.ReplicaXs)+1)
|
||||||
copy(all, ss.Replicas)
|
copy(all, ss.ReplicaXs)
|
||||||
all[len(ss.Replicas)] = ss.master
|
all[len(ss.ReplicaXs)] = ss.masterX
|
||||||
return all
|
return all
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -762,24 +693,24 @@ func (ss *SqlStore) RecycleDBConnections(d time.Duration) {
|
|||||||
originalDuration := time.Duration(*ss.settings.ConnMaxLifetimeMilliseconds) * time.Millisecond
|
originalDuration := time.Duration(*ss.settings.ConnMaxLifetimeMilliseconds) * time.Millisecond
|
||||||
// Set the max lifetimes for all connections.
|
// Set the max lifetimes for all connections.
|
||||||
for _, conn := range ss.GetAllConns() {
|
for _, conn := range ss.GetAllConns() {
|
||||||
conn.Db.SetConnMaxLifetime(d)
|
conn.SetConnMaxLifetime(d)
|
||||||
}
|
}
|
||||||
// Wait for that period with an additional 2 seconds of scheduling delay.
|
// Wait for that period with an additional 2 seconds of scheduling delay.
|
||||||
time.Sleep(d + 2*time.Second)
|
time.Sleep(d + 2*time.Second)
|
||||||
// Reset max lifetime back to original value.
|
// Reset max lifetime back to original value.
|
||||||
for _, conn := range ss.GetAllConns() {
|
for _, conn := range ss.GetAllConns() {
|
||||||
conn.Db.SetConnMaxLifetime(originalDuration)
|
conn.SetConnMaxLifetime(originalDuration)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ss *SqlStore) Close() {
|
func (ss *SqlStore) Close() {
|
||||||
ss.master.Db.Close()
|
ss.masterX.Close()
|
||||||
for _, replica := range ss.Replicas {
|
for _, replica := range ss.ReplicaXs {
|
||||||
replica.Db.Close()
|
replica.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, replica := range ss.searchReplicas {
|
for _, replica := range ss.searchReplicaXs {
|
||||||
replica.Db.Close()
|
replica.Close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"github.com/go-sql-driver/mysql"
|
"github.com/go-sql-driver/mysql"
|
||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
"github.com/mattermost/gorp"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -186,12 +185,12 @@ func TestStoreLicenseRace(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
store.GetReplica()
|
store.GetReplicaX()
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
store.GetSearchReplica()
|
store.GetSearchReplicaX()
|
||||||
wg.Done()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -276,14 +275,14 @@ func TestGetReplica(t *testing.T) {
|
|||||||
|
|
||||||
store.UpdateLicense(&model.License{})
|
store.UpdateLicense(&model.License{})
|
||||||
|
|
||||||
replicas := make(map[*gorp.DbMap]bool)
|
replicas := make(map[*sqlxDBWrapper]bool)
|
||||||
for i := 0; i < 5; i++ {
|
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++ {
|
for i := 0; i < 5; i++ {
|
||||||
searchReplicas[store.GetSearchReplica()] = true
|
searchReplicas[store.GetSearchReplicaX()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.DataSourceReplicaNum > 0 {
|
if testCase.DataSourceReplicaNum > 0 {
|
||||||
@@ -291,13 +290,13 @@ func TestGetReplica(t *testing.T) {
|
|||||||
assert.Len(t, replicas, testCase.DataSourceReplicaNum)
|
assert.Len(t, replicas, testCase.DataSourceReplicaNum)
|
||||||
|
|
||||||
for replica := range replicas {
|
for replica := range replicas {
|
||||||
assert.NotSame(t, store.GetMaster(), replica)
|
assert.NotSame(t, store.GetMasterX(), replica)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if assert.Len(t, replicas, 1) {
|
} else if assert.Len(t, replicas, 1) {
|
||||||
// Otherwise ensure the replicas contains only the master.
|
// Otherwise ensure the replicas contains only the master.
|
||||||
for replica := range replicas {
|
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)
|
assert.Len(t, searchReplicas, testCase.DataSourceSearchReplicaNum)
|
||||||
|
|
||||||
for searchReplica := range searchReplicas {
|
for searchReplica := range searchReplicas {
|
||||||
assert.NotSame(t, store.GetMaster(), searchReplica)
|
assert.NotSame(t, store.GetMasterX(), searchReplica)
|
||||||
for replica := range replicas {
|
for replica := range replicas {
|
||||||
assert.NotSame(t, searchReplica, replica)
|
assert.NotSame(t, searchReplica, replica)
|
||||||
}
|
}
|
||||||
@@ -319,7 +318,7 @@ func TestGetReplica(t *testing.T) {
|
|||||||
} else if testCase.DataSourceReplicaNum == 0 && assert.Len(t, searchReplicas, 1) {
|
} else if testCase.DataSourceReplicaNum == 0 && assert.Len(t, searchReplicas, 1) {
|
||||||
// Otherwise ensure the search replicas contains the master.
|
// Otherwise ensure the search replicas contains the master.
|
||||||
for searchReplica := range searchReplicas {
|
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)
|
storetest.CleanupSqlSettings(settings)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
replicas := make(map[*gorp.DbMap]bool)
|
replicas := make(map[*sqlxDBWrapper]bool)
|
||||||
for i := 0; i < 5; i++ {
|
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++ {
|
for i := 0; i < 5; i++ {
|
||||||
searchReplicas[store.GetSearchReplica()] = true
|
searchReplicas[store.GetSearchReplicaX()] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.DataSourceReplicaNum > 0 {
|
if testCase.DataSourceReplicaNum > 0 {
|
||||||
@@ -359,13 +358,13 @@ func TestGetReplica(t *testing.T) {
|
|||||||
assert.Len(t, replicas, 1)
|
assert.Len(t, replicas, 1)
|
||||||
|
|
||||||
for replica := range replicas {
|
for replica := range replicas {
|
||||||
assert.Same(t, store.GetMaster(), replica)
|
assert.Same(t, store.GetMasterX(), replica)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if assert.Len(t, replicas, 1) {
|
} else if assert.Len(t, replicas, 1) {
|
||||||
// Otherwise ensure the replicas contains only the master.
|
// Otherwise ensure the replicas contains only the master.
|
||||||
for replica := range replicas {
|
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)
|
assert.Len(t, searchReplicas, 1)
|
||||||
|
|
||||||
for searchReplica := range searchReplicas {
|
for searchReplica := range searchReplicas {
|
||||||
assert.Same(t, store.GetMaster(), searchReplica)
|
assert.Same(t, store.GetMasterX(), searchReplica)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if testCase.DataSourceReplicaNum > 0 {
|
} else if testCase.DataSourceReplicaNum > 0 {
|
||||||
@@ -385,7 +384,7 @@ func TestGetReplica(t *testing.T) {
|
|||||||
} else if assert.Len(t, searchReplicas, 1) {
|
} else if assert.Len(t, searchReplicas, 1) {
|
||||||
// Otherwise ensure the search replicas contains the master.
|
// Otherwise ensure the search replicas contains the master.
|
||||||
for searchReplica := range searchReplicas {
|
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) {
|
StoreTest(t, func(t *testing.T, ss store.Store) {
|
||||||
sqlStore := ss.(*SqlStore)
|
sqlStore := ss.(*SqlStore)
|
||||||
var query string
|
var query string
|
||||||
timeout := sqlStore.master.QueryTimeout
|
timeout := sqlStore.masterX.queryTimeout
|
||||||
sqlStore.master.QueryTimeout = 1
|
sqlStore.masterX.queryTimeout = 1
|
||||||
defer func() {
|
defer func() {
|
||||||
sqlStore.master.QueryTimeout = timeout
|
sqlStore.masterX.queryTimeout = timeout
|
||||||
}()
|
}()
|
||||||
if sqlStore.DriverName() == model.DatabaseDriverMysql {
|
if sqlStore.DriverName() == model.DatabaseDriverMysql {
|
||||||
query = `SELECT SLEEP(2);`
|
query = `SELECT SLEEP(2);`
|
||||||
|
|||||||
@@ -922,7 +922,7 @@ func (s SqlTeamStore) GetMember(ctx context.Context, teamId string, userId strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dbMember teamMemberWithSchemeRoles
|
var dbMember teamMemberWithSchemeRoles
|
||||||
err = s.DBFromContext(ctx).SelectOne(&dbMember, queryString, args...)
|
err = s.DBXFromContext(ctx).Get(&dbMember, queryString, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, store.NewErrNotFound("TeamMember", fmt.Sprintf("teamId=%s, userId=%s", teamId, userId))
|
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{}
|
dbMembers := teamMemberWithSchemeRolesList{}
|
||||||
_, err = s.SqlStore.DBFromContext(ctx).Select(&dbMembers, queryString, args...)
|
err = s.SqlStore.DBXFromContext(ctx).Select(&dbMembers, queryString, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to find TeamMembers with userId=%s", userId)
|
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) {
|
func upgradeDatabaseToVersion33(sqlStore *SqlStore) {
|
||||||
if shouldPerformUpgrade(sqlStore, Version320, Version330) {
|
if shouldPerformUpgrade(sqlStore, Version320, Version330) {
|
||||||
if sqlStore.DoesColumnExist("Users", "ThemeProps") {
|
if sqlStore.DoesColumnExist("Users", "ThemeProps") {
|
||||||
params := map[string]interface{}{
|
transaction, err := sqlStore.GetMasterX().Beginx()
|
||||||
"Category": model.PreferenceCategoryTheme,
|
|
||||||
"Name": "",
|
|
||||||
}
|
|
||||||
|
|
||||||
transaction, err := sqlStore.GetMaster().Begin()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
themeMigrationFailed(err)
|
themeMigrationFailed(err)
|
||||||
}
|
}
|
||||||
defer finalizeTransaction(transaction)
|
defer finalizeTransactionX(transaction)
|
||||||
|
|
||||||
// copy data across
|
// copy data across
|
||||||
if _, err := transaction.ExecNoTimeout(
|
if _, err := transaction.ExecNoTimeout(
|
||||||
`INSERT INTO
|
`INSERT INTO
|
||||||
Preferences(UserId, Category, Name, Value)
|
Preferences(UserId, Category, Name, Value)
|
||||||
SELECT
|
SELECT
|
||||||
Id, '`+model.PreferenceCategoryTheme+`', '', ThemeProps
|
Id, '` + model.PreferenceCategoryTheme + `', '', ThemeProps
|
||||||
FROM
|
FROM
|
||||||
Users
|
Users
|
||||||
WHERE
|
WHERE
|
||||||
Users.ThemeProps != 'null'`, params); err != nil {
|
Users.ThemeProps != 'null'`); err != nil {
|
||||||
themeMigrationFailed(err)
|
themeMigrationFailed(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -554,8 +549,8 @@ func upgradeDatabaseToVersion510(sqlStore *SqlStore) {
|
|||||||
func upgradeDatabaseToVersion511(sqlStore *SqlStore) {
|
func upgradeDatabaseToVersion511(sqlStore *SqlStore) {
|
||||||
if shouldPerformUpgrade(sqlStore, Version5100, Version5110) {
|
if shouldPerformUpgrade(sqlStore, Version5100, Version5110) {
|
||||||
// Enforce all teams have an InviteID set
|
// Enforce all teams have an InviteID set
|
||||||
var teams []*model.Team
|
teams := []*model.Team{}
|
||||||
if _, err := sqlStore.GetReplica().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
|
if err := sqlStore.GetReplicaX().Select(&teams, "SELECT * FROM Teams WHERE InviteId = ''"); err != nil {
|
||||||
mlog.Error("Error fetching Teams without InviteID", mlog.Err(err))
|
mlog.Error("Error fetching Teams without InviteID", mlog.Err(err))
|
||||||
} else {
|
} else {
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
@@ -701,7 +696,7 @@ func precheckMigrationToVersion528(sqlStore *SqlStore) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var schemeIDWrong, typeWrong int
|
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 {
|
if err = row.Scan(&schemeIDWrong, &typeWrong); err != nil && err != sql.ErrNoRows {
|
||||||
return err
|
return err
|
||||||
} else if err == nil && schemeIDWrong > 0 {
|
} else if err == nil && schemeIDWrong > 0 {
|
||||||
|
|||||||
@@ -390,7 +390,7 @@ func (us SqlUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User
|
|||||||
}
|
}
|
||||||
|
|
||||||
users := []*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")
|
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 {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "users_get_tosql")
|
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 user model.User
|
||||||
var props, notifyProps, timezone []byte
|
var props, notifyProps, timezone []byte
|
||||||
@@ -774,7 +774,7 @@ func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID st
|
|||||||
}
|
}
|
||||||
|
|
||||||
users := []*model.User{}
|
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 {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to find Users")
|
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")
|
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")
|
return nil, errors.Wrap(err, "failed to find Users")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1679,7 +1679,7 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
|
|||||||
OrderBy("u.CreateAt").
|
OrderBy("u.CreateAt").
|
||||||
Limit(uint64(limit)).
|
Limit(uint64(limit)).
|
||||||
ToSql()
|
ToSql()
|
||||||
_, err := us.GetSearchReplica().Select(&users, usersQuery, args...)
|
err := us.GetSearchReplicaX().Select(&users, usersQuery, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to find Users")
|
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)
|
userIds = append(userIds, user.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var channelMembers []*model.ChannelMember
|
channelMembers := []*model.ChannelMember{}
|
||||||
channelMembersQuery, args, _ := us.getQueryBuilder().
|
channelMembersQuery, args, _ := us.getQueryBuilder().
|
||||||
Select(`
|
Select(`
|
||||||
cm.ChannelId,
|
cm.ChannelId,
|
||||||
@@ -1709,18 +1709,18 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
|
|||||||
Join("Channels c ON cm.ChannelId = c.Id").
|
Join("Channels c ON cm.ChannelId = c.Id").
|
||||||
Where(sq.Eq{"c.Type": model.ChannelTypeOpen, "cm.UserId": userIds}).
|
Where(sq.Eq{"c.Type": model.ChannelTypeOpen, "cm.UserId": userIds}).
|
||||||
ToSql()
|
ToSql()
|
||||||
_, err = us.GetSearchReplica().Select(&channelMembers, channelMembersQuery, args...)
|
err = us.GetSearchReplicaX().Select(&channelMembers, channelMembersQuery, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to find ChannelMembers")
|
return nil, errors.Wrap(err, "failed to find ChannelMembers")
|
||||||
}
|
}
|
||||||
|
|
||||||
var teamMembers []*model.TeamMember
|
teamMembers := []*model.TeamMember{}
|
||||||
teamMembersQuery, args, _ := us.getQueryBuilder().
|
teamMembersQuery, args, _ := us.getQueryBuilder().
|
||||||
Select("TeamId, UserId, Roles, DeleteAt, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest, SchemeUser, SchemeAdmin").
|
Select("TeamId, UserId, Roles, DeleteAt, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest, SchemeUser, SchemeAdmin").
|
||||||
From("TeamMembers").
|
From("TeamMembers").
|
||||||
Where(sq.Eq{"UserId": userIds, "DeleteAt": 0}).
|
Where(sq.Eq{"UserId": userIds, "DeleteAt": 0}).
|
||||||
ToSql()
|
ToSql()
|
||||||
_, err = us.GetSearchReplica().Select(&teamMembers, teamMembersQuery, args...)
|
err = us.GetSearchReplicaX().Select(&teamMembers, teamMembersQuery, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "failed to find TeamMembers")
|
return nil, errors.Wrap(err, "failed to find TeamMembers")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,7 @@ type SqlUserTermsOfServiceStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newSqlUserTermsOfServiceStore(sqlStore *SqlStore) store.UserTermsOfServiceStore {
|
func newSqlUserTermsOfServiceStore(sqlStore *SqlStore) store.UserTermsOfServiceStore {
|
||||||
s := SqlUserTermsOfServiceStore{sqlStore}
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlUserTermsOfServiceStore) GetByUser(userId string) (*model.UserTermsOfService, error) {
|
func (s SqlUserTermsOfServiceStore) GetByUser(userId string) (*model.UserTermsOfService, error) {
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
"github.com/mattermost/gorp"
|
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v6/shared/mlog"
|
"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
|
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.
|
// finalizeTransactionX ensures a transaction is closed after use, rolling back if not already committed.
|
||||||
func finalizeTransactionX(transaction *sqlxTxWrapper) {
|
func finalizeTransactionX(transaction *sqlxTxWrapper) {
|
||||||
// Rollback returns sql.ErrTxDone if the transaction was already closed.
|
// 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))
|
panic(fmt.Errorf("cannot read file: %v", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handle := h.SQLStore.GetMaster()
|
handle := h.SQLStore.GetMasterX()
|
||||||
_, err = handle.Exec(string(buf))
|
_, err = handle.Exec(string(buf))
|
||||||
if err != nil {
|
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"))
|
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 {
|
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...)
|
_, err := replica.Exec(query, args...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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/bundle
|
||||||
github.com/mattermost/go-i18n/i18n/language
|
github.com/mattermost/go-i18n/i18n/language
|
||||||
github.com/mattermost/go-i18n/i18n/translation
|
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
|
# github.com/mattermost/gosaml2 v0.3.3
|
||||||
## explicit
|
## explicit
|
||||||
github.com/mattermost/gosaml2
|
github.com/mattermost/gosaml2
|
||||||
@@ -429,6 +426,8 @@ github.com/mattn/go-isatty
|
|||||||
# github.com/mattn/go-runewidth v0.0.13
|
# github.com/mattn/go-runewidth v0.0.13
|
||||||
## explicit
|
## explicit
|
||||||
github.com/mattn/go-runewidth
|
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 v1.0.2-0.20181231171920-c182affec369
|
||||||
github.com/matttproud/golang_protobuf_extensions/pbutil
|
github.com/matttproud/golang_protobuf_extensions/pbutil
|
||||||
# github.com/mholt/archiver/v3 v3.5.1
|
# github.com/mholt/archiver/v3 v3.5.1
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user