Слияние кода завершено, страница обновится автоматически
/*
* Copyright 2018. bigpigeon. All rights reserved.
* Use of this source code is governed by a MIT style
* license that can be found in the LICENSE file.
*/
package toyorm
import (
"database/sql"
"fmt"
"os"
"reflect"
)
type DBValSelector interface {
Select(int) int
}
type DBPrimarySelector func(n int, key ...interface{}) int
func dbPrimaryKeySelector(n int, keys ...interface{}) int {
sum := 0
for _, k := range keys {
switch val := k.(type) {
case int:
sum += val
case int32:
sum += int(val)
case uint:
sum += int(val)
case uint32:
sum += int(val)
case string:
for _, c := range val {
sum += int(c)
}
default:
panic("primary key type not match")
}
}
return sum % n
}
type ToyCollection struct {
dbs []*sql.DB
DefaultHandlerChain map[string]CollectionHandlersChain
DefaultModelHandlerChain map[reflect.Type]map[string]CollectionHandlersChain
ToyKernel
}
func OpenCollection(driverName string, dataSourceName ...string) (*ToyCollection, error) {
t := ToyCollection{
ToyKernel: ToyKernel{
Logger: os.Stdout,
},
DefaultHandlerChain: map[string]CollectionHandlersChain{
"CreateTable": {CollectionHandlerSimplePreload("CreateTable"), CollectionHandlerAssignToAllDb, CollectionHandlerCreateTable},
"CreateTableIfNotExist": {CollectionHandlerSimplePreload("CreateTableIfNotExist"), CollectionHandlerAssignToAllDb, CollectionHandlerExistTableAbort, CollectionHandlerCreateTable},
"DropTableIfExist": {CollectionHandlerDropTablePreload("DropTableIfExist"), CollectionHandlerAssignToAllDb, CollectionHandlerNotExistTableAbort, CollectionHandlerDropTable},
"DropTable": {CollectionHandlerDropTablePreload("DropTable"), CollectionHandlerAssignToAllDb, CollectionHandlerDropTable},
"Insert": {CollectionHandlerPreloadContainerCheck, CollectionHandlerPreloadInsertOrSave("Insert"), HandlerCollectionCasVersionPushOne, CollectionHandlerInsertTimeGenerate, CollectionHandlerInsertAssignDbIndex, CollectionHandlerInsert},
"Save": {CollectionHandlerPreloadContainerCheck, CollectionHandlerPreloadInsertOrSave("Save"), HandlerCollectionCasVersionPushOne, CollectionHandlerInsertAssignDbIndex, CollectionHandlerSaveTimeGenerate, CollectionHandlerSave},
"USave": {CollectionHandlerPreloadContainerCheck, CollectionHandlerPreloadInsertOrSave("USave"), HandlerCollectionCasVersionPushOne, CollectionHandlerInsertAssignDbIndex, CollectionHandlerSaveTimeGenerate, CollectionHandlerUSave},
"Find": {CollectionHandlerPreloadContainerCheck, CollectionHandlerSoftDeleteCheck, CollectionHandlerPreloadFind, CollectionHandlerAssignToAllDb, CollectionHandlerFind},
"FindOne": {CollectionHandlerPreloadContainerCheck, CollectionHandlerSoftDeleteCheck, CollectionHandlerPreloadFind, CollectionHandlerFindOneAssignDbIndex, CollectionHandlerFindOne},
"Update": {CollectionHandlerSoftDeleteCheck, CollectionHandlerUpdateTimeGenerate, CollectionHandlerAssignToAllDb, CollectionHandlerUpdate},
"HardDelete": {HandlerCollectionPreloadDelete, CollectionHandlerAssignToAllDb, HandlerCollectionHardDelete},
"SoftDelete": {HandlerCollectionPreloadDelete, CollectionHandlerAssignToAllDb, HandlerCollectionSoftDelete},
"HardDeleteWithPrimaryKey": {HandlerCollectionPreloadDelete, HandlerCollectionSearchWithPrimaryKey, CollectionHandlerAssignToAllDb, HandlerCollectionHardDelete},
"SoftDeleteWithPrimaryKey": {HandlerCollectionPreloadDelete, HandlerCollectionSearchWithPrimaryKey, CollectionHandlerAssignToAllDb, HandlerCollectionSoftDelete},
},
DefaultModelHandlerChain: map[reflect.Type]map[string]CollectionHandlersChain{},
}
switch driverName {
case "mysql":
t.Dialect = MySqlDialect{}
case "sqlite3":
t.Dialect = Sqlite3Dialect{}
case "postgres":
t.Dialect = PostgreSqlDialect{}
default:
panic(ErrNotMatchDialect)
}
for _, source := range dataSourceName {
db, err := sql.Open(driverName, source)
if err != nil {
t.Close()
return nil, err
}
t.dbs = append(t.dbs, db)
}
return &t, nil
}
func (t *ToyCollection) Model(v interface{}) *CollectionBrick {
var model *Model
vVal := LoopDivePtr(reflect.ValueOf(v))
// lazy init model
model = t.GetModel(vVal)
brick := NewCollectionBrick(t, model)
if t.debug {
brick = brick.Debug()
}
return brick
}
func (t *ToyCollection) ModelHandlers(option string, model *Model) CollectionHandlersChain {
handlers := make(CollectionHandlersChain, 0, len(t.DefaultHandlerChain[option])+len(t.DefaultModelHandlerChain[model.ReflectType][option]))
handlers = append(handlers, t.DefaultModelHandlerChain[model.ReflectType][option]...)
handlers = append(handlers, t.DefaultHandlerChain[option]...)
return handlers
}
func (t *ToyCollection) SetModelHandlers(option string, model *Model, handlers CollectionHandlersChain) {
if t.DefaultModelHandlerChain[model.ReflectType] == nil {
t.DefaultModelHandlerChain[model.ReflectType] = map[string]CollectionHandlersChain{}
}
t.DefaultModelHandlerChain[model.ReflectType][option] = handlers
}
func (t *ToyCollection) MiddleModel(v, sv interface{}) *CollectionBrick {
vVal := LoopDivePtr(reflect.ValueOf(v))
svVal := LoopDivePtr(reflect.ValueOf(sv))
model, subModel := t.GetModel(vVal), t.GetModel(svVal)
middleModel := NewMiddleModel(model, subModel)
return NewCollectionBrick(t, middleModel)
}
func (t *ToyCollection) Close() error {
if t == nil {
return nil
}
errs := ErrCollectionQueryRow{}
for i, db := range t.dbs {
err := db.Close()
if err != nil {
errs[i] = err
}
}
return errs
}
func (t *ToyCollection) BelongToPreload(model *Model, field Field) *BelongToPreload {
val := LoopDivePtr(field.FieldValue())
fmt.Printf("%#v\n", field.FieldValue())
if val.Kind() != reflect.Struct {
return nil
}
if subModel := t.GetModel(val); subModel != nil {
if relationField := model.GetFieldWithName(GetBelongsIDFieldName(subModel, field)); relationField != nil {
return t.BelongToBind(model, subModel, field, relationField)
}
}
return nil
}
func (t *ToyCollection) OneToOnePreload(model *Model, field Field) *OneToOnePreload {
val := LoopDivePtr(field.FieldValue())
if val.Kind() != reflect.Struct {
return nil
}
if subModel := t.GetModel(val); subModel != nil {
if relationField := subModel.GetFieldWithName(GetRelationFieldName(model)); relationField != nil {
return t.OneToOneBind(model, subModel, field, relationField)
}
}
return nil
}
func (t *ToyCollection) OneToManyPreload(model *Model, field Field) *OneToManyPreload {
val := LoopDivePtr(field.FieldValue())
if val.Kind() == reflect.Slice {
elemVal := LoopDiveSliceAndPtr(val)
if subModel := t.GetModel(elemVal); subModel != nil {
if relationField := subModel.GetFieldWithName(GetRelationFieldName(model)); relationField != nil {
return t.OneToManyBind(model, subModel, field, relationField)
}
}
}
return nil
}
func (t *ToyCollection) ManyToManyPreload(model *Model, field Field, isRight bool) *ManyToManyPreload {
return t.manyToManyPreloadWithTag(model, field, isRight, `toyorm:"primary key"`)
}
func (t *ToyCollection) manyToManyPreloadWithTag(model *Model, field Field, isRight bool, tag reflect.StructTag) *ManyToManyPreload {
val := LoopDivePtr(field.FieldValue())
if val.Kind() == reflect.Slice {
elemVal := LoopDiveSliceAndPtr(val)
if subModel := t.GetModel(elemVal); subModel != nil {
middleModel := newMiddleModel(model, subModel, tag)
relationField := GetMiddleField(model, middleModel, isRight)
subRelationField := GetMiddleField(subModel, middleModel, !isRight)
return t.ManyToManyPreloadBind(model, subModel, middleModel, field, relationField, subRelationField)
}
}
return nil
}
func (t *ToyCollection) BelongToBind(model, subModel *Model, containerField, relationField Field) *BelongToPreload {
if LoopTypeIndirect(relationField.StructField().Type) != subModel.GetOnePrimary().StructField().Type {
panic("relation key must have same type with sub model primary key")
}
return &BelongToPreload{
Model: model,
SubModel: subModel,
RelationField: relationField,
ContainerField: containerField,
}
}
func (t *ToyCollection) OneToOneBind(model, subModel *Model, containerField, relationField Field) *OneToOnePreload {
if LoopTypeIndirect(relationField.StructField().Type) != model.GetOnePrimary().StructField().Type {
panic("relation key must have same type with model primary key")
}
return &OneToOnePreload{
Model: model,
SubModel: subModel,
RelationField: relationField,
ContainerField: containerField,
}
}
func (t *ToyCollection) OneToManyBind(model, subModel *Model, containerField, relationField Field) *OneToManyPreload {
if LoopTypeIndirect(relationField.StructField().Type) != model.GetOnePrimary().StructField().Type {
panic("relation key must have same type with model primary key")
}
return &OneToManyPreload{
Model: model,
SubModel: subModel,
RelationField: relationField,
ContainerField: containerField,
}
}
func (t *ToyCollection) ManyToManyPreloadBind(model, subModel, middleModel *Model, containerField, relationField, subRelationField Field) *ManyToManyPreload {
if LoopTypeIndirect(relationField.StructField().Type) != model.GetOnePrimary().StructField().Type {
panic("relation key must have same type with model primary key")
}
if LoopTypeIndirect(subRelationField.StructField().Type) != subModel.GetOnePrimary().StructField().Type {
panic("sub relation key must have same type with sub model primary key")
}
return &ManyToManyPreload{
Model: model,
SubModel: subModel,
MiddleModel: middleModel,
ContainerField: containerField,
RelationField: relationField,
SubRelationField: subRelationField,
}
}
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )