Skip to content

Commit

Permalink
add Sorted.Create.Union
Browse files Browse the repository at this point in the history
  • Loading branch information
xh3b4sd committed Dec 9, 2023
1 parent a5125bd commit 5d65181
Show file tree
Hide file tree
Showing 11 changed files with 226 additions and 47 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,7 @@ func Test_Client_Single_Sorted_Create_Order(t *testing.T) {

var cli redigo.Interface
{
c := redigo.Config{
Kind: redigo.KindSingle,
}

cli, err = redigo.New(c)
if err != nil {
t.Fatal(err)
}

err = cli.Purge()
if err != nil {
t.Fatal(err)
}
cli = prgAll(redigo.Default())
}

{
Expand Down Expand Up @@ -91,95 +79,210 @@ func Test_Client_Single_Sorted_Create_Score(t *testing.T) {

var cli redigo.Interface
{
c := redigo.Config{
Kind: redigo.KindSingle,
}

cli, err = redigo.New(c)
if err != nil {
t.Fatal(err)
}

err = cli.Purge()
if err != nil {
t.Fatal(err)
}
cli = prgAll(redigo.Default())
}

{
err := cli.Sorted().Create().Index("ssk", "foo", 0.8, "a", "b")
err = cli.Sorted().Create().Index("ssk", "foo", 0.8, "a", "b")
if err != nil {
t.Fatal(err)
}
}

{
err := cli.Sorted().Create().Index("ssk", "bar", 0.7, "c", "d")
err = cli.Sorted().Create().Index("ssk", "bar", 0.7, "c", "d")
if err != nil {
t.Fatal(err)
}
}

{
err := cli.Sorted().Create().Index("ssk", "zap", 0.8, "e", "f")
err = cli.Sorted().Create().Index("ssk", "zap", 0.8, "e", "f")
if !sorted.IsAlreadyExistsError(err) {
t.Fatal("expected", "alreadyExistsError", "got", err)
}
}

{
err := cli.Sorted().Create().Index("ssk", "foo", 0.8, "g", "h")
err = cli.Sorted().Create().Index("ssk", "foo", 0.8, "g", "h")
if !sorted.IsAlreadyExistsError(err) {
t.Fatal("expected", "alreadyExistsError", "got", err)
}
}
}

func Test_Client_Single_Sorted_Create_Value(t *testing.T) {
func Test_Client_Single_Sorted_Create_Union(t *testing.T) {
var err error

var cli redigo.Interface
{
c := redigo.Config{
Kind: redigo.KindSingle,
cli = prgAll(redigo.Default())
}

{
res, err := cli.Sorted().Search().Union("k1", "k2")
if err != nil {
t.Fatal(err)
}
if len(res) != 0 {
t.Fatal("expected", 0, "got", len(res))
}
}

cli, err = redigo.New(c)
{
err = cli.Sorted().Create().Index("k1", "v3", 0.3)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k1", "v4", 0.4)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k1", "v5", 0.5)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k1", "v6", 0.6)
if err != nil {
t.Fatal(err)
}
}

err = cli.Purge()
{
res, err := cli.Sorted().Search().Union("k1")
if err != nil {
t.Fatal(err)
}
if len(res) != 4 {
t.Fatal("expected", 4, "got", len(res))
}
if res[0] != "v3" {
t.Fatal("expected", "v3", "got", res[0])
}
if res[1] != "v4" {
t.Fatal("expected", "v4", "got", res[1])
}
if res[2] != "v5" {
t.Fatal("expected", "v5", "got", res[2])
}
if res[3] != "v6" {
t.Fatal("expected", "v6", "got", res[3])
}
}

{
err := cli.Sorted().Create().Score("ssk", "foo", 0.8)
res, err := cli.Sorted().Search().Union("k1", "k2")
if err != nil {
t.Fatal(err)
}
if len(res) != 4 {
t.Fatal("expected", 4, "got", len(res))
}
if res[0] != "v3" {
t.Fatal("expected", "v3", "got", res[0])
}
if res[1] != "v4" {
t.Fatal("expected", "v4", "got", res[1])
}
if res[2] != "v5" {
t.Fatal("expected", "v5", "got", res[2])
}
if res[3] != "v6" {
t.Fatal("expected", "v6", "got", res[3])
}
}

{
err := cli.Sorted().Create().Score("ssk", "bar", 0.7)
err = cli.Sorted().Create().Index("k2", "v2", 0.2)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k2", "v4", 0.4)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k2", "v5", 0.5)
if err != nil {
t.Fatal(err)
}
err = cli.Sorted().Create().Index("k2", "v7", 0.7)
if err != nil {
t.Fatal(err)
}
}

{
cou, err := cli.Sorted().Create().Union("k3", "k1", "k2")
if err != nil {
t.Fatal(err)
}
if cou != 6 {
t.Fatal("expected", 6, "got", cou)
}
}

{
res, err := cli.Sorted().Search().Order("k3", 0, -1)
if err != nil {
t.Fatal(err)
}
if len(res) != 6 {
t.Fatal("expected", 6, "got", len(res))
}
if res[0] != "v2" {
t.Fatal("expected", "v2", "got", res[0])
}
if res[1] != "v3" {
t.Fatal("expected", "v3", "got", res[1])
}
if res[2] != "v4" {
t.Fatal("expected", "v4", "got", res[2])
}
if res[3] != "v5" {
t.Fatal("expected", "v5", "got", res[3])
}
if res[4] != "v6" {
t.Fatal("expected", "v6", "got", res[4])
}
if res[5] != "v7" {
t.Fatal("expected", "v7", "got", res[5])
}
}
}

func Test_Client_Single_Sorted_Create_Value(t *testing.T) {
var err error

var cli redigo.Interface
{
cli = prgAll(redigo.Default())
}

{
err = cli.Sorted().Create().Score("ssk", "foo", 0.8)
if err != nil {
t.Fatal(err)
}
}

{
err = cli.Sorted().Create().Score("ssk", "bar", 0.7)
if err != nil {
t.Fatal(err)
}
}

// Verify we can create elements with duplicated scores.
{
err := cli.Sorted().Create().Score("ssk", "zap", 0.8)
err = cli.Sorted().Create().Score("ssk", "zap", 0.8)
if err != nil {
t.Fatal(err)
}
}

// Verify values must be unique after all.
{
err := cli.Sorted().Create().Score("ssk", "foo", 0.8)
err = cli.Sorted().Create().Score("ssk", "foo", 0.8)
if !sorted.IsAlreadyExistsError(err) {
t.Fatal("expected", "alreadyExistsError", "got", err)
}
Expand Down Expand Up @@ -208,7 +311,7 @@ func Test_Client_Single_Sorted_Create_Value(t *testing.T) {
// score. When foo is deleted, which has score 0.8 then zap must still exist
// with the same score as we verify in the next step.
{
err := cli.Sorted().Delete().Index("ssk", "foo")
err = cli.Sorted().Delete().Index("ssk", "foo")
if err != nil {
t.Fatal(err)
}
Expand Down
21 changes: 21 additions & 0 deletions conformance/single_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build single

package conformance

import (
"github.com/xh3b4sd/redigo"
"github.com/xh3b4sd/tracer"
)

// prgAll is a convenience function for calling FLUSHALL. The provided redigo
// interface is returned as is.
func prgAll(red redigo.Interface) redigo.Interface {
{
err := red.Purge()
if err != nil {
tracer.Panic(tracer.Mask(err))
}
}

return red
}
File renamed without changes.
9 changes: 9 additions & 0 deletions pkg/sorted/create/fake.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package create
type Fake struct {
FakeIndex func() error
FakeScore func() error
FakeUnion func() (int64, error)
}

func (f *Fake) Index(key string, val string, sco float64, ind ...string) error {
Expand All @@ -20,3 +21,11 @@ func (f *Fake) Score(key string, val string, sco float64) error {

return nil
}

func (f *Fake) Union(dst string, key ...string) (int64, error) {
if f.FakeUnion != nil {
return f.FakeUnion()
}

return 0, nil
}
45 changes: 38 additions & 7 deletions pkg/sorted/create/redis.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ func (r *Redis) Index(key string, val string, sco float64, ind ...string) error

if len(ind) != 0 {
m := map[string]int{}
for _, s := range ind {
m[s] = m[s] + 1
for _, x := range ind {
m[x] = m[x] + 1
}

for _, v := range m {
Expand All @@ -49,11 +49,11 @@ func (r *Redis) Index(key string, val string, sco float64, ind ...string) error
}
}

for _, s := range ind {
if s == "" {
for _, x := range ind {
if x == "" {
return tracer.Maskf(executionFailedError, "index must not be empty")
}
if strings.Count(s, " ") != 0 {
if strings.Count(x, " ") != 0 {
return tracer.Maskf(executionFailedError, "index must not contain whitespace")
}
}
Expand All @@ -66,8 +66,8 @@ func (r *Redis) Index(key string, val string, sco float64, ind ...string) error
arg = append(arg, val) // ARGV[1]
arg = append(arg, sco) // ARGV[2]

for _, s := range ind {
arg = append(arg, s)
for _, x := range ind {
arg = append(arg, x)
}
}

Expand Down Expand Up @@ -117,3 +117,34 @@ func (r *Redis) Score(key string, val string, sco float64) error {

return nil
}

func (r *Redis) Union(dst string, key ...string) (int64, error) {
var err error

var con redis.Conn
{
con = r.poo.Get()
defer con.Close()
}

var arg []interface{}
{
arg = append(arg, dst, len(key))

for _, x := range key {
arg = append(arg, prefix.WithKeys(r.pre, x))
}

arg = append(arg, "AGGREGATE", "MIN")
}

var res int64
{
res, err = redis.Int64(con.Do("ZUNIONSTORE", arg...))
if err != nil {
return 0, tracer.Mask(err)
}
}

return res, nil
}
Loading

0 comments on commit 5d65181

Please sign in to comment.