Skip to content
This repository was archived by the owner on Mar 4, 2025. It is now read-only.

Commit 17d37a1

Browse files
committed
common: Add new parameter to diff function for specifying merge strategy
This adds a new parameter to the diff function to specify the merge strategy. This is mostly intended for later use and at the moment does not do much except for toggling on or off the output of SQL statements in the generated changeset object. The way this is meant to be used (without guarantees that this is going to work) is to use the NoMerge strategy when no merging is intended in order to save some CPU cycles. The PreservePkMerge strategy is intended for generating the SQL statements needed to create database B out of database A in this scenario: A --> B It can also be used when the user needs the primary key of their tables to be preserved, i.e. when it carries some meaning. The NewPkMerge strategy generates the same SQL statements except for the INSERT statements which create new primary keys instead of keeping the original ones. This is intended for merging databases B and C into database D in this scenario: A --> B --> D \ ^ \--> C ---/ Here the diff between A and C using the NewPkMerge strategy can be applied on B to create D - at least when conflicting UPDATEs are handled. As soon as we implement actual merging we might want to add a function to guess the merge strategy depending on whether or not the table has a primary key, it is AUTOINCREMENTing, and it is of type INTEGER or some similar algorithm and add a "guess" merge strategy here. This commit also adds support for the new parameter to the API handler. If no value is provided we default to the "none" merge strategy.
1 parent 02ac2c0 commit 17d37a1

File tree

2 files changed

+38
-11
lines changed

2 files changed

+38
-11
lines changed

api/handlers.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,13 +84,26 @@ func columnsHandler(w http.ResponseWriter, r *http.Request) {
8484
// * "dbname_b" is the name of the second database being diffed (optional, if not provided same as first name)
8585
// * "commit_a" is the first commit for diffing
8686
// * "commit_b" is the second commit for diffing
87+
// * "merge" specifies the merge strategy (possible values: "none", "preserve_pk", "new_pk"; optional, defaults to "none")
8788
func diffHandler(w http.ResponseWriter, r *http.Request) {
8889
loggedInUser, err := checkAuth(w, r)
8990
if err != nil {
9091
jsonErr(w, err.Error(), http.StatusUnauthorized)
9192
return
9293
}
9394

95+
// Get merge strategy and parse value. Default to "none"
96+
merge := r.PostFormValue("merge")
97+
merge_strategy := com.NoMerge
98+
if merge == "preserve_pk" {
99+
merge_strategy = com.PreservePkMerge
100+
} else if merge == "new_pk" {
101+
merge_strategy = com.NewPkMerge
102+
} else if merge != "" && merge != "none" {
103+
jsonErr(w, "Invalid merge strategy", http.StatusBadRequest)
104+
return
105+
}
106+
94107
// Retrieve owner, name, and commit ids
95108
oa := r.PostFormValue("dbowner_a")
96109
na := r.PostFormValue("dbname_a")
@@ -164,7 +177,7 @@ func diffHandler(w http.ResponseWriter, r *http.Request) {
164177
}
165178

166179
// Perform diff
167-
diffs, err := com.Diff(dbOwnerA, "/", dbNameA, ca, dbOwnerB, "/", dbNameB, cb, loggedInUser)
180+
diffs, err := com.Diff(dbOwnerA, "/", dbNameA, ca, dbOwnerB, "/", dbNameB, cb, loggedInUser, merge_strategy)
168181
if err != nil {
169182
jsonErr(w, err.Error(), http.StatusInternalServerError)
170183
return

common/diff.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ const (
1717
ACTION_MODIFY = "modify"
1818
)
1919

20+
type MergeStrategy int
21+
22+
const (
23+
NoMerge MergeStrategy = iota
24+
PreservePkMerge
25+
NewPkMerge
26+
)
27+
2028
type SchemaDiff struct {
2129
ActionType DiffType `json:"action_type"`
2230
Sql string `json:"sql"`
@@ -41,7 +49,7 @@ type Diffs struct {
4149
}
4250

4351
// Diff generates the differences between the two commits commitA and commitB of the two databases specified in the other parameters
44-
func Diff(ownerA string, folderA string, nameA string, commitA string, ownerB string, folderB string, nameB string, commitB string, loggedInUser string) (Diffs, error) {
52+
func Diff(ownerA string, folderA string, nameA string, commitA string, ownerB string, folderB string, nameB string, commitB string, loggedInUser string, merge MergeStrategy) (Diffs, error) {
4553
// Check if the user has access to the requested databases
4654
bucketA, idA, _, err := MinioLocation(ownerA, folderA, nameA, commitA, loggedInUser)
4755
if err != nil {
@@ -77,11 +85,11 @@ func Diff(ownerA string, folderA string, nameA string, commitA string, ownerB st
7785
}
7886

7987
// Call dbDiff which does the actual diffing of the database files
80-
return dbDiff(dbA, dbB)
88+
return dbDiff(dbA, dbB, merge)
8189
}
8290

8391
// dbDiff generates the differences between the two database files in dbA and dbD
84-
func dbDiff(dbA string, dbB string) (Diffs, error) {
92+
func dbDiff(dbA string, dbB string, merge MergeStrategy) (Diffs, error) {
8593
var diff Diffs
8694

8795
// Check if this is the same database and exit early
@@ -122,7 +130,7 @@ func dbDiff(dbA string, dbB string) (Diffs, error) {
122130
err = stmt.Select(func(s *sqlite.Stmt) error {
123131
objectName, _ := s.ScanText(0)
124132
objectType, _ := s.ScanText(1)
125-
changed, objectDiff, err := diffSingleObject(sdb, objectName, objectType)
133+
changed, objectDiff, err := diffSingleObject(sdb, objectName, objectType, merge)
126134
if err != nil {
127135
return err
128136
}
@@ -144,7 +152,7 @@ func dbDiff(dbA string, dbB string) (Diffs, error) {
144152

145153
// diffSingleObject compares the object with name objectName and of type objectType in the main and aux schemata of the connection sdb
146154
// and returns three values: a boolean to indicate whether there are differences, a DiffObjectChangeset object containing all the differences, and an optional error object
147-
func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string) (bool, DiffObjectChangeset, error) {
155+
func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string, merge MergeStrategy) (bool, DiffObjectChangeset, error) {
148156
// Prepare diff object to return
149157
var diff DiffObjectChangeset
150158
diff.ObjectName = objectName
@@ -164,7 +172,9 @@ func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string) (b
164172
// Check for dropped object
165173
if sqlInMain != "" && sqlInAux == "" {
166174
diff.Schema.ActionType = ACTION_DELETE
167-
diff.Schema.Sql = "DROP " + strings.ToUpper(objectType) + " " + EscapeId(objectName) + ";"
175+
if merge != NoMerge {
176+
diff.Schema.Sql = "DROP " + strings.ToUpper(objectType) + " " + EscapeId(objectName) + ";"
177+
}
168178

169179
// If this is a table, also add all the deleted data to the diff
170180
if objectType == "table" {
@@ -182,11 +192,13 @@ func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string) (b
182192
// Check for added object
183193
if sqlInMain == "" && sqlInAux != "" {
184194
diff.Schema.ActionType = ACTION_ADD
185-
diff.Schema.Sql = sqlInAux + ";"
195+
if merge != NoMerge {
196+
diff.Schema.Sql = sqlInAux + ";"
197+
}
186198

187199
// If this is a table, also add all the added data to the diff
188200
if objectType == "table" {
189-
diff.Data, err = dataDiffForAllTableRows(sdb, "aux", objectName, ACTION_ADD, true)
201+
diff.Data, err = dataDiffForAllTableRows(sdb, "aux", objectName, ACTION_ADD, merge != NoMerge)
190202
if err != nil {
191203
return false, DiffObjectChangeset{}, err
192204
}
@@ -199,7 +211,9 @@ func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string) (b
199211
// Check for modified object
200212
if sqlInMain != "" && sqlInAux != "" && sqlInMain != sqlInAux {
201213
diff.Schema.ActionType = ACTION_MODIFY
202-
diff.Schema.Sql = "DROP " + strings.ToUpper(objectType) + " " + EscapeId(objectName) + ";" + sqlInAux + ";"
214+
if merge != NoMerge {
215+
diff.Schema.Sql = "DROP " + strings.ToUpper(objectType) + " " + EscapeId(objectName) + ";" + sqlInAux + ";"
216+
}
203217

204218
// TODO If this is a table, be more clever and try to get away with ALTER TABLE instead of DROP and CREATE
205219

@@ -209,7 +223,7 @@ func diffSingleObject(sdb *sqlite.Conn, objectName string, objectType string) (b
209223
if err != nil {
210224
return false, DiffObjectChangeset{}, err
211225
}
212-
add_data, err := dataDiffForAllTableRows(sdb, "aux", objectName, ACTION_ADD, true)
226+
add_data, err := dataDiffForAllTableRows(sdb, "aux", objectName, ACTION_ADD, merge != NoMerge)
213227
if err != nil {
214228
return false, DiffObjectChangeset{}, err
215229
}

0 commit comments

Comments
 (0)