mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-08-14 10:34:02 +08:00
90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
package sync
|
|
|
|
import (
|
|
"GoNavi-Wails/internal/connection"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// diffRowsByKeyColumns compares rows by the complete, ordered key tuple.
|
|
// Updates and deletes retain every key component for the database driver.
|
|
func diffRowsByKeyColumns(keyColumns []string, sourceRows, targetRows []map[string]interface{}) ([]map[string]interface{}, []connection.UpdateRow, []map[string]interface{}, int) {
|
|
targetMap := make(map[string]map[string]interface{}, len(targetRows))
|
|
for _, row := range targetRows {
|
|
key, ok := syncRowKey(row, keyColumns)
|
|
if !ok {
|
|
continue
|
|
}
|
|
targetMap[key] = row
|
|
}
|
|
|
|
sourceKeySet := make(map[string]struct{}, len(sourceRows))
|
|
inserts := make([]map[string]interface{}, 0)
|
|
updates := make([]connection.UpdateRow, 0)
|
|
same := 0
|
|
for _, sourceRow := range sourceRows {
|
|
key, ok := syncRowKey(sourceRow, keyColumns)
|
|
if !ok {
|
|
continue
|
|
}
|
|
sourceKeySet[key] = struct{}{}
|
|
if targetRow, exists := targetMap[key]; exists {
|
|
changes := make(map[string]interface{})
|
|
for column, value := range sourceRow {
|
|
if fmt.Sprintf("%v", value) != fmt.Sprintf("%v", targetRow[column]) {
|
|
changes[column] = value
|
|
}
|
|
}
|
|
if len(changes) == 0 {
|
|
same++
|
|
continue
|
|
}
|
|
updates = append(updates, connection.UpdateRow{
|
|
Keys: syncRowKeys(sourceRow, keyColumns),
|
|
Values: changes,
|
|
})
|
|
continue
|
|
}
|
|
inserts = append(inserts, sourceRow)
|
|
}
|
|
|
|
deletes := make([]map[string]interface{}, 0)
|
|
for key, row := range targetMap {
|
|
if _, exists := sourceKeySet[key]; exists {
|
|
continue
|
|
}
|
|
deletes = append(deletes, syncRowKeys(row, keyColumns))
|
|
}
|
|
return inserts, updates, deletes, same
|
|
}
|
|
|
|
func syncRowKeys(row map[string]interface{}, keyColumns []string) map[string]interface{} {
|
|
keys := make(map[string]interface{}, len(keyColumns))
|
|
for _, column := range keyColumns {
|
|
keys[column] = row[column]
|
|
}
|
|
return keys
|
|
}
|
|
|
|
func syncRowKey(row map[string]interface{}, keyColumns []string) (string, bool) {
|
|
if len(keyColumns) == 0 {
|
|
return "", false
|
|
}
|
|
values := make([]interface{}, 0, len(keyColumns))
|
|
for _, column := range keyColumns {
|
|
value, ok := row[column]
|
|
if !ok || value == nil {
|
|
return "", false
|
|
}
|
|
if bytes, ok := value.([]byte); ok {
|
|
value = string(bytes)
|
|
}
|
|
values = append(values, value)
|
|
}
|
|
encoded, err := json.Marshal(values)
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
return string(encoded), true
|
|
}
|