add apaas code
This commit is contained in:
parent
e5b867e785
commit
820dc0aa89
92
apaas/checker.go
Normal file
92
apaas/checker.go
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Checker interface {
|
||||||
|
Check(string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtraCheck(rule map[string]*ExtraFieldMeta, extra string) error {
|
||||||
|
var data map[string]any
|
||||||
|
err := json.Unmarshal([]byte(extra), &data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for k, v := range data {
|
||||||
|
r, ok := rule[k]
|
||||||
|
if !ok || r == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = FieldCheck(r, v)
|
||||||
|
if err != nil {
|
||||||
|
return GenError(err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FieldCheck(rule *ExtraFieldMeta, value any) error {
|
||||||
|
if rule == nil || value == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
switch val := value.(type) {
|
||||||
|
case map[string]any:
|
||||||
|
if len(rule.ObjectMeta) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for k, v := range val {
|
||||||
|
r, ok := rule.ObjectMeta[k]
|
||||||
|
if !ok || r == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
err = FieldCheck(r, v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s), value(type=map[%s], suberror=%s)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], k, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case []any:
|
||||||
|
if rule.Type != FieldArray {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type=array, value=%#v)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], val)
|
||||||
|
}
|
||||||
|
if len(rule.ArrayMeta) != 0 {
|
||||||
|
for i, v := range val {
|
||||||
|
err = FieldCheck(rule.ArrayMeta[i], v)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s), value(type array, [%d] element suberror=%s)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], i, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case string:
|
||||||
|
if rule.Type != FieldString {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type=string, value=%#v)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], val)
|
||||||
|
}
|
||||||
|
case float64:
|
||||||
|
if rule.Type != FieldInt && rule.Type != FieldFloat64 {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type=float/int, value=%#v)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], val)
|
||||||
|
}
|
||||||
|
if rule.Type == FieldInt && float64(int(val)) != val {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type=float, value=%#v)",
|
||||||
|
rule.Key, FieldMapString[rule.Type], val)
|
||||||
|
}
|
||||||
|
case bool:
|
||||||
|
if rule.Type != FieldBool {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type=bool, value=%#v)",
|
||||||
|
rule.Key, FieldMapString[rule.Type])
|
||||||
|
}
|
||||||
|
case nil:
|
||||||
|
if rule.Type != FieldArray || rule.Type != FieldObject {
|
||||||
|
return fmt.Errorf("rule(key=%s, type=%s) dismatch value(type nil)",
|
||||||
|
rule.Key, FieldMapString[rule.Type])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
53
apaas/collection.go
Normal file
53
apaas/collection.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
)
|
||||||
|
|
||||||
|
var gDBCol atomic.Value
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dbCol := &DBCollection{
|
||||||
|
dbs: make(map[string]*DBMeta, 128),
|
||||||
|
}
|
||||||
|
SetDBCol(dbCol)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetDBCol(dbCol *DBCollection) {
|
||||||
|
if dbCol != nil {
|
||||||
|
gDBCol.Store(dbCol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDBCol() *DBCollection {
|
||||||
|
dbCol, ok := gDBCol.Load().(*DBCollection)
|
||||||
|
if ok {
|
||||||
|
return dbCol
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type DBCollection struct {
|
||||||
|
dbs map[string]*DBMeta
|
||||||
|
lock sync.RWMutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DBCollection) GetDB(dbName string) (*DBMeta, bool) {
|
||||||
|
p.lock.RLock()
|
||||||
|
v, ok := p.dbs[dbName]
|
||||||
|
p.lock.RUnlock()
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DBCollection) SetDB(dbName string, dbMeta *DBMeta) {
|
||||||
|
p.lock.Lock()
|
||||||
|
p.dbs[dbName] = dbMeta
|
||||||
|
p.lock.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DBCollection) DeleteDB(dbName string) {
|
||||||
|
p.lock.Lock()
|
||||||
|
delete(p.dbs, dbName)
|
||||||
|
p.lock.Unlock()
|
||||||
|
}
|
1
apaas/dailer.go
Normal file
1
apaas/dailer.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package apaas
|
9
apaas/error.go
Normal file
9
apaas/error.go
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
const MSG_PREFIX = "[apaas_engine]"
|
||||||
|
|
||||||
|
func GenError(msg string) error {
|
||||||
|
return fmt.Errorf("%s %s", MSG_PREFIX, msg)
|
||||||
|
}
|
94
apaas/fetcher.go
Normal file
94
apaas/fetcher.go
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gorm.io/gorm/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
type DBFetcher interface {
|
||||||
|
Fetch() ([]*ApaasTable, error)
|
||||||
|
// each fetcher has only uniq name, Name is must DBName
|
||||||
|
// if DBName is nil, default fetch all
|
||||||
|
DBName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
var gAllFetcher = map[string]DBFetcher{}
|
||||||
|
var gDeltaFetcher = map[string]DBFetcher{}
|
||||||
|
|
||||||
|
func AddDBFetcher(f DBFetcher) {
|
||||||
|
gAllFetcher[f.DBName()] = f
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update All DB metas, called by apaas_db_engine SDK
|
||||||
|
func UpdateAllDBCol() {
|
||||||
|
for name, f := range gAllFetcher {
|
||||||
|
if f.DBName() == "" {
|
||||||
|
tables, err := f.Fetch()
|
||||||
|
if err != nil {
|
||||||
|
logger.Default.Error(context.Background(), "%s fetcher(name=%s, DBName=%s) Fetch data error=%s", MSG_PREFIX, name, f.DBName(), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.Default.Info(context.Background(), "%s fetcher(name=%s, DBName=%s) Fetch data len=%d", MSG_PREFIX, name, f.DBName(), len(tables))
|
||||||
|
|
||||||
|
dbCol := &DBCollection{
|
||||||
|
dbs: make(map[string]*DBMeta, 128),
|
||||||
|
}
|
||||||
|
for _, table := range tables {
|
||||||
|
v, ok := dbCol.dbs[table.DBName]
|
||||||
|
if !ok {
|
||||||
|
v := &DBMeta{
|
||||||
|
tableList: make([]*ApaasTable, 0, len(tables)>>2),
|
||||||
|
tableView: make(map[string]*ApaasTable, len(tables)>>2),
|
||||||
|
lookupIDView: make(map[string]*ApaasTable, len(tables)>>2),
|
||||||
|
}
|
||||||
|
dbCol.dbs[table.DBName] = v
|
||||||
|
}
|
||||||
|
v.tableList = append(v.tableList, table)
|
||||||
|
v.tableView[table.TableName] = table
|
||||||
|
if table.LookupIDField != nil {
|
||||||
|
v.lookupIDView[table.LookupIDField.Name] = table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetDBCol(dbCol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for name, f := range gAllFetcher {
|
||||||
|
if f.DBName() == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tables, err := f.Fetch()
|
||||||
|
if err != nil {
|
||||||
|
logger.Default.Error(context.Background(), "%s fetcher(name=%s, DBName=%s) Fetch data error=%s", MSG_PREFIX, name, f.DBName(), err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
logger.Default.Info(context.Background(), "%s fetcher(name=%s, DBName=%s) Fetch data len=%d", MSG_PREFIX, name, f.DBName(), len(tables))
|
||||||
|
|
||||||
|
if len(tables) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if len(f.DBName()) != 0 {
|
||||||
|
dbMeta := &DBMeta{
|
||||||
|
tableList: tables,
|
||||||
|
}
|
||||||
|
dbMeta.tableView = make(map[string]*ApaasTable, len(tables))
|
||||||
|
dbMeta.lookupIDView = make(map[string]*ApaasTable, len(tables))
|
||||||
|
for _, table := range tables {
|
||||||
|
dbMeta.tableView[table.TableName] = table
|
||||||
|
if table.LookupIDField != nil {
|
||||||
|
dbMeta.lookupIDView[table.LookupIDField.Name] = table
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GetDBCol().SetDB(f.DBName(), dbMeta)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Update DB metas, called by apaas_db_engine SDK
|
||||||
|
func UpdateDeltaDBCol() {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
29
apaas/idl.go
Normal file
29
apaas/idl.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
type ApaasQueryType int8
|
||||||
|
|
||||||
|
const (
|
||||||
|
_skipQueryType ApaasQueryType = iota
|
||||||
|
SelectType
|
||||||
|
CreateType
|
||||||
|
InsertType
|
||||||
|
UpdateType
|
||||||
|
DeleteType
|
||||||
|
RawType
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApaasQueryArgs struct {
|
||||||
|
Select any
|
||||||
|
From any
|
||||||
|
Where any
|
||||||
|
Join any
|
||||||
|
Group any
|
||||||
|
Order any
|
||||||
|
Limit any
|
||||||
|
Offset any
|
||||||
|
Update any
|
||||||
|
Delete any
|
||||||
|
create any
|
||||||
|
RawSql string
|
||||||
|
QueryType ApaasQueryType
|
||||||
|
}
|
150
apaas/reflect.go
Normal file
150
apaas/reflect.go
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _unknown_field = reflect.StructField{}
|
||||||
|
|
||||||
|
func GetFieldTypeByColumnNameV2(value reflect.Value, fieldColumnName string) (reflect.StructField, bool) {
|
||||||
|
// check obj is pointer or not
|
||||||
|
if value.Kind() == reflect.Ptr {
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
typ := value.Type()
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
fieldValue := value.Field(i)
|
||||||
|
if field.Anonymous {
|
||||||
|
return GetFieldTypeByColumnNameV2(fieldValue, fieldColumnName)
|
||||||
|
}
|
||||||
|
tag := field.Tag.Get("gorm")
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if cname, ok := getColumnNameByColumnTag(tag); ok && cname == fieldColumnName {
|
||||||
|
return field, ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _unknown_field, false
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
case:
|
||||||
|
|
||||||
|
type Faction struct {
|
||||||
|
ID int64 `gorm:"column:id;primaryKey;autoIncrement:true" json:"id"`
|
||||||
|
LiveID int64 `gorm:"column:live_id" json:"live_id"`
|
||||||
|
BizID int64 `gorm:"column:biz_id" json:"biz_id"`
|
||||||
|
FactionID int64 `gorm:"column:faction_id;not null" json:"faction_id"`
|
||||||
|
FactionName string `gorm:"column:faction_name" json:"faction_name"`
|
||||||
|
OrgID int64 `gorm:"column:org_id;comment:union外键" json:"org_id" apass_engine_lookup_id:"webcast.union.org_id"` // union外键
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldColumnName: faction_id
|
||||||
|
*/
|
||||||
|
func GetFieldTypeByColumnName(obj any, fieldColumnName string) (reflect.StructField, bool) {
|
||||||
|
return GetFieldTypeByColumnNameV2(reflect.ValueOf(obj), fieldColumnName)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
case: `gorm:"column:id;primaryKey;autoIncrement:true"
|
||||||
|
*/
|
||||||
|
func getColumnNameByColumnTag(tag string) (string, bool) {
|
||||||
|
fs := strings.Split(tag, ";")
|
||||||
|
if len(fs) >= 1 {
|
||||||
|
sfs := strings.Split(fs[0], ":")
|
||||||
|
if sfs[0] == "column" {
|
||||||
|
return sfs[1], true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFieldTypeByColumnNameV3(typ reflect.Type, fieldColumnName string) (reflect.StructField, bool) {
|
||||||
|
// check obj is pointer or not
|
||||||
|
if typ.Kind() == reflect.Ptr {
|
||||||
|
typ = typ.Elem()
|
||||||
|
}
|
||||||
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
|
field := typ.Field(i)
|
||||||
|
if field.Anonymous {
|
||||||
|
return GetFieldTypeByColumnNameV3(field.Type, fieldColumnName)
|
||||||
|
}
|
||||||
|
tag := field.Tag.Get("gorm")
|
||||||
|
if tag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if cname, ok := getColumnNameByColumnTag(tag); ok && cname == fieldColumnName {
|
||||||
|
return field, ok
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _unknown_field, false
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParseLookupTagMeta(tag, columnName, dbName, tableName string) (*ApaasLookupMeta, error) {
|
||||||
|
fmt.Printf("[apaas_engine] tag: %s, columnName: %s, dbName: %s, tableName: %s\n", tag, columnName, dbName, tableName)
|
||||||
|
if tag == "" {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
fs := strings.Split(tag, ".")
|
||||||
|
if len(fs) > MaxTagDeep {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, lookup deep=%d>%d", tag, len(fs), MaxTagDeep))
|
||||||
|
}
|
||||||
|
meta := &ApaasLookupMeta{
|
||||||
|
CName: columnName,
|
||||||
|
LookupMeta: make([]*LookupMeta, len(fs)-1),
|
||||||
|
LastField: fs[len(fs)-1],
|
||||||
|
OrgTag: fs,
|
||||||
|
}
|
||||||
|
dbCol := GetDBCol()
|
||||||
|
if dbCol == nil {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, cann't get db collection", tag))
|
||||||
|
}
|
||||||
|
dbMeta, ok := dbCol.GetDB(dbName)
|
||||||
|
if !ok || dbMeta == nil {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, cann't get db(name=%s) meta", tag, dbName))
|
||||||
|
}
|
||||||
|
|
||||||
|
tableMeta, ok := dbMeta.tableView[tableName]
|
||||||
|
if !ok {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, cann't get table(name=%s) meta", tag, tableName))
|
||||||
|
}
|
||||||
|
var idx int = 0
|
||||||
|
for idx < len(fs)-1 {
|
||||||
|
lp := &LookupMeta{
|
||||||
|
FieldName: fs[idx],
|
||||||
|
ForeignMeta: ForeignMeta{
|
||||||
|
DBName: dbName,
|
||||||
|
FName: fs[idx+1],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
found := false
|
||||||
|
for _, ff := range tableMeta.ForeignFields {
|
||||||
|
if ff.Name == fs[idx] {
|
||||||
|
if fs[idx+1] != ff.foreignMeta.FName {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, db=%s, table=%s, field=%s, foreign(table=%s), foreign field=%s not equal to lookup field=%s)", tag, dbName, tableName, ff.Name, ff.foreignMeta.TName, fs[idx+1]))
|
||||||
|
}
|
||||||
|
if dbName != ff.foreignMeta.DBName {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, db=%s, table=%s, field=%s, foreign(table=%s), foreign db=%s not equal to lookup db=%s)", tag, tag, dbName, tableName, ff.Name, ff.foreignMeta.DBName, dbName))
|
||||||
|
}
|
||||||
|
lp.ForeignMeta.TName = ff.foreignMeta.TName
|
||||||
|
lp.ForeignMeta.FTMeta = ff.foreignMeta.FTMeta
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, db=%s, table=%s, field=%s is not foreign key", tag, tag, dbName, tableName, fs[idx]))
|
||||||
|
}
|
||||||
|
meta.LookupMeta[idx] = lp
|
||||||
|
tableName = lp.ForeignMeta.TName
|
||||||
|
tableMeta, ok = dbMeta.tableView[tableName]
|
||||||
|
if !ok {
|
||||||
|
return nil, GenError(fmt.Sprintf("apass_engine_lookup_value=%s, cann't get table(name=%s) meta", tag, tableName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return meta, nil
|
||||||
|
}
|
235
apaas/types.go
Normal file
235
apaas/types.go
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
package apaas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
TagID = "apass_engine_lookup_id"
|
||||||
|
TagValue = "apass_engine_lookup_value"
|
||||||
|
MaxTagDeep = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
type ApaasFieldType uint8
|
||||||
|
type FieldType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
_skipFieldType FieldType = iota
|
||||||
|
FieldBool
|
||||||
|
FieldInt
|
||||||
|
FieldInt64
|
||||||
|
FieldFloat
|
||||||
|
FieldFloat64
|
||||||
|
FieldString
|
||||||
|
FieldTime
|
||||||
|
FieldBit
|
||||||
|
FieldBin
|
||||||
|
FieldArray
|
||||||
|
FieldObject
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
_skipApaasFieldType ApaasFieldType = iota
|
||||||
|
ApaasLookupID
|
||||||
|
ApaasLookupValue
|
||||||
|
ApaasExtraType
|
||||||
|
ApaasFormulaType
|
||||||
|
)
|
||||||
|
|
||||||
|
var FieldMapString = []string{
|
||||||
|
"_skipApaasFieldTyle",
|
||||||
|
"FieldBool",
|
||||||
|
"FieldInt",
|
||||||
|
"FieldInt64",
|
||||||
|
"FieldFloat",
|
||||||
|
"FieldFloat64",
|
||||||
|
"FieldString",
|
||||||
|
"FieldTime",
|
||||||
|
"FieldBit",
|
||||||
|
"FieldBin",
|
||||||
|
"FieldArray",
|
||||||
|
"FieldObject",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p FieldType) String() string {
|
||||||
|
return FieldMapString[p]
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
description: store dynamic field info when is an instance like tag
|
||||||
|
|
||||||
|
`apass_engine_lookup_value`
|
||||||
|
|
||||||
|
case:
|
||||||
|
|
||||||
|
type RoomAnchorView struct {
|
||||||
|
Room
|
||||||
|
Gender string `gorm:"column:gender" json:"gender" apass_engine_lookup_value:"anchor_id.uid.gender"`
|
||||||
|
Career string `gorm:"column:career" json:"career" apass_engine_lookup_value:"anchor_id.uid.career"`
|
||||||
|
Name string `gorm:"column:name" json:"name" apass_engine_lookup_value:"anchor_id.uid.name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoomAnchorFactionView struct {
|
||||||
|
Room
|
||||||
|
Gender string `gorm:"column:gender" json:"gender" apass_engine_lookup_value:"anchor_id.uid.gender"`
|
||||||
|
Career string `gorm:"column:career" json:"career" apass_engine_lookup_value:"anchor_id.uid.career"`
|
||||||
|
Name string `gorm:"column:name" json:"name" apass_engine_lookup_value:"anchor_id.uid.name"`
|
||||||
|
OrgName string `gorm:"column:org_name" json:"org_name" apass_engine_lookup_value:"anchor_id.faction_id.faction_name"`
|
||||||
|
UnionInfo string `gorm:"column:union_info" json:"union_info" apass_engine_lookup_value:"anchor_id.faction_id.org_id.union_info"`
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
type ApaasLookupMeta struct {
|
||||||
|
// field gorm column tag name/table field's name. example: union_info
|
||||||
|
CName string
|
||||||
|
// lookup orgin meta. example: [anchor_id.faction_id.org_id.union_info]
|
||||||
|
/*
|
||||||
|
1. anchor_id; 2. faction_id; 3: org_id;
|
||||||
|
1. anchor.anchor_id;2. Vction.faction_id;3: union.org_id;
|
||||||
|
*/
|
||||||
|
LookupMeta []*LookupMeta
|
||||||
|
LastField string // org_name/union_name
|
||||||
|
|
||||||
|
/*
|
||||||
|
OrgTag only set value when used in SDK mode
|
||||||
|
*/
|
||||||
|
// lookup org tag [anchor_id, faction_id, org_id, org_name]
|
||||||
|
OrgTag []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup orgin meta. example: [anchor_id.faction_id.org_id.union_info]
|
||||||
|
type LookupMeta struct {
|
||||||
|
FieldName string
|
||||||
|
ForeignMeta ForeignMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApaasTable struct {
|
||||||
|
TableName string
|
||||||
|
DBName string
|
||||||
|
Fields []*ApaasField
|
||||||
|
FieldsByName map[string]*ApaasField
|
||||||
|
LookupIDField *ApaasField // example: room.room_id, user.uid, faction.faction_id
|
||||||
|
ForeignFields []*ApaasField // foreign key. example: room.anchor_id, named of relookupid
|
||||||
|
FormulaFields []*ApaasField // example: union.title=update_time + org_name
|
||||||
|
LookupValueFields []*ApaasField // example: org_id.org_name, anchor_id.org_id.union_id.union_name
|
||||||
|
ExtraFields []*ApaasField // example: anchor.extra, room.extra
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApaasField struct {
|
||||||
|
Name string
|
||||||
|
Type string
|
||||||
|
FType FieldType
|
||||||
|
IsUniq bool
|
||||||
|
IsForeign bool
|
||||||
|
foreignMeta *ForeignMeta
|
||||||
|
IsApaasType bool
|
||||||
|
ApaasMeta *ApaasMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ApaasField) parseFieldType() {
|
||||||
|
tp := strings.ToUpper(p.Type)
|
||||||
|
ftp := _skipFieldType
|
||||||
|
switch tp {
|
||||||
|
case "BOOL":
|
||||||
|
ftp = FieldBool
|
||||||
|
case "INT", "TINYINT", "SMALLINT", "MEDIUMINT":
|
||||||
|
ftp = FieldInt
|
||||||
|
case "BIGINT":
|
||||||
|
ftp = FieldInt64
|
||||||
|
case "FLOAT":
|
||||||
|
ftp = FieldFloat
|
||||||
|
case "DOUBLE", "DECIMAL", "REAL":
|
||||||
|
ftp = FieldFloat64
|
||||||
|
case "DATE", "DATETIME", "TIMESTAMP", "TIME", "YEAR":
|
||||||
|
ftp = FieldTime
|
||||||
|
case "VARCHAR", "CHAR", "ENUM", "TEXT", "TINYTEXT", "MEDIUMTEXT", "LONGTEXT", "JSON":
|
||||||
|
ftp = FieldString
|
||||||
|
case "BLOB", "TINYBLOB", "MEDIUMBLOB", "LONGBLOB", "BINARY", "VARBINARY":
|
||||||
|
ftp = FieldBin
|
||||||
|
case "BIT":
|
||||||
|
ftp = FieldBit
|
||||||
|
default:
|
||||||
|
ftp = FieldString
|
||||||
|
}
|
||||||
|
p.FType = ftp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ApaasField) GetApaasMeta() *ApaasMeta {
|
||||||
|
return p.ApaasMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
type ForeignMeta struct {
|
||||||
|
DBName string
|
||||||
|
TName string
|
||||||
|
FName string
|
||||||
|
FTMeta *ApaasTable
|
||||||
|
}
|
||||||
|
|
||||||
|
type ApaasMeta struct {
|
||||||
|
ApaasFType ApaasFieldType
|
||||||
|
ExtraMeta map[string]*ExtraFieldMeta
|
||||||
|
FormulaMeta *FormulaMeta
|
||||||
|
LookupMeta *ApaasLookupMeta
|
||||||
|
Checker
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ApaasMeta) IsApaasFieldType() bool {
|
||||||
|
return p.ApaasFType == _skipApaasFieldType
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) IsExtraField() bool {
|
||||||
|
return p.ApaasFType == ApaasExtraType
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) IsFormulaField() bool {
|
||||||
|
return p.ApaasFType == ApaasFormulaType
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) IsLookupID() bool {
|
||||||
|
return p.ApaasFType == ApaasLookupID
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) IsLookupValue() bool {
|
||||||
|
return p.ApaasFType == ApaasLookupValue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ApaasMeta) GetApaasFieldType() ApaasFieldType {
|
||||||
|
return p.ApaasFType
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) GetExtraMeta() map[string]*ExtraFieldMeta {
|
||||||
|
return p.ExtraMeta
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) GetFormulaMeta() *FormulaMeta {
|
||||||
|
return p.FormulaMeta
|
||||||
|
}
|
||||||
|
func (p *ApaasMeta) Check(extra string) error {
|
||||||
|
// step1: extra rule check
|
||||||
|
err := ExtraCheck(p.ExtraMeta, extra)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type ExtraFieldMeta struct {
|
||||||
|
Key string
|
||||||
|
Type FieldType // Bool/Int/Float/String/Object/Array
|
||||||
|
ObjectMeta map[string]*ExtraFieldMeta // if Type is Object, use ObjectMeta
|
||||||
|
ArrayMeta []*ExtraFieldMeta // if Type is Array, need ArrayMeta
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormulaMeta struct {
|
||||||
|
InputFields map[string]*ApaasField
|
||||||
|
FormulaRule *FormulaRule
|
||||||
|
}
|
||||||
|
|
||||||
|
type FormulaRule struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
type DBMeta struct {
|
||||||
|
tableList []*ApaasTable
|
||||||
|
tableView map[string]*ApaasTable
|
||||||
|
lookupIDView map[string]*ApaasTable // each table has one one and only key to supprort lookup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DBMeta) GetTableByLookupID(lookID string) (*ApaasTable, bool) {
|
||||||
|
v, ok := p.lookupIDView[lookID]
|
||||||
|
return v, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *DBMeta) GetTableByName(tableName string) (*ApaasTable, bool) {
|
||||||
|
v, ok := p.tableView[tableName]
|
||||||
|
return v, ok
|
||||||
|
}
|
1
apaas/view.go
Normal file
1
apaas/view.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package apaas
|
18
apaas_mode.go
Normal file
18
apaas_mode.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package gorm
|
||||||
|
|
||||||
|
type ApaasModeType uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
DirectMode ApaasModeType = iota
|
||||||
|
EngineMode
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m ApaasModeType) String() string {
|
||||||
|
switch m {
|
||||||
|
case DirectMode:
|
||||||
|
return "DirectMode"
|
||||||
|
case EngineMode:
|
||||||
|
return "EngineMode"
|
||||||
|
}
|
||||||
|
return "DirectMode"
|
||||||
|
}
|
16
callbacks.go
16
callbacks.go
@ -8,6 +8,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gorm.io/gorm/apaas"
|
||||||
"gorm.io/gorm/schema"
|
"gorm.io/gorm/schema"
|
||||||
"gorm.io/gorm/utils"
|
"gorm.io/gorm/utils"
|
||||||
)
|
)
|
||||||
@ -109,8 +110,8 @@ func (p *processor) Execute(db *DB) *DB {
|
|||||||
db.AddError(err)
|
db.AddError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
parseLookupTagMeta(stmt)
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign stmt.ReflectValue
|
// assign stmt.ReflectValue
|
||||||
if stmt.Dest != nil {
|
if stmt.Dest != nil {
|
||||||
stmt.ReflectValue = reflect.ValueOf(stmt.Dest)
|
stmt.ReflectValue = reflect.ValueOf(stmt.Dest)
|
||||||
@ -358,3 +359,16 @@ func removeCallbacks(cs []*callback, nameMap map[string]bool) []*callback {
|
|||||||
}
|
}
|
||||||
return callbacks
|
return callbacks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseLookupTagMeta(stmt *Statement) {
|
||||||
|
for _, field := range stmt.Schema.Fields {
|
||||||
|
lookupMeta, err := apaas.ParseLookupTagMeta(field.Tag.Get(apaas.TagValue), field.DBName, stmt.DBName, stmt.Schema.Table)
|
||||||
|
if err != nil {
|
||||||
|
stmt.DB.AddError(err)
|
||||||
|
}
|
||||||
|
if lookupMeta != nil {
|
||||||
|
field.LookupMeta = lookupMeta
|
||||||
|
stmt.ApaasMode = EngineMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
79
callbacks/apaas_callbacks.go
Normal file
79
callbacks/apaas_callbacks.go
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
package callbacks
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
"gorm.io/gorm"
|
||||||
|
"gorm.io/gorm/apaas"
|
||||||
|
)
|
||||||
|
|
||||||
|
var dbNameCaller func(*gorm.DB) (string, error)
|
||||||
|
|
||||||
|
func SetDBNameCaller(fn func(*gorm.DB) (string, error)) {
|
||||||
|
dbNameCaller = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExtraCheckerCallBack(stage string) func(db *gorm.DB) {
|
||||||
|
return func(db *gorm.DB) {
|
||||||
|
if db.Error == nil && db.Statement.Schema != nil {
|
||||||
|
if db.Config.DBName == "" {
|
||||||
|
if dbNameCaller != nil {
|
||||||
|
db.Config.DBName, _ = dbNameCaller(db)
|
||||||
|
} else {
|
||||||
|
db.Config.DBName, _ = db.GetDBName()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dbName := db.Config.DBName
|
||||||
|
if dbName == "" {
|
||||||
|
//db.Error = db.AddError(GenError(fmt.Sprintf("%s ExtraCheckerCallBack(stage=%s) GetDBName nil", MSG_PREFIX, stage)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
db.Logger.Info(db.Statement.Context, "===schema: %#v\n", db.Statement.Schema.Fields)
|
||||||
|
for i, s := range db.Statement.Schema.Fields {
|
||||||
|
db.Logger.Info(db.Statement.Context, "===schema[i=%d]: %#v\n", i, *s)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
dbCol := apaas.GetDBCol()
|
||||||
|
if dbCol == nil {
|
||||||
|
//db.Error = db.AddError(GenError(fmt.Sprintf("%s ExtraCheckerCallBack(stage=%s) GetDBCollection nil ", MSG_PREFIX, stage)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dbMeta, ok := dbCol.GetDB(dbName)
|
||||||
|
if !ok {
|
||||||
|
//db.Error = db.AddError(GenError(fmt.Sprintf("%s ExtraCheckerCallBack(stage=%s) GetDB(db=%s) nil", dbName, MSG_PREFIX, stage)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tableMeta, ok := dbMeta.GetTableByName(db.Statement.Table)
|
||||||
|
if !ok {
|
||||||
|
//db.Error = db.AddError(GenError(fmt.Sprintf("%s ExtraCheckerCallBack(stage=%s) GetTable(db=%s,table=%s) GetDB nil", MSG_PREFIX, stage, dbName, db.Statement.Table)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
db.Logger.Info(db.Statement.Context, "%s ExtraCheckerCallBack(stage=%s) db_name=%s, table=%s", apaas.MSG_PREFIX, stage, dbName, tableMeta.TableName)
|
||||||
|
val := reflect.ValueOf(db.Statement.Dest)
|
||||||
|
for _, extraField := range tableMeta.ExtraFields {
|
||||||
|
db.Logger.Info(db.Statement.Context, "%s ExtraCheckerCallBack(stage=%s) db_name=%s, table=%s, check extra field=%s begin", apaas.MSG_PREFIX, stage, dbName, db.Statement.Table, extraField.Name)
|
||||||
|
field, ok := db.Statement.Schema.FieldsByDBName[extraField.Name]
|
||||||
|
if !ok {
|
||||||
|
db.Error = db.AddError(apaas.GenError(fmt.Sprintf("ExtraCheckerCallBack(stage=%s) Extra Field(db=%s,table=%s,field=%s) not found value in DestValue", stage, dbName, db.Statement.Table, field.DBName)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v, _ := field.ValueOf(db.Statement.Context, val)
|
||||||
|
strV, ok := v.(string)
|
||||||
|
pStrV, ok1 := v.(*string)
|
||||||
|
if !ok && !ok1 {
|
||||||
|
db.Error = db.AddError(apaas.GenError(fmt.Sprintf("ExtraCheckerCallBack(stage=%s) Extra Field(db=%s,table=%s,field=%s) is not string/*string value in DestValue", stage, dbName, db.Statement.Table, field.DBName)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ok1 {
|
||||||
|
strV = *pStrV
|
||||||
|
}
|
||||||
|
if err := extraField.GetApaasMeta().Check(strV); err != nil {
|
||||||
|
db.Error = db.AddError(apaas.GenError(fmt.Sprintf("ExtraCheckerCallBack(stage=%s) Extra Field(db=%s,table=%s,field=%s) check error=%s", stage, dbName, db.Statement.Table, field.DBName, err.Error())))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -38,12 +38,17 @@ func RegisterDefaultCallbacks(db *gorm.DB, config *Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createCallback := db.Callback().Create()
|
createCallback := db.Callback().Create()
|
||||||
|
// =====apaas callback==========
|
||||||
|
// apaas create callback register before transaction
|
||||||
|
createCallback.Before("gorm:create").Register("apaas_plugin:before_create", ExtraCheckerCallBack("create"))
|
||||||
|
// =====apaas callback end======
|
||||||
createCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction)
|
createCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction)
|
||||||
createCallback.Register("gorm:before_create", BeforeCreate)
|
createCallback.Register("gorm:before_create", BeforeCreate)
|
||||||
createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations(true))
|
createCallback.Register("gorm:save_before_associations", SaveBeforeAssociations(true))
|
||||||
createCallback.Register("gorm:create", Create(config))
|
createCallback.Register("gorm:create", Create(config))
|
||||||
createCallback.Register("gorm:save_after_associations", SaveAfterAssociations(true))
|
createCallback.Register("gorm:save_after_associations", SaveAfterAssociations(true))
|
||||||
createCallback.Register("gorm:after_create", AfterCreate)
|
createCallback.Register("gorm:after_create", AfterCreate)
|
||||||
|
|
||||||
createCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
|
createCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
|
||||||
createCallback.Clauses = config.CreateClauses
|
createCallback.Clauses = config.CreateClauses
|
||||||
|
|
||||||
@ -63,6 +68,10 @@ func RegisterDefaultCallbacks(db *gorm.DB, config *Config) {
|
|||||||
deleteCallback.Clauses = config.DeleteClauses
|
deleteCallback.Clauses = config.DeleteClauses
|
||||||
|
|
||||||
updateCallback := db.Callback().Update()
|
updateCallback := db.Callback().Update()
|
||||||
|
// =====apaas callback==========
|
||||||
|
// apaas update callback register before transaction
|
||||||
|
updateCallback.Register("apaas_plugin:before_update", ExtraCheckerCallBack("update"))
|
||||||
|
// =====apaas callback end======
|
||||||
updateCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction)
|
updateCallback.Match(enableTransaction).Register("gorm:begin_transaction", BeginTransaction)
|
||||||
updateCallback.Register("gorm:setup_reflect_value", SetupUpdateReflectValue)
|
updateCallback.Register("gorm:setup_reflect_value", SetupUpdateReflectValue)
|
||||||
updateCallback.Register("gorm:before_update", BeforeUpdate)
|
updateCallback.Register("gorm:before_update", BeforeUpdate)
|
||||||
@ -70,6 +79,7 @@ func RegisterDefaultCallbacks(db *gorm.DB, config *Config) {
|
|||||||
updateCallback.Register("gorm:update", Update(config))
|
updateCallback.Register("gorm:update", Update(config))
|
||||||
updateCallback.Register("gorm:save_after_associations", SaveAfterAssociations(false))
|
updateCallback.Register("gorm:save_after_associations", SaveAfterAssociations(false))
|
||||||
updateCallback.Register("gorm:after_update", AfterUpdate)
|
updateCallback.Register("gorm:after_update", AfterUpdate)
|
||||||
|
|
||||||
updateCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
|
updateCallback.Match(enableTransaction).Register("gorm:commit_or_rollback_transaction", CommitOrRollbackTransaction)
|
||||||
updateCallback.Clauses = config.UpdateClauses
|
updateCallback.Clauses = config.UpdateClauses
|
||||||
|
|
||||||
|
@ -74,6 +74,7 @@ func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) {
|
|||||||
func (db *DB) Save(value interface{}) (tx *DB) {
|
func (db *DB) Save(value interface{}) (tx *DB) {
|
||||||
tx = db.getInstance()
|
tx = db.getInstance()
|
||||||
tx.Statement.Dest = value
|
tx.Statement.Dest = value
|
||||||
|
db.Logger.Info(db.Statement.Context, "-----gorm save value: %#v", tx.Statement.Dest)
|
||||||
|
|
||||||
reflectValue := reflect.Indirect(reflect.ValueOf(value))
|
reflectValue := reflect.Indirect(reflect.ValueOf(value))
|
||||||
for reflectValue.Kind() == reflect.Ptr || reflectValue.Kind() == reflect.Interface {
|
for reflectValue.Kind() == reflect.Ptr || reflectValue.Kind() == reflect.Interface {
|
||||||
|
4
go.mod
4
go.mod
@ -5,5 +5,7 @@ go 1.18
|
|||||||
require (
|
require (
|
||||||
github.com/jinzhu/inflection v1.0.0
|
github.com/jinzhu/inflection v1.0.0
|
||||||
github.com/jinzhu/now v1.1.5
|
github.com/jinzhu/now v1.1.5
|
||||||
golang.org/x/text v0.20.0
|
golang.org/x/text v0.14.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace gorm.io/gorm => ./
|
||||||
|
4
go.sum
4
go.sum
@ -2,5 +2,5 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
|
|||||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
30
gorm.go
30
gorm.go
@ -69,6 +69,10 @@ type Config struct {
|
|||||||
|
|
||||||
callbacks *callbacks
|
callbacks *callbacks
|
||||||
cacheStore *sync.Map
|
cacheStore *sync.Map
|
||||||
|
|
||||||
|
/* ====Apaas Begin==== */
|
||||||
|
DBName string
|
||||||
|
/* ====Apaas End====== */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply update config to new config
|
// Apply update config to new config
|
||||||
@ -224,6 +228,9 @@ func Open(dialector Dialector, opts ...Option) (db *DB, err error) {
|
|||||||
config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
|
config.Logger.Error(context.Background(), "failed to initialize database, got error %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dbName, _ := db.GetDBName()
|
||||||
|
db.Config.DBName = dbName
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,3 +531,26 @@ func (db *DB) ToSQL(queryFn func(tx *DB) *DB) string {
|
|||||||
|
|
||||||
return db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
|
return db.Dialector.Explain(stmt.SQL.String(), stmt.Vars...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetDBName() (string, error) {
|
||||||
|
var dbName string
|
||||||
|
var err error
|
||||||
|
// must be create new db
|
||||||
|
db1 := db.WithContext(context.Background())
|
||||||
|
// 检测数据库类型
|
||||||
|
switch db1.Dialector.Name() {
|
||||||
|
case "mysql":
|
||||||
|
err = db1.Raw("SELECT DATABASE()").Scan(&dbName).Error
|
||||||
|
case "postgres":
|
||||||
|
err = db1.Raw("SELECT current_database()").Scan(&dbName).Error
|
||||||
|
case "sqlite":
|
||||||
|
// SQLite中数据库名通常是文件路径
|
||||||
|
var path string
|
||||||
|
err = db1.Raw("PRAGMA database_list").Scan(&struct{ Name, File string }{}).Error
|
||||||
|
dbName = path
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("unsupported database dialect")
|
||||||
|
}
|
||||||
|
|
||||||
|
return dbName, err
|
||||||
|
}
|
||||||
|
@ -74,7 +74,7 @@ var (
|
|||||||
// Default Default logger
|
// Default Default logger
|
||||||
Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{
|
Default = New(log.New(os.Stdout, "\r\n", log.LstdFlags), Config{
|
||||||
SlowThreshold: 200 * time.Millisecond,
|
SlowThreshold: 200 * time.Millisecond,
|
||||||
LogLevel: Warn,
|
LogLevel: Info,
|
||||||
IgnoreRecordNotFoundError: false,
|
IgnoreRecordNotFoundError: false,
|
||||||
Colorful: true,
|
Colorful: true,
|
||||||
})
|
})
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jinzhu/now"
|
"github.com/jinzhu/now"
|
||||||
|
"gorm.io/gorm/apaas"
|
||||||
"gorm.io/gorm/clause"
|
"gorm.io/gorm/clause"
|
||||||
"gorm.io/gorm/utils"
|
"gorm.io/gorm/utils"
|
||||||
)
|
)
|
||||||
@ -96,6 +97,10 @@ type Field struct {
|
|||||||
// It causes field unnecessarily migration.
|
// It causes field unnecessarily migration.
|
||||||
// Therefore, we need to record the UniqueIndex on this column (exclude Mul UniqueIndex) for MigrateColumnUnique.
|
// Therefore, we need to record the UniqueIndex on this column (exclude Mul UniqueIndex) for MigrateColumnUnique.
|
||||||
UniqueIndex string
|
UniqueIndex string
|
||||||
|
|
||||||
|
// ==========apaas engine field begin==========
|
||||||
|
LookupMeta *apaas.ApaasLookupMeta
|
||||||
|
// ==========apaas engine field end==========
|
||||||
}
|
}
|
||||||
|
|
||||||
func (field *Field) BindName() string {
|
func (field *Field) BindName() string {
|
||||||
@ -131,7 +136,6 @@ func (schema *Schema) ParseField(fieldStruct reflect.StructField) *Field {
|
|||||||
Comment: tagSetting["COMMENT"],
|
Comment: tagSetting["COMMENT"],
|
||||||
AutoIncrementIncrement: DefaultAutoIncrementIncrement,
|
AutoIncrementIncrement: DefaultAutoIncrementIncrement,
|
||||||
}
|
}
|
||||||
|
|
||||||
for field.IndirectFieldType.Kind() == reflect.Ptr {
|
for field.IndirectFieldType.Kind() == reflect.Ptr {
|
||||||
field.IndirectFieldType = field.IndirectFieldType.Elem()
|
field.IndirectFieldType = field.IndirectFieldType.Elem()
|
||||||
}
|
}
|
||||||
|
@ -57,6 +57,11 @@ type Schema struct {
|
|||||||
initialized chan struct{}
|
initialized chan struct{}
|
||||||
namer Namer
|
namer Namer
|
||||||
cacheStore *sync.Map
|
cacheStore *sync.Map
|
||||||
|
// functional for apaas engine add by fangming
|
||||||
|
// ==========apaas engine field begin==========
|
||||||
|
ApaasLookupFields []*Field
|
||||||
|
ApaasFormulaFields []*Field
|
||||||
|
// ==========apaas engine field end==========
|
||||||
}
|
}
|
||||||
|
|
||||||
func (schema Schema) String() string {
|
func (schema Schema) String() string {
|
||||||
|
@ -47,6 +47,11 @@ type Statement struct {
|
|||||||
attrs []interface{}
|
attrs []interface{}
|
||||||
assigns []interface{}
|
assigns []interface{}
|
||||||
scopes []func(*DB) *DB
|
scopes []func(*DB) *DB
|
||||||
|
|
||||||
|
// ==========apaas engine field begin==========
|
||||||
|
// apaas mode for gormDB
|
||||||
|
ApaasMode ApaasModeType
|
||||||
|
// ==========apaas engine field end==========
|
||||||
}
|
}
|
||||||
|
|
||||||
type join struct {
|
type join struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user