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  }