automigrate

package module
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2020 License: MIT Imports: 17 Imported by: 1

README

automigrate

由 github.com/jinzhu/gorm v1.9.14 修改而来,用于 goframe 的orm automigrate功能

目前只做了 sqlserver的功能,其他数据库自行搬运 gorm的 dialects包

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrRecordNotFound returns a "record not found error". Occurs only when attempting to query the database with a struct; querying with a slice won't return this error
	ErrRecordNotFound = errors.New("record not found")
	// ErrInvalidSQL occurs when you attempt a query with invalid SQL
	ErrInvalidSQL = errors.New("invalid SQL")
	// ErrInvalidTransaction occurs when you are trying to `Commit` or `Rollback`
	ErrInvalidTransaction = errors.New("no valid transaction")
	// ErrCantStartTransaction can't start transaction when you are trying to start one with `Begin`
	ErrCantStartTransaction = errors.New("can't start transaction")
	// ErrUnaddressable unaddressable value
	ErrUnaddressable = errors.New("using unaddressable value")
)
View Source
var DefaultCallback = &Callback{logger: nopLogger{}}

DefaultCallback default callbacks defined by gorm

View Source
var DefaultTableNameHandler = func(db *DB, defaultTableName string) string {
	return defaultTableName
}

DefaultTableNameHandler default table name handler

View Source
var LogFormatter = func(values ...interface{}) (messages []interface{}) {
	if len(values) > 1 {
		var (
			sql             string
			formattedValues []string
			level           = values[0]
			currentTime     = "\n\033[33m[" + NowFunc().Format("2006-01-02 15:04:05") + "]\033[0m"
			source          = fmt.Sprintf("\033[35m(%v)\033[0m", values[1])
		)

		messages = []interface{}{source, currentTime}

		if len(values) == 2 {

			currentTime = currentTime[1:]

			source = fmt.Sprintf("\033[35m%v\033[0m", values[1])

			messages = []interface{}{currentTime, source}
		}

		if level == "sql" {

			messages = append(messages, fmt.Sprintf(" \033[36;1m[%.2fms]\033[0m ", float64(values[2].(time.Duration).Nanoseconds()/1e4)/100.0))

			for _, value := range values[4].([]interface{}) {
				indirectValue := reflect.Indirect(reflect.ValueOf(value))
				if indirectValue.IsValid() {
					value = indirectValue.Interface()
					if t, ok := value.(time.Time); ok {
						if t.IsZero() {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", "0000-00-00 00:00:00"))
						} else {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", t.Format("2006-01-02 15:04:05")))
						}
					} else if b, ok := value.([]byte); ok {
						if str := string(b); isPrintable(str) {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", str))
						} else {
							formattedValues = append(formattedValues, "'<binary>'")
						}
					} else if r, ok := value.(driver.Valuer); ok {
						if value, err := r.Value(); err == nil && value != nil {
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
						} else {
							formattedValues = append(formattedValues, "NULL")
						}
					} else {
						switch value.(type) {
						case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, bool:
							formattedValues = append(formattedValues, fmt.Sprintf("%v", value))
						default:
							formattedValues = append(formattedValues, fmt.Sprintf("'%v'", value))
						}
					}
				} else {
					formattedValues = append(formattedValues, "NULL")
				}
			}

			if numericPlaceHolderRegexp.MatchString(values[3].(string)) {
				sql = values[3].(string)
				for index, value := range formattedValues {
					placeholder := fmt.Sprintf(`\$%d([^\d]|$)`, index+1)
					sql = regexp.MustCompile(placeholder).ReplaceAllString(sql, value+"$1")
				}
			} else {
				formattedValuesLength := len(formattedValues)
				for index, value := range sqlRegexp.Split(values[3].(string), -1) {
					sql += value
					if index < formattedValuesLength {
						sql += formattedValues[index]
					}
				}
			}

			messages = append(messages, sql)
			messages = append(messages, fmt.Sprintf(" \n\033[36;31m[%v]\033[0m ", strconv.FormatInt(values[5].(int64), 10)+" rows affected or returned "))
		} else {
			messages = append(messages, "\033[31;1m")
			messages = append(messages, values[2:]...)
			messages = append(messages, "\033[0m")
		}
	}

	return
}
View Source
var NowFunc = func() time.Time {
	return time.Now()
}

NowFunc returns current time, this function is exported in order to be able to give the flexibility to the developer to customize it according to their needs, e.g:

gorm.NowFunc = func() time.Time {
  return time.Now().UTC()
}
View Source
var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) {
	// Get redirected field type
	var (
		reflectType = field.Struct.Type
		dataType, _ = field.TagSettingsGet("TYPE")
	)

	for reflectType.Kind() == reflect.Ptr {
		reflectType = reflectType.Elem()
	}

	fieldValue = reflect.Indirect(reflect.New(reflectType))

	if gormDataType, ok := fieldValue.Interface().(interface {
		GormDataType(Dialect) string
	}); ok {
		dataType = gormDataType.GormDataType(dialect)
	}

	if dataType == "" {
		var getScannerValue func(reflect.Value)
		getScannerValue = func(value reflect.Value) {
			fieldValue = value
			if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
				getScannerValue(fieldValue.Field(0))
			}
		}
		getScannerValue(fieldValue)
	}

	if num, ok := field.TagSettingsGet("SIZE"); ok {
		size, _ = strconv.Atoi(num)
	} else {
		size = 255
	}

	notNull, _ := field.TagSettingsGet("NOT NULL")
	unique, _ := field.TagSettingsGet("UNIQUE")
	additionalType = notNull + " " + unique
	if value, ok := field.TagSettingsGet("DEFAULT"); ok {
		additionalType = additionalType + " DEFAULT " + value
	}

	if value, ok := field.TagSettingsGet("COMMENT"); ok {
		additionalType = additionalType + " COMMENT " + value
	}

	return fieldValue, dataType, size, strings.TrimSpace(additionalType)
}

ParseFieldStructForDialect get field's sql data type

View Source
var TheNamingStrategy = &NamingStrategy{
	DB:     defaultNamer,
	Table:  defaultNamer,
	Column: defaultNamer,
}

TheNamingStrategy is being initialized with defaultNamingStrategy

Functions

func AddNamingStrategy

func AddNamingStrategy(ns *NamingStrategy)

AddNamingStrategy sets the naming strategy

func IsByteArrayOrSlice

func IsByteArrayOrSlice(value reflect.Value) bool

IsByteArrayOrSlice returns true of the reflected value is an array or slice

func IsRecordNotFoundError

func IsRecordNotFoundError(err error) bool

IsRecordNotFoundError returns true if error contains a RecordNotFound error

func RegisterDialect

func RegisterDialect(name string, dialect Dialect)

RegisterDialect register new dialect

func ToColumnName

func ToColumnName(name string) string

ToColumnName convert string to db name

func ToDBName

func ToDBName(name string) string

ToDBName convert string to db name

func ToTableName

func ToTableName(name string) string

ToTableName convert string to table name

Types

type Callback

type Callback struct {
	// contains filtered or unexported fields
}

Callback is a struct that contains all CRUD callbacks

Field `creates` contains callbacks will be call when creating object
Field `updates` contains callbacks will be call when updating object
Field `deletes` contains callbacks will be call when deleting object
Field `queries` contains callbacks will be call when querying object with query methods like Find, First, Related, Association...
Field `rowQueries` contains callbacks will be call when querying object with Row, Rows...
Field `processors` contains all callback processors, will be used to generate above callbacks in order

func (*Callback) Create

func (c *Callback) Create() *CallbackProcessor

Create could be used to register callbacks for creating object

db.Callback().Create().After("gorm:create").Register("plugin:run_after_create", func(*Scope) {
  // business logic
  ...

  // set error if some thing wrong happened, will rollback the creating
  scope.Err(errors.New("error"))
})

func (*Callback) Delete

func (c *Callback) Delete() *CallbackProcessor

Delete could be used to register callbacks for deleting object, refer `Create` for usage

func (*Callback) Query

func (c *Callback) Query() *CallbackProcessor

Query could be used to register callbacks for querying objects with query methods like `Find`, `First`, `Related`, `Association`... Refer `Create` for usage

func (*Callback) RowQuery

func (c *Callback) RowQuery() *CallbackProcessor

RowQuery could be used to register callbacks for querying objects with `Row`, `Rows`, refer `Create` for usage

func (*Callback) Update

func (c *Callback) Update() *CallbackProcessor

Update could be used to register callbacks for updating object, refer `Create` for usage

type CallbackProcessor

type CallbackProcessor struct {
	// contains filtered or unexported fields
}

CallbackProcessor contains callback informations

func (*CallbackProcessor) After

func (cp *CallbackProcessor) After(callbackName string) *CallbackProcessor

After insert a new callback after callback `callbackName`, refer `Callbacks.Create`

func (*CallbackProcessor) Before

func (cp *CallbackProcessor) Before(callbackName string) *CallbackProcessor

Before insert a new callback before callback `callbackName`, refer `Callbacks.Create`

func (*CallbackProcessor) Get

func (cp *CallbackProcessor) Get(callbackName string) (callback func(scope *Scope))

Get registered callback

db.Callback().Create().Get("gorm:create")

func (*CallbackProcessor) Register

func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope))

Register a new callback, refer `Callbacks.Create`

func (*CallbackProcessor) Remove

func (cp *CallbackProcessor) Remove(callbackName string)

Remove a registered callback

db.Callback().Create().Remove("gorm:update_time_stamp_when_create")

func (*CallbackProcessor) Replace

func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope))

Replace a registered callback with new callback

    db.Callback().Create().Replace("gorm:update_time_stamp_when_create", func(*Scope) {
		   scope.SetColumn("CreatedAt", now)
		   scope.SetColumn("UpdatedAt", now)
    })

type DB

type DB struct {
	sync.RWMutex
	Value        interface{}
	Error        error
	RowsAffected int64
	// contains filtered or unexported fields
}

func NewDB

func NewDB(name string, db gdb.DB) *DB

func (*DB) AddError

func (s *DB) AddError(err error) error

AddError add error to the db

func (*DB) AddIndex

func (s *DB) AddIndex(indexName string, columns ...string) *DB

AddIndex add index for columns with given name

func (*DB) AddUniqueIndex

func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB

AddUniqueIndex add unique index for columns with given name

func (*DB) AutoMigrate

func (s *DB) AutoMigrate(values ...interface{}) *DB

func (*DB) Exec

func (s *DB) Exec(sql string, values ...interface{}) *DB

Exec execute raw sql

func (*DB) Get

func (s *DB) Get(name string) (value interface{}, ok bool)

Get get setting by name

func (*DB) GetErrors

func (s *DB) GetErrors() []error

GetErrors get happened errors from the db

func (*DB) InstantSet

func (s *DB) InstantSet(name string, value interface{}) *DB

InstantSet instant set setting, will affect current db

func (*DB) Model

func (s *DB) Model(value interface{}) *DB

Model specify the model you would like to run db operations

// update all users's name to `hello`
db.Model(&User{}).Update("name", "hello")
// if user's primary key is non-blank, will use it as condition, then will only update the user's name to `hello`
db.Model(&user).Update("name", "hello")

func (*DB) NewScope

func (s *DB) NewScope(value interface{}) *Scope

func (*DB) Set

func (s *DB) Set(name string, value interface{}) *DB

Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting

func (*DB) Table

func (s *DB) Table(name string) *DB

Table specify the table you would like to run db operations

func (*DB) Unscoped

func (s *DB) Unscoped() *DB

Unscoped return all record including deleted record, refer Soft Delete https://jinzhu.github.io/gorm/crud.html#soft-delete

type DefaultForeignKeyNamer

type DefaultForeignKeyNamer struct {
}

DefaultForeignKeyNamer contains the default foreign key name generator method

func (DefaultForeignKeyNamer) BuildKeyName

func (DefaultForeignKeyNamer) BuildKeyName(kind, tableName string, fields ...string) string

BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference

type Dialect

type Dialect interface {
	// GetName get dialect's name
	GetName() string

	// SetDB set db for dialect
	SetDB(db gdb.DB)

	// BindVar return the placeholder for actual values in SQL statements, in many dbs it is "?", Postgres using $1
	BindVar(i int) string
	// Quote quotes field name to avoid SQL parsing exceptions by using a reserved word as a field name
	Quote(key string) string
	// DataTypeOf return data's sql type
	DataTypeOf(field *StructField) string

	// HasIndex check has index or not
	HasIndex(tableName string, indexName string) bool
	// HasForeignKey check has foreign key or not
	HasForeignKey(tableName string, foreignKeyName string) bool
	// RemoveIndex remove index
	RemoveIndex(tableName string, indexName string) error
	// HasTable check has table or not
	HasTable(tableName string) bool
	// HasColumn check has column or not
	HasColumn(tableName string, columnName string) bool
	// ModifyColumn modify column's type
	ModifyColumn(tableName string, columnName string, typ string) error

	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
	LimitAndOffsetSQL(limit, offset interface{}) (string, error)
	// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
	SelectFromDummyTable() string
	// LastInsertIDOutputInterstitial most dbs support LastInsertId, but mssql needs to use `OUTPUT`
	LastInsertIDOutputInterstitial(tableName, columnName string, columns []string) string
	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
	LastInsertIDReturningSuffix(tableName, columnName string) string
	// DefaultValueStr
	DefaultValueStr() string

	// BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
	BuildKeyName(kind, tableName string, fields ...string) string

	// NormalizeIndexAndColumn returns valid index name and column name depending on each dialect
	NormalizeIndexAndColumn(indexName, columnName string) (string, string)

	// CurrentDatabase return current database name
	CurrentDatabase() string
}

Dialect interface contains behaviors that differ across SQL database

func GetDialect

func GetDialect(name string) (dialect Dialect, ok bool)

GetDialect gets the dialect for the specified dialect name

type Errors

type Errors []error

Errors contains all happened errors

func (Errors) Add

func (errs Errors) Add(newErrors ...error) Errors

Add adds an error to a given slice of errors

func (Errors) Error

func (errs Errors) Error() string

Error takes a slice of all errors that have occurred and returns it as a formatted string

func (Errors) GetErrors

func (errs Errors) GetErrors() []error

GetErrors gets all errors that have occurred and returns a slice of errors (Error type)

type Field

type Field struct {
	*StructField
	IsBlank bool
	Field   reflect.Value
}

Field model field definition

func (*Field) Set

func (field *Field) Set(value interface{}) (err error)

Set set a value to the field

type JoinTableForeignKey

type JoinTableForeignKey struct {
	DBName            string
	AssociationDBName string
}

JoinTableForeignKey join table foreign key struct

type JoinTableHandler

type JoinTableHandler struct {
	TableName   string          `sql:"-"`
	Source      JoinTableSource `sql:"-"`
	Destination JoinTableSource `sql:"-"`
}

JoinTableHandler default join table handler

func (JoinTableHandler) Add

func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error

Add create relationship in join table for source and destination

func (*JoinTableHandler) DestinationForeignKeys

func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey

DestinationForeignKeys return destination foreign keys

func (*JoinTableHandler) Setup

func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)

Setup initialize a default join table handler

func (*JoinTableHandler) SourceForeignKeys

func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey

SourceForeignKeys return source foreign keys

func (JoinTableHandler) Table

func (s JoinTableHandler) Table(db *DB) string

Table return join table's table name

type JoinTableHandlerInterface

type JoinTableHandlerInterface interface {
	// initialize join table handler
	Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)
	// Table return join table's table name
	Table(db *DB) string
	// Add create relationship in join table for source and destination
	Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error
	// SourceForeignKeys return source foreign keys
	SourceForeignKeys() []JoinTableForeignKey
	// DestinationForeignKeys return destination foreign keys
	DestinationForeignKeys() []JoinTableForeignKey
}

JoinTableHandlerInterface is an interface for how to handle many2many relations

type JoinTableSource

type JoinTableSource struct {
	ModelType   reflect.Type
	ForeignKeys []JoinTableForeignKey
}

JoinTableSource is a struct that contains model type and foreign keys

type LogWriter

type LogWriter interface {
	Println(v ...interface{})
}

LogWriter log writer interface

type Logger

type Logger struct {
	LogWriter
}

Logger default logger

func (Logger) Print

func (logger Logger) Print(values ...interface{})

Print format & print log

type Model

type Model struct {
	ID        uint `automigrate:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time `sql:"index"`
}

type ModelStruct

type ModelStruct struct {
	PrimaryFields []*StructField
	StructFields  []*StructField
	ModelType     reflect.Type
	// contains filtered or unexported fields
}

ModelStruct model definition

func (*ModelStruct) TableName

func (s *ModelStruct) TableName(db *DB) string

TableName returns model's table name

type Namer

type Namer func(string) string

Namer is a function type which is given a string and return a string

type NamingStrategy

type NamingStrategy struct {
	DB     Namer
	Table  Namer
	Column Namer
}

NamingStrategy represents naming strategies

func (*NamingStrategy) ColumnName

func (ns *NamingStrategy) ColumnName(name string) string

ColumnName alters the given name by Column

func (*NamingStrategy) DBName

func (ns *NamingStrategy) DBName(name string) string

DBName alters the given name by DB

func (*NamingStrategy) TableName

func (ns *NamingStrategy) TableName(name string) string

TableName alters the given name by Table

type Relationship

type Relationship struct {
	Kind                         string
	PolymorphicType              string
	PolymorphicDBName            string
	PolymorphicValue             string
	ForeignFieldNames            []string
	ForeignDBNames               []string
	AssociationForeignFieldNames []string
	AssociationForeignDBNames    []string
	JoinTableHandler             JoinTableHandlerInterface
}

Relationship described the relationship between models

type Scope

type Scope struct {
	Search  *search
	Value   interface{}
	SQL     string
	SQLVars []interface{}
	// contains filtered or unexported fields
}

func (*Scope) AddToVars

func (scope *Scope) AddToVars(value interface{}) string

AddToVars add value as sql's vars, used to prevent SQL injection

func (*Scope) CombinedConditionSql

func (scope *Scope) CombinedConditionSql() string

CombinedConditionSql return combined condition sql

func (*Scope) Dialect

func (scope *Scope) Dialect() Dialect

Dialect get dialect

func (*Scope) Err

func (scope *Scope) Err(err error) error

Err add error to Scope

func (*Scope) Exec

func (scope *Scope) Exec() *Scope

Exec perform generated SQL

func (*Scope) FieldByName

func (scope *Scope) FieldByName(name string) (field *Field, ok bool)

FieldByName find `gorm.Field` with field name or db name

func (*Scope) Fields

func (scope *Scope) Fields() []*Field

Fields get value's fields

func (*Scope) Get

func (scope *Scope) Get(name string) (interface{}, bool)

Get get setting by name

func (*Scope) GetModelStruct

func (scope *Scope) GetModelStruct() *ModelStruct

GetModelStruct get value's model struct, relationships based on struct and tag definition

func (*Scope) GetStructFields

func (scope *Scope) GetStructFields() (fields []*StructField)

GetStructFields get model's field structs

func (*Scope) IndirectValue

func (scope *Scope) IndirectValue() reflect.Value

IndirectValue return scope's reflect value's indirect value

func (*Scope) InstanceGet

func (scope *Scope) InstanceGet(name string) (interface{}, bool)

InstanceGet get instance setting from current operation

func (*Scope) InstanceID

func (scope *Scope) InstanceID() string

InstanceID get InstanceID for scope

func (*Scope) InstanceSet

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope

InstanceSet set instance setting for current operation, but not for operations in callbacks, like saving associations callback

func (*Scope) New

func (scope *Scope) New(value interface{}) *Scope

New create a new Scope without search information

func (*Scope) NewDB

func (scope *Scope) NewDB() *DB

NewDB create a new DB without search information

func (*Scope) PrimaryField

func (scope *Scope) PrimaryField() *Field

PrimaryField return scope's main primary field, if defined more that one primary fields, will return the one having column name `id` or the first one

func (*Scope) PrimaryFields

func (scope *Scope) PrimaryFields() (fields []*Field)

PrimaryFields return scope's primary fields

func (*Scope) PrimaryKey

func (scope *Scope) PrimaryKey() string

PrimaryKey get main primary field's db name

func (*Scope) PrimaryKeyValue

func (scope *Scope) PrimaryKeyValue() interface{}

PrimaryKeyValue get the primary key's value

func (*Scope) PrimaryKeyZero

func (scope *Scope) PrimaryKeyZero() bool

PrimaryKeyZero check main primary field's value is blank or not

func (*Scope) Quote

func (scope *Scope) Quote(str string) string

Quote used to quote string to escape them for database

func (*Scope) QuotedTableName

func (scope *Scope) QuotedTableName() (name string)

QuotedTableName return quoted table name

func (*Scope) Raw

func (scope *Scope) Raw(sql string) *Scope

Raw set raw sql

func (*Scope) Set

func (scope *Scope) Set(name string, value interface{}) *Scope

Set set value by name

func (*Scope) TableName

func (scope *Scope) TableName() string

type SqlExpr

type SqlExpr struct {
	// contains filtered or unexported fields
}

SQL expression

func Expr

func Expr(expression string, args ...interface{}) *SqlExpr

Expr generate raw SQL expression, for example:

DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))

type StructField

type StructField struct {
	DBName          string
	Name            string
	Names           []string
	IsPrimaryKey    bool
	IsNormal        bool
	IsIgnored       bool
	IsScanner       bool
	HasDefaultValue bool
	Tag             reflect.StructTag
	TagSettings     map[string]string
	Struct          reflect.StructField
	IsForeignKey    bool
	Relationship    *Relationship
	// contains filtered or unexported fields
}

StructField model field's struct definition

func (*StructField) TagSettingsDelete

func (sf *StructField) TagSettingsDelete(key string)

TagSettingsDelete deletes a tag

func (*StructField) TagSettingsGet

func (sf *StructField) TagSettingsGet(key string) (string, bool)

TagSettingsGet returns a tag from the tag settings

func (*StructField) TagSettingsSet

func (sf *StructField) TagSettingsSet(key, val string)

TagSettingsSet Sets a tag in the tag settings map

Directories

Path Synopsis
dialects
example module

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL