forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/go-gorp/gorp/v3/table.go

456 lines
6.9 KiB
Go
Raw Normal View History

2024-02-18 10:42:21 +00:00
// Copyright 2012 James Cooper. All rights reserved.
2024-02-18 10:42:21 +00:00
// Use of this source code is governed by a MIT-style
2024-02-18 10:42:21 +00:00
// license that can be found in the LICENSE file.
package gorp
import (
"bytes"
"fmt"
"reflect"
"strings"
)
// TableMap represents a mapping between a Go struct and a database table
2024-02-18 10:42:21 +00:00
// Use dbmap.AddTable() or dbmap.AddTableWithName() to create these
2024-02-18 10:42:21 +00:00
type TableMap struct {
2024-02-18 10:42:21 +00:00
// Name of database table.
TableName string
SchemaName string
gotype reflect.Type
Columns []*ColumnMap
keys []*ColumnMap
indexes []*IndexMap
2024-02-18 10:42:21 +00:00
uniqueTogether [][]string
version *ColumnMap
insertPlan bindPlan
updatePlan bindPlan
deletePlan bindPlan
getPlan bindPlan
dbmap *DbMap
2024-02-18 10:42:21 +00:00
}
// ResetSql removes cached insert/update/select/delete SQL strings
2024-02-18 10:42:21 +00:00
// associated with this TableMap. Call this if you've modified
2024-02-18 10:42:21 +00:00
// any column names or the table name itself.
2024-02-18 10:42:21 +00:00
func (t *TableMap) ResetSql() {
2024-02-18 10:42:21 +00:00
t.insertPlan = bindPlan{}
2024-02-18 10:42:21 +00:00
t.updatePlan = bindPlan{}
2024-02-18 10:42:21 +00:00
t.deletePlan = bindPlan{}
2024-02-18 10:42:21 +00:00
t.getPlan = bindPlan{}
2024-02-18 10:42:21 +00:00
}
// SetKeys lets you specify the fields on a struct that map to primary
2024-02-18 10:42:21 +00:00
// key columns on the table. If isAutoIncr is set, result.LastInsertId()
2024-02-18 10:42:21 +00:00
// will be used after INSERT to bind the generated id to the Go struct.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Panics if isAutoIncr is true, and fieldNames length != 1
2024-02-18 10:42:21 +00:00
func (t *TableMap) SetKeys(isAutoIncr bool, fieldNames ...string) *TableMap {
2024-02-18 10:42:21 +00:00
if isAutoIncr && len(fieldNames) != 1 {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf(
2024-02-18 10:42:21 +00:00
"gorp: SetKeys: fieldNames length must be 1 if key is auto-increment. (Saw %v fieldNames)",
2024-02-18 10:42:21 +00:00
len(fieldNames)))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
t.keys = make([]*ColumnMap, 0)
2024-02-18 10:42:21 +00:00
for _, name := range fieldNames {
2024-02-18 10:42:21 +00:00
colmap := t.ColMap(name)
2024-02-18 10:42:21 +00:00
colmap.isPK = true
2024-02-18 10:42:21 +00:00
colmap.isAutoIncr = isAutoIncr
2024-02-18 10:42:21 +00:00
t.keys = append(t.keys, colmap)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
t.ResetSql()
return t
2024-02-18 10:42:21 +00:00
}
// SetUniqueTogether lets you specify uniqueness constraints across multiple
2024-02-18 10:42:21 +00:00
// columns on the table. Each call adds an additional constraint for the
2024-02-18 10:42:21 +00:00
// specified columns.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Panics if fieldNames length < 2.
2024-02-18 10:42:21 +00:00
func (t *TableMap) SetUniqueTogether(fieldNames ...string) *TableMap {
2024-02-18 10:42:21 +00:00
if len(fieldNames) < 2 {
2024-02-18 10:42:21 +00:00
panic(fmt.Sprintf(
2024-02-18 10:42:21 +00:00
"gorp: SetUniqueTogether: must provide at least two fieldNames to set uniqueness constraint."))
2024-02-18 10:42:21 +00:00
}
columns := make([]string, 0, len(fieldNames))
2024-02-18 10:42:21 +00:00
for _, name := range fieldNames {
2024-02-18 10:42:21 +00:00
columns = append(columns, name)
2024-02-18 10:42:21 +00:00
}
for _, existingColumns := range t.uniqueTogether {
2024-02-18 10:42:21 +00:00
if equal(existingColumns, columns) {
2024-02-18 10:42:21 +00:00
return t
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
t.uniqueTogether = append(t.uniqueTogether, columns)
2024-02-18 10:42:21 +00:00
t.ResetSql()
return t
2024-02-18 10:42:21 +00:00
}
// ColMap returns the ColumnMap pointer matching the given struct field
2024-02-18 10:42:21 +00:00
// name. It panics if the struct does not contain a field matching this
2024-02-18 10:42:21 +00:00
// name.
2024-02-18 10:42:21 +00:00
func (t *TableMap) ColMap(field string) *ColumnMap {
2024-02-18 10:42:21 +00:00
col := colMapOrNil(t, field)
2024-02-18 10:42:21 +00:00
if col == nil {
2024-02-18 10:42:21 +00:00
e := fmt.Sprintf("No ColumnMap in table %s type %s with field %s",
2024-02-18 10:42:21 +00:00
t.TableName, t.gotype.Name(), field)
panic(e)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return col
2024-02-18 10:42:21 +00:00
}
func colMapOrNil(t *TableMap, field string) *ColumnMap {
2024-02-18 10:42:21 +00:00
for _, col := range t.Columns {
2024-02-18 10:42:21 +00:00
if col.fieldName == field || col.ColumnName == field {
2024-02-18 10:42:21 +00:00
return col
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
// IdxMap returns the IndexMap pointer matching the given index name.
2024-02-18 10:42:21 +00:00
func (t *TableMap) IdxMap(field string) *IndexMap {
2024-02-18 10:42:21 +00:00
for _, idx := range t.indexes {
2024-02-18 10:42:21 +00:00
if idx.IndexName == field {
2024-02-18 10:42:21 +00:00
return idx
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return nil
2024-02-18 10:42:21 +00:00
}
// AddIndex registers the index with gorp for specified table with given parameters.
2024-02-18 10:42:21 +00:00
// This operation is idempotent. If index is already mapped, the
2024-02-18 10:42:21 +00:00
// existing *IndexMap is returned
2024-02-18 10:42:21 +00:00
// Function will panic if one of the given for index columns does not exists
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
2024-02-18 10:42:21 +00:00
func (t *TableMap) AddIndex(name string, idxtype string, columns []string) *IndexMap {
2024-02-18 10:42:21 +00:00
// check if we have a index with this name already
2024-02-18 10:42:21 +00:00
for _, idx := range t.indexes {
2024-02-18 10:42:21 +00:00
if idx.IndexName == name {
2024-02-18 10:42:21 +00:00
return idx
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
for _, icol := range columns {
2024-02-18 10:42:21 +00:00
if res := t.ColMap(icol); res == nil {
2024-02-18 10:42:21 +00:00
e := fmt.Sprintf("No ColumnName in table %s to create index on", t.TableName)
2024-02-18 10:42:21 +00:00
panic(e)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
idx := &IndexMap{IndexName: name, Unique: false, IndexType: idxtype, columns: columns}
2024-02-18 10:42:21 +00:00
t.indexes = append(t.indexes, idx)
2024-02-18 10:42:21 +00:00
t.ResetSql()
2024-02-18 10:42:21 +00:00
return idx
2024-02-18 10:42:21 +00:00
}
// SetVersionCol sets the column to use as the Version field. By default
2024-02-18 10:42:21 +00:00
// the "Version" field is used. Returns the column found, or panics
2024-02-18 10:42:21 +00:00
// if the struct does not contain a field matching this name.
2024-02-18 10:42:21 +00:00
//
2024-02-18 10:42:21 +00:00
// Automatically calls ResetSql() to ensure SQL statements are regenerated.
2024-02-18 10:42:21 +00:00
func (t *TableMap) SetVersionCol(field string) *ColumnMap {
2024-02-18 10:42:21 +00:00
c := t.ColMap(field)
2024-02-18 10:42:21 +00:00
t.version = c
2024-02-18 10:42:21 +00:00
t.ResetSql()
2024-02-18 10:42:21 +00:00
return c
2024-02-18 10:42:21 +00:00
}
// SqlForCreateTable gets a sequence of SQL commands that will create
2024-02-18 10:42:21 +00:00
// the specified table and any associated schema
2024-02-18 10:42:21 +00:00
func (t *TableMap) SqlForCreate(ifNotExists bool) string {
2024-02-18 10:42:21 +00:00
s := bytes.Buffer{}
2024-02-18 10:42:21 +00:00
dialect := t.dbmap.Dialect
if strings.TrimSpace(t.SchemaName) != "" {
2024-02-18 10:42:21 +00:00
schemaCreate := "create schema"
2024-02-18 10:42:21 +00:00
if ifNotExists {
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.IfSchemaNotExists(schemaCreate, t.SchemaName))
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
s.WriteString(schemaCreate)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(fmt.Sprintf(" %s;", t.SchemaName))
2024-02-18 10:42:21 +00:00
}
tableCreate := "create table"
2024-02-18 10:42:21 +00:00
if ifNotExists {
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.IfTableNotExists(tableCreate, t.SchemaName, t.TableName))
2024-02-18 10:42:21 +00:00
} else {
2024-02-18 10:42:21 +00:00
s.WriteString(tableCreate)
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(fmt.Sprintf(" %s (", dialect.QuotedTableForQuery(t.SchemaName, t.TableName)))
x := 0
2024-02-18 10:42:21 +00:00
for _, col := range t.Columns {
2024-02-18 10:42:21 +00:00
if !col.Transient {
2024-02-18 10:42:21 +00:00
if x > 0 {
2024-02-18 10:42:21 +00:00
s.WriteString(", ")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
stype := dialect.ToSqlType(col.gotype, col.MaxSize, col.isAutoIncr)
2024-02-18 10:42:21 +00:00
s.WriteString(fmt.Sprintf("%s %s", dialect.QuoteField(col.ColumnName), stype))
if col.isPK || col.isNotNull {
2024-02-18 10:42:21 +00:00
s.WriteString(" not null")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if col.isPK && len(t.keys) == 1 {
2024-02-18 10:42:21 +00:00
s.WriteString(" primary key")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if col.Unique {
2024-02-18 10:42:21 +00:00
s.WriteString(" unique")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if col.isAutoIncr {
2024-02-18 10:42:21 +00:00
s.WriteString(fmt.Sprintf(" %s", dialect.AutoIncrStr()))
2024-02-18 10:42:21 +00:00
}
x++
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if len(t.keys) > 1 {
2024-02-18 10:42:21 +00:00
s.WriteString(", primary key (")
2024-02-18 10:42:21 +00:00
for x := range t.keys {
2024-02-18 10:42:21 +00:00
if x > 0 {
2024-02-18 10:42:21 +00:00
s.WriteString(", ")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.QuoteField(t.keys[x].ColumnName))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(")")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
if len(t.uniqueTogether) > 0 {
2024-02-18 10:42:21 +00:00
for _, columns := range t.uniqueTogether {
2024-02-18 10:42:21 +00:00
s.WriteString(", unique (")
2024-02-18 10:42:21 +00:00
for i, column := range columns {
2024-02-18 10:42:21 +00:00
if i > 0 {
2024-02-18 10:42:21 +00:00
s.WriteString(", ")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.QuoteField(column))
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(")")
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
s.WriteString(") ")
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.CreateTableSuffix())
2024-02-18 10:42:21 +00:00
s.WriteString(dialect.QuerySuffix())
2024-02-18 10:42:21 +00:00
return s.String()
2024-02-18 10:42:21 +00:00
}
func equal(a, b []string) bool {
2024-02-18 10:42:21 +00:00
if len(a) != len(b) {
2024-02-18 10:42:21 +00:00
return false
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
for i := range a {
2024-02-18 10:42:21 +00:00
if a[i] != b[i] {
2024-02-18 10:42:21 +00:00
return false
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
}
2024-02-18 10:42:21 +00:00
return true
2024-02-18 10:42:21 +00:00
}