Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: redis/rueidis
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v1.0.33
Choose a base ref
...
head repository: redis/rueidis
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v1.0.34
Choose a head ref

Commits on Mar 27, 2024

  1. feat: update circle ci to use dynamic config

    Signed-off-by: moonorange <monoma632@gmail.com>
    moonorange committed Mar 27, 2024

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    Copy the full SHA
    cbefea8 View commit details

Commits on Mar 28, 2024

  1. feat: update circle ci to use dynamic config take2

    Signed-off-by: moonorange <monoma632@gmail.com>
    moonorange committed Mar 28, 2024
    Copy the full SHA
    4455e48 View commit details
  2. Update README.md

    trim21 authored Mar 28, 2024
    Copy the full SHA
    c3813c5 View commit details
  3. fix: relocate generate_config.sh to the .circleci folder

    Signed-off-by: moonorange <monoma632@gmail.com>
    moonorange committed Mar 28, 2024
    Copy the full SHA
    2e9c449 View commit details
  4. Update README.md

    trim21 authored Mar 28, 2024
    Copy the full SHA
    a9ae1bb View commit details

Commits on Mar 29, 2024

  1. Merge pull request #518 from trim21/patch-1

    docs: fix rueidisprob readme
    rueian authored Mar 29, 2024
    Copy the full SHA
    f3cacbe View commit details

Commits on Mar 30, 2024

  1. Merge pull request #517 from moonorange/improve_circle_ci_test

    Refine the .circleci/config.yml by using dynamic config
    rueian authored Mar 30, 2024
    Copy the full SHA
    a74b679 View commit details

Commits on Mar 31, 2024

  1. feat: add counting bloom filter

    proost committed Mar 31, 2024
    Copy the full SHA
    0fb6c1f View commit details
  2. feat: allow duplication of adding

    proost committed Mar 31, 2024
    Copy the full SHA
    7566423 View commit details

Commits on Apr 1, 2024

  1. style: make short

    proost committed Apr 1, 2024
    Copy the full SHA
    7069d90 View commit details
  2. feat: DecodeSliceOfJSON

    sgasho committed Apr 1, 2024
    Copy the full SHA
    db3abf5 View commit details
  3. some renames

    sgasho committed Apr 1, 2024
    Copy the full SHA
    86a8cdc View commit details

Commits on Apr 2, 2024

  1. not accepting only []T

    sgasho committed Apr 2, 2024
    Copy the full SHA
    227572f View commit details
  2. accept []T and additional tests

    sgasho committed Apr 2, 2024
    Copy the full SHA
    a132b06 View commit details
  3. Add WithDBStatement to add db.statement attribute to rueidisotel

    chkp-omris committed Apr 2, 2024
    Copy the full SHA
    328edeb View commit details
  4. Merge pull request #522 from sgasho/feature/#521_slicescan

    feat: Add a helper generic function DecodeSliceOfJSON
    rueian authored Apr 2, 2024
    Copy the full SHA
    2ac91fb View commit details
  5. Add test for WithDBStatement

    chkp-omris committed Apr 2, 2024
    Copy the full SHA
    165b74f View commit details

Commits on Apr 3, 2024

  1. docs: DecodeSliceOfJSON in README.md

    sgasho committed Apr 3, 2024
    Copy the full SHA
    589f678 View commit details

Commits on Apr 4, 2024

  1. review fix

    sgasho committed Apr 4, 2024
    Copy the full SHA
    b42ea58 View commit details
  2. Change dbStmtEnabled to dbStmtFunc and add StatementFunc to map a com…

    …mand's tokens to the string of db.statement
    chkp-omris committed Apr 4, 2024
    Copy the full SHA
    f399414 View commit details
  3. emphasize counterexample

    sgasho committed Apr 4, 2024
    Copy the full SHA
    8247fa3 View commit details
  4. Add WithDBStatement to unit tests with actual client

    chkp-omris committed Apr 4, 2024
    Copy the full SHA
    82218eb View commit details
  5. Merge pull request #524 from sgasho/docs/DecodeSliceOfJSON_usages

    docs: DecodeSliceOfJSON in README.md
    rueian authored Apr 4, 2024
    Copy the full SHA
    7e8fc9d View commit details
  6. Merge pull request #523 from chkp-omris/main

    Add WithDBStatement to add db.statement attribute to rueidisotel
    rueian authored Apr 4, 2024
    Copy the full SHA
    95ec07c View commit details

Commits on Apr 6, 2024

  1. feat: add item min count multi

    proost committed Apr 6, 2024
    Copy the full SHA
    abda0c8 View commit details
  2. style: shorter return

    proost committed Apr 6, 2024
    Copy the full SHA
    bc2f494 View commit details

Commits on Apr 7, 2024

  1. refactor: remove deduplicated remove multi

    proost committed Apr 7, 2024
    Copy the full SHA
    f959dc3 View commit details
  2. Merge pull request #519 from proost/feat-counting-bloom-filter

    feat: add counting bloom filter
    rueian authored Apr 7, 2024
    Copy the full SHA
    6a8ba48 View commit details

Commits on Apr 9, 2024

  1. feat: bump v1.0.34

    rueian committed Apr 9, 2024
    Copy the full SHA
    7f21310 View commit details
90 changes: 17 additions & 73 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,79 +1,23 @@
version: 2.1
setup: true
orbs:
go: circleci/go@1.7.3
continuation: circleci/continuation@0.1.2
jobs:
build:
machine:
image: ubuntu-2204:current
resource_class: large
parallelism: 3
setup:
executor: continuation/default
steps:
- checkout
- go/install:
version: 1.21.0
- run: # test ./go.mod
command: |
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ./dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./rueidishook/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/rueidishook
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./mock/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/mock
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./om/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/om
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./rueidisaside/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/rueidisaside
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./rueidiscompat/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/rueidiscompat
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./rueidisotel/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/rueidisotel
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- run: # test ./rueidisprob/go.mod
command: |
cd $CIRCLE_WORKING_DIRECTORY/rueidisprob
list=$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: $list"
for n in {1..5}; do ../dockertest.sh $list && break; done
no_output_timeout: 15m

- store_test_results:
path: .
- run: curl -Os https://uploader.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov -t ${CODECOV_TOKEN}
- run:
name: Generate config
# Generate dynamic configuration based on go.mod files
command: |
./.circleci/generate_config.sh > generated_config.yml
- continuation/continue:
configuration_path: generated_config.yml # use newly generated config to continue

# our single workflow, that triggers the setup job defined above
workflows:
setup:
jobs:
- setup
58 changes: 58 additions & 0 deletions .circleci/generate_config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash

# Find all directories containing go.mod files
modules=$(find . -maxdepth 2 -type f -name "go.mod" | xargs -n 1 dirname | sort -u)

# Start the generated config with the version
cat << EOF
version: 2.1
orbs:
go: circleci/go@1.7.3
jobs:
build:
machine:
image: ubuntu-2204:current
resource_class: large
parallelism: 3
steps:
- checkout
- go/install:
version: 1.21.0
EOF

# Loop through each module and generate job configurations
for module in $modules; do
module_name=$(basename "$module")
if [ "$module_name" = "." ]; then
cat << EOF
- run: # test ./go.mod
name: Test $module_name
command: |
list=\$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: \$list"
for n in {1..5}; do
./dockertest.sh \$list && break
done
no_output_timeout: 15m
EOF
else
cat << EOF
- run: # test ./$module_name/go.mod
name: Test $module_name
command: |
cd "\$CIRCLE_WORKING_DIRECTORY/$module_name"
list=\$(go list ./... | circleci tests split --split-by=timings)
echo "Test Packages: \$list"
for n in {1..5}; do
../dockertest.sh \$list && break
done
no_output_timeout: 15m
EOF
fi
done

cat << EOF
- store_test_results:
path: .
- run: curl -Os https://uploader.codecov.io/latest/linux/codecov && chmod +x codecov && ./codecov -t ${CODECOV_TOKEN}
EOF
53 changes: 52 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -484,6 +484,57 @@ client.Do(ctx, client.B().FtSearch().Index("idx").Query("@f:v").Build()).AsFtSea
client.Do(ctx, client.B().Geosearch().Key("k").Fromlonlat(1, 1).Bybox(1).Height(1).Km().Build()).AsGeosearch()
```

## Use DecodeSliceOfJSON to scan array result

DecodeSliceOfJSON is useful when you would like to scan the results of an array into a slice of a specific struct.

```golang
type User struct {
Name string `json:"name"`
}

// Set some values
if err = client.Do(ctx, client.B().Set().Key("user1").Value(`{"name": "name1"}`).Build()).Error(); err != nil {
return err
}
if err = client.Do(ctx, client.B().Set().Key("user2").Value(`{"name": "name2"}`).Build()).Error(); err != nil {
return err
}

// Scan MGET results into []*User
var users []*User // or []User is also scannable
if err := rueidis.DecodeSliceOfJSON(client.Do(ctx, client.B().Mget().Key("user1", "user2").Build()), &users); err != nil {
return err
}

for _, user := range users {
fmt.Printf("%+v\n", user)
}
/*
&{name:name1}
&{name:name2}
*/
```

### !!!!!! DO NOT DO THIS !!!!!!

Please make sure that all values in the result have same JSON structure.

```golang
// Set a pure string value
if err = client.Do(ctx, client.B().Set().Key("user1").Value("userName1").Build()).Error(); err != nil {
return err
}

// Bad
users := make([]*User, 0)
if err := rueidis.DecodeSliceOfJSON(client.Do(ctx, client.B().Mget().Key("user1").Build()), &users); err != nil {
return err
}
// -> Error: invalid character 'u' looking for beginning of value
// in this case, use client.Do(ctx, client.B().Mget().Key("user1").Build()).AsStrSlice()
```

---

## Contributing
@@ -502,4 +553,4 @@ go generate
### Testing

Please use the [./dockertest.sh](./dockertest.sh) script for running test cases locally.
And please try your best to have 100% test coverage on code changes.
And please try your best to have 100% test coverage on code changes.
22 changes: 22 additions & 0 deletions helper.go
Original file line number Diff line number Diff line change
@@ -181,6 +181,28 @@ func JsonMSet(client Client, ctx context.Context, kvs map[string]string, path st
return doMultiSet(client, ctx, cmds.s)
}

// DecodeSliceOfJSON is a helper that struct-scans each RedisMessage into dest, which must be a slice of pointer.
func DecodeSliceOfJSON[T any](result RedisResult, dest *[]T) error {
values, err := result.ToArray()
if err != nil {
return err
}

ts := make([]T, len(values))
for i, v := range values {
var t T
if err = v.DecodeJSON(&t); err != nil {
if IsRedisNil(err) {
continue
}
return err
}
ts[i] = t
}
*dest = ts
return nil
}

func clientMGet(client Client, ctx context.Context, cmd Completed, keys []string) (ret map[string]RedisMessage, err error) {
arr, err := client.Do(ctx, cmd).ToArray()
if err != nil {
107 changes: 107 additions & 0 deletions helper_test.go
Original file line number Diff line number Diff line change
@@ -812,3 +812,110 @@ func TestJsonMSet(t *testing.T) {
})
})
}

func TestDecodeSliceOfJSON(t *testing.T) {
type Inner struct {
Field string
}
type T struct {
ID int
Name string
Inners []*Inner
}
values := []RedisMessage{
{string: `{"ID":1, "Name": "n1", "Inners": [{"Field": "f1"}]}`, typ: '+'},
{string: `{"ID":2, "Name": "n2", "Inners": [{"Field": "f2"}]}`, typ: '+'},
}
result := RedisResult{val: RedisMessage{typ: '*', values: values}}

t.Run("Scan []*T", func(t *testing.T) {
got := make([]*T, 0)
want := []*T{
{ID: 1, Name: "n1", Inners: []*Inner{{Field: "f1"}}},
{ID: 2, Name: "n2", Inners: []*Inner{{Field: "f2"}}},
}
if err := DecodeSliceOfJSON(result, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, got) {
t.Fatalf("DecodeSliceOfJSON not get value as expected %v", got)
}
})

t.Run("Scan []T", func(t *testing.T) {
got := make([]T, 0)
want := []T{
{ID: 1, Name: "n1", Inners: []*Inner{{Field: "f1"}}},
{ID: 2, Name: "n2", Inners: []*Inner{{Field: "f2"}}},
}
if err := DecodeSliceOfJSON(result, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, got) {
t.Fatalf("DecodeSliceOfJSON not get value as expected %v", got)
}
})

t.Run("Scan []*T: has nil error message", func(t *testing.T) {
hasNilValues := []RedisMessage{
{string: `{"ID":1, "Name": "n1", "Inners": [{"Field": "f1"}]}`, typ: '+'},
{typ: '_'},
{string: `{"ID":2, "Name": "n2", "Inners": [{"Field": "f2"}]}`, typ: '+'},
}
hasNilResult := RedisResult{val: RedisMessage{typ: '*', values: hasNilValues}}

got := make([]*T, 0)
want := []*T{
{ID: 1, Name: "n1", Inners: []*Inner{{Field: "f1"}}},
nil,
{ID: 2, Name: "n2", Inners: []*Inner{{Field: "f2"}}},
}
if err := DecodeSliceOfJSON(hasNilResult, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, got) {
t.Fatalf("DecodeSliceOfJSON not get value as expected %v", got)
}
})

t.Run("Scan []T: has nil error message", func(t *testing.T) {
hasNilValues := []RedisMessage{
{string: `{"ID":1, "Name": "n1", "Inners": [{"Field": "f1"}]}`, typ: '+'},
{typ: '_'},
{string: `{"ID":2, "Name": "n2", "Inners": [{"Field": "f2"}]}`, typ: '+'},
}
hasNilResult := RedisResult{val: RedisMessage{typ: '*', values: hasNilValues}}

got := make([]T, 0)
want := []T{
{ID: 1, Name: "n1", Inners: []*Inner{{Field: "f1"}}},
{ID: 0, Name: "", Inners: nil},
{ID: 2, Name: "n2", Inners: []*Inner{{Field: "f2"}}},
}
if err := DecodeSliceOfJSON(hasNilResult, &got); err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(want, got) {
t.Fatalf("DecodeSliceOfJSON not get value as expected %v", got)
}
})

t.Run("error result", func(t *testing.T) {
if err := DecodeSliceOfJSON(RedisResult{val: RedisMessage{typ: '-'}}, &[]*T{}); err == nil {
t.Fatal("DecodeSliceOfJSON not failed as expected")
}
})

t.Run("has non-nil error message in result", func(t *testing.T) {
hasErrValues := []RedisMessage{
{string: `{"ID":1, "Name": "n1", "Inners": [{"Field": "f1"}]}`, typ: '+'},
{string: `invalid`, typ: '-'},
}
hasErrResult := RedisResult{val: RedisMessage{typ: '*', values: hasErrValues}}

got := make([]*T, 0)
if err := DecodeSliceOfJSON(hasErrResult, &got); err == nil {
t.Fatal("DecodeSliceOfJSON not failed as expected")
}
})
}
2 changes: 1 addition & 1 deletion mock/go.mod
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ go 1.20
replace github.com/redis/rueidis => ../

require (
github.com/redis/rueidis v1.0.33
github.com/redis/rueidis v1.0.34
go.uber.org/mock v0.3.0
)

2 changes: 1 addition & 1 deletion om/go.mod
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ replace github.com/redis/rueidis => ../

require (
github.com/oklog/ulid/v2 v2.1.0
github.com/redis/rueidis v1.0.33
github.com/redis/rueidis v1.0.34
)

require golang.org/x/sys v0.17.0 // indirect
2 changes: 1 addition & 1 deletion pipe.go
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ import (
)

const LibName = "rueidis"
const LibVer = "1.0.33"
const LibVer = "1.0.34"

var noHello = regexp.MustCompile("unknown command .?(HELLO|hello).?")

2 changes: 1 addition & 1 deletion rueidisaside/go.mod
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@ replace github.com/redis/rueidis => ../

require (
github.com/oklog/ulid/v2 v2.1.0
github.com/redis/rueidis v1.0.33
github.com/redis/rueidis v1.0.34
)

require golang.org/x/sys v0.17.0 // indirect
Loading