-
Notifications
You must be signed in to change notification settings - Fork 2k
/
diff.go
176 lines (167 loc) · 5.25 KB
/
diff.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package schemadiff
import (
"vitess.io/vitess/go/vt/sqlparser"
)
// DDLActionStr returns the action implied by the given diff: CREATE", "DROP", "ALTER" or empty
func DDLActionStr(diff EntityDiff) (string, error) {
if diff == nil {
return "", nil
}
if ddl, ok := diff.Statement().(sqlparser.DDLStatement); ok {
return ddl.GetAction().ToString(), nil
}
return "", ErrUnexpectedDiffAction
}
// AllSubsequent returns a list of diffs starting the given diff and followed by all subsequent diffs, if any
func AllSubsequent(diff EntityDiff) (diffs []EntityDiff) {
for diff != nil && !diff.IsEmpty() {
diffs = append(diffs, diff)
diff = diff.SubsequentDiff()
}
return diffs
}
// DiffCreateTablesQueries compares two `CREATE TABLE ...` queries (in string form) and returns the diff from table1 to table2.
// Either or both of the queries can be empty. Based on this, the diff could be
// nil, CreateTable, DropTable or AlterTable
func DiffCreateTablesQueries(env *Environment, query1 string, query2 string, hints *DiffHints) (EntityDiff, error) {
var fromCreateTable *sqlparser.CreateTable
var ok bool
if query1 != "" {
stmt, err := env.Parser().ParseStrictDDL(query1)
if err != nil {
return nil, err
}
fromCreateTable, ok = stmt.(*sqlparser.CreateTable)
if !ok {
return nil, ErrExpectedCreateTable
}
}
var toCreateTable *sqlparser.CreateTable
if query2 != "" {
stmt, err := env.Parser().ParseStrictDDL(query2)
if err != nil {
return nil, err
}
toCreateTable, ok = stmt.(*sqlparser.CreateTable)
if !ok {
return nil, ErrExpectedCreateTable
}
}
return DiffTables(env, fromCreateTable, toCreateTable, hints)
}
// DiffTables compares two tables and returns the diff from table1 to table2.
// Either or both of the CreateTable statements can be nil. Based on this, the diff could be
// nil, CreateTable, DropTable or AlterTable
func DiffTables(env *Environment, create1 *sqlparser.CreateTable, create2 *sqlparser.CreateTable, hints *DiffHints) (EntityDiff, error) {
switch {
case create1 == nil && create2 == nil:
return nil, nil
case create1 == nil:
c2, err := NewCreateTableEntity(env, create2)
if err != nil {
return nil, err
}
return c2.Create(), nil
case create2 == nil:
c1, err := NewCreateTableEntity(env, create1)
if err != nil {
return nil, err
}
return c1.Drop(), nil
default:
c1, err := NewCreateTableEntity(env, create1)
if err != nil {
return nil, err
}
c2, err := NewCreateTableEntity(env, create2)
if err != nil {
return nil, err
}
return c1.Diff(c2, hints)
}
}
// DiffCreateViewsQueries compares two `CREATE TABLE ...` queries (in string form) and returns the diff from table1 to table2.
// Either or both of the queries can be empty. Based on this, the diff could be
// nil, CreateView, DropView or AlterView
func DiffCreateViewsQueries(env *Environment, query1 string, query2 string, hints *DiffHints) (EntityDiff, error) {
var fromCreateView *sqlparser.CreateView
var ok bool
if query1 != "" {
stmt, err := env.Parser().ParseStrictDDL(query1)
if err != nil {
return nil, err
}
fromCreateView, ok = stmt.(*sqlparser.CreateView)
if !ok {
return nil, ErrExpectedCreateView
}
}
var toCreateView *sqlparser.CreateView
if query2 != "" {
stmt, err := env.Parser().ParseStrictDDL(query2)
if err != nil {
return nil, err
}
toCreateView, ok = stmt.(*sqlparser.CreateView)
if !ok {
return nil, ErrExpectedCreateView
}
}
return DiffViews(env, fromCreateView, toCreateView, hints)
}
// DiffViews compares two views and returns the diff from view1 to view2
// Either or both of the CreateView statements can be nil. Based on this, the diff could be
// nil, CreateView, DropView or AlterView
func DiffViews(env *Environment, create1 *sqlparser.CreateView, create2 *sqlparser.CreateView, hints *DiffHints) (EntityDiff, error) {
switch {
case create1 == nil && create2 == nil:
return nil, nil
case create1 == nil:
c2, err := NewCreateViewEntity(env, create2)
if err != nil {
return nil, err
}
return c2.Create(), nil
case create2 == nil:
c1, err := NewCreateViewEntity(env, create1)
if err != nil {
return nil, err
}
return c1.Drop(), nil
default:
c1, err := NewCreateViewEntity(env, create1)
if err != nil {
return nil, err
}
c2, err := NewCreateViewEntity(env, create2)
if err != nil {
return nil, err
}
return c1.Diff(c2, hints)
}
}
// DiffSchemasSQL compares two schemas and returns the rich diff that turns
// 1st schema into 2nd. Schemas are build from SQL, each of which can contain an arbitrary number of
// CREATE TABLE and CREATE VIEW statements.
func DiffSchemasSQL(env *Environment, sql1 string, sql2 string, hints *DiffHints) (*SchemaDiff, error) {
schema1, err := NewSchemaFromSQL(env, sql1)
if err != nil {
return nil, err
}
schema2, err := NewSchemaFromSQL(env, sql2)
if err != nil {
return nil, err
}
return schema1.SchemaDiff(schema2, hints)
}
// DiffSchemas compares two schemas and returns the list of diffs that turn
// 1st schema into 2nd. Any of the schemas may be nil.
func DiffSchemas(env *Environment, schema1 *Schema, schema2 *Schema, hints *DiffHints) (*SchemaDiff, error) {
if schema1 == nil {
schema1 = newEmptySchema(env)
}
if schema2 == nil {
schema2 = newEmptySchema(env)
}
return schema1.SchemaDiff(schema2, hints)
}