blob: 5cab18d617c89f2bc30f75af765a5876b56331d6 [file] [log] [blame]
serkant.uluderyae5afeff2021-02-23 18:00:23 +03001package redis
2
3import (
4 "context"
5 "crypto/sha1"
6 "encoding/hex"
7 "io"
8 "strings"
9)
10
Abhay Kumar40252eb2025-10-13 13:25:53 +000011type Scripter interface {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030012 Eval(ctx context.Context, script string, keys []string, args ...interface{}) *Cmd
13 EvalSha(ctx context.Context, sha1 string, keys []string, args ...interface{}) *Cmd
14 ScriptExists(ctx context.Context, hashes ...string) *BoolSliceCmd
15 ScriptLoad(ctx context.Context, script string) *StringCmd
16}
17
18var (
Abhay Kumar40252eb2025-10-13 13:25:53 +000019 _ Scripter = (*Client)(nil)
20 _ Scripter = (*Ring)(nil)
21 _ Scripter = (*ClusterClient)(nil)
serkant.uluderyae5afeff2021-02-23 18:00:23 +030022)
23
24type Script struct {
25 src, hash string
26}
27
28func NewScript(src string) *Script {
29 h := sha1.New()
30 _, _ = io.WriteString(h, src)
31 return &Script{
32 src: src,
33 hash: hex.EncodeToString(h.Sum(nil)),
34 }
35}
36
37func (s *Script) Hash() string {
38 return s.hash
39}
40
Abhay Kumar40252eb2025-10-13 13:25:53 +000041func (s *Script) Load(ctx context.Context, c Scripter) *StringCmd {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030042 return c.ScriptLoad(ctx, s.src)
43}
44
Abhay Kumar40252eb2025-10-13 13:25:53 +000045func (s *Script) Exists(ctx context.Context, c Scripter) *BoolSliceCmd {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030046 return c.ScriptExists(ctx, s.hash)
47}
48
Abhay Kumar40252eb2025-10-13 13:25:53 +000049func (s *Script) Eval(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030050 return c.Eval(ctx, s.src, keys, args...)
51}
52
Abhay Kumar40252eb2025-10-13 13:25:53 +000053func (s *Script) EvalSha(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030054 return c.EvalSha(ctx, s.hash, keys, args...)
55}
56
57// Run optimistically uses EVALSHA to run the script. If script does not exist
58// it is retried using EVAL.
Abhay Kumar40252eb2025-10-13 13:25:53 +000059func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
serkant.uluderyae5afeff2021-02-23 18:00:23 +030060 r := s.EvalSha(ctx, c, keys, args...)
61 if err := r.Err(); err != nil && strings.HasPrefix(err.Error(), "NOSCRIPT ") {
62 return s.Eval(ctx, c, keys, args...)
63 }
64 return r
65}