Skip to content

Commit a828b06

Browse files
committed
🧪 gorm 驱动测试
1 parent 68c4aa4 commit a828b06

File tree

8 files changed

+1150
-0
lines changed

8 files changed

+1150
-0
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,5 @@ require (
2828
go.uber.org/zap v1.17.0
2929
google.golang.org/protobuf v1.28.0
3030
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
31+
gorm.io/gorm v1.24.3
3132
)

go.sum

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,10 @@ github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpT
285285
github.com/hashicorp/serf v0.9.7/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4=
286286
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
287287
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
288+
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
289+
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
290+
github.com/jinzhu/now v1.1.4 h1:tHnRBy1i5F2Dh8BAFxqFzxKqqvezXrL2OW1TnX+Mlas=
291+
github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
288292
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
289293
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
290294
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -965,6 +969,8 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
965969
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
966970
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
967971
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
972+
gorm.io/gorm v1.24.3 h1:WL2ifUmzR/SLp85CSURAfybcHnGZ+yLSGSxgYXlFBHg=
973+
gorm.io/gorm v1.24.3/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
968974
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
969975
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
970976
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

gorm_driver/ddlmod.go

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
package gorm_driver
2+
3+
import (
4+
"database/sql"
5+
"errors"
6+
"fmt"
7+
"regexp"
8+
"strings"
9+
10+
"gorm.io/gorm/migrator"
11+
)
12+
13+
var (
14+
sqliteSeparator = "`|\"|'|\t"
15+
indexRegexp = regexp.MustCompile(fmt.Sprintf("CREATE(?: UNIQUE)? INDEX [%v][\\w\\d]+[%v] ON (.*)$", sqliteSeparator, sqliteSeparator))
16+
tableRegexp = regexp.MustCompile(fmt.Sprintf("(?i)(CREATE TABLE [%v]?[\\w\\d]+[%v]?)(?: \\((.*)\\))?", sqliteSeparator, sqliteSeparator))
17+
separatorRegexp = regexp.MustCompile(fmt.Sprintf("[%v]", sqliteSeparator))
18+
columnsRegexp = regexp.MustCompile(fmt.Sprintf("\\([%v]?([\\w\\d]+)[%v]?(?:,[%v]?([\\w\\d]+)[%v]){0,}\\)", sqliteSeparator, sqliteSeparator, sqliteSeparator, sqliteSeparator))
19+
columnRegexp = regexp.MustCompile(fmt.Sprintf("^[%v]?([\\w\\d]+)[%v]?\\s+([\\w\\(\\)\\d]+)(.*)$", sqliteSeparator, sqliteSeparator))
20+
defaultValueRegexp = regexp.MustCompile("(?i) DEFAULT \\(?(.+)?\\)?( |COLLATE|GENERATED|$)")
21+
)
22+
23+
type ddl struct {
24+
head string
25+
fields []string
26+
columns []migrator.ColumnType
27+
}
28+
29+
func parseDDL(strs ...string) (*ddl, error) {
30+
var result ddl
31+
for _, str := range strs {
32+
if sections := tableRegexp.FindStringSubmatch(str); len(sections) > 0 {
33+
var (
34+
ddlBody = sections[2]
35+
bracketLevel int
36+
quote rune
37+
buf string
38+
)
39+
40+
result.head = sections[1]
41+
42+
for idx, c := range []rune(ddlBody) {
43+
var next rune = 0
44+
if idx+1 < len(ddlBody) {
45+
next = []rune(ddlBody)[idx+1]
46+
}
47+
48+
if sc := string(c); separatorRegexp.MatchString(sc) {
49+
if c == next {
50+
buf += sc // Skip escaped quote
51+
idx++
52+
} else if quote > 0 {
53+
quote = 0
54+
} else {
55+
quote = c
56+
}
57+
} else if quote == 0 {
58+
if c == '(' {
59+
bracketLevel++
60+
} else if c == ')' {
61+
bracketLevel--
62+
} else if bracketLevel == 0 {
63+
if c == ',' {
64+
result.fields = append(result.fields, strings.TrimSpace(buf))
65+
buf = ""
66+
continue
67+
}
68+
}
69+
}
70+
71+
if bracketLevel < 0 {
72+
return nil, errors.New("invalid DDL, unbalanced brackets")
73+
}
74+
75+
buf += string(c)
76+
}
77+
78+
if bracketLevel != 0 {
79+
return nil, errors.New("invalid DDL, unbalanced brackets")
80+
}
81+
82+
if buf != "" {
83+
result.fields = append(result.fields, strings.TrimSpace(buf))
84+
}
85+
86+
for _, f := range result.fields {
87+
fUpper := strings.ToUpper(f)
88+
if strings.HasPrefix(fUpper, "CHECK") ||
89+
strings.HasPrefix(fUpper, "CONSTRAINT") {
90+
continue
91+
}
92+
93+
if strings.HasPrefix(fUpper, "PRIMARY KEY") {
94+
matches := columnsRegexp.FindStringSubmatch(f)
95+
if len(matches) > 1 {
96+
for _, name := range matches[1:] {
97+
for idx, column := range result.columns {
98+
if column.NameValue.String == name {
99+
column.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true}
100+
result.columns[idx] = column
101+
break
102+
}
103+
}
104+
}
105+
}
106+
} else if matches := columnRegexp.FindStringSubmatch(f); len(matches) > 0 {
107+
columnType := migrator.ColumnType{
108+
NameValue: sql.NullString{String: matches[1], Valid: true},
109+
DataTypeValue: sql.NullString{String: matches[2], Valid: true},
110+
ColumnTypeValue: sql.NullString{String: matches[2], Valid: true},
111+
PrimaryKeyValue: sql.NullBool{Valid: true},
112+
UniqueValue: sql.NullBool{Valid: true},
113+
NullableValue: sql.NullBool{Valid: true},
114+
DefaultValueValue: sql.NullString{Valid: true},
115+
}
116+
117+
matchUpper := strings.ToUpper(matches[3])
118+
if strings.Contains(matchUpper, " NOT NULL") {
119+
columnType.NullableValue = sql.NullBool{Bool: false, Valid: true}
120+
} else if strings.Contains(matchUpper, " NULL") {
121+
columnType.NullableValue = sql.NullBool{Bool: true, Valid: true}
122+
}
123+
if strings.Contains(matchUpper, " UNIQUE") {
124+
columnType.UniqueValue = sql.NullBool{Bool: true, Valid: true}
125+
}
126+
if strings.Contains(matchUpper, " PRIMARY") {
127+
columnType.PrimaryKeyValue = sql.NullBool{Bool: true, Valid: true}
128+
}
129+
if defaultMatches := defaultValueRegexp.FindStringSubmatch(matches[3]); len(defaultMatches) > 1 {
130+
columnType.DefaultValueValue = sql.NullString{String: strings.Trim(defaultMatches[1], `"`), Valid: true}
131+
}
132+
133+
result.columns = append(result.columns, columnType)
134+
}
135+
}
136+
} else if matches := indexRegexp.FindStringSubmatch(str); len(matches) > 0 {
137+
if columns := columnsRegexp.FindStringSubmatch(matches[1]); len(columns) == 1 {
138+
for idx, c := range result.columns {
139+
if c.NameValue.String == columns[0] {
140+
c.UniqueValue = sql.NullBool{Bool: true, Valid: true}
141+
result.columns[idx] = c
142+
}
143+
}
144+
}
145+
} else {
146+
return nil, errors.New("invalid DDL")
147+
}
148+
}
149+
150+
return &result, nil
151+
}
152+
153+
func (d *ddl) compile() string {
154+
if len(d.fields) == 0 {
155+
return d.head
156+
}
157+
158+
return fmt.Sprintf("%s (%s)", d.head, strings.Join(d.fields, ","))
159+
}
160+
161+
func (d *ddl) addConstraint(name string, sql string) {
162+
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
163+
164+
for i := 0; i < len(d.fields); i++ {
165+
if reg.MatchString(d.fields[i]) {
166+
d.fields[i] = sql
167+
return
168+
}
169+
}
170+
171+
d.fields = append(d.fields, sql)
172+
}
173+
174+
func (d *ddl) removeConstraint(name string) bool {
175+
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
176+
177+
for i := 0; i < len(d.fields); i++ {
178+
if reg.MatchString(d.fields[i]) {
179+
d.fields = append(d.fields[:i], d.fields[i+1:]...)
180+
return true
181+
}
182+
}
183+
return false
184+
}
185+
186+
func (d *ddl) hasConstraint(name string) bool {
187+
reg := regexp.MustCompile("^CONSTRAINT [\"`]?" + regexp.QuoteMeta(name) + "[\"` ]")
188+
189+
for _, f := range d.fields {
190+
if reg.MatchString(f) {
191+
return true
192+
}
193+
}
194+
return false
195+
}
196+
197+
func (d *ddl) getColumns() []string {
198+
res := []string{}
199+
200+
for _, f := range d.fields {
201+
fUpper := strings.ToUpper(f)
202+
if strings.HasPrefix(fUpper, "PRIMARY KEY") ||
203+
strings.HasPrefix(fUpper, "CHECK") ||
204+
strings.HasPrefix(fUpper, "CONSTRAINT") {
205+
continue
206+
}
207+
208+
reg := regexp.MustCompile("^[\"`']?([\\w\\d]+)[\"`']?")
209+
match := reg.FindStringSubmatch(f)
210+
211+
if match != nil {
212+
res = append(res, "`"+match[1]+"`")
213+
}
214+
}
215+
return res
216+
}

0 commit comments

Comments
 (0)