2016-04-04 10:27:51 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 GitHub Inc.
|
|
|
|
See https://github.com/github/gh-osc/blob/master/LICENSE
|
|
|
|
*/
|
|
|
|
|
|
|
|
package sql
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"reflect"
|
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2016-04-11 15:27:16 +00:00
|
|
|
// ColumnsMap maps a column onto its ordinal position
|
|
|
|
type ColumnsMap map[string]int
|
|
|
|
|
|
|
|
func NewColumnsMap(orderedNames []string) ColumnsMap {
|
|
|
|
columnsMap := make(map[string]int)
|
|
|
|
for i, column := range orderedNames {
|
|
|
|
columnsMap[column] = i
|
|
|
|
}
|
|
|
|
return ColumnsMap(columnsMap)
|
|
|
|
}
|
|
|
|
|
2016-04-04 10:27:51 +00:00
|
|
|
// ColumnList makes for a named list of columns
|
2016-04-11 15:27:16 +00:00
|
|
|
type ColumnList struct {
|
|
|
|
Names []string
|
|
|
|
Ordinals ColumnsMap
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewColumnList creates an object given ordered list of column names
|
|
|
|
func NewColumnList(names []string) *ColumnList {
|
|
|
|
result := &ColumnList{
|
|
|
|
Names: names,
|
|
|
|
}
|
|
|
|
result.Ordinals = NewColumnsMap(result.Names)
|
|
|
|
return result
|
|
|
|
}
|
2016-04-04 10:27:51 +00:00
|
|
|
|
|
|
|
// ParseColumnList parses a comma delimited list of column names
|
|
|
|
func ParseColumnList(columns string) *ColumnList {
|
2016-04-11 15:27:16 +00:00
|
|
|
result := &ColumnList{
|
|
|
|
Names: strings.Split(columns, ","),
|
|
|
|
}
|
|
|
|
result.Ordinals = NewColumnsMap(result.Names)
|
|
|
|
return result
|
2016-04-04 10:27:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *ColumnList) String() string {
|
2016-04-11 15:27:16 +00:00
|
|
|
return strings.Join(this.Names, ",")
|
2016-04-04 10:27:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *ColumnList) Equals(other *ColumnList) bool {
|
2016-04-11 15:27:16 +00:00
|
|
|
return reflect.DeepEqual(this.Names, other.Names)
|
2016-04-04 10:27:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-11 15:27:16 +00:00
|
|
|
// IsSubsetOf returns 'true' when column names of this list are a subset of
|
|
|
|
// another list, in arbitrary order (order agnostic)
|
|
|
|
func (this *ColumnList) IsSubsetOf(other *ColumnList) bool {
|
|
|
|
for _, column := range this.Names {
|
|
|
|
if _, exists := other.Ordinals[column]; !exists {
|
|
|
|
return false
|
|
|
|
}
|
2016-04-08 12:35:06 +00:00
|
|
|
}
|
2016-04-11 15:27:16 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
func (this *ColumnList) Len() int {
|
|
|
|
return len(this.Names)
|
2016-04-08 12:35:06 +00:00
|
|
|
}
|
|
|
|
|
2016-04-04 10:27:51 +00:00
|
|
|
// UniqueKey is the combination of a key's name and columns
|
|
|
|
type UniqueKey struct {
|
2016-04-18 17:57:18 +00:00
|
|
|
Name string
|
|
|
|
Columns ColumnList
|
|
|
|
HasNullable bool
|
|
|
|
IsAutoIncrement bool
|
2016-04-04 10:27:51 +00:00
|
|
|
}
|
|
|
|
|
2016-04-06 16:44:54 +00:00
|
|
|
// IsPrimary checks if this unique key is primary
|
2016-04-04 10:27:51 +00:00
|
|
|
func (this *UniqueKey) IsPrimary() bool {
|
|
|
|
return this.Name == "PRIMARY"
|
|
|
|
}
|
|
|
|
|
2016-04-11 15:27:16 +00:00
|
|
|
func (this *UniqueKey) Len() int {
|
|
|
|
return this.Columns.Len()
|
|
|
|
}
|
|
|
|
|
2016-04-04 10:27:51 +00:00
|
|
|
func (this *UniqueKey) String() string {
|
2016-04-18 17:57:18 +00:00
|
|
|
description := this.Name
|
|
|
|
if this.IsAutoIncrement {
|
|
|
|
description = fmt.Sprintf("%s (auto_incrmenet)", description)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%s: %s; has nullable: %+v", description, this.Columns.Names, this.HasNullable)
|
2016-04-04 10:27:51 +00:00
|
|
|
}
|
2016-04-04 16:19:46 +00:00
|
|
|
|
|
|
|
type ColumnValues struct {
|
|
|
|
abstractValues []interface{}
|
|
|
|
ValuesPointers []interface{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewColumnValues(length int) *ColumnValues {
|
|
|
|
result := &ColumnValues{
|
|
|
|
abstractValues: make([]interface{}, length),
|
|
|
|
ValuesPointers: make([]interface{}, length),
|
|
|
|
}
|
|
|
|
for i := 0; i < length; i++ {
|
|
|
|
result.ValuesPointers[i] = &result.abstractValues[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2016-04-06 16:44:54 +00:00
|
|
|
func ToColumnValues(abstractValues []interface{}) *ColumnValues {
|
|
|
|
result := &ColumnValues{
|
|
|
|
abstractValues: abstractValues,
|
|
|
|
ValuesPointers: make([]interface{}, len(abstractValues)),
|
|
|
|
}
|
|
|
|
for i := 0; i < len(abstractValues); i++ {
|
|
|
|
result.ValuesPointers[i] = &result.abstractValues[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
2016-04-04 16:19:46 +00:00
|
|
|
func (this *ColumnValues) AbstractValues() []interface{} {
|
|
|
|
return this.abstractValues
|
|
|
|
}
|
|
|
|
|
2016-04-07 13:57:12 +00:00
|
|
|
func (this *ColumnValues) StringColumn(index int) string {
|
|
|
|
val := this.AbstractValues()[index]
|
|
|
|
if ints, ok := val.([]uint8); ok {
|
|
|
|
return string(ints)
|
|
|
|
}
|
|
|
|
return fmt.Sprintf("%+v", val)
|
|
|
|
}
|
|
|
|
|
2016-04-04 16:19:46 +00:00
|
|
|
func (this *ColumnValues) String() string {
|
|
|
|
stringValues := []string{}
|
2016-04-07 13:57:12 +00:00
|
|
|
for i := range this.AbstractValues() {
|
|
|
|
stringValues = append(stringValues, this.StringColumn(i))
|
2016-04-04 16:19:46 +00:00
|
|
|
}
|
|
|
|
return strings.Join(stringValues, ",")
|
|
|
|
}
|