Skip to content

Commit af513ad

Browse files
yhc9311rueian
authored andcommitted
Rueidis/script new file (#601)
* script new file * add license * remove print * fix: RunRo output function
1 parent cd82183 commit af513ad

File tree

2 files changed

+177
-0
lines changed

2 files changed

+177
-0
lines changed

valkeycompat/script.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) 2013 The github.com/go-redis/redis Authors.
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are
6+
// met:
7+
//
8+
// * Redistributions of source code must retain the above copyright
9+
// notice, this list of conditions and the following disclaimer.
10+
// * Redistributions in binary form must reproduce the above
11+
// copyright notice, this list of conditions and the following disclaimer
12+
// in the documentation and/or other materials provided with the
13+
// distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
package valkeycompat
28+
29+
import (
30+
"context"
31+
"crypto/sha1"
32+
"encoding/hex"
33+
"io"
34+
"strings"
35+
)
36+
37+
type Scripter interface {
38+
Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
39+
EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
40+
EvalRO(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
41+
EvalShaRO(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
42+
ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
43+
ScriptLoad(ctx context.Context, script string) *StringCmd
44+
}
45+
46+
var (
47+
_ Scripter = (*Compat)(nil)
48+
)
49+
50+
type Script struct {
51+
src, hash string
52+
}
53+
54+
func NewScript(src string) *Script {
55+
h := sha1.New()
56+
_, _ = io.WriteString(h, src)
57+
return &Script{
58+
src: src,
59+
hash: hex.EncodeToString(h.Sum(nil)),
60+
}
61+
}
62+
63+
func (s *Script) Hash() string {
64+
return s.hash
65+
}
66+
67+
func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd {
68+
return c.ScriptLoad(ctx, s.src)
69+
}
70+
71+
func (s *Script) Exists(ctx context.Context, c Scripter) *BoolSliceCmd {
72+
return c.ScriptExists(ctx, s.hash)
73+
}
74+
75+
func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
76+
return c.Eval(ctx, s.src, keys, args...)
77+
}
78+
79+
func (s *Script) EvalRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
80+
return c.EvalRO(ctx, s.src, keys, args...)
81+
}
82+
83+
func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
84+
return c.EvalSha(ctx, s.hash, keys, args...)
85+
}
86+
87+
func (s *Script) EvalShaRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
88+
return c.EvalShaRO(ctx, s.hash, keys, args...)
89+
}
90+
91+
// Run optimistically uses EVALSHA to run the script. If script does not exist
92+
// it is retried using EVAL.
93+
func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
94+
r := s.EvalSha(ctx, c, keys, args...)
95+
if err := r.Err(); err != nil {
96+
msg := err.Error()
97+
msg = strings.TrimPrefix(msg, "ERR ")
98+
if strings.HasPrefix(msg, "NOSCRIPT") {
99+
return s.Eval(ctx, c, keys, args...)
100+
}
101+
}
102+
return r
103+
}
104+
105+
// RunRO optimistically uses EVALSHA_RO to run the script. If script does not exist
106+
// it is retried using EVAL_RO.
107+
func (s *Script) RunRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
108+
r := s.EvalShaRO(ctx, c, keys, args...)
109+
if err := r.Err(); err != nil {
110+
msg := err.Error()
111+
msg = strings.TrimPrefix(msg, "ERR ")
112+
if strings.HasPrefix(msg, "NOSCRIPT") {
113+
return s.EvalRO(ctx, c, keys, args...)
114+
}
115+
}
116+
return r
117+
}

valkeycompat/script_test.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2013 The github.com/go-redis/redis Authors.
2+
// All rights reserved.
3+
//
4+
// Redistribution and use in source and binary forms, with or without
5+
// modification, are permitted provided that the following conditions are
6+
// met:
7+
//
8+
// * Redistributions of source code must retain the above copyright
9+
// notice, this list of conditions and the following disclaimer.
10+
// * Redistributions in binary form must reproduce the above
11+
// copyright notice, this list of conditions and the following disclaimer
12+
// in the documentation and/or other materials provided with the
13+
// distribution.
14+
//
15+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16+
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17+
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18+
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19+
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20+
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21+
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22+
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23+
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
27+
package valkeycompat
28+
29+
import (
30+
"context"
31+
"fmt"
32+
33+
"github.com/valkey-io/valkey-go"
34+
)
35+
36+
func ExampleScript() {
37+
ctx = context.Background()
38+
IncrByXX := NewScript(`
39+
if redis.call("GET", KEYS[1]) ~= false then
40+
return redis.call("INCRBY", KEYS[1], ARGV[1])
41+
end
42+
return false
43+
`)
44+
client, err := valkey.NewClient(valkey.ClientOption{InitAddress: []string{"127.0.0.1:6379"}})
45+
if err != nil {
46+
panic(err)
47+
}
48+
defer client.Close()
49+
rdb := NewAdapter(client)
50+
n, err := IncrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Result()
51+
fmt.Println(n, err)
52+
53+
err = rdb.Set(ctx, "xx_counter", "40", 0).Err()
54+
if err != nil {
55+
panic(err)
56+
}
57+
58+
n, err = IncrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Result()
59+
fmt.Println(n, err)
60+
}

0 commit comments

Comments
 (0)