forked from coocood/qbs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpostgres.go
124 lines (113 loc) · 2.68 KB
/
postgres.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
package qbs
import (
"database/sql"
"fmt"
"strings"
"time"
)
type postgres struct {
base
}
func NewPostgres() Dialect {
d := new(postgres)
d.base.Dialect = d
return d
}
func (d postgres) quote(s string) string {
sep := "."
a := []string{}
c := strings.Split(s, sep)
for _, v := range c {
a = append(a, fmt.Sprintf(`"%s"`, v))
}
return strings.Join(a, sep)
}
func (d postgres) sqlType(f interface{}, size int) string {
switch f.(type) {
case time.Time:
return "timestamp with time zone"
case bool:
return "boolean"
case int, int8, int16, int32, uint, uint8, uint16, uint32:
return "integer"
case int64, uint64:
return "bigint"
case float32, float64:
return "double precision"
case []byte:
return "bytea"
case string:
if size > 0 && size < 65532 {
return fmt.Sprintf("varchar(%d)", size)
}
return "text"
}
panic("invalid sql type")
}
func (d postgres) insert(q *Qbs) (int64, error) {
sql, args := d.Dialect.insertSql(q.criteria)
row := q.QueryRow(sql, args...)
value := q.criteria.model.pk.value
var err error
var id int64
if _, ok := value.(int64); ok {
err = row.Scan(&id)
} else if _, ok := value.(string); ok {
var str string
err = row.Scan(&str)
}
return id, err
}
func (d postgres) insertSql(criteria *criteria) (string, []interface{}) {
sql, values := d.base.insertSql(criteria)
sql += " RETURNING " + d.Dialect.quote(criteria.model.pk.name)
return sql, values
}
func (d postgres) indexExists(mg *Migration, tableName, indexName string) bool {
var row *sql.Row
var name string
query := "SELECT indexname FROM pg_indexes "
query += "WHERE tablename = ? AND indexname = ?"
query = d.substituteMarkers(query)
row = mg.Db.QueryRow(query, tableName, indexName)
row.Scan(&name)
return name != ""
}
func (d postgres) substituteMarkers(query string) string {
position := 1
chunks := make([]string, 0, len(query)*2)
for _, v := range query {
if v == '?' {
chunks = append(chunks, fmt.Sprintf("$%d", position))
position++
} else {
chunks = append(chunks, string(v))
}
}
return strings.Join(chunks, "")
}
func (d postgres) columnsInTable(mg *Migration, table interface{}) map[string]bool {
tn := tableName(table)
columns := make(map[string]bool)
query := "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ?"
query = mg.Dialect.substituteMarkers(query)
rows, err := mg.Db.Query(query, tn)
defer rows.Close()
if err != nil {
panic(err)
}
for rows.Next() {
column := ""
err := rows.Scan(&column)
if err == nil {
columns[column] = true
}
}
return columns
}
func (d postgres) primaryKeySql(isString bool, size int) string {
if isString {
return "text PRIMARY KEY"
}
return "bigserial PRIMARY KEY"
}