diff --git a/README.md b/README.md index 5ad96eb3..385936db 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,3 @@ in this process. ## License Flamenco is licensed under the GPLv3+ license. - -Flamenco Manager includes a copy of https://github.com/go-gorm/sqlite.git, -adjusted to use the pure-Go SQLite from https://modernc.org/sqlite. It is -licensed under the MIT license by Jinzhu . diff --git a/go.mod b/go.mod index aa986c1c..e5eec089 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,8 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91 // indirect github.com/ghodss/yaml v1.0.0 // indirect + github.com/glebarez/go-sqlite v1.14.7 // indirect + github.com/glebarez/sqlite v1.3.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/swag v0.19.5 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect diff --git a/go.sum b/go.sum index 8aed14d6..ab4294dd 100644 --- a/go.sum +++ b/go.sum @@ -26,6 +26,10 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.7.4/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY= +github.com/glebarez/go-sqlite v1.14.7 h1:eXrKp59O5eWBfxv2Xfq5d7uex4+clKrOtWfMzzGSkoM= +github.com/glebarez/go-sqlite v1.14.7/go.mod h1:TKAw5tjyB/ocvVht7Xv4772qRAun5CG/xLCEbkDwNUc= +github.com/glebarez/sqlite v1.3.5 h1:R9op5nxb9Z10t4VXQSdAVyqRalLhWdLrlaT/iuvOGHI= +github.com/glebarez/sqlite v1.3.5/go.mod h1:ZffEtp/afVhV+jvIzQi8wlYEIkuGAYshr9OPKM/NmQc= github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJpoZOs= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= @@ -245,6 +249,7 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.22.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= gorm.io/gorm v1.23.2 h1:xmq9QRMWL8HTJyhAUBXy8FqIIQCYESeKfJL4DoGKiWQ= gorm.io/gorm v1.23.2/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= @@ -304,6 +309,7 @@ modernc.org/ccgo/v3 v3.12.86/go.mod h1:dN7S26DLTgVSni1PVA3KxxHTcykyDurf3OgUzNqTS modernc.org/ccgo/v3 v3.12.90/go.mod h1:obhSc3CdivCRpYZmrvO88TXlW0NvoSVvdh/ccRjJYko= modernc.org/ccgo/v3 v3.12.92/go.mod h1:5yDdN7ti9KWPi5bRVWPl8UNhpEAtCjuEE7ayQnzzqHA= modernc.org/ccgo/v3 v3.13.1/go.mod h1:aBYVOUfIlcSnrsRVU8VRS35y2DIfpgkmVkYZ0tpIXi4= +modernc.org/ccgo/v3 v3.14.0/go.mod h1:hBrkiBlUwvr5vV/ZH9YzXIp982jKE8Ek8tR1ytoAL6Q= modernc.org/ccgo/v3 v3.15.1/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0= modernc.org/ccgo/v3 v3.15.9/go.mod h1:md59wBwDT2LznX/OTCPoVS6KIsdRgY8xqQwBV+hkTH0= modernc.org/ccgo/v3 v3.15.10/go.mod h1:wQKxoFn0ynxMuCLfFD09c8XPUCc8obfchoVR9Cn0fI8= @@ -353,6 +359,8 @@ modernc.org/libc v1.11.88/go.mod h1:h3oIVe8dxmTcchcFuCcJ4nAWaoiwzKCdv82MM0oiIdQ= modernc.org/libc v1.11.98/go.mod h1:ynK5sbjsU77AP+nn61+k+wxUGRx9rOFcIqWYYMaDZ4c= modernc.org/libc v1.11.101/go.mod h1:wLLYgEiY2D17NbBOEp+mIJJJBGSiy7fLL4ZrGGZ+8jI= modernc.org/libc v1.12.0/go.mod h1:2MH3DaF/gCU8i/UBiVE1VFRos4o523M7zipmwH8SIgQ= +modernc.org/libc v1.13.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= +modernc.org/libc v1.13.2/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= modernc.org/libc v1.14.1/go.mod h1:npFeGWjmZTjFeWALQLrvklVmAxv4m80jnG3+xI8FdJk= modernc.org/libc v1.14.2/go.mod h1:MX1GBLnRLNdvmK9azU9LCxZ5lMyhrbEMK8rG3X/Fe34= modernc.org/libc v1.14.3/go.mod h1:GPIvQVOVPizzlqyRX3l756/3ppsAgg1QgPxjr5Q4agQ= @@ -368,13 +376,16 @@ modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14= modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= +modernc.org/sqlite v1.14.5/go.mod h1:YyX5Rx0WbXokitdWl2GJIDy4BrPxBP0PwwhpXOHCDLE= modernc.org/sqlite v1.14.6 h1:Jt5P3k80EtDBWaq1beAxnWW+5MdHXbZITujnRS7+zWg= modernc.org/sqlite v1.14.6/go.mod h1:yiCvMv3HblGmzENNIaNtFhfaNIwcla4u2JQEwJPzfEc= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= +modernc.org/tcl v1.10.0/go.mod h1:WzWapmP/7dHVhFoyPpEaNSVTL8xtewhouN/cqSJ5A2s= modernc.org/tcl v1.11.0 h1:B/zzEYjINeaki38KcIqdQRQx7W3WE7TkrlTwGnbm2II= modernc.org/tcl v1.11.0/go.mod h1:zsTUpbQ+NxQEjOjCUlImDLPv1sG8Ww0qp66ZvyOxCgw= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= +modernc.org/z v1.2.21/go.mod h1:uXrObx4pGqXWIMliC5MiKuwAyMrltzwpteOFUP1PWCc= modernc.org/z v1.3.0 h1:4RWULo1Nvaq5ZBhbLe74u8p6tV4Mmm0ZrPBXYPm/xjM= modernc.org/z v1.3.0/go.mod h1:+mvgLH814oDjtATDdT3rs84JnUIpkvAF5B8AVkNlE2g= diff --git a/internal/manager/persistence/db.go b/internal/manager/persistence/db.go index e978eb8b..c42835f5 100644 --- a/internal/manager/persistence/db.go +++ b/internal/manager/persistence/db.go @@ -27,7 +27,7 @@ import ( "github.com/rs/zerolog/log" "gorm.io/gorm" - sqlite "git.blender.org/flamenco/pkg/gorm-modernc-sqlite" + "github.com/glebarez/sqlite" ) // DB provides the database interface. diff --git a/pkg/gorm-modernc-sqlite/License b/pkg/gorm-modernc-sqlite/License deleted file mode 100644 index 037e1653..00000000 --- a/pkg/gorm-modernc-sqlite/License +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-NOW Jinzhu - -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. diff --git a/pkg/gorm-modernc-sqlite/README.md b/pkg/gorm-modernc-sqlite/README.md deleted file mode 100644 index 943a682d..00000000 --- a/pkg/gorm-modernc-sqlite/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# GORM Sqlite Driver - -This is a clone of the [Gorm SQLite driver](https://github.com/go-gorm/sqlite), -adjusted by Sybren Stüvel to use modernc.org/sqlite instead -of the SQLite C-bindings wrapper. - - -## USAGE - -```go -import ( - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -// modernc.org/sqlite -db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{}) -``` - -Checkout [https://gorm.io](https://gorm.io) for details. diff --git a/pkg/gorm-modernc-sqlite/ddlmod.go b/pkg/gorm-modernc-sqlite/ddlmod.go deleted file mode 100644 index 73c20ea0..00000000 --- a/pkg/gorm-modernc-sqlite/ddlmod.go +++ /dev/null @@ -1,216 +0,0 @@ -package sqlite - -import ( - "database/sql" - "errors" - "fmt" - "regexp" - "strings" - - "gorm.io/gorm/migrator" -) - -var ( - sqliteSeparator = "`|\"|'|\t" - indexRegexp = regexp.MustCompile(fmt.Sprintf("CREATE(?: UNIQUE)? INDEX [%v][\\w\\d]+[%v] ON (.*)$", sqliteSeparator, sqliteSeparator)) - tableRegexp = regexp.MustCompile(fmt.Sprintf("(?i)(CREATE TABLE [%v]?[\\w\\d]+[%v]?)(?: \\((.*)\\))?", sqliteSeparator, sqliteSeparator)) - separatorRegexp = regexp.MustCompile(fmt.Sprintf("[%v]", sqliteSeparator)) - columnsRegexp = regexp.MustCompile(fmt.Sprintf("\\([%v]?([\\w\\d]+)[%v]?(?:,[%v]?([\\w\\d]+)[%v]){0,}\\)", sqliteSeparator, sqliteSeparator, sqliteSeparator, sqliteSeparator)) - columnRegexp = regexp.MustCompile(fmt.Sprintf("^[%v]?([\\w\\d]+)[%v]?\\s+([\\w\\(\\)\\d]+)(.*)$", sqliteSeparator, sqliteSeparator)) - defaultValueRegexp = regexp.MustCompile("(?i) DEFAULT \\(?(.+)?\\)?( |COLLATE|GENERATED|$)") -) - -type ddl struct { - head string - fields []string - columns []migrator.ColumnType -} - -func parseDDL(strs ...string) (*ddl, error) { - var result ddl - for _, str := range strs { - if sections := tableRegexp.FindStringSubmatch(str); len(sections) > 0 { - var ( - ddlBody = sections[2] - bracketLevel int - quote rune - buf string - ) - - result.head = sections[1] - - for idx, c := range []rune(ddlBody) { - var next rune = 0 - if idx+1 < len(ddlBody) { - next = []rune(ddlBody)[idx+1] - } - - if sc := string(c); separatorRegexp.MatchString(sc) { - if c == next { - buf += sc // Skip escaped quote - idx++ - } else if quote > 0 { - quote = 0 - } else { - quote = c - } - } else if quote == 0 { - if c == '(' { - bracketLevel++ - } else if c == ')' { - bracketLevel-- - } else if bracketLevel == 0 { - if c == ',' { - result.fields = append(result.fields, strings.TrimSpace(buf)) - buf = "" - continue - } - } - } - - if bracketLevel < 0 { - return nil, errors.New("invalid DDL, unbalanced brackets") - } - - buf += string(c) - } - - if bracketLevel != 0 { - return nil, errors.New("invalid DDL, unbalanced brackets") - } - - if buf != "" { - result.fields = append(result.fields, strings.TrimSpace(buf)) - } - - for _, f := range result.fields { - fUpper := strings.ToUpper(f) - if strings.HasPrefix(fUpper, "CHECK") || - strings.HasPrefix(fUpper, "CONSTRAINT") { - continue - } - - if strings.HasPrefix(fUpper, "PRIMARY KEY") { - matches := columnsRegexp.FindStringSubmatch(f) - if len(matches) > 1 { - for _, name := range matches[1:] { - for idx, column := range result.columns { - if column.NameValue.String == name { - column.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} - result.columns[idx] = column - break - } - } - } - } - } else if matches := columnRegexp.FindStringSubmatch(f); len(matches) > 0 { - columnType := migrator.ColumnType{ - NameValue: sql.NullString{String: matches[1], Valid: true}, - DataTypeValue: sql.NullString{String: matches[2], Valid: true}, - ColumnTypeValue: sql.NullString{String: matches[2], Valid: true}, - PrimaryKeyValue: sql.NullBool{Valid: true}, - UniqueValue: sql.NullBool{Valid: true}, - NullableValue: sql.NullBool{Valid: true}, - DefaultValueValue: sql.NullString{Valid: true}, - } - - matchUpper := strings.ToUpper(matches[3]) - if strings.Contains(matchUpper, " NOT NULL") { - columnType.NullableValue = sql.NullBool{Bool: false, Valid: true} - } else if strings.Contains(matchUpper, " NULL") { - columnType.NullableValue = sql.NullBool{Bool: true, Valid: true} - } - if strings.Contains(matchUpper, " UNIQUE") { - columnType.UniqueValue = sql.NullBool{Bool: true, Valid: true} - } - if strings.Contains(matchUpper, " PRIMARY") { - columnType.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true} - } - if defaultMatches := defaultValueRegexp.FindStringSubmatch(matches[3]); len(defaultMatches) > 1 { - columnType.DefaultValueValue = sql.NullString{String: strings.Trim(defaultMatches[1], `"`), Valid: true} - } - - result.columns = append(result.columns, columnType) - } - } - } else if matches := indexRegexp.FindStringSubmatch(str); len(matches) > 0 { - if columns := columnsRegexp.FindStringSubmatch(matches[1]); len(columns) == 1 { - for idx, c := range result.columns { - if c.NameValue.String == columns[0] { - c.UniqueValue = sql.NullBool{Bool: true, Valid: true} - result.columns[idx] = c - } - } - } - } else { - return nil, errors.New("invalid DDL") - } - } - - return &result, nil -} - -func (d *ddl) compile() string { - if len(d.fields) == 0 { - return d.head - } - - return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ",")) -} - -func (d *ddl) addConstraint(name string, sql string) { - reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") - - for i := 0; i < len(d.fields); i++ { - if reg.MatchString(d.fields[i]) { - d.fields[i] = sql - return - } - } - - d.fields = append(d.fields, sql) -} - -func (d *ddl) removeConstraint(name string) bool { - reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") - - for i := 0; i < len(d.fields); i++ { - if reg.MatchString(d.fields[i]) { - d.fields = append(d.fields[:i], d.fields[i+1:]...) - return true - } - } - return false -} - -func (d *ddl) hasConstraint(name string) bool { - reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]") - - for _, f := range d.fields { - if reg.MatchString(f) { - return true - } - } - return false -} - -func (d *ddl) getColumns() []string { - res := []string{} - - for _, f := range d.fields { - fUpper := strings.ToUpper(f) - if strings.HasPrefix(fUpper, "PRIMARY KEY") || - strings.HasPrefix(fUpper, "CHECK") || - strings.HasPrefix(fUpper, "CONSTRAINT") { - continue - } - - reg := regexp.MustCompile("^[\"`']?([\\w\\d]+)[\"`']?") - match := reg.FindStringSubmatch(f) - - if match != nil { - res = append(res, "`"+match[1]+"`") - } - } - return res -} diff --git a/pkg/gorm-modernc-sqlite/ddlmod_test.go b/pkg/gorm-modernc-sqlite/ddlmod_test.go deleted file mode 100644 index 4d1f5c7f..00000000 --- a/pkg/gorm-modernc-sqlite/ddlmod_test.go +++ /dev/null @@ -1,197 +0,0 @@ -package sqlite - -import ( - "database/sql" - "testing" - - "github.com/stretchr/testify/assert" - "gorm.io/gorm/migrator" -) - -func TestParseDDL(t *testing.T) { - params := []struct { - name string - sql []string - nFields int - columns []migrator.ColumnType - }{ - {"with_fk", []string{ - "CREATE TABLE `notes` (`id` integer NOT NULL,`text` varchar(500) DEFAULT \"hello\",`age` integer DEFAULT 18,`user_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))", - "CREATE UNIQUE INDEX `idx_profiles_refer` ON `profiles`(`text`)", - }, 6, []migrator.ColumnType{ - {NameValue: sql.NullString{String: "id", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, PrimaryKeyValue: sql.NullBool{Bool: true, Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, DefaultValueValue: sql.NullString{Valid: true}}, - {NameValue: sql.NullString{String: "text", Valid: true}, DataTypeValue: sql.NullString{String: "varchar(500)", Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(500)", Valid: true}, DefaultValueValue: sql.NullString{String: "hello", Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - {NameValue: sql.NullString{String: "age", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{String: "18", Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - {NameValue: sql.NullString{String: "user_id", Valid: true}, DataTypeValue: sql.NullString{String: "integer", Valid: true}, ColumnTypeValue: sql.NullString{String: "integer", Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - }, - }, - {"with_check", []string{"CREATE TABLE Persons (ID int NOT NULL,LastName varchar(255) NOT NULL,FirstName varchar(255),Age int,CHECK (Age>=18),CHECK (FirstName<>'John'))"}, 6, []migrator.ColumnType{ - {NameValue: sql.NullString{String: "ID", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, NullableValue: sql.NullBool{Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - {NameValue: sql.NullString{String: "LastName", Valid: true}, DataTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, NullableValue: sql.NullBool{Bool: false, Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - {NameValue: sql.NullString{String: "FirstName", Valid: true}, DataTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, ColumnTypeValue: sql.NullString{String: "varchar(255)", Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - {NameValue: sql.NullString{String: "Age", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, NullableValue: sql.NullBool{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - }}, - {"lowercase", []string{"create table test (ID int NOT NULL)"}, 1, []migrator.ColumnType{ - {NameValue: sql.NullString{String: "ID", Valid: true}, DataTypeValue: sql.NullString{String: "int", Valid: true}, ColumnTypeValue: sql.NullString{String: "int", Valid: true}, NullableValue: sql.NullBool{Bool: false, Valid: true}, DefaultValueValue: sql.NullString{Valid: true}, UniqueValue: sql.NullBool{Valid: true}, PrimaryKeyValue: sql.NullBool{Valid: true}}, - }, - }, - {"no brackets", []string{"create table test"}, 0, nil}, - } - - for _, p := range params { - t.Run(p.name, func(t *testing.T) { - ddl, err := parseDDL(p.sql...) - - if err != nil { - panic(err.Error()) - } - - assert.Equal(t, p.sql[0], ddl.compile()) - assert.Len(t, ddl.fields, p.nFields) - assert.Equal(t, ddl.columns, p.columns) - }) - } -} - -func TestParseDDL_error(t *testing.T) { - params := []struct { - name string - sql string - }{ - {"invalid_cmd", "CREATE TABLE"}, - {"unbalanced_brackets", "CREATE TABLE test (ID int NOT NULL,Name varchar(255)"}, - {"unbalanced_brackets2", "CREATE TABLE test (ID int NOT NULL,Name varchar(255)))"}, - } - - for _, p := range params { - t.Run(p.name, func(t *testing.T) { - _, err := parseDDL(p.sql) - if err == nil { - t.Fail() - } - }) - } -} - -func TestAddConstraint(t *testing.T) { - params := []struct { - name string - fields []string - cName string - sql string - expect []string - }{ - { - name: "add_new", - fields: []string{"`id` integer NOT NULL"}, - cName: "fk_users_notes", - sql: "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))", - expect: []string{"`id` integer NOT NULL", "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"}, - }, - { - name: "update", - fields: []string{"`id` integer NOT NULL", "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"}, - cName: "fk_users_notes", - sql: "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)) ON UPDATE CASCADE ON DELETE CASCADE", - expect: []string{"`id` integer NOT NULL", "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`)) ON UPDATE CASCADE ON DELETE CASCADE"}, - }, - { - name: "add_check", - fields: []string{"`id` integer NOT NULL"}, - cName: "name_checker", - sql: "CONSTRAINT `name_checker` CHECK (`name` <> 'jinzhu')", - expect: []string{"`id` integer NOT NULL", "CONSTRAINT `name_checker` CHECK (`name` <> 'jinzhu')"}, - }, - { - name: "update_check", - fields: []string{"`id` integer NOT NULL", "CONSTRAINT `name_checker` CHECK (`name` <> 'thetadev')"}, - cName: "name_checker", - sql: "CONSTRAINT `name_checker` CHECK (`name` <> 'jinzhu')", - expect: []string{"`id` integer NOT NULL", "CONSTRAINT `name_checker` CHECK (`name` <> 'jinzhu')"}, - }, - } - - for _, p := range params { - t.Run(p.name, func(t *testing.T) { - testDDL := ddl{fields: p.fields} - - testDDL.addConstraint(p.cName, p.sql) - assert.Equal(t, p.expect, testDDL.fields) - }) - } -} - -func TestRemoveConstraint(t *testing.T) { - params := []struct { - name string - fields []string - cName string - success bool - expect []string - }{ - { - name: "fk", - fields: []string{"`id` integer NOT NULL", "CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))"}, - cName: "fk_users_notes", - success: true, - expect: []string{"`id` integer NOT NULL"}, - }, - { - name: "check", - fields: []string{"CONSTRAINT `name_checker` CHECK (`name` <> 'thetadev')", "`id` integer NOT NULL"}, - cName: "name_checker", - success: true, - expect: []string{"`id` integer NOT NULL"}, - }, - { - name: "none", - fields: []string{"CONSTRAINT `name_checker` CHECK (`name` <> 'thetadev')", "`id` integer NOT NULL"}, - cName: "nothing", - success: false, - expect: []string{"CONSTRAINT `name_checker` CHECK (`name` <> 'thetadev')", "`id` integer NOT NULL"}, - }, - } - - for _, p := range params { - t.Run(p.name, func(t *testing.T) { - testDDL := ddl{fields: p.fields} - - success := testDDL.removeConstraint(p.cName) - - assert.Equal(t, p.success, success) - assert.Equal(t, p.expect, testDDL.fields) - }) - } -} - -func TestGetColumns(t *testing.T) { - params := []struct { - name string - ddl string - columns []string - }{ - { - name: "with_fk", - ddl: "CREATE TABLE `notes` (`id` integer NOT NULL,`text` varchar(500),`user_id` integer,PRIMARY KEY (`id`),CONSTRAINT `fk_users_notes` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`))", - columns: []string{"`id`", "`text`", "`user_id`"}, - }, - { - name: "with_check", - ddl: "CREATE TABLE Persons (ID int NOT NULL,LastName varchar(255) NOT NULL,FirstName varchar(255),Age int,CHECK (Age>=18),CHECK (FirstName!='John'))", - columns: []string{"`ID`", "`LastName`", "`FirstName`", "`Age`"}, - }, - } - - for _, p := range params { - t.Run(p.name, func(t *testing.T) { - testDDL, err := parseDDL(p.ddl) - if err != nil { - panic(err.Error()) - } - - cols := testDDL.getColumns() - - assert.Equal(t, p.columns, cols) - }) - } -} diff --git a/pkg/gorm-modernc-sqlite/errors.go b/pkg/gorm-modernc-sqlite/errors.go deleted file mode 100644 index 67b4d98a..00000000 --- a/pkg/gorm-modernc-sqlite/errors.go +++ /dev/null @@ -1,7 +0,0 @@ -package sqlite - -import "errors" - -var ( - ErrConstraintsNotImplemented = errors.New("constraints not implemented on sqlite, consider using DisableForeignKeyConstraintWhenMigrating, more details https://github.com/go-gorm/gorm/wiki/GORM-V2-Release-Note-Draft#all-new-migrator") -) diff --git a/pkg/gorm-modernc-sqlite/migrator.go b/pkg/gorm-modernc-sqlite/migrator.go deleted file mode 100644 index 641b1f46..00000000 --- a/pkg/gorm-modernc-sqlite/migrator.go +++ /dev/null @@ -1,418 +0,0 @@ -package sqlite - -import ( - "database/sql" - "fmt" - "regexp" - "strings" - - "gorm.io/gorm" - "gorm.io/gorm/clause" - "gorm.io/gorm/migrator" - "gorm.io/gorm/schema" -) - -type Migrator struct { - migrator.Migrator -} - -func (m *Migrator) RunWithoutForeignKey(fc func() error) error { - var enabled int - m.DB.Raw("PRAGMA foreign_keys").Scan(&enabled) - if enabled == 1 { - m.DB.Exec("PRAGMA foreign_keys = OFF") - defer m.DB.Exec("PRAGMA foreign_keys = ON") - } - - return fc() -} - -func (m Migrator) HasTable(value interface{}) bool { - var count int - m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { - return m.DB.Raw("SELECT count(*) FROM sqlite_master WHERE type='table' AND name=?", stmt.Table).Row().Scan(&count) - }) - return count > 0 -} - -func (m Migrator) DropTable(values ...interface{}) error { - return m.RunWithoutForeignKey(func() error { - values = m.ReorderModels(values, false) - tx := m.DB.Session(&gorm.Session{}) - - for i := len(values) - 1; i >= 0; i-- { - if err := m.RunWithValue(values[i], func(stmt *gorm.Statement) error { - return tx.Exec("DROP TABLE IF EXISTS ?", clause.Table{Name: stmt.Table}).Error - }); err != nil { - return err - } - } - - return nil - }) -} - -func (m Migrator) GetTables() (tableList []string, err error) { - return tableList, m.DB.Raw("SELECT name FROM sqlite_master where type=?", "table").Scan(&tableList).Error -} - -func (m Migrator) HasColumn(value interface{}, name string) bool { - var count int - m.Migrator.RunWithValue(value, func(stmt *gorm.Statement) error { - if stmt.Schema != nil { - if field := stmt.Schema.LookUpField(name); field != nil { - name = field.DBName - } - } - - if name != "" { - m.DB.Raw( - "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", - "table", stmt.Table, `%"`+name+`" %`, `%`+name+` %`, "%`"+name+"`%", "%["+name+"]%", "%\t"+name+"\t%", - ).Row().Scan(&count) - } - return nil - }) - return count > 0 -} - -func (m Migrator) AlterColumn(value interface{}, name string) error { - return m.RunWithoutForeignKey(func() error { - return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { - if field := stmt.Schema.LookUpField(name); field != nil { - reg, err := regexp.Compile("(`|'|\"| )" + field.DBName + "(`|'|\"| ) .*?,") - if err != nil { - return "", nil, err - } - - createSQL := reg.ReplaceAllString(rawDDL, fmt.Sprintf("`%v` ?,", field.DBName)) - - return createSQL, []interface{}{m.FullDataTypeOf(field)}, nil - } - return "", nil, fmt.Errorf("failed to alter field with name %v", name) - }) - }) -} - -// ColumnTypes return columnTypes []gorm.ColumnType and execErr error -func (m Migrator) ColumnTypes(value interface{}) ([]gorm.ColumnType, error) { - columnTypes := make([]gorm.ColumnType, 0) - execErr := m.RunWithValue(value, func(stmt *gorm.Statement) (err error) { - var ( - sqls []string - sqlDDL *ddl - ) - - if err := m.DB.Raw("SELECT sql FROM sqlite_master WHERE type IN ? AND tbl_name = ? AND sql IS NOT NULL order by type = ? desc", []string{"table", "index"}, stmt.Table, "table").Scan(&sqls).Error; err != nil { - return err - } - - if sqlDDL, err = parseDDL(sqls...); err != nil { - return err - } - - rows, err := m.DB.Session(&gorm.Session{}).Table(stmt.Table).Limit(1).Rows() - if err != nil { - return err - } - defer func() { - err = rows.Close() - }() - - var rawColumnTypes []*sql.ColumnType - rawColumnTypes, err = rows.ColumnTypes() - if err != nil { - return err - } - - for _, c := range rawColumnTypes { - columnType := migrator.ColumnType{SQLColumnType: c} - for _, column := range sqlDDL.columns { - if column.NameValue.String == c.Name() { - column.SQLColumnType = c - columnType = column - break - } - } - columnTypes = append(columnTypes, columnType) - } - - return err - }) - - return columnTypes, execErr -} - -func (m Migrator) DropColumn(value interface{}, name string) error { - return m.recreateTable(value, nil, func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { - if field := stmt.Schema.LookUpField(name); field != nil { - name = field.DBName - } - - reg, err := regexp.Compile("(`|'|\"| |\\[)" + name + "(`|'|\"| |\\]) .*?,") - if err != nil { - return "", nil, err - } - - createSQL := reg.ReplaceAllString(rawDDL, "") - - return createSQL, nil, nil - }) -} - -func (m Migrator) CreateConstraint(value interface{}, name string) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - constraint, chk, table := m.GuessConstraintAndTable(stmt, name) - - return m.recreateTable(value, &table, - func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { - var ( - constraintName string - constraintSql string - constraintValues []interface{} - ) - - if constraint != nil { - constraintName = constraint.Name - constraintSql, constraintValues = buildConstraint(constraint) - } else if chk != nil { - constraintName = chk.Name - constraintSql = "CONSTRAINT ? CHECK (?)" - constraintValues = []interface{}{clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint}} - } else { - return "", nil, nil - } - - createDDL, err := parseDDL(rawDDL) - if err != nil { - return "", nil, err - } - createDDL.addConstraint(constraintName, constraintSql) - createSQL := createDDL.compile() - - return createSQL, constraintValues, nil - }) - }) -} - -func (m Migrator) DropConstraint(value interface{}, name string) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - constraint, chk, table := m.GuessConstraintAndTable(stmt, name) - if constraint != nil { - name = constraint.Name - } else if chk != nil { - name = chk.Name - } - - return m.recreateTable(value, &table, - func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error) { - createDDL, err := parseDDL(rawDDL) - if err != nil { - return "", nil, err - } - createDDL.removeConstraint(name) - createSQL := createDDL.compile() - - return createSQL, nil, nil - }) - }) -} - -func (m Migrator) HasConstraint(value interface{}, name string) bool { - var count int64 - m.RunWithValue(value, func(stmt *gorm.Statement) error { - constraint, chk, table := m.GuessConstraintAndTable(stmt, name) - if constraint != nil { - name = constraint.Name - } else if chk != nil { - name = chk.Name - } - - m.DB.Raw( - "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND (sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ? OR sql LIKE ?)", - "table", table, `%CONSTRAINT "`+name+`" %`, `%CONSTRAINT `+name+` %`, "%CONSTRAINT `"+name+"`%", "%CONSTRAINT ["+name+"]%", "%CONSTRAINT \t"+name+"\t%", - ).Row().Scan(&count) - - return nil - }) - - return count > 0 -} - -func (m Migrator) CurrentDatabase() (name string) { - var null interface{} - m.DB.Raw("PRAGMA database_list").Row().Scan(&null, &name, &null) - return -} - -func (m Migrator) BuildIndexOptions(opts []schema.IndexOption, stmt *gorm.Statement) (results []interface{}) { - for _, opt := range opts { - str := stmt.Quote(opt.DBName) - if opt.Expression != "" { - str = opt.Expression - } - - if opt.Collate != "" { - str += " COLLATE " + opt.Collate - } - - if opt.Sort != "" { - str += " " + opt.Sort - } - results = append(results, clause.Expr{SQL: str}) - } - return -} - -func (m Migrator) CreateIndex(value interface{}, name string) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - if idx := stmt.Schema.LookIndex(name); idx != nil { - opts := m.BuildIndexOptions(idx.Fields, stmt) - values := []interface{}{clause.Column{Name: idx.Name}, clause.Table{Name: stmt.Table}, opts} - - createIndexSQL := "CREATE " - if idx.Class != "" { - createIndexSQL += idx.Class + " " - } - createIndexSQL += "INDEX ?" - - if idx.Type != "" { - createIndexSQL += " USING " + idx.Type - } - createIndexSQL += " ON ??" - - if idx.Where != "" { - createIndexSQL += " WHERE " + idx.Where - } - - return m.DB.Exec(createIndexSQL, values...).Error - } - - return fmt.Errorf("failed to create index with name %v", name) - }) -} - -func (m Migrator) HasIndex(value interface{}, name string) bool { - var count int - m.RunWithValue(value, func(stmt *gorm.Statement) error { - if idx := stmt.Schema.LookIndex(name); idx != nil { - name = idx.Name - } - - if name != "" { - m.DB.Raw( - "SELECT count(*) FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, name, - ).Row().Scan(&count) - } - return nil - }) - return count > 0 -} - -func (m Migrator) RenameIndex(value interface{}, oldName, newName string) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - var sql string - m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "index", stmt.Table, oldName).Row().Scan(&sql) - if sql != "" { - return m.DB.Exec(strings.Replace(sql, oldName, newName, 1)).Error - } - return fmt.Errorf("failed to find index with name %v", oldName) - }) -} - -func (m Migrator) DropIndex(value interface{}, name string) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - if idx := stmt.Schema.LookIndex(name); idx != nil { - name = idx.Name - } - - return m.DB.Exec("DROP INDEX ?", clause.Column{Name: name}).Error - }) -} - -func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) { - sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??" - if constraint.OnDelete != "" { - sql += " ON DELETE " + constraint.OnDelete - } - - if constraint.OnUpdate != "" { - sql += " ON UPDATE " + constraint.OnUpdate - } - - var foreignKeys, references []interface{} - for _, field := range constraint.ForeignKeys { - foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName}) - } - - for _, field := range constraint.References { - references = append(references, clause.Column{Name: field.DBName}) - } - results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references) - return -} - -func (m Migrator) getRawDDL(table string) (string, error) { - var createSQL string - m.DB.Raw("SELECT sql FROM sqlite_master WHERE type = ? AND tbl_name = ? AND name = ?", "table", table, table).Row().Scan(&createSQL) - - if m.DB.Error != nil { - return "", m.DB.Error - } - return createSQL, nil -} - -func (m Migrator) recreateTable(value interface{}, tablePtr *string, - getCreateSQL func(rawDDL string, stmt *gorm.Statement) (sql string, sqlArgs []interface{}, err error)) error { - return m.RunWithValue(value, func(stmt *gorm.Statement) error { - table := stmt.Table - if tablePtr != nil { - table = *tablePtr - } - - rawDDL, err := m.getRawDDL(table) - if err != nil { - return err - } - - newTableName := table + "__temp" - - createSQL, sqlArgs, err := getCreateSQL(rawDDL, stmt) - if err != nil { - return err - } - if createSQL == "" { - return nil - } - - tableReg, err := regexp.Compile(" ('|`|\"| )" + table + "('|`|\"| ) ") - if err != nil { - return err - } - createSQL = tableReg.ReplaceAllString(createSQL, fmt.Sprintf(" `%v` ", newTableName)) - - createDDL, err := parseDDL(createSQL) - if err != nil { - return err - } - columns := createDDL.getColumns() - - return m.DB.Transaction(func(tx *gorm.DB) error { - if err := tx.Exec(createSQL, sqlArgs...).Error; err != nil { - return err - } - - queries := []string{ - fmt.Sprintf("INSERT INTO `%v`(%v) SELECT %v FROM `%v`", newTableName, strings.Join(columns, ","), strings.Join(columns, ","), table), - fmt.Sprintf("DROP TABLE `%v`", table), - fmt.Sprintf("ALTER TABLE `%v` RENAME TO `%v`", newTableName, table), - } - for _, query := range queries { - if err := tx.Exec(query).Error; err != nil { - return err - } - } - return nil - }) - }) -} diff --git a/pkg/gorm-modernc-sqlite/sqlite.go b/pkg/gorm-modernc-sqlite/sqlite.go deleted file mode 100644 index 6e856ea3..00000000 --- a/pkg/gorm-modernc-sqlite/sqlite.go +++ /dev/null @@ -1,219 +0,0 @@ -package sqlite - -import ( - "context" - "database/sql" - "strconv" - "strings" - - "gorm.io/gorm/callbacks" - - "gorm.io/gorm" - "gorm.io/gorm/clause" - "gorm.io/gorm/logger" - "gorm.io/gorm/migrator" - "gorm.io/gorm/schema" - - _ "modernc.org/sqlite" -) - -// DriverName is the default driver name for SQLite. -const DriverName = "sqlite" - -type Dialector struct { - DriverName string - DSN string - Conn gorm.ConnPool -} - -func Open(dsn string) gorm.Dialector { - return &Dialector{DSN: dsn} -} - -func (dialector Dialector) Name() string { - return "sqlite" -} - -func (dialector Dialector) Initialize(db *gorm.DB) (err error) { - if dialector.DriverName == "" { - dialector.DriverName = DriverName - } - - if dialector.Conn != nil { - db.ConnPool = dialector.Conn - } else { - conn, err := sql.Open(dialector.DriverName, dialector.DSN) - if err != nil { - return err - } - db.ConnPool = conn - } - - var version string - if err := db.ConnPool.QueryRowContext(context.Background(), "select sqlite_version()").Scan(&version); err != nil { - return err - } - // https://www.sqlite.org/releaselog/3_35_0.html - if compareVersion(version, "3.35.0") >= 0 { - callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ - CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"}, - UpdateClauses: []string{"UPDATE", "SET", "WHERE", "RETURNING"}, - DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"}, - LastInsertIDReversed: true, - }) - } else { - callbacks.RegisterDefaultCallbacks(db, &callbacks.Config{ - LastInsertIDReversed: true, - }) - } - - for k, v := range dialector.ClauseBuilders() { - db.ClauseBuilders[k] = v - } - return -} - -func (dialector Dialector) ClauseBuilders() map[string]clause.ClauseBuilder { - return map[string]clause.ClauseBuilder{ - "INSERT": func(c clause.Clause, builder clause.Builder) { - if insert, ok := c.Expression.(clause.Insert); ok { - if stmt, ok := builder.(*gorm.Statement); ok { - stmt.WriteString("INSERT ") - if insert.Modifier != "" { - stmt.WriteString(insert.Modifier) - stmt.WriteByte(' ') - } - - stmt.WriteString("INTO ") - if insert.Table.Name == "" { - stmt.WriteQuoted(stmt.Table) - } else { - stmt.WriteQuoted(insert.Table) - } - return - } - } - - c.Build(builder) - }, - "LIMIT": func(c clause.Clause, builder clause.Builder) { - if limit, ok := c.Expression.(clause.Limit); ok { - if limit.Limit > 0 || limit.Offset > 0 { - if limit.Limit <= 0 { - limit.Limit = -1 - } - builder.WriteString("LIMIT " + strconv.Itoa(limit.Limit)) - } - if limit.Offset > 0 { - builder.WriteString(" OFFSET " + strconv.Itoa(limit.Offset)) - } - } - }, - "FOR": func(c clause.Clause, builder clause.Builder) { - if _, ok := c.Expression.(clause.Locking); ok { - // SQLite3 does not support row-level locking. - return - } - c.Build(builder) - }, - } -} - -func (dialector Dialector) DefaultValueOf(field *schema.Field) clause.Expression { - if field.AutoIncrement { - return clause.Expr{SQL: "NULL"} - } - - // doesn't work, will raise error - return clause.Expr{SQL: "DEFAULT"} -} - -func (dialector Dialector) Migrator(db *gorm.DB) gorm.Migrator { - return Migrator{migrator.Migrator{Config: migrator.Config{ - DB: db, - Dialector: dialector, - CreateIndexAfterCreateTable: true, - }}} -} - -func (dialector Dialector) BindVarTo(writer clause.Writer, stmt *gorm.Statement, v interface{}) { - writer.WriteByte('?') -} - -func (dialector Dialector) QuoteTo(writer clause.Writer, str string) { - writer.WriteByte('`') - if strings.Contains(str, ".") { - for idx, str := range strings.Split(str, ".") { - if idx > 0 { - writer.WriteString(".`") - } - writer.WriteString(str) - writer.WriteByte('`') - } - } else { - writer.WriteString(str) - writer.WriteByte('`') - } -} - -func (dialector Dialector) Explain(sql string, vars ...interface{}) string { - return logger.ExplainSQL(sql, nil, `"`, vars...) -} - -func (dialector Dialector) DataTypeOf(field *schema.Field) string { - switch field.DataType { - case schema.Bool: - return "numeric" - case schema.Int, schema.Uint: - if field.AutoIncrement && !field.PrimaryKey { - // https://www.sqlite.org/autoinc.html - return "integer PRIMARY KEY AUTOINCREMENT" - } else { - return "integer" - } - case schema.Float: - return "real" - case schema.String: - return "text" - case schema.Time: - return "datetime" - case schema.Bytes: - return "blob" - } - - return string(field.DataType) -} - -func (dialectopr Dialector) SavePoint(tx *gorm.DB, name string) error { - tx.Exec("SAVEPOINT " + name) - return nil -} - -func (dialectopr Dialector) RollbackTo(tx *gorm.DB, name string) error { - tx.Exec("ROLLBACK TO SAVEPOINT " + name) - return nil -} - -func compareVersion(version1, version2 string) int { - n, m := len(version1), len(version2) - i, j := 0, 0 - for i < n || j < m { - x := 0 - for ; i < n && version1[i] != '.'; i++ { - x = x*10 + int(version1[i]-'0') - } - i++ - y := 0 - for ; j < m && version2[j] != '.'; j++ { - y = y*10 + int(version2[j]-'0') - } - j++ - if x > y { - return 1 - } - if x < y { - return -1 - } - } - return 0 -} diff --git a/pkg/gorm-modernc-sqlite/sqlite_test.go b/pkg/gorm-modernc-sqlite/sqlite_test.go deleted file mode 100644 index 138646a1..00000000 --- a/pkg/gorm-modernc-sqlite/sqlite_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package sqlite - -import ( - "fmt" - "testing" - - "gorm.io/gorm" - _ "modernc.org/sqlite" -) - -func TestDialector(t *testing.T) { - // This is the DSN of the in-memory SQLite database for these tests. - const InMemoryDSN = "file:testdatabase?mode=memory&cache=shared" - - rows := []struct { - description string - dialector *Dialector - openSuccess bool - query string - querySuccess bool - }{ - { - description: "Default driver", - dialector: &Dialector{ - DSN: InMemoryDSN, - }, - openSuccess: true, - query: "SELECT 1", - querySuccess: true, - }, - { - description: "Explicit default driver", - dialector: &Dialector{ - DriverName: DriverName, - DSN: InMemoryDSN, - }, - openSuccess: true, - query: "SELECT 1", - querySuccess: true, - }, - { - description: "Bad driver", - dialector: &Dialector{ - DriverName: "not-a-real-driver", - DSN: InMemoryDSN, - }, - openSuccess: false, - }, - } - for rowIndex, row := range rows { - t.Run(fmt.Sprintf("%d/%s", rowIndex, row.description), func(t *testing.T) { - db, err := gorm.Open(row.dialector, &gorm.Config{}) - if !row.openSuccess { - if err == nil { - t.Errorf("Expected Open to fail.") - } - return - } - - if err != nil { - t.Errorf("Expected Open to succeed; got error: %v", err) - } - if db == nil { - t.Errorf("Expected db to be non-nil.") - } - if row.query != "" { - err = db.Exec(row.query).Error - if !row.querySuccess { - if err == nil { - t.Errorf("Expected query to fail.") - } - return - } - - if err != nil { - t.Errorf("Expected query to succeed; got error: %v", err) - } - } - }) - } -}