diff --git a/ExpressionEngine.go b/ExpressionEngine.go index aeda9ff..d7db966 100644 --- a/ExpressionEngine.go +++ b/ExpressionEngine.go @@ -8,10 +8,13 @@ type ExpressionEngine interface { //编译一个表达式 //参数:lexerArg 表达式内容 //返回:interface{} 编译结果,error 错误 - Lexer(expression string) (interface{}, error) + Lexer(lexerArg string) (interface{}, error) //执行一个表达式 //参数:lexerResult=编译结果,arg=参数 //返回:执行结果,错误 Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error) + + //取Lexer缓存,可不提供。需要提供单例 + LexerCache() ExpressionEngineLexerCache } diff --git a/ExpressionEngineExpr.go b/ExpressionEngineExpr.go index b4c4278..fed8971 100644 --- a/ExpressionEngineExpr.go +++ b/ExpressionEngineExpr.go @@ -6,30 +6,31 @@ import ( ) type ExpressionEngineExpr struct { + mapCache *ExpressionEngineLexerMapCache } - //引擎名称 -func (this *ExpressionEngineExpr)Name() string{ +func (this *ExpressionEngineExpr) Name() string { return "ExpressionEngineExpr" } + //编译一个表达式 //参数:lexerArg 表达式内容 //返回:interface{} 编译结果,error 错误 -func (this *ExpressionEngineExpr)Lexer(expression string) (interface{}, error){ +func (this *ExpressionEngineExpr) Lexer(expression string) (interface{}, error) { expression = this.repleaceExpression(expression) - return expr.Parse(expression) + var result, err = expr.Parse(expression) + return result, err } //执行一个表达式 //参数:lexerResult=编译结果,arg=参数 //返回:执行结果,错误 -func (this *ExpressionEngineExpr)Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error){ +func (this *ExpressionEngineExpr) Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error) { output, err := expr.Run(lexerResult.(expr.Node), arg) - return output,err + return output, err } - //替换表达式中的值 and,or,参数 替换为实际值 func (this *ExpressionEngineExpr) repleaceExpression(expression string) string { if expression == "" { @@ -66,3 +67,12 @@ func (this *ExpressionEngineExpr) split(str string) (stringItems []string) { } return newStrings } + +//Lexer缓存,可不提供。 +func (this *ExpressionEngineExpr) LexerCache() ExpressionEngineLexerCache { + if this.mapCache==nil{ + var cache= ExpressionEngineLexerMapCache{}.New() + this.mapCache=&cache + } + return this.mapCache +} \ No newline at end of file diff --git a/ExpressionEngineGovaluate.go b/ExpressionEngineGovaluate.go index 0416cf1..e99205a 100644 --- a/ExpressionEngineGovaluate.go +++ b/ExpressionEngineGovaluate.go @@ -63,3 +63,8 @@ func (this *ExpressionEngineGovaluate) split(str string) (stringItems []string) } return newStrings } + +//Lexer缓存,可不提供。 +func (this *ExpressionEngineGovaluate) LexerCache() ExpressionEngineLexerCache{ + return nil +} \ No newline at end of file diff --git a/ExpressionEngineJee.go b/ExpressionEngineJee.go index 78ee768..f809a8e 100644 --- a/ExpressionEngineJee.go +++ b/ExpressionEngineJee.go @@ -116,3 +116,8 @@ func (this *ExpressionEngineJee) LexerAndOrSupport(lexerArg string) string { } return lexerArg } + +//Lexer缓存,可不提供。 +func (this *ExpressionEngineJee) LexerCache() ExpressionEngineLexerCache{ + return nil +} \ No newline at end of file diff --git a/ExpressionEngineLexerCache.go b/ExpressionEngineLexerCache.go new file mode 100644 index 0000000..2487916 --- /dev/null +++ b/ExpressionEngineLexerCache.go @@ -0,0 +1,7 @@ +package GoMybatis + +//Lexer 结果缓存 +type ExpressionEngineLexerCache interface { + Set(expression string,lexer interface{}) error + Get(expression string) (interface{}, error) +} diff --git a/ExpressionEngineLexerCacheable.go b/ExpressionEngineLexerCacheable.go new file mode 100644 index 0000000..d34d09e --- /dev/null +++ b/ExpressionEngineLexerCacheable.go @@ -0,0 +1,6 @@ +package GoMybatis + +type ExpressionEngineLexerCacheable interface { + SetUseLexerCache(use bool) error + LexerCacheable() bool +} diff --git a/ExpressionEngineLexerMapCache.go b/ExpressionEngineLexerMapCache.go new file mode 100644 index 0000000..2df3b73 --- /dev/null +++ b/ExpressionEngineLexerMapCache.go @@ -0,0 +1,27 @@ +package GoMybatis + +import ( + "github.com/zhuxiujia/GoMybatis/utils" +) + +type ExpressionEngineLexerMapCache struct { + mapCache map[string]interface{} +} + +func (this ExpressionEngineLexerMapCache) New() ExpressionEngineLexerMapCache { + if this.mapCache == nil { + this.mapCache = make(map[string]interface{}) + } + return this +} + +func (this *ExpressionEngineLexerMapCache) Set(expression string, lexer interface{}) error { + if expression == "" { + return utils.NewError("ExpressionEngineLexerMapCache", "set lexerMap chache key can not be ''!") + } + this.mapCache[expression] = lexer + return nil +} +func (this *ExpressionEngineLexerMapCache) Get(expression string) (interface{}, error) { + return this.mapCache[expression], nil +} diff --git a/ExpressionEngineLexerMapCache_test.go b/ExpressionEngineLexerMapCache_test.go new file mode 100644 index 0000000..2b7c535 --- /dev/null +++ b/ExpressionEngineLexerMapCache_test.go @@ -0,0 +1,27 @@ +package GoMybatis + +import ( + "fmt" + "testing" +) + +func TestExpressionEngineLexerMapCache_Get(t *testing.T) { + engine := ExpressionEngineLexerMapCache{}.New() + err := engine.Set("foo", 1) + if err != nil { + t.Fatal(err) + } +} + +func TestExpressionEngineLexerMapCache_Set(t *testing.T) { + engine := ExpressionEngineLexerMapCache{}.New() + err := engine.Set("foo", 1) + if err != nil { + t.Fatal(err) + } + result, err := engine.Get("foo") + if err != nil { + t.Fatal(err) + } + fmt.Println(result) +} diff --git a/ExpressionEngineProxy.go b/ExpressionEngineProxy.go new file mode 100644 index 0000000..38ce894 --- /dev/null +++ b/ExpressionEngineProxy.go @@ -0,0 +1,74 @@ +package GoMybatis + +import "github.com/zhuxiujia/GoMybatis/utils" + +type ExpressionEngineProxy struct { + expressionEngine ExpressionEngine + lexerCacheable bool //是否使用lexer缓存,默认false +} + +//engine :表达式引擎,useLexerCache:是否缓存Lexer表达式编译结果 +func (ExpressionEngineProxy) New(engine ExpressionEngine, useLexerCache bool) ExpressionEngineProxy { + return ExpressionEngineProxy{ + expressionEngine: engine, + lexerCacheable: useLexerCache, + } +} + +//引擎名称 +func (this ExpressionEngineProxy) Name() string { + if this.expressionEngine == nil { + return "" + } + return this.expressionEngine.Name() +} + +//编译一个表达式 +//参数:lexerArg 表达式内容 +//返回:interface{} 编译结果,error 错误 +func (this *ExpressionEngineProxy) Lexer(expression string) (interface{}, error) { + if this.expressionEngine == nil { + return nil, utils.NewError("ExpressionEngineProxy", "ExpressionEngineProxy not init for ExpressionEngineProxy{}.New(...)") + } + if this.expressionEngine.LexerCache() != nil && this.lexerCacheable { + //如果 提供缓存,则使用缓存 + cacheResult, cacheErr := this.expressionEngine.LexerCache().Get(expression) + if cacheErr != nil { + return nil, cacheErr + } + if cacheResult != nil { + return cacheResult, nil + } + } + var result, err = this.expressionEngine.Lexer(expression) + if this.expressionEngine.LexerCache() != nil && this.lexerCacheable { + //如果 提供缓存,则使用缓存 + this.expressionEngine.LexerCache().Set(expression, result) + } + return result, err +} + +//执行一个表达式 +//参数:lexerResult=编译结果,arg=参数 +//返回:执行结果,错误 +func (this *ExpressionEngineProxy) Eval(lexerResult interface{}, arg interface{}, operation int) (interface{}, error) { + if this.expressionEngine == nil { + return nil, utils.NewError("ExpressionEngineProxy", "ExpressionEngineProxy not init for ExpressionEngineProxy{}.New(...)") + } + return this.expressionEngine.Eval(lexerResult, arg, operation) +} + +func (this *ExpressionEngineProxy) LexerCache() ExpressionEngineLexerCache { + if this.expressionEngine == nil { + return nil + } + return this.expressionEngine.LexerCache() +} + +func (this *ExpressionEngineProxy) SetUseLexerCache(isUseCache bool) error { + this.lexerCacheable = isUseCache + return nil +} +func (this *ExpressionEngineProxy) LexerCacheable() bool { + return this.lexerCacheable +} diff --git a/ExpressionEngineProxy_test.go b/ExpressionEngineProxy_test.go new file mode 100644 index 0000000..89585ab --- /dev/null +++ b/ExpressionEngineProxy_test.go @@ -0,0 +1,62 @@ +package GoMybatis + +import ( + "fmt" + "github.com/zhuxiujia/GoMybatis/example" + "testing" +) + +func TestExpressionEngineProxy_Eval(t *testing.T) { + var engine=ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false) + var lexer,err=engine.Lexer("foo") + if err!= nil{ + t.Fatal(err) + } + var arg=make(map[string]interface{}) + arg["foo"]="Bar" + result,err:=engine.Eval(lexer,arg,0) + if err!= nil{ + t.Fatal(err) + } + if result.(string) != "Bar"{ + t.Fatal("result != 'Bar'") + } + fmt.Println(result) +} + +func TestExpressionEngineProxy_Lexer(t *testing.T) { + var engine=ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false) + var _,err=engine.Lexer("foo") + if err!= nil{ + t.Fatal(err) + } +} + +func BenchmarkExpressionEngineProxy_Eval(b *testing.B) { + b.StopTimer() + var activity = example.Activity{ + Id: "1", + DeleteFlag: 1, + } + + var engine = ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},false) + var evaluateParameters = make(map[string]interface{}) + + evaluateParameters["activity"] = &activity + + b.StartTimer() + for i := 0; i < b.N; i++ { + var expression = "activity.DeleteFlag == 1 and activity.DeleteFlag != 0 " + evalExpression, err := engine.Lexer(expression) + if err != nil { + b.Fatal(err) + } + result, err := engine.Eval(evalExpression, evaluateParameters, 0) + if err != nil { + b.Fatal(err) + } + if result.(bool) { + + } + } +} \ No newline at end of file diff --git a/GoMybatis.go b/GoMybatis.go index 892c288..a555d38 100644 --- a/GoMybatis.go +++ b/GoMybatis.go @@ -19,7 +19,7 @@ func WriteMapperByEngine(value reflect.Value, xml []byte, sessionEngine *Session if DefaultSessionFactory == nil { DefaultSessionFactory = &factory } - WriteMapper(value, xml, DefaultSessionFactory, GoMybatisSqlResultDecoder{}, GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{}, &ExpressionEngineExpr{}), enableLog) + WriteMapper(value, xml, DefaultSessionFactory, GoMybatisSqlResultDecoder{}, GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{}, ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},true)), enableLog) } //根据sessionEngine写入到mapperPtr @@ -100,7 +100,7 @@ func beanCheck(value reflect.Value,builder SqlBuilder) { var customLen = 0 for argIndex := 0; argIndex < fieldItem.Type.NumIn(); argIndex++ { var inType = fieldItem.Type.In(argIndex) - if builder.ExpressionEngine().Name()=="ExpressionEngineGovaluate" && inType.Kind() == reflect.Ptr && inType.String() != GoMybatis_Session_Ptr { + if builder.ExpressionEngineProxy().Name()=="ExpressionEngineGovaluate" && inType.Kind() == reflect.Ptr && inType.String() != GoMybatis_Session_Ptr { panic(`[GoMybats] ` + fieldItem.Name + `() arg = ` + inType.String() + ` can not be a ptr ! must delete '*'!`) } if isCustomStruct(inType) { diff --git a/SqlBuilder.go b/SqlBuilder.go index e64b438..c404226 100644 --- a/SqlBuilder.go +++ b/SqlBuilder.go @@ -11,7 +11,7 @@ import ( type SqlBuilder interface { BuildSql(paramMap map[string]SqlArg, mapperXml *MapperXml, enableLog bool) (string, error) - ExpressionEngine() ExpressionEngine + ExpressionEngineProxy() ExpressionEngineProxy SqlArgTypeConvert() SqlArgTypeConvert ExpressionTypeConvert() ExpressionTypeConvert } @@ -19,11 +19,11 @@ type SqlBuilder interface { type GoMybatisSqlBuilder struct { expressionTypeConvert ExpressionTypeConvert sqlArgTypeConvert SqlArgTypeConvert - expressionEngine ExpressionEngine + expressionEngineProxy ExpressionEngineProxy } -func (this GoMybatisSqlBuilder) ExpressionEngine() ExpressionEngine { - return this.expressionEngine +func (this GoMybatisSqlBuilder) ExpressionEngineProxy() ExpressionEngineProxy { + return this.expressionEngineProxy } func (this GoMybatisSqlBuilder) SqlArgTypeConvert() SqlArgTypeConvert { return this.sqlArgTypeConvert @@ -32,10 +32,10 @@ func (this GoMybatisSqlBuilder) ExpressionTypeConvert() ExpressionTypeConvert { return this.expressionTypeConvert } -func (this GoMybatisSqlBuilder) New(ExpressionTypeConvert ExpressionTypeConvert, SqlArgTypeConvert SqlArgTypeConvert, expressionEngine ExpressionEngine) GoMybatisSqlBuilder { +func (this GoMybatisSqlBuilder) New(ExpressionTypeConvert ExpressionTypeConvert, SqlArgTypeConvert SqlArgTypeConvert, expressionEngine ExpressionEngineProxy) GoMybatisSqlBuilder { this.expressionTypeConvert = ExpressionTypeConvert this.sqlArgTypeConvert = SqlArgTypeConvert - this.expressionEngine = expressionEngine + this.expressionEngineProxy = expressionEngine return this } @@ -75,7 +75,7 @@ func (this *GoMybatisSqlBuilder) createFromElement(itemTree []ElementItem, sql * break case Element_String: //string element - var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, this.expressionEngine) + var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, &this.expressionEngineProxy) if err != nil { return err } @@ -90,7 +90,7 @@ func (this *GoMybatisSqlBuilder) createFromElement(itemTree []ElementItem, sql * } if result { //test > true,write sql string - var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, this.expressionEngine) + var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, &this.expressionEngineProxy) if err != nil { return err } @@ -239,7 +239,7 @@ func (this *GoMybatisSqlBuilder) createFromElement(itemTree []ElementItem, sql * } if result { //test > true,write sql string - var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, this.expressionEngine) + var replaceSql, err = replaceArg(v.DataString, defaultArgMap, this.sqlArgTypeConvert, &this.expressionEngineProxy) if err != nil { return err } @@ -293,14 +293,14 @@ func (this *GoMybatisSqlBuilder) createFromElement(itemTree []ElementItem, sql * func (this *GoMybatisSqlBuilder) doIfElement(expression string, param map[string]SqlArg, evaluateParameters map[string]interface{}) (bool, error) { //this.repleaceExpression(expression, param) - ifElementevalExpression, err := this.expressionEngine.Lexer(expression) + ifElementevalExpression, err := this.expressionEngineProxy.Lexer(expression) if err != nil { return false, err } if evaluateParameters == nil { evaluateParameters = this.expressParamterMap(param, this.expressionTypeConvert) } - result, err := this.expressionEngine.Eval(ifElementevalExpression, evaluateParameters, 0) + result, err := this.expressionEngineProxy.Eval(ifElementevalExpression, evaluateParameters, 0) if err != nil { err = utils.NewError("SqlBuilder", "[GoMybatis] fail,`, err.Error()) return false, err @@ -321,12 +321,12 @@ func (this *GoMybatisSqlBuilder) bindBindElementArg(args map[string]SqlArg, item } return args } - bindEvalExpression, err := this.expressionEngine.Lexer(value) + bindEvalExpression, err := this.expressionEngineProxy.Lexer(value) if err != nil { return args } var evaluateParameters = this.expressParamterMap(args, this.expressionTypeConvert) - result, err := this.expressionEngine.Eval(bindEvalExpression, evaluateParameters, 0) + result, err := this.expressionEngineProxy.Eval(bindEvalExpression, evaluateParameters, 0) if err != nil { return args } diff --git a/SqlBuilder_test.go b/SqlBuilder_test.go index 3c5f872..0ef2da3 100644 --- a/SqlBuilder_test.go +++ b/SqlBuilder_test.go @@ -35,7 +35,7 @@ func Benchmark_SqlBuilder(b *testing.B) { ` var mapperTree = LoadMapperXml([]byte(mapper)) - var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},&ExpressionEngineGovaluate{}) + var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},true)) var paramMap = make(map[string]SqlArg) paramMap["name"] = SqlArg{ Value: "", @@ -106,7 +106,7 @@ func Test_SqlBuilder_Tps(t *testing.T) { ` var mapperTree = LoadMapperXml([]byte(mapper)) - var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},&ExpressionEngineExpr{}) + var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},true)) var paramMap = make(map[string]SqlArg) paramMap["name"] = SqlArg{ Value: "", @@ -212,7 +212,7 @@ func TestGoMybatisSqlBuilder_BuildSql(t *testing.T) { ` var mapperTree = LoadMapperXml([]byte(mapper)) - var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},&ExpressionEngineGovaluate{}) + var builder = GoMybatisSqlBuilder{}.New(GoMybatisExpressionTypeConvert{}, GoMybatisSqlArgTypeConvert{},ExpressionEngineProxy{}.New(&ExpressionEngineExpr{},true)) var paramMap = make(map[string]SqlArg) paramMap["name"] = SqlArg{ Value: "name",