Refactor based on golint

This commit is contained in:
Jinzhu 2016-03-07 14:54:20 +08:00
parent 3055bad1e8
commit ec110657da
20 changed files with 185 additions and 109 deletions

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
) )
// defaultCallback hold default callbacks defined by gorm // DefaultCallback default callbacks defined by gorm
var DefaultCallback = &Callback{} var DefaultCallback = &Callback{}
// Callback contains callbacks that used when CURD objects // Callback contains callbacks that used when CURD objects

View File

@ -85,14 +85,14 @@ func createCallback(scope *Scope) {
returningColumn = scope.Quote(primaryField.DBName) returningColumn = scope.Quote(primaryField.DBName)
} }
lastInsertIdReturningSuffix := scope.Dialect().LastInsertIdReturningSuffix(quotedTableName, returningColumn) lastInsertIDReturningSuffix := scope.Dialect().LastInsertIDReturningSuffix(quotedTableName, returningColumn)
if len(columns) == 0 { if len(columns) == 0 {
scope.Raw(fmt.Sprintf( scope.Raw(fmt.Sprintf(
"INSERT INTO %v DEFAULT VALUES%v%v", "INSERT INTO %v DEFAULT VALUES%v%v",
quotedTableName, quotedTableName,
addExtraSpaceIfExist(extraOption), addExtraSpaceIfExist(extraOption),
addExtraSpaceIfExist(lastInsertIdReturningSuffix), addExtraSpaceIfExist(lastInsertIDReturningSuffix),
)) ))
} else { } else {
scope.Raw(fmt.Sprintf( scope.Raw(fmt.Sprintf(
@ -101,13 +101,13 @@ func createCallback(scope *Scope) {
strings.Join(columns, ","), strings.Join(columns, ","),
strings.Join(placeholders, ","), strings.Join(placeholders, ","),
addExtraSpaceIfExist(extraOption), addExtraSpaceIfExist(extraOption),
addExtraSpaceIfExist(lastInsertIdReturningSuffix), addExtraSpaceIfExist(lastInsertIDReturningSuffix),
)) ))
} }
// execute create sql // execute create sql
if lastInsertIdReturningSuffix == "" || primaryField == nil { if lastInsertIDReturningSuffix == "" || primaryField == nil {
if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil { if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
// set rows affected count // set rows affected count
scope.db.RowsAffected, _ = result.RowsAffected() scope.db.RowsAffected, _ = result.RowsAffected()
@ -119,7 +119,7 @@ func createCallback(scope *Scope) {
} }
} }
} else { } else {
if err := scope.SqlDB().QueryRow(scope.Sql, scope.SqlVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil { if err := scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...).Scan(primaryField.Field.Addr().Interface()); scope.Err(err) == nil {
scope.db.RowsAffected = 1 scope.db.RowsAffected = 1
} }
} }

View File

@ -48,15 +48,15 @@ func queryCallback(scope *Scope) {
return return
} }
scope.prepareQuerySql() scope.prepareQuerySQL()
if !scope.HasError() { if !scope.HasError() {
scope.db.RowsAffected = 0 scope.db.RowsAffected = 0
if str, ok := scope.Get("gorm:query_option"); ok { if str, ok := scope.Get("gorm:query_option"); ok {
scope.Sql += addExtraSpaceIfExist(fmt.Sprint(str)) scope.SQL += addExtraSpaceIfExist(fmt.Sprint(str))
} }
if rows, err := scope.SqlDB().Query(scope.Sql, scope.SqlVars...); scope.Err(err) == nil { if rows, err := scope.SQLDB().Query(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
defer rows.Close() defer rows.Close()
columns, _ := rows.Columns() columns, _ := rows.Columns()
@ -80,7 +80,7 @@ func queryCallback(scope *Scope) {
} }
if scope.db.RowsAffected == 0 && !isSlice { if scope.db.RowsAffected == 0 && !isSlice {
scope.Err(RecordNotFound) scope.Err(ErrRecordNotFound)
} }
} }
} }

View File

@ -39,7 +39,7 @@ type Dialect interface {
// SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL` // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL`
SelectFromDummyTable() string SelectFromDummyTable() string
// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING` // LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
LastInsertIdReturningSuffix(tableName, columnName string) string LastInsertIDReturningSuffix(tableName, columnName string) string
} }
var dialectsMap = map[string]Dialect{} var dialectsMap = map[string]Dialect{}

View File

@ -132,6 +132,6 @@ func (commonDialect) SelectFromDummyTable() string {
return "" return ""
} }
func (commonDialect) LastInsertIdReturningSuffix(tableName, columnName string) string { func (commonDialect) LastInsertIDReturningSuffix(tableName, columnName string) string {
return "" return ""
} }

View File

@ -106,11 +106,11 @@ func (s postgres) currentDatabase() (name string) {
return return
} }
func (s postgres) LastInsertIdReturningSuffix(tableName, key string) string { func (s postgres) LastInsertIDReturningSuffix(tableName, key string) string {
return fmt.Sprintf("RETURNING %v.%v", tableName, key) return fmt.Sprintf("RETURNING %v.%v", tableName, key)
} }
func (postgres) SupportLastInsertId() bool { func (postgres) SupportLastInsertID() bool {
return false return false
} }

View File

@ -145,6 +145,6 @@ func (mssql) SelectFromDummyTable() string {
return "" return ""
} }
func (mssql) LastInsertIdReturningSuffix(tableName, columnName string) string { func (mssql) LastInsertIDReturningSuffix(tableName, columnName string) string {
return "" return ""
} }

View File

@ -6,24 +6,31 @@ import (
) )
var ( var (
RecordNotFound = errors.New("record not found") // ErrRecordNotFound record not found, happens when you are looking up with a struct, and haven't find any matched data
InvalidSql = errors.New("invalid sql") ErrRecordNotFound = errors.New("record not found")
NoValidTransaction = errors.New("no valid transaction") // ErrInvalidSQL invalid SQL, happens when you passed invalid SQL
CantStartTransaction = errors.New("can't start transaction") ErrInvalidSQL = errors.New("invalid SQL")
// ErrInvalidTransaction invalid transaction 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")
) )
type errorsInterface interface { type errorsInterface interface {
GetErrors() []error GetErrors() []error
} }
// Errors contains all happened errors
type Errors struct { type Errors struct {
errors []error errors []error
} }
// GetErrors get all happened errors
func (errs Errors) GetErrors() []error { func (errs Errors) GetErrors() []error {
return errs.errors return errs.errors
} }
// Add add an error
func (errs *Errors) Add(err error) { func (errs *Errors) Add(err error) {
if errors, ok := err.(errorsInterface); ok { if errors, ok := err.(errorsInterface); ok {
for _, err := range errors.GetErrors() { for _, err := range errors.GetErrors() {
@ -39,6 +46,7 @@ func (errs *Errors) Add(err error) {
} }
} }
// Error format happened errors
func (errs Errors) Error() string { func (errs Errors) Error() string {
var errors = []string{} var errors = []string{}
for _, e := range errs.errors { for _, e := range errs.errors {

View File

@ -7,12 +7,14 @@ import (
"reflect" "reflect"
) )
// Field model field definition
type Field struct { type Field struct {
*StructField *StructField
IsBlank bool IsBlank bool
Field reflect.Value Field reflect.Value
} }
// Set set a value to the field
func (field *Field) Set(value interface{}) (err error) { func (field *Field) Set(value interface{}) (err error) {
if !field.Field.IsValid() { if !field.Field.IsValid() {
return errors.New("field value not valid") return errors.New("field value not valid")

View File

@ -7,40 +7,54 @@ import (
"strings" "strings"
) )
// JoinTableHandlerInterface is an interface for how to handle many2many relations
type JoinTableHandlerInterface interface { type JoinTableHandlerInterface interface {
// initialize join table handler
Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)
// Table return join table's table name
Table(db *DB) string Table(db *DB) string
// Add create relationship in join table for source and destination
Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error
// Delete delete relationship in join table for sources
Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error
// JoinWith query with `Join` conditions
JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB
// SourceForeignKeys return source foreign keys
SourceForeignKeys() []JoinTableForeignKey SourceForeignKeys() []JoinTableForeignKey
// DestinationForeignKeys return destination foreign keys
DestinationForeignKeys() []JoinTableForeignKey DestinationForeignKeys() []JoinTableForeignKey
} }
// JoinTableForeignKey join table foreign key struct
type JoinTableForeignKey struct { type JoinTableForeignKey struct {
DBName string DBName string
AssociationDBName string AssociationDBName string
} }
// JoinTableSource is a struct that contains model type and foreign keys
type JoinTableSource struct { type JoinTableSource struct {
ModelType reflect.Type ModelType reflect.Type
ForeignKeys []JoinTableForeignKey ForeignKeys []JoinTableForeignKey
} }
// JoinTableHandler default join table handler
type JoinTableHandler struct { type JoinTableHandler struct {
TableName string `sql:"-"` TableName string `sql:"-"`
Source JoinTableSource `sql:"-"` Source JoinTableSource `sql:"-"`
Destination JoinTableSource `sql:"-"` Destination JoinTableSource `sql:"-"`
} }
// SourceForeignKeys return source foreign keys
func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey { func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey {
return s.Source.ForeignKeys return s.Source.ForeignKeys
} }
// DestinationForeignKeys return destination foreign keys
func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey { func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey {
return s.Destination.ForeignKeys return s.Destination.ForeignKeys
} }
// Setup initialize a default join table handler
func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) { func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type) {
s.TableName = tableName s.TableName = tableName
@ -61,11 +75,12 @@ func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, s
} }
} }
// Table return join table's table name
func (s JoinTableHandler) Table(db *DB) string { func (s JoinTableHandler) Table(db *DB) string {
return s.TableName return s.TableName
} }
func (s JoinTableHandler) GetSearchMap(db *DB, sources ...interface{}) map[string]interface{} { func (s JoinTableHandler) getSearchMap(db *DB, sources ...interface{}) map[string]interface{} {
values := map[string]interface{}{} values := map[string]interface{}{}
for _, source := range sources { for _, source := range sources {
@ -89,9 +104,10 @@ func (s JoinTableHandler) GetSearchMap(db *DB, sources ...interface{}) map[strin
return values return values
} }
func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source1 interface{}, source2 interface{}) error { // Add create relationship in join table for source and destination
func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error {
scope := db.NewScope("") scope := db.NewScope("")
searchMap := s.GetSearchMap(db, source1, source2) searchMap := s.getSearchMap(db, source, destination)
var assignColumns, binVars, conditions []string var assignColumns, binVars, conditions []string
var values []interface{} var values []interface{}
@ -120,6 +136,7 @@ func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source1
return db.Exec(sql, values...).Error return db.Exec(sql, values...).Error
} }
// Delete delete relationship in join table for sources
func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error { func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error {
var ( var (
scope = db.NewScope(nil) scope = db.NewScope(nil)
@ -127,7 +144,7 @@ func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sour
values []interface{} values []interface{}
) )
for key, value := range s.GetSearchMap(db, sources...) { for key, value := range s.getSearchMap(db, sources...) {
conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key))) conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
values = append(values, value) values = append(values, value)
} }
@ -135,6 +152,7 @@ func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sour
return db.Table(handler.Table(db)).Where(strings.Join(conditions, " AND "), values...).Delete("").Error return db.Table(handler.Table(db)).Where(strings.Join(conditions, " AND "), values...).Delete("").Error
} }
// JoinWith query with `Join` conditions
func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB { func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB {
var ( var (
scope = db.NewScope(source) scope = db.NewScope(source)

View File

@ -11,23 +11,25 @@ import (
"unicode" "unicode"
) )
var (
defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)}
sqlRegexp = regexp.MustCompile(`(\$\d+)|\?`)
)
type logger interface { type logger interface {
Print(v ...interface{}) Print(v ...interface{})
} }
type LogWriter interface { type logWriter interface {
Println(v ...interface{}) Println(v ...interface{})
} }
// Logger default logger
type Logger struct { type Logger struct {
LogWriter logWriter
} }
var defaultLogger = Logger{log.New(os.Stdout, "\r\n", 0)} // Print format & print log
// Format log
var sqlRegexp = regexp.MustCompile(`(\$\d+)|\?`)
func (logger Logger) Print(values ...interface{}) { func (logger Logger) Print(values ...interface{}) {
if len(values) > 1 { if len(values) > 1 {
level := values[0] level := values[0]

70
main.go
View File

@ -6,19 +6,9 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"strings" "strings"
"time"
) )
// NowFunc returns current time, this function is exported in order to be able // DB contains information for current db connection
// to give the flexibility to the developer to customize it according to their
// needs
//
// e.g: return time.Now().UTC()
//
var NowFunc = func() time.Time {
return time.Now()
}
type DB struct { type DB struct {
Value interface{} Value interface{}
Error error Error error
@ -36,6 +26,14 @@ type DB struct {
joinTableHandlers map[string]JoinTableHandler joinTableHandlers map[string]JoinTableHandler
} }
// Open open a new db connection, need to import driver first, for example:
//
// import _ "github.com/go-sql-driver/mysql"
// func main() {
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
// }
// GORM has wrapped some drivers, for easier to remember its name, so you could import the mysql driver with
// import _ "github.com/jinzhu/gorm/dialects/mysql"
func Open(dialect string, args ...interface{}) (*DB, error) { func Open(dialect string, args ...interface{}) (*DB, error) {
var db DB var db DB
var err error var err error
@ -44,7 +42,7 @@ func Open(dialect string, args ...interface{}) (*DB, error) {
err = errors.New("invalid database source") err = errors.New("invalid database source")
} else { } else {
var source string var source string
var dbSql sqlCommon var dbSQL sqlCommon
switch value := args[0].(type) { switch value := args[0].(type) {
case string: case string:
@ -55,19 +53,19 @@ func Open(dialect string, args ...interface{}) (*DB, error) {
driver = value driver = value
source = args[1].(string) source = args[1].(string)
} }
dbSql, err = sql.Open(driver, source) dbSQL, err = sql.Open(driver, source)
case sqlCommon: case sqlCommon:
source = reflect.Indirect(reflect.ValueOf(value)).FieldByName("dsn").String() source = reflect.Indirect(reflect.ValueOf(value)).FieldByName("dsn").String()
dbSql = value dbSQL = value
} }
db = DB{ db = DB{
dialect: newDialect(dialect, dbSql.(*sql.DB)), dialect: newDialect(dialect, dbSQL.(*sql.DB)),
logger: defaultLogger, logger: defaultLogger,
callbacks: DefaultCallback, callbacks: DefaultCallback,
source: source, source: source,
values: map[string]interface{}{}, values: map[string]interface{}{},
db: dbSql, db: dbSQL,
} }
db.parent = &db db.parent = &db
@ -79,14 +77,17 @@ func Open(dialect string, args ...interface{}) (*DB, error) {
return &db, err return &db, err
} }
// Close close current db connection
func (s *DB) Close() error { func (s *DB) Close() error {
return s.parent.db.(*sql.DB).Close() return s.parent.db.(*sql.DB).Close()
} }
// DB get `*sql.DB` from current connection
func (s *DB) DB() *sql.DB { func (s *DB) DB() *sql.DB {
return s.db.(*sql.DB) return s.db.(*sql.DB)
} }
// New initialize a new db connection without any search conditions
func (s *DB) New() *DB { func (s *DB) New() *DB {
clone := s.clone() clone := s.clone()
clone.search = nil clone.search = nil
@ -94,29 +95,34 @@ func (s *DB) New() *DB {
return clone return clone
} }
// NewScope create scope for callbacks, including DB's search information // NewScope create a scope for current operation
func (s *DB) NewScope(value interface{}) *Scope { func (s *DB) NewScope(value interface{}) *Scope {
dbClone := s.clone() dbClone := s.clone()
dbClone.Value = value dbClone.Value = value
return &Scope{db: dbClone, Search: dbClone.search.clone(), Value: value} return &Scope{db: dbClone, Search: dbClone.search.clone(), Value: value}
} }
// CommonDB Return the underlying sql.DB or sql.Tx instance. // CommonDB return the underlying sql.DB or sql.Tx instance.
// Use of this method is discouraged. It's mainly intended to allow // Use of this method is discouraged. It's mainly intended to allow
// coexistence with legacy non-GORM code. // coexistence with legacy non-GORM code.
func (s *DB) CommonDB() sqlCommon { func (s *DB) CommonDB() sqlCommon {
return s.db return s.db
} }
// Callback return Callbacks container, you could add/remove/change callbacks with it
// db.Callback().Create().Register("update_created_at", updateCreated)
// Refer: https://jinzhu.github.io/gorm/development.html#callbacks for more
func (s *DB) Callback() *Callback { func (s *DB) Callback() *Callback {
s.parent.callbacks = s.parent.callbacks.clone() s.parent.callbacks = s.parent.callbacks.clone()
return s.parent.callbacks return s.parent.callbacks
} }
func (s *DB) SetLogger(l logger) { // SetLogger replace default logger
s.logger = l func (s *DB) SetLogger(log logger) {
s.logger = log
} }
// LogMode set log mode, `true` for detailed logs, `false` for no log, default, will only print error logs
func (s *DB) LogMode(enable bool) *DB { func (s *DB) LogMode(enable bool) *DB {
if enable { if enable {
s.logMode = 2 s.logMode = 2
@ -126,51 +132,65 @@ func (s *DB) LogMode(enable bool) *DB {
return s return s
} }
// SingularTable use singular table by default
func (s *DB) SingularTable(enable bool) { func (s *DB) SingularTable(enable bool) {
modelStructsMap = newModelStructsMap() modelStructsMap = newModelStructsMap()
s.parent.singularTable = enable s.parent.singularTable = enable
} }
// Where return a new relation, accepts use `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/curd.html#query
func (s *DB) Where(query interface{}, args ...interface{}) *DB { func (s *DB) Where(query interface{}, args ...interface{}) *DB {
return s.clone().search.Where(query, args...).db return s.clone().search.Where(query, args...).db
} }
// Or match before conditions or this one, similar to `Where`
func (s *DB) Or(query interface{}, args ...interface{}) *DB { func (s *DB) Or(query interface{}, args ...interface{}) *DB {
return s.clone().search.Or(query, args...).db return s.clone().search.Or(query, args...).db
} }
// Not don't match current conditions, similar to `Where`
func (s *DB) Not(query interface{}, args ...interface{}) *DB { func (s *DB) Not(query interface{}, args ...interface{}) *DB {
return s.clone().search.Not(query, args...).db return s.clone().search.Not(query, args...).db
} }
// Limit specify the number of records to be retrieved
func (s *DB) Limit(limit int) *DB { func (s *DB) Limit(limit int) *DB {
return s.clone().search.Limit(limit).db return s.clone().search.Limit(limit).db
} }
// Offset specify the number of records to skip before starting to return the records
func (s *DB) Offset(offset int) *DB { func (s *DB) Offset(offset int) *DB {
return s.clone().search.Offset(offset).db return s.clone().search.Offset(offset).db
} }
// Order specify order when retrieve records from database, pass `true` as the second argument to overwrite `Order` conditions
func (s *DB) Order(value string, reorder ...bool) *DB { func (s *DB) Order(value string, reorder ...bool) *DB {
return s.clone().search.Order(value, reorder...).db return s.clone().search.Order(value, reorder...).db
} }
// Select When querying, specify fields that you want to retrieve from database, by default, will select all fields;
// When creating/updating, specify fields that you want to save to database
func (s *DB) Select(query interface{}, args ...interface{}) *DB { func (s *DB) Select(query interface{}, args ...interface{}) *DB {
return s.clone().search.Select(query, args...).db return s.clone().search.Select(query, args...).db
} }
// Omit specify fields that you want to ignore when save to database when creating/updating
func (s *DB) Omit(columns ...string) *DB { func (s *DB) Omit(columns ...string) *DB {
return s.clone().search.Omit(columns...).db return s.clone().search.Omit(columns...).db
} }
// Group specify the group method on the find
func (s *DB) Group(query string) *DB { func (s *DB) Group(query string) *DB {
return s.clone().search.Group(query).db return s.clone().search.Group(query).db
} }
// Having specify HAVING conditions for GROUP BY
func (s *DB) Having(query string, values ...interface{}) *DB { func (s *DB) Having(query string, values ...interface{}) *DB {
return s.clone().search.Having(query, values...).db return s.clone().search.Having(query, values...).db
} }
// Joins specify Joins conditions
// db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Find(&user)
func (s *DB) Joins(query string, args ...interface{}) *DB { func (s *DB) Joins(query string, args ...interface{}) *DB {
return s.clone().search.Joins(query, args...).db return s.clone().search.Joins(query, args...).db
} }
@ -352,7 +372,7 @@ func (s *DB) Begin() *DB {
c.db = interface{}(tx).(sqlCommon) c.db = interface{}(tx).(sqlCommon)
c.AddError(err) c.AddError(err)
} else { } else {
c.AddError(CantStartTransaction) c.AddError(ErrCantStartTransaction)
} }
return c return c
} }
@ -361,7 +381,7 @@ func (s *DB) Commit() *DB {
if db, ok := s.db.(sqlTx); ok { if db, ok := s.db.(sqlTx); ok {
s.AddError(db.Commit()) s.AddError(db.Commit())
} else { } else {
s.AddError(NoValidTransaction) s.AddError(ErrInvalidTransaction)
} }
return s return s
} }
@ -370,7 +390,7 @@ func (s *DB) Rollback() *DB {
if db, ok := s.db.(sqlTx); ok { if db, ok := s.db.(sqlTx); ok {
s.AddError(db.Rollback()) s.AddError(db.Rollback())
} else { } else {
s.AddError(NoValidTransaction) s.AddError(ErrInvalidTransaction)
} }
return s return s
} }
@ -380,7 +400,7 @@ func (s *DB) NewRecord(value interface{}) bool {
} }
func (s *DB) RecordNotFound() bool { func (s *DB) RecordNotFound() bool {
return s.Error == RecordNotFound return s.Error == ErrRecordNotFound
} }
// CreateTable create table for models // CreateTable create table for models
@ -541,7 +561,7 @@ func (s *DB) SetJoinTableHandler(source interface{}, column string, handler Join
func (s *DB) AddError(err error) error { func (s *DB) AddError(err error) error {
if err != nil { if err != nil {
if err != RecordNotFound { if err != ErrRecordNotFound {
if s.logMode == 0 { if s.logMode == 0 {
go s.print(fileWithLineNum(), err) go s.print(fileWithLineNum(), err)
} else { } else {

View File

@ -479,7 +479,7 @@ func TestRaw(t *testing.T) {
} }
DB.Exec("update users set name=? where name in (?)", "jinzhu", []string{user1.Name, user2.Name, user3.Name}) DB.Exec("update users set name=? where name in (?)", "jinzhu", []string{user1.Name, user2.Name, user3.Name})
if DB.Where("name in (?)", []string{user1.Name, user2.Name, user3.Name}).First(&User{}).Error != gorm.RecordNotFound { if DB.Where("name in (?)", []string{user1.Name, user2.Name, user3.Name}).First(&User{}).Error != gorm.ErrRecordNotFound {
t.Error("Raw sql to update records") t.Error("Raw sql to update records")
} }
} }
@ -709,7 +709,7 @@ func TestOpenExistingDB(t *testing.T) {
} }
var user User var user User
if db.Where("name = ?", "jnfeinstein").First(&user).Error == gorm.RecordNotFound { if db.Where("name = ?", "jnfeinstein").First(&user).Error == gorm.ErrRecordNotFound {
t.Errorf("Should have found existing record") t.Errorf("Should have found existing record")
} }
} }

View File

@ -2,6 +2,7 @@ package gorm
import "time" import "time"
// Model base model definition, including `ID`, `CreatedAt`, `UpdatedAt`, `DeletedAt`, which could be embeded in your models
type Model struct { type Model struct {
ID uint `gorm:"primary_key"` ID uint `gorm:"primary_key"`
CreatedAt time.Time CreatedAt time.Time

View File

@ -12,6 +12,7 @@ import (
"github.com/jinzhu/inflection" "github.com/jinzhu/inflection"
) )
// DefaultTableNameHandler default table name handler
var DefaultTableNameHandler = func(db *DB, defaultTableName string) string { var DefaultTableNameHandler = func(db *DB, defaultTableName string) string {
return defaultTableName return defaultTableName
} }
@ -39,6 +40,7 @@ func newModelStructsMap() *safeModelStructsMap {
var modelStructsMap = newModelStructsMap() var modelStructsMap = newModelStructsMap()
// ModelStruct model definition
type ModelStruct struct { type ModelStruct struct {
PrimaryFields []*StructField PrimaryFields []*StructField
StructFields []*StructField StructFields []*StructField
@ -46,10 +48,12 @@ type ModelStruct struct {
defaultTableName string defaultTableName string
} }
// TableName get model's table name
func (s *ModelStruct) TableName(db *DB) string { func (s *ModelStruct) TableName(db *DB) string {
return DefaultTableNameHandler(db, s.defaultTableName) return DefaultTableNameHandler(db, s.defaultTableName)
} }
// StructField model field's struct definition
type StructField struct { type StructField struct {
DBName string DBName string
Name string Name string
@ -506,6 +510,7 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
return &modelStruct return &modelStruct
} }
// GetStructFields get model's field structs
func (scope *Scope) GetStructFields() (fields []*StructField) { func (scope *Scope) GetStructFields() (fields []*StructField) {
return scope.GetModelStruct().StructFields return scope.GetModelStruct().StructFields
} }

View File

@ -133,7 +133,7 @@ func TestNestedPreload1(t *testing.T) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want)) t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
} }
if err := DB.Preload("Level2").Preload("Level2.Level1").Find(&got, "name = ?", "not_found").Error; err != gorm.RecordNotFound { if err := DB.Preload("Level2").Preload("Level2.Level1").Find(&got, "name = ?", "not_found").Error; err != gorm.ErrRecordNotFound {
t.Error(err) t.Error(err)
} }
} }
@ -981,7 +981,7 @@ func TestNestedManyToManyPreload(t *testing.T) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want)) t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
} }
if err := DB.Preload("Level2s.Level1s").Find(&got, "value = ?", "not_found").Error; err != gorm.RecordNotFound { if err := DB.Preload("Level2s.Level1s").Find(&got, "value = ?", "not_found").Error; err != gorm.ErrRecordNotFound {
t.Error(err) t.Error(err)
} }
} }
@ -1038,7 +1038,7 @@ func TestNestedManyToManyPreload2(t *testing.T) {
t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want)) t.Errorf("got %s; want %s", toJSONString(got), toJSONString(want))
} }
if err := DB.Preload("Level2.Level1s").Find(&got, "value = ?", "not_found").Error; err != gorm.RecordNotFound { if err := DB.Preload("Level2.Level1s").Find(&got, "value = ?", "not_found").Error; err != gorm.ErrRecordNotFound {
t.Error(err) t.Error(err)
} }
} }

View File

@ -10,11 +10,12 @@ import (
"reflect" "reflect"
) )
// Scope contain any information of current operation when you perform any operation on the database
type Scope struct { type Scope struct {
Search *search Search *search
Value interface{} Value interface{}
Sql string SQL string
SqlVars []interface{} SQLVars []interface{}
db *DB db *DB
instanceID string instanceID string
primaryKeyField *Field primaryKeyField *Field
@ -23,6 +24,7 @@ type Scope struct {
selectAttrs *[]string selectAttrs *[]string
} }
// IndirectValue return scope's reflect value's indirect value
func (scope *Scope) IndirectValue() reflect.Value { func (scope *Scope) IndirectValue() reflect.Value {
return indirect(reflect.ValueOf(scope.Value)) return indirect(reflect.ValueOf(scope.Value))
} }
@ -43,12 +45,13 @@ func (scope *Scope) NewDB() *DB {
return nil return nil
} }
// DB return scope's DB connection
func (scope *Scope) DB() *DB { func (scope *Scope) DB() *DB {
return scope.db return scope.db
} }
// SqlDB return *sql.DB // SQLDB return *sql.DB
func (scope *Scope) SqlDB() sqlCommon { func (scope *Scope) SQLDB() sqlCommon {
return scope.db.db return scope.db.db
} }
@ -100,6 +103,7 @@ func (scope *Scope) HasError() bool {
return scope.db.Error != nil return scope.db.Error != nil
} }
// PrimaryFields return scope's primary fields
func (scope *Scope) PrimaryFields() (fields []*Field) { func (scope *Scope) PrimaryFields() (fields []*Field) {
for _, field := range scope.Fields() { for _, field := range scope.Fields() {
if field.IsPrimaryKey { if field.IsPrimaryKey {
@ -109,6 +113,7 @@ func (scope *Scope) PrimaryFields() (fields []*Field) {
return fields return fields
} }
// 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 *Scope) PrimaryField() *Field { func (scope *Scope) PrimaryField() *Field {
if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 { if primaryFields := scope.GetModelStruct().PrimaryFields; len(primaryFields) > 0 {
if len(primaryFields) > 1 { if len(primaryFields) > 1 {
@ -241,8 +246,8 @@ func (scope *Scope) AddToVars(value interface{}) string {
return exp return exp
} }
scope.SqlVars = append(scope.SqlVars, value) scope.SQLVars = append(scope.SQLVars, value)
return scope.Dialect().BindVar(len(scope.SqlVars)) return scope.Dialect().BindVar(len(scope.SQLVars))
} }
type tabler interface { type tabler interface {
@ -282,10 +287,10 @@ func (scope *Scope) QuotedTableName() (name string) {
return scope.Quote(scope.TableName()) return scope.Quote(scope.TableName())
} }
// CombinedConditionSql get combined condition sql // CombinedConditionSql return combined condition sql
func (scope *Scope) CombinedConditionSql() string { func (scope *Scope) CombinedConditionSql() string {
return scope.joinsSql() + scope.whereSql() + scope.groupSql() + return scope.joinsSQL() + scope.whereSQL() + scope.groupSQL() +
scope.havingSql() + scope.orderSql() + scope.limitAndOffsetSql() scope.havingSQL() + scope.orderSQL() + scope.limitAndOffsetSQL()
} }
// FieldByName find gorm.Field with name and db name // FieldByName find gorm.Field with name and db name
@ -308,7 +313,7 @@ func (scope *Scope) FieldByName(name string) (field *Field, ok bool) {
// Raw set sql // Raw set sql
func (scope *Scope) Raw(sql string) *Scope { func (scope *Scope) Raw(sql string) *Scope {
scope.Sql = strings.Replace(sql, "$$", "?", -1) scope.SQL = strings.Replace(sql, "$$", "?", -1)
return scope return scope
} }
@ -317,7 +322,7 @@ func (scope *Scope) Exec() *Scope {
defer scope.trace(NowFunc()) defer scope.trace(NowFunc())
if !scope.HasError() { if !scope.HasError() {
if result, err := scope.SqlDB().Exec(scope.Sql, scope.SqlVars...); scope.Err(err) == nil { if result, err := scope.SQLDB().Exec(scope.SQL, scope.SQLVars...); scope.Err(err) == nil {
if count, err := result.RowsAffected(); scope.Err(err) == nil { if count, err := result.RowsAffected(); scope.Err(err) == nil {
scope.db.RowsAffected = count scope.db.RowsAffected = count
} }
@ -345,17 +350,19 @@ func (scope *Scope) InstanceID() string {
return scope.instanceID return scope.instanceID
} }
// InstanceSet set value for current instance, but not for associations
func (scope *Scope) InstanceSet(name string, value interface{}) *Scope { func (scope *Scope) InstanceSet(name string, value interface{}) *Scope {
return scope.Set(name+scope.InstanceID(), value) return scope.Set(name+scope.InstanceID(), value)
} }
// InstanceGet get setting from current instance
func (scope *Scope) InstanceGet(name string) (interface{}, bool) { func (scope *Scope) InstanceGet(name string) (interface{}, bool) {
return scope.Get(name + scope.InstanceID()) return scope.Get(name + scope.InstanceID())
} }
// Begin start a transaction // Begin start a transaction
func (scope *Scope) Begin() *Scope { func (scope *Scope) Begin() *Scope {
if db, ok := scope.SqlDB().(sqlDb); ok { if db, ok := scope.SQLDB().(sqlDb); ok {
if tx, err := db.Begin(); err == nil { if tx, err := db.Begin(); err == nil {
scope.db.db = interface{}(tx).(sqlCommon) scope.db.db = interface{}(tx).(sqlCommon)
scope.InstanceSet("gorm:started_transaction", true) scope.InstanceSet("gorm:started_transaction", true)
@ -379,6 +386,7 @@ func (scope *Scope) CommitOrRollback() *Scope {
return scope return scope
} }
// SelectAttrs retur nselected attributes
func (scope *Scope) SelectAttrs() []string { func (scope *Scope) SelectAttrs() []string {
if scope.selectAttrs == nil { if scope.selectAttrs == nil {
attrs := []string{} attrs := []string{}
@ -398,6 +406,7 @@ func (scope *Scope) SelectAttrs() []string {
return *scope.selectAttrs return *scope.selectAttrs
} }
// OmitAttrs return omited attributes
func (scope *Scope) OmitAttrs() []string { func (scope *Scope) OmitAttrs() []string {
return scope.Search.omits return scope.Search.omits
} }

View File

@ -76,7 +76,7 @@ func (scope *Scope) buildWhereCondition(clause map[string]interface{}) (str stri
} }
func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string) { func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string) {
var notEqualSql string var notEqualSQL string
var primaryKey = scope.PrimaryKey() var primaryKey = scope.PrimaryKey()
switch value := clause["query"].(type) { switch value := clause["query"].(type) {
@ -87,10 +87,10 @@ func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string
return fmt.Sprintf("(%v <> %v)", scope.Quote(primaryKey), id) return fmt.Sprintf("(%v <> %v)", scope.Quote(primaryKey), id)
} else if regexp.MustCompile("(?i) (=|<>|>|<|LIKE|IS|IN) ").MatchString(value) { } else if regexp.MustCompile("(?i) (=|<>|>|<|LIKE|IS|IN) ").MatchString(value) {
str = fmt.Sprintf(" NOT (%v) ", value) str = fmt.Sprintf(" NOT (%v) ", value)
notEqualSql = fmt.Sprintf("NOT (%v)", value) notEqualSQL = fmt.Sprintf("NOT (%v)", value)
} else { } else {
str = fmt.Sprintf("(%v NOT IN (?))", scope.Quote(value)) str = fmt.Sprintf("(%v NOT IN (?))", scope.Quote(value))
notEqualSql = fmt.Sprintf("(%v <> ?)", scope.Quote(value)) notEqualSQL = fmt.Sprintf("(%v <> ?)", scope.Quote(value))
} }
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, sql.NullInt64: case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, sql.NullInt64:
return fmt.Sprintf("(%v <> %v)", scope.Quote(primaryKey), value) return fmt.Sprintf("(%v <> %v)", scope.Quote(primaryKey), value)
@ -139,7 +139,7 @@ func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string
if scanner, ok := interface{}(arg).(driver.Valuer); ok { if scanner, ok := interface{}(arg).(driver.Valuer); ok {
arg, _ = scanner.Value() arg, _ = scanner.Value()
} }
str = strings.Replace(notEqualSql, "?", scope.AddToVars(arg), 1) str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1)
} }
} }
return return
@ -173,7 +173,7 @@ func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string)
return return
} }
func (scope *Scope) whereSql() (sql string) { func (scope *Scope) whereSQL() (sql string) {
var ( var (
quotedTableName = scope.QuotedTableName() quotedTableName = scope.QuotedTableName()
primaryConditions, andConditions, orConditions []string primaryConditions, andConditions, orConditions []string
@ -209,28 +209,28 @@ func (scope *Scope) whereSql() (sql string) {
} }
} }
orSql := strings.Join(orConditions, " OR ") orSQL := strings.Join(orConditions, " OR ")
combinedSql := strings.Join(andConditions, " AND ") combinedSQL := strings.Join(andConditions, " AND ")
if len(combinedSql) > 0 { if len(combinedSQL) > 0 {
if len(orSql) > 0 { if len(orSQL) > 0 {
combinedSql = combinedSql + " OR " + orSql combinedSQL = combinedSQL + " OR " + orSQL
} }
} else { } else {
combinedSql = orSql combinedSQL = orSQL
} }
if len(primaryConditions) > 0 { if len(primaryConditions) > 0 {
sql = "WHERE " + strings.Join(primaryConditions, " AND ") sql = "WHERE " + strings.Join(primaryConditions, " AND ")
if len(combinedSql) > 0 { if len(combinedSQL) > 0 {
sql = sql + " AND (" + combinedSql + ")" sql = sql + " AND (" + combinedSQL + ")"
} }
} else if len(combinedSql) > 0 { } else if len(combinedSQL) > 0 {
sql = "WHERE " + combinedSql sql = "WHERE " + combinedSQL
} }
return return
} }
func (scope *Scope) selectSql() string { func (scope *Scope) selectSQL() string {
if len(scope.Search.selects) == 0 { if len(scope.Search.selects) == 0 {
if len(scope.Search.joinConditions) > 0 { if len(scope.Search.joinConditions) > 0 {
return fmt.Sprintf("%v.*", scope.QuotedTableName()) return fmt.Sprintf("%v.*", scope.QuotedTableName())
@ -240,25 +240,25 @@ func (scope *Scope) selectSql() string {
return scope.buildSelectQuery(scope.Search.selects) return scope.buildSelectQuery(scope.Search.selects)
} }
func (scope *Scope) orderSql() string { func (scope *Scope) orderSQL() string {
if len(scope.Search.orders) == 0 || scope.Search.countingQuery { if len(scope.Search.orders) == 0 || scope.Search.countingQuery {
return "" return ""
} }
return " ORDER BY " + strings.Join(scope.Search.orders, ",") return " ORDER BY " + strings.Join(scope.Search.orders, ",")
} }
func (scope *Scope) limitAndOffsetSql() string { func (scope *Scope) limitAndOffsetSQL() string {
return scope.Dialect().LimitAndOffsetSQL(scope.Search.limit, scope.Search.offset) return scope.Dialect().LimitAndOffsetSQL(scope.Search.limit, scope.Search.offset)
} }
func (scope *Scope) groupSql() string { func (scope *Scope) groupSQL() string {
if len(scope.Search.group) == 0 { if len(scope.Search.group) == 0 {
return "" return ""
} }
return " GROUP BY " + scope.Search.group return " GROUP BY " + scope.Search.group
} }
func (scope *Scope) havingSql() string { func (scope *Scope) havingSQL() string {
if len(scope.Search.havingConditions) == 0 { if len(scope.Search.havingConditions) == 0 {
return "" return ""
} }
@ -270,15 +270,15 @@ func (scope *Scope) havingSql() string {
} }
} }
combinedSql := strings.Join(andConditions, " AND ") combinedSQL := strings.Join(andConditions, " AND ")
if len(combinedSql) == 0 { if len(combinedSQL) == 0 {
return "" return ""
} }
return " HAVING " + combinedSql return " HAVING " + combinedSQL
} }
func (scope *Scope) joinsSql() string { func (scope *Scope) joinsSQL() string {
var joinConditions []string var joinConditions []string
for _, clause := range scope.Search.joinConditions { for _, clause := range scope.Search.joinConditions {
if sql := scope.buildWhereCondition(clause); sql != "" { if sql := scope.buildWhereCondition(clause); sql != "" {
@ -289,11 +289,11 @@ func (scope *Scope) joinsSql() string {
return strings.Join(joinConditions, " ") + " " return strings.Join(joinConditions, " ") + " "
} }
func (scope *Scope) prepareQuerySql() { func (scope *Scope) prepareQuerySQL() {
if scope.Search.raw { if scope.Search.raw {
scope.Raw(strings.TrimSuffix(strings.TrimPrefix(scope.CombinedConditionSql(), " WHERE ("), ")")) scope.Raw(strings.TrimSuffix(strings.TrimPrefix(scope.CombinedConditionSql(), " WHERE ("), ")"))
} else { } else {
scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSql(), scope.QuotedTableName(), scope.CombinedConditionSql())) scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.QuotedTableName(), scope.CombinedConditionSql()))
} }
return return
} }
@ -345,15 +345,15 @@ func (scope *Scope) updatedAttrsWithValues(values map[string]interface{}) (resul
func (scope *Scope) row() *sql.Row { func (scope *Scope) row() *sql.Row {
defer scope.trace(NowFunc()) defer scope.trace(NowFunc())
scope.callCallbacks(scope.db.parent.callbacks.rowQueries) scope.callCallbacks(scope.db.parent.callbacks.rowQueries)
scope.prepareQuerySql() scope.prepareQuerySQL()
return scope.SqlDB().QueryRow(scope.Sql, scope.SqlVars...) return scope.SQLDB().QueryRow(scope.SQL, scope.SQLVars...)
} }
func (scope *Scope) rows() (*sql.Rows, error) { func (scope *Scope) rows() (*sql.Rows, error) {
defer scope.trace(NowFunc()) defer scope.trace(NowFunc())
scope.callCallbacks(scope.db.parent.callbacks.rowQueries) scope.callCallbacks(scope.db.parent.callbacks.rowQueries)
scope.prepareQuerySql() scope.prepareQuerySQL()
return scope.SqlDB().Query(scope.Sql, scope.SqlVars...) return scope.SQLDB().Query(scope.SQL, scope.SQLVars...)
} }
func (scope *Scope) initialize() *Scope { func (scope *Scope) initialize() *Scope {
@ -404,8 +404,8 @@ func (scope *Scope) typeName() string {
// trace print sql log // trace print sql log
func (scope *Scope) trace(t time.Time) { func (scope *Scope) trace(t time.Time) {
if len(scope.Sql) > 0 { if len(scope.SQL) > 0 {
scope.db.slog(scope.Sql, t, scope.SqlVars...) scope.db.slog(scope.SQL, t, scope.SQLVars...)
} }
} }
@ -599,7 +599,7 @@ func (scope *Scope) addIndex(unique bool, indexName string, column ...string) {
sqlCreate = "CREATE UNIQUE INDEX" sqlCreate = "CREATE UNIQUE INDEX"
} }
scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSql())).Exec() scope.Raw(fmt.Sprintf("%s %v ON %v(%v) %v", sqlCreate, indexName, scope.QuotedTableName(), strings.Join(columns, ", "), scope.whereSQL())).Exec()
} }
func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) { func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {

View File

@ -93,7 +93,7 @@ func (s *search) Offset(offset int) *search {
} }
func (s *search) Group(query string) *search { func (s *search) Group(query string) *search {
s.group = s.getInterfaceAsSql(query) s.group = s.getInterfaceAsSQL(query)
return s return s
} }
@ -134,12 +134,12 @@ func (s *search) Table(name string) *search {
return s return s
} }
func (s *search) getInterfaceAsSql(value interface{}) (str string) { func (s *search) getInterfaceAsSQL(value interface{}) (str string) {
switch value.(type) { switch value.(type) {
case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64: case string, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
str = fmt.Sprintf("%v", value) str = fmt.Sprintf("%v", value)
default: default:
s.db.AddError(InvalidSql) s.db.AddError(ErrInvalidSQL)
} }
if str == "-1" { if str == "-1" {

View File

@ -9,8 +9,19 @@ import (
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"time"
) )
// 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: return time.Now().UTC()
//
var NowFunc = func() time.Time {
return time.Now()
}
// Copied from golint // Copied from golint
var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"} var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
var commonInitialismsReplacer *strings.Replacer var commonInitialismsReplacer *strings.Replacer