Go sqlx framework gère les champs de structure avec la nomenclature de soulignement

à propos de sqlx

sqlx est une bibliothèque d'opérations de base de données Golang, qui fournit un ensemble d'API étendues basées database/sqlsur , qui est un sur-ensemble de l'API de bibliothèque native.

Par défaut, sqlx obtiendra les champs de base de données correspondants lors de l'analyse et de l'analyse de la structure, et les priorités sont les suivantes :

  1. S'il y a une balise db dans la balise, obtenez le nom de champ correspondant de la base de données en fonction de la balise, voir sqlx.go#43 pour le code source .
  2. S'il n'y a pas de balise db dans la balise, tous les noms de champs en minuscules seront utilisés comme noms de champs correspondants de la base de données. Voir sqlx.go#27 pour le code source .

Selon la spécification de développement SQL et les principes de base de TiDB - Spécification de dénomination d'objet "Il est recommandé d'utiliser des mots anglais significatifs pour la dénomination, séparés par des traits de soulignement au milieu des mots", nous devons changer la deuxième casse "tout en minuscules" en " méthode de nommage souligné" .

Il faut deux étapes pour modifier la fonction de génération de champ de base de données sqlx.

  1. Écrivez la fonction NameMapper de la nomenclature de soulignement.
  2. Modifiez la fonction NameMapper par défaut.

Écrivez la méthode de nommage de soulignement NameMapper function

D'après le code source, nous savons que par défaut, sqlx utilise la méthode des chaînes de la bibliothèque strings.ToLowernative pour le traitement des champs.Cette fonction n'a qu'un paramètre nommé nom et type chaîne.

Ensuite, nous pouvons nous référer au code source gormde (par défaut, gorm utilise la méthode de nommage souligné pour générer les champs de la base de données) pour extraire toDBNamela fonction, voir gorm - schema/naming.go:117 pour plus de détails .

Voici la fonction de génération de champ de nomenclature de soulignement proposée par l'auteurtoDBName :

import "strings"

var commonInitialismsReplacer = newCommonInitialismsReplacer()

func newCommonInitialismsReplacer() *strings.Replacer {
    
    
	// https://github.com/golang/lint/blob/master/lint.go#L770
	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", "UID", "UI", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}

	commonInitialismsForReplacer := make([]string, 0, len(commonInitialisms))
	for _, initialism := range commonInitialisms {
    
    
		commonInitialismsForReplacer = append(commonInitialismsForReplacer, initialism, strings.Title(strings.ToLower(initialism)))
	}
	replacer := strings.NewReplacer(commonInitialismsForReplacer...)
	return replacer
}

func toDBName(name string) string {
    
    
	if name == "" {
    
    
		return ""
	}

	var (
		value                          = commonInitialismsReplacer.Replace(name)
		buf                            strings.Builder
		lastCase, nextCase, nextNumber bool // upper case == true
		curCase                        = value[0] <= 'Z' && value[0] >= 'A'
	)

	for i, v := range value[:len(value)-1] {
    
    
		nextCase = value[i+1] <= 'Z' && value[i+1] >= 'A'
		nextNumber = value[i+1] >= '0' && value[i+1] <= '9'

		if curCase {
    
    
			if lastCase && (nextCase || nextNumber) {
    
    
				buf.WriteRune(v + 32)
			} else {
    
    
				if i > 0 && value[i-1] != '_' && value[i+1] != '_' {
    
    
					buf.WriteByte('_')
				}
				buf.WriteRune(v + 32)
			}
		} else {
    
    
			buf.WriteRune(v)
		}

		lastCase = curCase
		curCase = nextCase
	}

	if curCase {
    
    
		if !lastCase && len(value) > 1 {
    
    
			buf.WriteByte('_')
		}
		buf.WriteByte(value[len(value)-1] + 32)
	} else {
    
    
		buf.WriteByte(value[len(value)-1])
	}
	ret := buf.String()
	return ret
}

Modifier la fonction NameMapper par défaut

Selon le code source de sqlx, nous savons NameMapperqu'il s'agit d' une variable globale de sqlx, nous n'avons donc qu'à modifier la variable pendant le processus d'initialisation du programme.

func init() {
    
    
	sqlx.NameMapper = toDBName
}

Montrer les résultats

La démo montrera la différence entre l'utilisation de toutes les fonctions de nomenclature en minuscules et le remplacement des traits de soulignement.

Il convient de noter que l'environnement de test utilise golang v1.17, sqlx v1.3.4 et TiDB v1.6.1.

  1. Nous devons d'abord créer une table de données testTable pour la démonstration.
CREATE TABLE `test_table` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL,
  `sex` varchar(256) NOT NULL,
  `counter` bigint(20) NOT NULL,
  `create_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `update_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `miss_counter` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  UNIQUE KEY `test_table_name_uindex` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin AUTO_INCREMENT=30001
  1. Ensuite, définissez une structure appelée testTable dans le programme Go, où MissCounterles champs seront affectés par NameMapper.
type testTable struct {
	ID          uint64
	Name        string // unique index
	Sex         string
	Counter     uint64 // 命中计数字段
	MissCounter uint64 // 非命中计数字段
	CreateAt    time.Time
	UpdateAt    time.Time
}
  1. Ensuite, nous devons écrire un code d'insertion pour démontrer l'impact des différentes fonctions de génération de champs de base de données.
func main(){
    
    
  tx, err := db.BeginTxx(ctx, &sql.TxOptions{
    
    })
	if err != nil {
    
    
		log.Error(err)
		return
	}
	
	const insertSQL = "INSERT INTO test_table (name, sex, counter, miss_counter) VALUES (:name, :sex, :counter, :miss_counter);"
	stmt, errPrepare := tx.PrepareNamedContext(ctx, insertSQL)
	if errPrepare != nil {
    
    
		log.Errorf("failed to prepare, err: %v", errPrepare)
		_ = tx.Rollback()
		return
	}
	for _, row := range []*testTable{
    
    
		{
    
    Name: "小李", Sex: "男", Counter: uint64(rand.Int63()), MissCounter: uint64(rand.Int63())},
		{
    
    Name: "小白", Sex: "女", Counter: uint64(rand.Int63()), MissCounter: uint64(rand.Int63())},
		{
    
    Name: "小黑", Sex: "男", Counter: uint64(rand.Int63()), MissCounter: uint64(rand.Int63())},
		{
    
    Name: "小天", Sex: "女", Counter: uint64(rand.Int63()), MissCounter: uint64(rand.Int63())},
	} {
    
    
		res, errExec := stmt.ExecContext(ctx, row)
		if errExec != nil {
    
    
			// for duplicate err
			if me, isMySQLErr := errExec.(*mysql.MySQLError); isMySQLErr && me.Number == 1062 /*duplicate is 1062*/ {
    
    
				log.Infof("skip duplicate err, err: %v, row: %+v", me, row)
				continue
			}
			log.Errorf("failed to stmt exec, err: %v", errExec)
			_ = tx.Rollback()
			return
		}
		insertID, _ := res.LastInsertId()
		log.Infof("success to stmt exec, row: %+v, id: %d", row, insertID)
	}
	if errCommit := tx.Commit(); errCommit != nil {
    
    
		log.Error(errCommit)
		return
	}
	log.Infof("finish")
}
  1. Dans le cas de l'utilisation de NameMapper en minuscules, l'exécution du programme signalera une erreur could not find name xxx.
2021-10-31T16:29:15.029+0800    ERROR   transaction/main.go:76  failed to stmt exec, err: could not find name miss_counter in &main.testTable{
    
    ID:0x0, Name:"小李, Sex:"男", Counter:0x4354432fe0f37484, MissCounter:0x45afa115903b7669, CreateAt:time.Date(1, time.January, 1, 0, 0, 0, 0, time.UTC), UpdateAt:time.Date(1, tim.January, 1, 0, 0, 0, 0, time.UTC)}
  1. Dans le cas d'un NameMapper qui utilise la notation de soulignement, le programme s'exécute sans problème.
2021-10-31T16:30:27.841+0800    INFO    transaction/main.go:81  success to stmt exec, row: &{
    
    ID:0 Name:小李 Sex:男 Counter:6239523519032355576 MissCounter:180608923895024 CreateAt:0001-01-01 00:00:00 +0000 UTC UpdateAt:0001-01-01 00:00:00 +0000 UTC}, id: 23
2021-10-31T16:30:27.842+0800    INFO    transaction/main.go:81  success to stmt exec, row: &{
    
    ID:0 Name:小白 Sex:女 Counter:2433768853952726858 MissCounter:7832533413053117 CreateAt:0001-01-01 00:00:00 +0000 UTC UpdateAt:0001-01-01 00:00:00 +0000 UTC}, id: 24
2021-10-31T16:30:27.844+0800    INFO    transaction/main.go:81  success to stmt exec, row: &{
    
    ID:0 Name:小黑 Sex:男 Counter:8462818185278118914 MissCounter:1149211500697067 CreateAt:0001-01-01 00:00:00 +0000 UTC UpdateAt:0001-01-01 00:00:00 +0000 UTC}, id: 25
2021-10-31T16:30:27.845+0800    INFO    transaction/main.go:81  success to stmt exec, row: &{
    
    ID:0 Name:小天 Sex:女 Counter:23243666993166910 MissCounter:9005766596808865 CreateAt:0001-01-01 00:00:00 +0000 UTC UpdateAt:0001-01-01 00:00:00 +0000 UTC}, id: 26
2021-10-31T16:30:27.848+0800    INFO    transaction/main.go:87  finish

Si cet article vous est utile, vous pouvez donner un like à l'auteur, merci.

Je suppose que tu aimes

Origine blog.csdn.net/yes169yes123/article/details/121066019
conseillé
Classement