mirror of
https://github.com/redis/go-redis.git
synced 2025-10-21 20:53:41 +03:00
Merge branch 'master' of https://github.com/redis/go-redis into add-vamana-vector-type-to-search
This commit is contained in:
2
.github/actions/run-tests/action.yml
vendored
2
.github/actions/run-tests/action.yml
vendored
@@ -25,7 +25,7 @@ runs:
|
||||
|
||||
# Mapping of redis version to redis testing containers
|
||||
declare -A redis_version_mapping=(
|
||||
["8.2.x"]="8.2-M01-pre"
|
||||
["8.2.x"]="8.2-rc2-pre"
|
||||
["8.0.x"]="8.0.2"
|
||||
["7.4.x"]="rs-7.4.0-v5"
|
||||
["7.2.x"]="rs-7.2.0-v17"
|
||||
|
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -2,9 +2,9 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master, v9, v9.7, v9.8]
|
||||
branches: [master, v9, v9.7, v9.8, 'ndyakov/*', 'ofekshenawa/*', 'htemelski-redis/*', 'ce/*']
|
||||
pull_request:
|
||||
branches: [master, v9, v9.7, v9.8]
|
||||
branches: [master, v9, v9.7, v9.8, 'ndyakov/*', 'ofekshenawa/*', 'htemelski-redis/*', 'ce/*']
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
|
||||
# Mapping of redis version to redis testing containers
|
||||
declare -A redis_version_mapping=(
|
||||
["8.2.x"]="8.2-M01-pre"
|
||||
["8.2.x"]="8.2-rc2-pre"
|
||||
["8.0.x"]="8.0.2"
|
||||
["7.4.x"]="rs-7.4.0-v5"
|
||||
)
|
||||
|
@@ -6169,6 +6169,34 @@ var _ = Describe("Commands", func() {
|
||||
Expect(n).To(Equal(int64(3)))
|
||||
})
|
||||
|
||||
It("should XTrimMaxLenMode", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
n, err := client.XTrimMaxLenMode(ctx, "stream", 0, "KEEPREF").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(BeNumerically(">=", 0))
|
||||
})
|
||||
|
||||
It("should XTrimMaxLenApproxMode", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
n, err := client.XTrimMaxLenApproxMode(ctx, "stream", 0, 0, "KEEPREF").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(BeNumerically(">=", 0))
|
||||
})
|
||||
|
||||
It("should XTrimMinIDMode", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
n, err := client.XTrimMinIDMode(ctx, "stream", "4-0", "KEEPREF").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(BeNumerically(">=", 0))
|
||||
})
|
||||
|
||||
It("should XTrimMinIDApproxMode", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
n, err := client.XTrimMinIDApproxMode(ctx, "stream", "4-0", 0, "KEEPREF").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(BeNumerically(">=", 0))
|
||||
})
|
||||
|
||||
It("should XAdd", func() {
|
||||
id, err := client.XAdd(ctx, &redis.XAddArgs{
|
||||
Stream: "stream",
|
||||
@@ -6222,6 +6250,37 @@ var _ = Describe("Commands", func() {
|
||||
Expect(n).To(Equal(int64(3)))
|
||||
})
|
||||
|
||||
It("should XAckDel", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
// First, create a consumer group
|
||||
err := client.XGroupCreate(ctx, "stream", "testgroup", "0").Err()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Read messages to create pending entries
|
||||
_, err = client.XReadGroup(ctx, &redis.XReadGroupArgs{
|
||||
Group: "testgroup",
|
||||
Consumer: "testconsumer",
|
||||
Streams: []string{"stream", ">"},
|
||||
}).Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
// Test XAckDel with KEEPREF mode
|
||||
n, err := client.XAckDel(ctx, "stream", "testgroup", "KEEPREF", "1-0", "2-0").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(HaveLen(2))
|
||||
|
||||
// Clean up
|
||||
client.XGroupDestroy(ctx, "stream", "testgroup")
|
||||
})
|
||||
|
||||
It("should XDelEx", func() {
|
||||
SkipBeforeRedisVersion(8.2, "doesn't work with older redis stack images")
|
||||
// Test XDelEx with KEEPREF mode
|
||||
n, err := client.XDelEx(ctx, "stream", "KEEPREF", "1-0", "2-0").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(n).To(HaveLen(2))
|
||||
})
|
||||
|
||||
It("should XLen", func() {
|
||||
n, err := client.XLen(ctx, "stream").Result()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
@@ -199,11 +199,11 @@ func ExampleClient_geoindex() {
|
||||
// OK
|
||||
// OK
|
||||
// OK
|
||||
// {1 [{product:46885 <nil> <nil> <nil> map[$:{"city":"Denver","description":"Navy Blue Slippers","location":"-104.991531, 39.742043","price":45.99}]}]}
|
||||
// {1 [{product:46885 <nil> <nil> <nil> map[$:{"city":"Denver","description":"Navy Blue Slippers","location":"-104.991531, 39.742043","price":45.99}] <nil>}]}
|
||||
// OK
|
||||
// OK
|
||||
// OK
|
||||
// OK
|
||||
// OK
|
||||
// {1 [{shape:4 <nil> <nil> <nil> map[$:[{"geom":"POINT (2 2)","name":"Purple Point"}]]}]}
|
||||
// {1 [{shape:4 <nil> <nil> <nil> map[$:[{"geom":"POINT (2 2)","name":"Purple Point"}]] <nil>}]}
|
||||
}
|
||||
|
@@ -219,7 +219,7 @@ func ExampleClient_search_json() {
|
||||
// STEP_END
|
||||
|
||||
// Output:
|
||||
// {1 [{user:3 <nil> <nil> <nil> map[$:{"age":35,"city":"Tel Aviv","email":"paul.zamir@example.com","name":"Paul Zamir"}]}]}
|
||||
// {1 [{user:3 <nil> <nil> <nil> map[$:{"age":35,"city":"Tel Aviv","email":"paul.zamir@example.com","name":"Paul Zamir"}] <nil>}]}
|
||||
// London
|
||||
// Tel Aviv
|
||||
// 0
|
||||
@@ -329,5 +329,5 @@ func ExampleClient_search_hash() {
|
||||
// STEP_END
|
||||
|
||||
// Output:
|
||||
// {1 [{huser:3 <nil> <nil> <nil> map[age:35 city:Tel Aviv email:paul.zamir@example.com name:Paul Zamir]}]}
|
||||
// {1 [{huser:3 <nil> <nil> <nil> map[age:35 city:Tel Aviv email:paul.zamir@example.com name:Paul Zamir] <nil>}]}
|
||||
}
|
||||
|
@@ -257,6 +257,6 @@ func ExampleClient_search_qs() {
|
||||
|
||||
// Output:
|
||||
// Documents found: 10
|
||||
// {1 [{bicycle:0 <nil> <nil> <nil> map[$:{"brand":"Velorim","condition":"new","description":"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.","model":"Jigger","price":270}]}]}
|
||||
// {1 [{bicycle:4 <nil> <nil> <nil> map[$:{"brand":"Noka Bikes","condition":"used","description":"Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.","model":"Kahuna","price":3200}]}]}
|
||||
// {1 [{bicycle:0 <nil> <nil> <nil> map[$:{"brand":"Velorim","condition":"new","description":"Small and powerful, the Jigger is the best ride for the smallest of tikes! This is the tiniest kids’ pedal bike on the market available without a coaster brake, the Jigger is the vehicle of choice for the rare tenacious little rider raring to go.","model":"Jigger","price":270}] <nil>}]}
|
||||
// {1 [{bicycle:4 <nil> <nil> <nil> map[$:{"brand":"Noka Bikes","condition":"used","description":"Whether you want to try your hand at XC racing or are looking for a lively trail bike that's just as inspiring on the climbs as it is over rougher ground, the Wilder is one heck of a bike built specifically for short women. Both the frames and components have been tweaked to include a women’s saddle, different bars and unique colourway.","model":"Kahuna","price":3200}] <nil>}]}
|
||||
}
|
||||
|
@@ -488,6 +488,7 @@ type Document struct {
|
||||
Payload *string
|
||||
SortKey *string
|
||||
Fields map[string]string
|
||||
Error error
|
||||
}
|
||||
|
||||
type AggregateQuery []interface{}
|
||||
@@ -1735,7 +1736,13 @@ func parseFTSearch(data []interface{}, noContent, withScores, withPayloads, with
|
||||
if i < len(data) {
|
||||
fields, ok := data[i].([]interface{})
|
||||
if !ok {
|
||||
return FTSearchResult{}, fmt.Errorf("invalid document fields format")
|
||||
if data[i] == proto.Nil || data[i] == nil {
|
||||
doc.Error = proto.Nil
|
||||
doc.Fields = map[string]string{}
|
||||
fields = []interface{}{}
|
||||
} else {
|
||||
return FTSearchResult{}, fmt.Errorf("invalid document fields format")
|
||||
}
|
||||
}
|
||||
|
||||
for j := 0; j < len(fields); j += 2 {
|
||||
|
@@ -7,7 +7,9 @@ import (
|
||||
|
||||
type StreamCmdable interface {
|
||||
XAdd(ctx context.Context, a *XAddArgs) *StringCmd
|
||||
XAckDel(ctx context.Context, stream string, group string, mode string, ids ...string) *SliceCmd
|
||||
XDel(ctx context.Context, stream string, ids ...string) *IntCmd
|
||||
XDelEx(ctx context.Context, stream string, mode string, ids ...string) *SliceCmd
|
||||
XLen(ctx context.Context, stream string) *IntCmd
|
||||
XRange(ctx context.Context, stream, start, stop string) *XMessageSliceCmd
|
||||
XRangeN(ctx context.Context, stream, start, stop string, count int64) *XMessageSliceCmd
|
||||
@@ -31,8 +33,12 @@ type StreamCmdable interface {
|
||||
XAutoClaimJustID(ctx context.Context, a *XAutoClaimArgs) *XAutoClaimJustIDCmd
|
||||
XTrimMaxLen(ctx context.Context, key string, maxLen int64) *IntCmd
|
||||
XTrimMaxLenApprox(ctx context.Context, key string, maxLen, limit int64) *IntCmd
|
||||
XTrimMaxLenMode(ctx context.Context, key string, maxLen int64, mode string) *IntCmd
|
||||
XTrimMaxLenApproxMode(ctx context.Context, key string, maxLen, limit int64, mode string) *IntCmd
|
||||
XTrimMinID(ctx context.Context, key string, minID string) *IntCmd
|
||||
XTrimMinIDApprox(ctx context.Context, key string, minID string, limit int64) *IntCmd
|
||||
XTrimMinIDMode(ctx context.Context, key string, minID string, mode string) *IntCmd
|
||||
XTrimMinIDApproxMode(ctx context.Context, key string, minID string, limit int64, mode string) *IntCmd
|
||||
XInfoGroups(ctx context.Context, key string) *XInfoGroupsCmd
|
||||
XInfoStream(ctx context.Context, key string) *XInfoStreamCmd
|
||||
XInfoStreamFull(ctx context.Context, key string, count int) *XInfoStreamFullCmd
|
||||
@@ -54,6 +60,7 @@ type XAddArgs struct {
|
||||
// Approx causes MaxLen and MinID to use "~" matcher (instead of "=").
|
||||
Approx bool
|
||||
Limit int64
|
||||
Mode string
|
||||
ID string
|
||||
Values interface{}
|
||||
}
|
||||
@@ -81,6 +88,11 @@ func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
|
||||
if a.Limit > 0 {
|
||||
args = append(args, "limit", a.Limit)
|
||||
}
|
||||
|
||||
if a.Mode != "" {
|
||||
args = append(args, a.Mode)
|
||||
}
|
||||
|
||||
if a.ID != "" {
|
||||
args = append(args, a.ID)
|
||||
} else {
|
||||
@@ -93,6 +105,16 @@ func (c cmdable) XAdd(ctx context.Context, a *XAddArgs) *StringCmd {
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XAckDel(ctx context.Context, stream string, group string, mode string, ids ...string) *SliceCmd {
|
||||
args := []interface{}{"xackdel", stream, group, mode, "ids", len(ids)}
|
||||
for _, id := range ids {
|
||||
args = append(args, id)
|
||||
}
|
||||
cmd := NewSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd {
|
||||
args := []interface{}{"xdel", stream}
|
||||
for _, id := range ids {
|
||||
@@ -103,6 +125,16 @@ func (c cmdable) XDel(ctx context.Context, stream string, ids ...string) *IntCmd
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XDelEx(ctx context.Context, stream string, mode string, ids ...string) *SliceCmd {
|
||||
args := []interface{}{"xdelex", stream, mode, "ids", len(ids)}
|
||||
for _, id := range ids {
|
||||
args = append(args, id)
|
||||
}
|
||||
cmd := NewSliceCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XLen(ctx context.Context, stream string) *IntCmd {
|
||||
cmd := NewIntCmd(ctx, "xlen", stream)
|
||||
_ = c(ctx, cmd)
|
||||
@@ -375,6 +407,8 @@ func xClaimArgs(a *XClaimArgs) []interface{} {
|
||||
return args
|
||||
}
|
||||
|
||||
// TODO: refactor xTrim, xTrimMode and the wrappers over the functions
|
||||
|
||||
// xTrim If approx is true, add the "~" parameter, otherwise it is the default "=" (redis default).
|
||||
// example:
|
||||
//
|
||||
@@ -418,6 +452,42 @@ func (c cmdable) XTrimMinIDApprox(ctx context.Context, key string, minID string,
|
||||
return c.xTrim(ctx, key, "minid", true, minID, limit)
|
||||
}
|
||||
|
||||
func (c cmdable) xTrimMode(
|
||||
ctx context.Context, key, strategy string,
|
||||
approx bool, threshold interface{}, limit int64,
|
||||
mode string,
|
||||
) *IntCmd {
|
||||
args := make([]interface{}, 0, 7)
|
||||
args = append(args, "xtrim", key, strategy)
|
||||
if approx {
|
||||
args = append(args, "~")
|
||||
}
|
||||
args = append(args, threshold)
|
||||
if limit > 0 {
|
||||
args = append(args, "limit", limit)
|
||||
}
|
||||
args = append(args, mode)
|
||||
cmd := NewIntCmd(ctx, args...)
|
||||
_ = c(ctx, cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMaxLenMode(ctx context.Context, key string, maxLen int64, mode string) *IntCmd {
|
||||
return c.xTrimMode(ctx, key, "maxlen", false, maxLen, 0, mode)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMaxLenApproxMode(ctx context.Context, key string, maxLen, limit int64, mode string) *IntCmd {
|
||||
return c.xTrimMode(ctx, key, "maxlen", true, maxLen, limit, mode)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMinIDMode(ctx context.Context, key string, minID string, mode string) *IntCmd {
|
||||
return c.xTrimMode(ctx, key, "minid", false, minID, 0, mode)
|
||||
}
|
||||
|
||||
func (c cmdable) XTrimMinIDApproxMode(ctx context.Context, key string, minID string, limit int64, mode string) *IntCmd {
|
||||
return c.xTrimMode(ctx, key, "minid", true, minID, limit, mode)
|
||||
}
|
||||
|
||||
func (c cmdable) XInfoConsumers(ctx context.Context, key string, group string) *XInfoConsumersCmd {
|
||||
cmd := NewXInfoConsumersCmd(ctx, key, group)
|
||||
_ = c(ctx, cmd)
|
||||
|
@@ -287,8 +287,7 @@ type VSimArgs struct {
|
||||
FilterEF int64
|
||||
Truth bool
|
||||
NoThread bool
|
||||
// The `VSim` command in Redis has the option, by the doc in Redis.io don't have.
|
||||
// Epsilon float64
|
||||
Epsilon float64
|
||||
}
|
||||
|
||||
func (v VSimArgs) appendArgs(args []any) []any {
|
||||
@@ -310,13 +309,13 @@ func (v VSimArgs) appendArgs(args []any) []any {
|
||||
if v.NoThread {
|
||||
args = append(args, "nothread")
|
||||
}
|
||||
// if v.Epsilon > 0 {
|
||||
// args = append(args, "Epsilon", v.Epsilon)
|
||||
// }
|
||||
if v.Epsilon > 0 {
|
||||
args = append(args, "Epsilon", v.Epsilon)
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
// `VSIM key (ELE | FP32 | VALUES num) (vector | element) [COUNT num]
|
||||
// `VSIM key (ELE | FP32 | VALUES num) (vector | element) [COUNT num] [EPSILON delta]
|
||||
// [EF search-exploration-factor] [FILTER expression] [FILTER-EF max-filtering-effort] [TRUTH] [NOTHREAD]`
|
||||
// note: the API is experimental and may be subject to change.
|
||||
func (c cmdable) VSimWithArgs(ctx context.Context, key string, val Vector, simArgs *VSimArgs) *StringSliceCmd {
|
||||
@@ -331,7 +330,7 @@ func (c cmdable) VSimWithArgs(ctx context.Context, key string, val Vector, simAr
|
||||
return cmd
|
||||
}
|
||||
|
||||
// `VSIM key (ELE | FP32 | VALUES num) (vector | element) [WITHSCORES] [COUNT num]
|
||||
// `VSIM key (ELE | FP32 | VALUES num) (vector | element) [WITHSCORES] [COUNT num] [EPSILON delta]
|
||||
// [EF search-exploration-factor] [FILTER expression] [FILTER-EF max-filtering-effort] [TRUTH] [NOTHREAD]`
|
||||
// note: the API is experimental and may be subject to change.
|
||||
func (c cmdable) VSimWithArgsWithScores(ctx context.Context, key string, val Vector, simArgs *VSimArgs) *VectorScoreSliceCmd {
|
||||
|
Reference in New Issue
Block a user