github.com/atomicnibble/pop@v4.13.2+incompatible/columns/columns.go (about) 1 package columns 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 "sync" 8 ) 9 10 // Columns represent a list of columns, related to a given table. 11 type Columns struct { 12 Cols map[string]*Column 13 lock *sync.RWMutex 14 TableName string 15 TableAlias string 16 } 17 18 // Add a column to the list. 19 func (c *Columns) Add(names ...string) []*Column { 20 var ret []*Column 21 c.lock.Lock() 22 23 tableAlias := c.TableAlias 24 if tableAlias == "" { 25 tableAlias = c.TableName 26 } 27 28 for _, name := range names { 29 30 var xs []string 31 var col *Column 32 ss := "" 33 //support for distinct xx, or distinct on (field) table.fields 34 if strings.HasSuffix(name, ",r") || strings.HasSuffix(name, ",w") { 35 xs = []string{name[0 : len(name)-2], name[len(name)-1:]} 36 } else { 37 xs = []string{name} 38 } 39 40 xs[0] = strings.TrimSpace(xs[0]) 41 //eg: id id2 - select id as id2 42 // also distinct columnname 43 // and distinct on (column1) column2 44 if strings.Contains(strings.ToUpper(xs[0]), " AS ") { 45 //eg: select id as id2 46 i := strings.LastIndex(strings.ToUpper(xs[0]), " AS ") 47 ss = xs[0] 48 xs[0] = xs[0][i+4 : len(xs[0])] //get id2 49 } else if strings.Contains(xs[0], " ") { 50 i := strings.LastIndex(name, " ") 51 ss = xs[0] 52 xs[0] = xs[0][i+1 : len(xs[0])] //get id2 53 } 54 55 col = c.Cols[xs[0]] 56 if col == nil { 57 if ss == "" { 58 ss = xs[0] 59 if tableAlias != "" { 60 ss = fmt.Sprintf("%s.%s", tableAlias, ss) 61 } 62 } 63 64 col = &Column{ 65 Name: xs[0], 66 SelectSQL: ss, 67 Readable: true, 68 Writeable: true, 69 } 70 71 if len(xs) > 1 { 72 if xs[1] == "r" { 73 col.Writeable = false 74 } else if xs[1] == "w" { 75 col.Readable = false 76 } 77 } else if col.Name == "id" { 78 col.Writeable = false 79 } 80 81 c.Cols[col.Name] = col 82 } 83 ret = append(ret, col) 84 } 85 86 c.lock.Unlock() 87 return ret 88 } 89 90 // Remove a column from the list. 91 func (c *Columns) Remove(names ...string) { 92 for _, name := range names { 93 xs := strings.Split(name, ",") 94 name = xs[0] 95 delete(c.Cols, name) 96 } 97 } 98 99 // Writeable gets a list of the writeable columns from the column list. 100 func (c Columns) Writeable() *WriteableColumns { 101 w := &WriteableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias)} 102 for _, col := range c.Cols { 103 if col.Writeable { 104 w.Cols[col.Name] = col 105 } 106 } 107 return w 108 } 109 110 // Readable gets a list of the readable columns from the column list. 111 func (c Columns) Readable() *ReadableColumns { 112 w := &ReadableColumns{NewColumnsWithAlias(c.TableName, c.TableAlias)} 113 for _, col := range c.Cols { 114 if col.Readable { 115 w.Cols[col.Name] = col 116 } 117 } 118 return w 119 } 120 121 // colNames returns a slice of column names in a deterministic order 122 func (c Columns) colNames() []string { 123 var xs []string 124 for _, t := range c.Cols { 125 xs = append(xs, t.Name) 126 } 127 sort.Strings(xs) 128 return xs 129 } 130 131 type quoter interface { 132 Quote(key string) string 133 } 134 135 // QuotedString gives the columns list quoted with the given quoter function. 136 func (c Columns) QuotedString(quoter quoter) string { 137 xs := c.colNames() 138 for i, n := range xs { 139 xs[i] = quoter.Quote(n) 140 } 141 return strings.Join(xs, ", ") 142 } 143 144 func (c Columns) String() string { 145 xs := c.colNames() 146 return strings.Join(xs, ", ") 147 } 148 149 // SymbolizedString returns a list of tokens (:token) to bind 150 // a value to an INSERT query. 151 func (c Columns) SymbolizedString() string { 152 xs := c.colNames() 153 for i, n := range xs { 154 xs[i] = ":" + n 155 } 156 return strings.Join(xs, ", ") 157 } 158 159 // NewColumns constructs a list of columns for a given table name. 160 func NewColumns(tableName string) Columns { 161 return NewColumnsWithAlias(tableName, "") 162 } 163 164 // NewColumnsWithAlias constructs a list of columns for a given table 165 // name, using a given alias for the table. 166 func NewColumnsWithAlias(tableName string, tableAlias string) Columns { 167 return Columns{ 168 lock: &sync.RWMutex{}, 169 Cols: map[string]*Column{}, 170 TableName: tableName, 171 TableAlias: tableAlias, 172 } 173 }