Skip to content
This repository was archived by the owner on Sep 7, 2021. It is now read-only.
This repository is currently being migrated. It's locked while the migration is in progress.

Commit 7a9249d

Browse files
authored
Get adds context cache feature (#1102)
* context * add context cache feature * remove global context cache * remove global context cache * reset statment * fix bug * remove unused params * refactor ContextCache * refactor ContextCache * update README * update README * disable global cache on context cache test
1 parent fa23a97 commit 7a9249d

File tree

7 files changed

+232
-1
lines changed

7 files changed

+232
-1
lines changed

README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ Xorm is a simple and powerful ORM for Go.
3434

3535
* Postgres schema support
3636

37+
* Context Cache support
38+
3739
## Drivers Support
3840

3941
Drivers for Go's sql package which currently support database/sql includes:
@@ -358,6 +360,56 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
358360
return session.Commit()
359361
```
360362

363+
* Or you can use `Transaction` to replace above codes.
364+
365+
```Go
366+
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
367+
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
368+
if _, err := session.Insert(&user1); err != nil {
369+
return nil, err
370+
}
371+
372+
user2 := Userinfo{Username: "yyy"}
373+
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
374+
return nil, err
375+
}
376+
377+
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
378+
return nil, err
379+
}
380+
return nil, nil
381+
})
382+
```
383+
384+
* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
385+
386+
```Go
387+
sess := engine.NewSession()
388+
defer sess.Close()
389+
390+
var context = xorm.NewMemoryContextCache()
391+
392+
var c2 ContextGetStruct
393+
has, err := sess.ID(1).ContextCache(context).Get(&c2)
394+
assert.NoError(t, err)
395+
assert.True(t, has)
396+
assert.EqualValues(t, 1, c2.Id)
397+
assert.EqualValues(t, "1", c2.Name)
398+
sql, args := sess.LastSQL()
399+
assert.True(t, len(sql) > 0)
400+
assert.True(t, len(args) > 0)
401+
402+
var c3 ContextGetStruct
403+
has, err = sess.ID(1).ContextCache(context).Get(&c3)
404+
assert.NoError(t, err)
405+
assert.True(t, has)
406+
assert.EqualValues(t, 1, c3.Id)
407+
assert.EqualValues(t, "1", c3.Name)
408+
sql, args = sess.LastSQL()
409+
assert.True(t, len(sql) == 0)
410+
assert.True(t, len(args) == 0)
411+
```
412+
361413
## Contributing
362414

363415
If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss.

README_CN.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作
3232

3333
* 内置SQL Builder支持
3434

35+
* 上下文缓存支持
36+
3537
## 驱动支持
3638

3739
目前支持的Go数据库驱动和对应的数据库如下:
@@ -360,6 +362,56 @@ if _, err := session.Exec("delete from userinfo where username = ?", user2.Usern
360362
return session.Commit()
361363
```
362364

365+
* 事物的简写方法
366+
367+
```Go
368+
res, err := engine.Transaction(func(sess *xorm.Session) (interface{}, error) {
369+
user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()}
370+
if _, err := session.Insert(&user1); err != nil {
371+
return nil, err
372+
}
373+
374+
user2 := Userinfo{Username: "yyy"}
375+
if _, err := session.Where("id = ?", 2).Update(&user2); err != nil {
376+
return nil, err
377+
}
378+
379+
if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil {
380+
return nil, err
381+
}
382+
return nil, nil
383+
})
384+
```
385+
386+
* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session.
387+
388+
```Go
389+
sess := engine.NewSession()
390+
defer sess.Close()
391+
392+
var context = xorm.NewMemoryContextCache()
393+
394+
var c2 ContextGetStruct
395+
has, err := sess.ID(1).ContextCache(context).Get(&c2)
396+
assert.NoError(t, err)
397+
assert.True(t, has)
398+
assert.EqualValues(t, 1, c2.Id)
399+
assert.EqualValues(t, "1", c2.Name)
400+
sql, args := sess.LastSQL()
401+
assert.True(t, len(sql) > 0)
402+
assert.True(t, len(args) > 0)
403+
404+
var c3 ContextGetStruct
405+
has, err = sess.ID(1).ContextCache(context).Get(&c3)
406+
assert.NoError(t, err)
407+
assert.True(t, has)
408+
assert.EqualValues(t, 1, c3.Id)
409+
assert.EqualValues(t, "1", c3.Name)
410+
sql, args = sess.LastSQL()
411+
assert.True(t, len(sql) == 0)
412+
assert.True(t, len(args) == 0)
413+
```
414+
363415
## 贡献
364416

365417
如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。

context_cache.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright 2018 The Xorm Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xorm
6+
7+
// ContextCache is the interface that operates the cache data.
8+
type ContextCache interface {
9+
// Put puts value into cache with key.
10+
Put(key string, val interface{})
11+
// Get gets cached value by given key.
12+
Get(key string) interface{}
13+
}
14+
15+
type memoryContextCache map[string]interface{}
16+
17+
// NewMemoryContextCache return memoryContextCache
18+
func NewMemoryContextCache() memoryContextCache {
19+
return make(map[string]interface{})
20+
}
21+
22+
// Put puts value into cache with key.
23+
func (m memoryContextCache) Put(key string, val interface{}) {
24+
m[key] = val
25+
}
26+
27+
// Get gets cached value by given key.
28+
func (m memoryContextCache) Get(key string) interface{} {
29+
return m[key]
30+
}

session.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ func (session *Session) Close() {
102102
}
103103
}
104104

105+
// ContextCache enable context cache or not
106+
func (session *Session) ContextCache(context ContextCache) *Session {
107+
session.statement.context = context
108+
return session
109+
}
110+
105111
// IsClosed returns if session is closed
106112
func (session *Session) IsClosed() bool {
107113
return session.db == nil

session_get.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package xorm
77
import (
88
"database/sql"
99
"errors"
10+
"fmt"
1011
"reflect"
1112
"strconv"
1213

@@ -66,7 +67,28 @@ func (session *Session) get(bean interface{}) (bool, error) {
6667
}
6768
}
6869

69-
return session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
70+
context := session.statement.context
71+
if context != nil {
72+
res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args))
73+
if res != nil {
74+
structValue := reflect.Indirect(reflect.ValueOf(bean))
75+
structValue.Set(reflect.Indirect(reflect.ValueOf(res)))
76+
session.lastSQL = ""
77+
session.lastSQLArgs = nil
78+
return true, nil
79+
}
80+
}
81+
82+
has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...)
83+
if err != nil || !has {
84+
return has, err
85+
}
86+
87+
if context != nil {
88+
context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean)
89+
}
90+
91+
return true, nil
7092
}
7193

7294
func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) {

session_get_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,3 +319,70 @@ func TestGetStructId(t *testing.T) {
319319
assert.True(t, has)
320320
assert.EqualValues(t, 2, maxid.Id)
321321
}
322+
323+
func TestContextGet(t *testing.T) {
324+
type ContextGetStruct struct {
325+
Id int64
326+
Name string
327+
}
328+
329+
assert.NoError(t, prepareEngine())
330+
assertSync(t, new(ContextGetStruct))
331+
332+
_, err := testEngine.Insert(&ContextGetStruct{Name: "1"})
333+
assert.NoError(t, err)
334+
335+
sess := testEngine.NewSession()
336+
defer sess.Close()
337+
338+
context := NewMemoryContextCache()
339+
340+
var c2 ContextGetStruct
341+
has, err := sess.ID(1).NoCache().ContextCache(context).Get(&c2)
342+
assert.NoError(t, err)
343+
assert.True(t, has)
344+
assert.EqualValues(t, 1, c2.Id)
345+
assert.EqualValues(t, "1", c2.Name)
346+
sql, args := sess.LastSQL()
347+
assert.True(t, len(sql) > 0)
348+
assert.True(t, len(args) > 0)
349+
350+
var c3 ContextGetStruct
351+
has, err = sess.ID(1).NoCache().ContextCache(context).Get(&c3)
352+
assert.NoError(t, err)
353+
assert.True(t, has)
354+
assert.EqualValues(t, 1, c3.Id)
355+
assert.EqualValues(t, "1", c3.Name)
356+
sql, args = sess.LastSQL()
357+
assert.True(t, len(sql) == 0)
358+
assert.True(t, len(args) == 0)
359+
}
360+
361+
func TestContextGet2(t *testing.T) {
362+
type ContextGetStruct2 struct {
363+
Id int64
364+
Name string
365+
}
366+
367+
assert.NoError(t, prepareEngine())
368+
assertSync(t, new(ContextGetStruct2))
369+
370+
_, err := testEngine.Insert(&ContextGetStruct2{Name: "1"})
371+
assert.NoError(t, err)
372+
373+
context := NewMemoryContextCache()
374+
375+
var c2 ContextGetStruct2
376+
has, err := testEngine.ID(1).NoCache().ContextCache(context).Get(&c2)
377+
assert.NoError(t, err)
378+
assert.True(t, has)
379+
assert.EqualValues(t, 1, c2.Id)
380+
assert.EqualValues(t, "1", c2.Name)
381+
382+
var c3 ContextGetStruct2
383+
has, err = testEngine.ID(1).NoCache().ContextCache(context).Get(&c3)
384+
assert.NoError(t, err)
385+
assert.True(t, has)
386+
assert.EqualValues(t, 1, c3.Id)
387+
assert.EqualValues(t, "1", c3.Name)
388+
}

statement.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type Statement struct {
5959
exprColumns map[string]exprParam
6060
cond builder.Cond
6161
bufferSize int
62+
context ContextCache
6263
}
6364

6465
// Init reset all the statement's fields
@@ -99,6 +100,7 @@ func (statement *Statement) Init() {
99100
statement.exprColumns = make(map[string]exprParam)
100101
statement.cond = builder.NewCond()
101102
statement.bufferSize = 0
103+
statement.context = nil
102104
}
103105

104106
// NoAutoCondition if you do not want convert bean's field as query condition, then use this function

0 commit comments

Comments
 (0)