Skip to content

Commit 2c3d7d8

Browse files
committed
added filesystem support
1 parent c37cadb commit 2c3d7d8

11 files changed

Lines changed: 282 additions & 8 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
bin
22
redixdata*
33
.DS_STORE
4+
data/

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Features
1111
- A really simple `key => value` store that speaks `redis` protocol but with our rules!.
1212
- A real system that you can abuse! it isn't intedented for cache only but a "database system".
1313
- `Async` (all writes happen in the background), or `Sync` it won't respond to the client before writing to the internal datastore.
14-
- Pluggable storage engines, currently it supports `postgresql`, and there may be more engines be introduced in the upcomning releases.
14+
- Pluggable storage engines, currently it supports (`postgresql`, `filesystem`), and there may be more engines be introduced in the upcomning releases.
1515
- It could be used using `redis` clients easily, i.e: "the famouus redis-cli"
1616

1717

@@ -23,9 +23,9 @@ Core Commands
2323
- `FLUSHDB`
2424
- `SELECT <DB index>`
2525
- `SET <key> <value> [EX seconds | KEEPTTL] [NX]`
26-
- `TTL <key>`
26+
- `TTL <key>` **(not supported while using `filesystem` engine)**
2727
- `GET <key> [DELETE]`, it has an alias for backward compatibility reasons called `GETDEL <key>`
28-
- `INCR <key> [<delta>]`, it has an alias for backward compatibility reasons called `INCRBY`
28+
- `INCR <key> [<delta>]`, it has an alias for backward compatibility reasons called `INCRBY` **(not supported while using `filesystem` engine)**
2929
- `DEL key [key ...]`
3030
- `HGETALL <prefix>`
3131
> Fetches the whole data under the specified prefix as a hashmap result

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.17
44

55
require (
66
github.com/hashicorp/hcl/v2 v2.11.1
7+
github.com/jackc/pgx/v4 v4.14.1
78
github.com/tidwall/redcon v1.4.3
89
)
910

@@ -18,7 +19,6 @@ require (
1819
github.com/jackc/pgproto3/v2 v2.2.0 // indirect
1920
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect
2021
github.com/jackc/pgtype v1.9.1 // indirect
21-
github.com/jackc/pgx/v4 v4.14.1 // indirect
2222
github.com/jackc/puddle v1.2.0 // indirect
2323
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
2424
github.com/tidwall/btree v0.7.1 // indirect

go.sum

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2
77
github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
88
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw=
99
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo=
10+
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
1011
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
1112
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
1213
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
@@ -19,6 +20,7 @@ github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG
1920
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
2021
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
2122
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
23+
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
2224
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
2325
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
2426
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -45,6 +47,7 @@ github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
4547
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
4648
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
4749
github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c=
50+
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc=
4851
github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak=
4952
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
5053
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
@@ -91,6 +94,7 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LE
9194
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
9295
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
9396
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
97+
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
9498
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
9599
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
96100
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@@ -99,7 +103,9 @@ github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
99103
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
100104
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
101105
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
106+
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
102107
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
108+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
103109
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
104110
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
105111
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@@ -109,6 +115,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
109115
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
110116
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
111117
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
118+
github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ=
112119
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
113120
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
114121
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
@@ -120,6 +127,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
120127
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
121128
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
122129
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
130+
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
123131
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
124132
github.com/tidwall/btree v0.7.1 h1:LPXN3VRIxsdMwyfbtPgOA60jLuj/eEmMpDjOh2szRPw=
125133
github.com/tidwall/btree v0.7.1/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
@@ -189,7 +197,6 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
189197
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
190198
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
191199
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
192-
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
193200
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
194201
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
195202
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -213,5 +220,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
213220
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
214221
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
215222
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
223+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
216224
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
217225
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=

internals/datastore/contract/engine.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ type Engine interface {
1010
Open(string) error
1111
Close() error
1212
Write(*WriteInput) (*WriteOutput, error)
13-
// BatchWrite([]*WriteInput) error
1413
Read(*ReadInput) (*ReadOutput, error)
1514
Iterate(*IteratorOpts) error
1615
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package filesystem
2+
3+
import (
4+
"io/ioutil"
5+
"os"
6+
"syscall"
7+
)
8+
9+
// ReadFileWithSharedLock reads the specified file using a shared-lock
10+
func ReadFileWithSharedLock(filename string) ([]byte, error) {
11+
f, err := os.OpenFile(filename, os.O_RDONLY, 0775)
12+
if err != nil {
13+
return nil, err
14+
}
15+
defer f.Close()
16+
17+
fd := int(f.Fd())
18+
19+
if err := syscall.Flock(fd, syscall.LOCK_SH); err != nil {
20+
return nil, err
21+
}
22+
defer syscall.Flock(fd, syscall.LOCK_UN)
23+
24+
data, err := ioutil.ReadAll(f)
25+
if err != nil {
26+
return nil, err
27+
}
28+
29+
return data, nil
30+
}
31+
32+
// WriteFileWithExclusiveLock reads the specified file using a shared-lock
33+
func WriteFileWithExclusiveLock(filename string, data []byte) (int, error) {
34+
f, err := os.OpenFile(filename, os.O_CREATE|os.O_RDWR|os.O_TRUNC|os.O_SYNC, 07775)
35+
if err != nil {
36+
return 0, err
37+
}
38+
defer f.Close()
39+
40+
fd := int(f.Fd())
41+
42+
if err := syscall.Flock(fd, syscall.LOCK_EX); err != nil {
43+
return 0, err
44+
}
45+
defer syscall.Flock(fd, syscall.LOCK_UN)
46+
47+
written, err := f.Write(data)
48+
if err != nil {
49+
return 0, err
50+
}
51+
52+
return written, nil
53+
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package filesystem
2+
3+
import (
4+
"bytes"
5+
"encoding/hex"
6+
"fmt"
7+
"io/fs"
8+
"os"
9+
"path/filepath"
10+
11+
"github.com/alash3al/redix/internals/datastore/contract"
12+
)
13+
14+
// Engine represents the contract.Engine implementation
15+
type Engine struct {
16+
storageDir string
17+
kvDir string
18+
}
19+
20+
// Open opens the database
21+
func (e *Engine) Open(dir string) (err error) {
22+
if err := os.MkdirAll(dir, 0775); err != nil && err != os.ErrExist {
23+
return err
24+
}
25+
26+
if err := os.MkdirAll(filepath.Join(dir, "/kv"), 0775); err != nil && err != os.ErrExist {
27+
return err
28+
}
29+
30+
absDir, err := filepath.Abs(dir)
31+
if err != nil {
32+
return err
33+
}
34+
35+
e.storageDir = absDir
36+
e.kvDir = filepath.Join(e.storageDir, "/kv")
37+
38+
return nil
39+
}
40+
41+
// Write writes into the database
42+
func (e *Engine) Write(input *contract.WriteInput) (*contract.WriteOutput, error) {
43+
if input == nil {
44+
return nil, fmt.Errorf("empty input specified")
45+
}
46+
47+
if input.Append {
48+
return nil, fmt.Errorf("(filesystem) unsupported feature (append)")
49+
}
50+
51+
if input.Increment {
52+
return nil, fmt.Errorf("(filesystem) unsupported feature (increment)")
53+
}
54+
55+
if input.OnlyIfNotExists {
56+
return nil, fmt.Errorf("(filesystem) unsupported feature (ifNotExists)")
57+
}
58+
59+
if input.TTL > 0 {
60+
return nil, fmt.Errorf("(filesystem) unsupported feature (TTL)")
61+
}
62+
63+
if input.Key == nil {
64+
if err := os.RemoveAll(e.kvDir); err != nil {
65+
return nil, err
66+
}
67+
68+
return nil, nil
69+
}
70+
71+
key := hex.EncodeToString(input.Key)
72+
keyDataPath := filepath.Join(e.kvDir, key)
73+
74+
if input.Value == nil {
75+
if err := os.Remove(keyDataPath); err != nil {
76+
return nil, err
77+
}
78+
79+
return nil, nil
80+
}
81+
82+
if err := os.MkdirAll(filepath.Join(e.kvDir, "/kv"), 0775); err != nil && err != os.ErrExist {
83+
return nil, err
84+
}
85+
86+
if _, err := WriteFileWithExclusiveLock(keyDataPath, input.Value); err != nil {
87+
return nil, err
88+
}
89+
90+
return &contract.WriteOutput{
91+
Value: input.Value,
92+
}, nil
93+
}
94+
95+
// Get reads from the database
96+
func (e *Engine) Read(input *contract.ReadInput) (*contract.ReadOutput, error) {
97+
if input == nil {
98+
return nil, fmt.Errorf("empty input specified")
99+
}
100+
101+
key := hex.EncodeToString(input.Key)
102+
keyDataPath := filepath.Join(e.kvDir, key)
103+
104+
data, err := ReadFileWithSharedLock(keyDataPath)
105+
if err != nil {
106+
if err == os.ErrNotExist {
107+
return &contract.ReadOutput{}, nil
108+
}
109+
110+
return nil, err
111+
}
112+
113+
if input.Delete {
114+
return nil, filepath.WalkDir(e.kvDir, func(path string, d fs.DirEntry, err error) error {
115+
if path == e.kvDir {
116+
return nil
117+
}
118+
119+
actualKey, err := hex.DecodeString(d.Name())
120+
if err != nil {
121+
return err
122+
}
123+
124+
if bytes.HasPrefix(actualKey, input.Key) {
125+
if err := os.Remove(path); err != nil {
126+
return err
127+
}
128+
}
129+
130+
return nil
131+
})
132+
}
133+
134+
return &contract.ReadOutput{
135+
Key: input.Key,
136+
Value: data,
137+
Exists: true,
138+
TTL: -1,
139+
}, nil
140+
}
141+
142+
// Iterate iterates on the whole database stops if the IteratorOpts returns an error
143+
func (e *Engine) Iterate(opts *contract.IteratorOpts) error {
144+
if opts == nil {
145+
return fmt.Errorf("empty options specified")
146+
}
147+
148+
if opts.Callback == nil {
149+
return fmt.Errorf("you must specify the callback")
150+
}
151+
152+
return filepath.WalkDir(e.kvDir, func(path string, d fs.DirEntry, err error) error {
153+
if path == e.kvDir {
154+
return nil
155+
}
156+
157+
actualKey, err := hex.DecodeString(d.Name())
158+
if err != nil {
159+
return err
160+
}
161+
162+
if bytes.HasPrefix(actualKey, opts.Prefix) {
163+
data, err := ReadFileWithSharedLock(path)
164+
if err != nil {
165+
return err
166+
}
167+
168+
if err := opts.Callback(&contract.ReadOutput{
169+
Key: bytes.TrimPrefix(actualKey, opts.Prefix),
170+
Value: data,
171+
Exists: true,
172+
TTL: -1,
173+
}); err != nil {
174+
return err
175+
}
176+
}
177+
178+
return nil
179+
})
180+
}
181+
182+
// Close closes the connection
183+
func (e *Engine) Close() error {
184+
return nil
185+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package filesystem
2+
3+
import "github.com/alash3al/redix/internals/datastore/contract"
4+
5+
// Global consts
6+
const (
7+
Name = "filesystem"
8+
)
9+
10+
func init() {
11+
contract.Register(Name, &Engine{})
12+
}

internals/datastore/engines/postgresql/postgres.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,14 @@ func (e *Engine) Write(input *contract.WriteInput) (*contract.WriteOutput, error
7272
return nil, fmt.Errorf("empty input specified")
7373
}
7474

75+
if input.Key == nil {
76+
if _, err := e.conn.Exec(context.Background(), "DELETE FROM redix_data_v5"); err != nil {
77+
return nil, err
78+
}
79+
80+
return nil, nil
81+
}
82+
7583
if input.Value == nil {
7684
if _, err := e.conn.Exec(context.Background(), "DELETE FROM redix_data_v5 WHERE _key LIKE $1", append(input.Key, '%')); err != nil {
7785
return nil, err

0 commit comments

Comments
 (0)