feat: add more manage features

This commit is contained in:
Samuel N Cui
2023-10-05 02:11:37 +08:00
parent c105763e3d
commit 973cbb91c2
20 changed files with 424 additions and 111 deletions

View File

@@ -35,15 +35,16 @@ func NewDBConn(dialect, dsn string) (*gorm.DB, error) {
return db, nil
}
func SQLEscape(sql string) string {
dest := make([]byte, 0, 2*len(sql))
var escape byte
for i := 0; i < len(sql); i++ {
c := sql[i]
func SQLEscape(str string) string {
runes := []rune(str)
result := make([]rune, 0, len(runes))
var escape rune
for i := 0; i < len(runes); i++ {
r := runes[i]
escape = 0
switch c {
switch r {
case 0: /* Must be escaped for 'mysql' */
escape = '0'
case '\n': /* Must be escaped for logs */
@@ -56,16 +57,16 @@ func SQLEscape(sql string) string {
escape = '\''
case '"': /* Better safe than sorry */
escape = '"'
case '\032': //十进制26,八进制32,十六进制1a, /* This gives problems on Win32 */
case '\032': // This gives problems on Win32
escape = 'Z'
}
if escape != 0 {
dest = append(dest, '\\', escape)
result = append(result, '\\', escape)
} else {
dest = append(dest, c)
result = append(result, r)
}
}
return string(dest)
return string(result)
}

View File

@@ -0,0 +1,14 @@
//go:build !((darwin && amd64) || (darwin && arm64) || (freebsd && amd64) || (linux && arm) || (linux && arm64) || (linux && 386) || (linux && amd64) || (linux && s390x) || (windows && amd64))
package resource
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
type innerSQLiteMigrator = sqlite.Migrator
func openSQLite(dsn string) gorm.Dialector {
return &sqliteDialector{sqlite.Open(dsn)}
}

156
resource/sqlite_fix.go.bak Normal file
View File

@@ -0,0 +1,156 @@
package resource
import (
"fmt"
"strings"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"gorm.io/gorm/migrator"
"gorm.io/gorm/schema"
)
// fix primary key autoincrement problem
type sqliteDialector struct {
gorm.Dialector
}
func (dialector *sqliteDialector) DataTypeOf(field *schema.Field) string {
switch field.DataType {
case schema.Int, schema.Uint:
if field.AutoIncrement {
// https://www.sqlite.org/autoinc.html
return "integer PRIMARY KEY AUTOINCREMENT"
}
}
return dialector.Dialector.DataTypeOf(field)
}
func (dialector *sqliteDialector) Migrator(db *gorm.DB) gorm.Migrator {
return sqliteMigrator{innerSQLiteMigrator{Migrator: migrator.Migrator{Config: migrator.Config{
DB: db,
Dialector: dialector,
CreateIndexAfterCreateTable: true,
}}}}
}
type sqliteMigrator struct {
innerSQLiteMigrator
}
// CreateTable create table in database for values
func (m sqliteMigrator) CreateTable(values ...interface{}) error {
for _, value := range m.ReorderModels(values, false) {
tx := m.DB.Session(&gorm.Session{})
if err := m.RunWithValue(value, func(stmt *gorm.Statement) (err error) {
var (
createTableSQL = "CREATE TABLE ? ("
values = []interface{}{m.CurrentTable(stmt)}
hasPrimaryKeyInDataType bool
)
for _, dbName := range stmt.Schema.DBNames {
field := stmt.Schema.FieldsByDBName[dbName]
if !field.IgnoreMigration {
createTableSQL += "? ?"
hasPrimaryKeyInDataType = hasPrimaryKeyInDataType || strings.Contains(strings.ToUpper(m.DataTypeOf(field)), "PRIMARY KEY")
values = append(values, clause.Column{Name: dbName}, m.DB.Migrator().FullDataTypeOf(field))
createTableSQL += ","
}
}
if !hasPrimaryKeyInDataType && len(stmt.Schema.PrimaryFields) > 0 {
createTableSQL += "PRIMARY KEY ?,"
primaryKeys := make([]interface{}, 0, len(stmt.Schema.PrimaryFields))
for _, field := range stmt.Schema.PrimaryFields {
primaryKeys = append(primaryKeys, clause.Column{Name: field.DBName})
}
values = append(values, primaryKeys)
}
for _, idx := range stmt.Schema.ParseIndexes() {
if m.CreateIndexAfterCreateTable {
defer func(value interface{}, name string) {
if err == nil {
err = tx.Migrator().CreateIndex(value, name)
}
}(value, idx.Name)
} else {
if idx.Class != "" {
createTableSQL += idx.Class + " "
}
createTableSQL += "INDEX ? ?"
if idx.Comment != "" {
createTableSQL += fmt.Sprintf(" COMMENT '%s'", idx.Comment)
}
if idx.Option != "" {
createTableSQL += " " + idx.Option
}
createTableSQL += ","
values = append(values, clause.Column{Name: idx.Name}, tx.Migrator().(migrator.BuildIndexOptionsInterface).BuildIndexOptions(idx.Fields, stmt))
}
}
if !m.DB.DisableForeignKeyConstraintWhenMigrating && !m.DB.IgnoreRelationshipsWhenMigrating {
for _, rel := range stmt.Schema.Relationships.Relations {
if rel.Field.IgnoreMigration {
continue
}
if constraint := rel.ParseConstraint(); constraint != nil {
if constraint.Schema == stmt.Schema {
sql, vars := buildConstraint(constraint)
createTableSQL += sql + ","
values = append(values, vars...)
}
}
}
}
for _, chk := range stmt.Schema.ParseCheckConstraints() {
createTableSQL += "CONSTRAINT ? CHECK (?),"
values = append(values, clause.Column{Name: chk.Name}, clause.Expr{SQL: chk.Constraint})
}
createTableSQL = strings.TrimSuffix(createTableSQL, ",")
createTableSQL += ")"
if tableOption, ok := m.DB.Get("gorm:table_options"); ok {
createTableSQL += fmt.Sprint(tableOption)
}
err = tx.Exec(createTableSQL, values...).Error
return err
}); err != nil {
return err
}
}
return nil
}
func buildConstraint(constraint *schema.Constraint) (sql string, results []interface{}) {
sql = "CONSTRAINT ? FOREIGN KEY ? REFERENCES ??"
if constraint.OnDelete != "" {
sql += " ON DELETE " + constraint.OnDelete
}
if constraint.OnUpdate != "" {
sql += " ON UPDATE " + constraint.OnUpdate
}
var foreignKeys, references []interface{}
for _, field := range constraint.ForeignKeys {
foreignKeys = append(foreignKeys, clause.Column{Name: field.DBName})
}
for _, field := range constraint.References {
references = append(references, clause.Column{Name: field.DBName})
}
results = append(results, clause.Table{Name: constraint.Name}, foreignKeys, clause.Table{Name: constraint.ReferenceSchema.Table}, references)
return
}

View File

@@ -0,0 +1,14 @@
//go:build (darwin && amd64) || (darwin && arm64) || (freebsd && amd64) || (linux && arm) || (linux && arm64) || (linux && 386) || (linux && amd64) || (linux && s390x) || (windows && amd64)
package resource
import (
"github.com/glebarez/sqlite"
"gorm.io/gorm"
)
type innerSQLiteMigrator = sqlite.Migrator
func openSQLite(dsn string) gorm.Dialector {
return &sqliteDialector{sqlite.Open(dsn)}
}