forked from gobuffalo/pop
/
columns.go
175 lines (153 loc) · 3.86 KB
/
columns.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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
package columns
import (
"fmt"
"sort"
"strings"
"sync"
)
// Columns represent a list of columns, related to a given table.
type Columns struct {
Cols map[string]*Column
lock *sync.RWMutex
TableName string
TableAlias string
IDField string
}
// Add a column to the list.
func (c *Columns) Add(names ...string) []*Column {
var ret []*Column
c.lock.Lock()
tableAlias := c.TableAlias
if tableAlias == "" {
tableAlias = c.TableName
}
for _, name := range names {
var xs []string
var col *Column
ss := ""
//support for distinct xx, or distinct on (field) table.fields
if strings.HasSuffix(name, ",r") || strings.HasSuffix(name, ",w") {
xs = []string{name[0 : len(name)-2], name[len(name)-1:]}
} else {
xs = []string{name}
}
xs[0] = strings.TrimSpace(xs[0])
//eg: id id2 - select id as id2
// also distinct columnname
// and distinct on (column1) column2
if strings.Contains(strings.ToUpper(xs[0]), " AS ") {
//eg: select id as id2
i := strings.LastIndex(strings.ToUpper(xs[0]), " AS ")
ss = xs[0]
xs[0] = xs[0][i+4 : len(xs[0])] //get id2
} else if strings.Contains(xs[0], " ") {
i := strings.LastIndex(name, " ")
ss = xs[0]
xs[0] = xs[0][i+1 : len(xs[0])] //get id2
}
col = c.Cols[xs[0]]
if col == nil {
if ss == "" {
ss = xs[0]
if tableAlias != "" {
ss = fmt.Sprintf("%s.%s", tableAlias, ss)
}
}
col = &Column{
Name: xs[0],
SelectSQL: ss,
Readable: true,
Writeable: true,
}
if len(xs) > 1 {
if xs[1] == "r" {
col.Writeable = false
} else if xs[1] == "w" {
col.Readable = false
}
} else if col.Name == c.IDField {
col.Writeable = false
}
c.Cols[col.Name] = col
}
ret = append(ret, col)
}
c.lock.Unlock()
return ret
}
// Remove a column from the list.
func (c *Columns) Remove(names ...string) {
for _, name := range names {
xs := strings.Split(name, ",")
name = xs[0]
delete(c.Cols, name)
}
}
// Writeable gets a list of the writeable columns from the column list.
func (c Columns) Writeable() *WriteableColumns {
w := &WriteableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias, c.IDField)}
for _, col := range c.Cols {
if col.Writeable {
w.Cols[col.Name] = col
}
}
return w
}
// Readable gets a list of the readable columns from the column list.
func (c Columns) Readable() *ReadableColumns {
w := &ReadableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias, c.IDField)}
for _, col := range c.Cols {
if col.Readable {
w.Cols[col.Name] = col
}
}
return w
}
// colNames returns a slice of column names in a deterministic order
func (c Columns) colNames() []string {
var xs []string
for _, t := range c.Cols {
xs = append(xs, t.Name)
}
sort.Strings(xs)
return xs
}
type quoter interface {
Quote(key string) string
}
// QuotedString gives the columns list quoted with the given quoter function.
func (c Columns) QuotedString(quoter quoter) string {
xs := c.colNames()
for i, n := range xs {
xs[i] = quoter.Quote(n)
}
return strings.Join(xs, ", ")
}
func (c Columns) String() string {
xs := c.colNames()
return strings.Join(xs, ", ")
}
// SymbolizedString returns a list of tokens (:token) to bind
// a value to an INSERT query.
func (c Columns) SymbolizedString() string {
xs := c.colNames()
for i, n := range xs {
xs[i] = ":" + n
}
return strings.Join(xs, ", ")
}
// NewColumns constructs a list of columns for a given table name.
func NewColumns(tableName, idField string) Columns {
return NewColumnsWithAlias(tableName, "", idField)
}
// NewColumnsWithAlias constructs a list of columns for a given table
// name, using a given alias for the table.
func NewColumnsWithAlias(tableName, tableAlias, idField string) Columns {
return Columns{
lock: &sync.RWMutex{},
Cols: map[string]*Column{},
TableName: tableName,
TableAlias: tableAlias,
IDField: idField,
}
}