-
Notifications
You must be signed in to change notification settings - Fork 0
/
describe_tables.go
95 lines (79 loc) · 1.86 KB
/
describe_tables.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
package pgutil
import (
"context"
"fmt"
"strings"
)
type TableDescription struct {
Namespace string
Name string
Columns []ColumnDescription
Constraints []ConstraintDescription
Indexes []IndexDescription
}
// Note: not a deep comparison
func (d TableDescription) Equals(other TableDescription) bool {
return true &&
d.Namespace == other.Namespace &&
d.Name == other.Name
}
type table struct {
Namespace string
Name string
}
var scanTables = NewSliceScanner(func(s Scanner) (t table, _ error) {
err := s.Scan(&t.Namespace, &t.Name)
return t, err
})
func DescribeTables(ctx context.Context, db DB) ([]TableDescription, error) {
tables, err := scanTables(db.Query(ctx, RawQuery(`
SELECT
t.table_schema AS namespace,
t.table_name AS name
FROM information_schema.tables t
WHERE
t.table_type = 'BASE TABLE' AND
t.table_schema NOT LIKE 'pg_%' AND
t.table_schema != 'information_schema'
ORDER BY t.table_schema, t.table_name
`)))
if err != nil {
return nil, err
}
columnMap, err := describeColumns(ctx, db)
if err != nil {
return nil, err
}
constraintMap, err := describeConstraints(ctx, db)
if err != nil {
return nil, err
}
indexMap, err := describeIndexes(ctx, db)
if err != nil {
return nil, err
}
var hydratedTables []TableDescription
for _, table := range tables {
key := fmt.Sprintf("%q.%q", table.Namespace, table.Name)
hydratedTables = append(hydratedTables, TableDescription{
Namespace: table.Namespace,
Name: table.Name,
Columns: columnMap[key],
Constraints: constraintMap[key],
Indexes: indexMap[key],
})
}
return hydratedTables, nil
}
//
//
func truthy(value string) bool {
// truthy strings + SQL spec YES_NO
return strings.ToLower(value) == "yes" || strings.ToLower(value) == "true"
}
func deref[T any](p *T) (v T) {
if p != nil {
v = *p
}
return
}