forked from joncrlsn/pgdiff
-
Notifications
You must be signed in to change notification settings - Fork 0
/
view.go
127 lines (106 loc) · 3.27 KB
/
view.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
//
// Copyright (c) 2016 Jon Carlson. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
//
package main
import "fmt"
import "sort"
import "database/sql"
import "github.com/joncrlsn/pgutil"
import "github.com/joncrlsn/misc"
// ==================================
// ViewRows definition
// ==================================
// ViewRows is a sortable slice of string maps
type ViewRows []map[string]string
func (slice ViewRows) Len() int {
return len(slice)
}
func (slice ViewRows) Less(i, j int) bool {
return slice[i]["viewname"] < slice[j]["viewname"]
}
func (slice ViewRows) Swap(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}
// ViewSchema holds a channel streaming view information from one of the databases as well as
// a reference to the current row of data we're viewing.
//
// ViewSchema implements the Schema interface defined in pgdiff.go
type ViewSchema struct {
rows ViewRows
rowNum int
done bool
}
// get returns the value from the current row for the given key
func (c *ViewSchema) get(key string) string {
if c.rowNum >= len(c.rows) {
return ""
}
return c.rows[c.rowNum][key]
}
// NextRow increments the rowNum and tells you whether or not there are more
func (c *ViewSchema) NextRow() bool {
if c.rowNum >= len(c.rows)-1 {
c.done = true
}
c.rowNum = c.rowNum + 1
return !c.done
}
// Compare tells you, in one pass, whether or not the first row matches, is less than, or greater than the second row
func (c *ViewSchema) Compare(obj interface{}) int {
c2, ok := obj.(*ViewSchema)
if !ok {
fmt.Println("Error!!!, Compare(obj) needs a ViewSchema instance", c2)
return +999
}
val := misc.CompareStrings(c.get("viewname"), c2.get("viewname"))
//fmt.Printf("-- Compared %v: %s with %s \n", val, c.get("viewname"), c2.get("viewname"))
return val
}
// Add returns SQL to create the view
func (c ViewSchema) Add() {
fmt.Printf("CREATE VIEW %s AS %s \n\n", c.get("viewname"), c.get("definition"))
}
// Drop returns SQL to drop the view
func (c ViewSchema) Drop() {
fmt.Printf("DROP VIEW IF EXISTS %s;\n\n", c.get("viewname"))
}
// Change handles the case where the names match, but the definition does not
func (c ViewSchema) Change(obj interface{}) {
c2, ok := obj.(*ViewSchema)
if !ok {
fmt.Println("Error!!!, Change needs a ViewSchema instance", c2)
}
if c.get("definition") != c2.get("definition") {
fmt.Printf("DROP VIEW %s;\n", c.get("viewname"))
fmt.Printf("CREATE VIEW %s AS %s \n\n", c.get("viewname"), c.get("definition"))
}
}
// compareViews outputs SQL to make the views match between DBs
func compareViews(conn1 *sql.DB, conn2 *sql.DB) {
sql := `
SELECT viewname
, definition
FROM pg_views
WHERE schemaname = 'public'
ORDER BY viewname;
`
rowChan1, _ := pgutil.QueryStrings(conn1, sql)
rowChan2, _ := pgutil.QueryStrings(conn2, sql)
rows1 := make(ViewRows, 0)
for row := range rowChan1 {
rows1 = append(rows1, row)
}
sort.Sort(rows1)
rows2 := make(ViewRows, 0)
for row := range rowChan2 {
rows2 = append(rows2, row)
}
sort.Sort(rows2)
// We have to explicitly type this as Schema here
var schema1 Schema = &ViewSchema{rows: rows1, rowNum: -1}
var schema2 Schema = &ViewSchema{rows: rows2, rowNum: -1}
// Compare the views
doDiff(schema1, schema2)
}