@@ -80,8 +80,9 @@ type FieldSchema struct {
80
80
}
81
81
82
82
type FTVectorArgs struct {
83
- FlatOptions * FTFlatOptions
84
- HNSWOptions * FTHNSWOptions
83
+ FlatOptions * FTFlatOptions
84
+ HNSWOptions * FTHNSWOptions
85
+ VamanaOptions * FTVamanaOptions
85
86
}
86
87
87
88
type FTFlatOptions struct {
@@ -103,6 +104,19 @@ type FTHNSWOptions struct {
103
104
Epsilon float64
104
105
}
105
106
107
+ type FTVamanaOptions struct {
108
+ Type string
109
+ Dim int
110
+ DistanceMetric string
111
+ Compression string
112
+ ConstructionWindowSize int
113
+ GraphMaxDegree int
114
+ SearchWindowSize int
115
+ Epsilon float64
116
+ TrainingThreshold int
117
+ ReduceDim int
118
+ }
119
+
106
120
type FTDropIndexOptions struct {
107
121
DeleteDocs bool
108
122
}
@@ -499,7 +513,7 @@ func (c cmdable) FTAggregate(ctx context.Context, index string, query string) *M
499
513
return cmd
500
514
}
501
515
502
- func FTAggregateQuery (query string , options * FTAggregateOptions ) AggregateQuery {
516
+ func FTAggregateQuery (query string , options * FTAggregateOptions ) ( AggregateQuery , error ) {
503
517
queryArgs := []interface {}{query }
504
518
if options != nil {
505
519
if options .Verbatim {
@@ -515,7 +529,7 @@ func FTAggregateQuery(query string, options *FTAggregateOptions) AggregateQuery
515
529
}
516
530
517
531
if options .LoadAll && options .Load != nil {
518
- panic ("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive" )
532
+ return nil , fmt . Errorf ("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive" )
519
533
}
520
534
if options .LoadAll {
521
535
queryArgs = append (queryArgs , "LOAD" , "*" )
@@ -571,7 +585,7 @@ func FTAggregateQuery(query string, options *FTAggregateOptions) AggregateQuery
571
585
for _ , sortBy := range options .SortBy {
572
586
sortByOptions = append (sortByOptions , sortBy .FieldName )
573
587
if sortBy .Asc && sortBy .Desc {
574
- panic ("FT.AGGREGATE: ASC and DESC are mutually exclusive" )
588
+ return nil , fmt . Errorf ("FT.AGGREGATE: ASC and DESC are mutually exclusive" )
575
589
}
576
590
if sortBy .Asc {
577
591
sortByOptions = append (sortByOptions , "ASC" )
@@ -616,7 +630,7 @@ func FTAggregateQuery(query string, options *FTAggregateOptions) AggregateQuery
616
630
queryArgs = append (queryArgs , "DIALECT" , 2 )
617
631
}
618
632
}
619
- return queryArgs
633
+ return queryArgs , nil
620
634
}
621
635
622
636
func ProcessAggregateResult (data []interface {}) (* FTAggregateResult , error ) {
@@ -718,7 +732,9 @@ func (c cmdable) FTAggregateWithArgs(ctx context.Context, index string, query st
718
732
args = append (args , "ADDSCORES" )
719
733
}
720
734
if options .LoadAll && options .Load != nil {
721
- panic ("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive" )
735
+ cmd := NewAggregateCmd (ctx , args ... )
736
+ cmd .SetErr (fmt .Errorf ("FT.AGGREGATE: LOADALL and LOAD are mutually exclusive" ))
737
+ return cmd
722
738
}
723
739
if options .LoadAll {
724
740
args = append (args , "LOAD" , "*" )
@@ -771,7 +787,9 @@ func (c cmdable) FTAggregateWithArgs(ctx context.Context, index string, query st
771
787
for _ , sortBy := range options .SortBy {
772
788
sortByOptions = append (sortByOptions , sortBy .FieldName )
773
789
if sortBy .Asc && sortBy .Desc {
774
- panic ("FT.AGGREGATE: ASC and DESC are mutually exclusive" )
790
+ cmd := NewAggregateCmd (ctx , args ... )
791
+ cmd .SetErr (fmt .Errorf ("FT.AGGREGATE: ASC and DESC are mutually exclusive" ))
792
+ return cmd
775
793
}
776
794
if sortBy .Asc {
777
795
sortByOptions = append (sortByOptions , "ASC" )
@@ -919,7 +937,9 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
919
937
args = append (args , "ON" , "JSON" )
920
938
}
921
939
if options .OnHash && options .OnJSON {
922
- panic ("FT.CREATE: ON HASH and ON JSON are mutually exclusive" )
940
+ cmd := NewStatusCmd (ctx , args ... )
941
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: ON HASH and ON JSON are mutually exclusive" ))
942
+ return cmd
923
943
}
924
944
if options .Prefix != nil {
925
945
args = append (args , "PREFIX" , len (options .Prefix ))
@@ -970,12 +990,16 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
970
990
}
971
991
}
972
992
if schema == nil {
973
- panic ("FT.CREATE: SCHEMA is required" )
993
+ cmd := NewStatusCmd (ctx , args ... )
994
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: SCHEMA is required" ))
995
+ return cmd
974
996
}
975
997
args = append (args , "SCHEMA" )
976
998
for _ , schema := range schema {
977
999
if schema .FieldName == "" || schema .FieldType == SearchFieldTypeInvalid {
978
- panic ("FT.CREATE: SCHEMA FieldName and FieldType are required" )
1000
+ cmd := NewStatusCmd (ctx , args ... )
1001
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: SCHEMA FieldName and FieldType are required" ))
1002
+ return cmd
979
1003
}
980
1004
args = append (args , schema .FieldName )
981
1005
if schema .As != "" {
@@ -984,15 +1008,32 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
984
1008
args = append (args , schema .FieldType .String ())
985
1009
if schema .VectorArgs != nil {
986
1010
if schema .FieldType != SearchFieldTypeVector {
987
- panic ("FT.CREATE: SCHEMA FieldType VECTOR is required for VectorArgs" )
1011
+ cmd := NewStatusCmd (ctx , args ... )
1012
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: SCHEMA FieldType VECTOR is required for VectorArgs" ))
1013
+ return cmd
1014
+ }
1015
+ // Check mutual exclusivity of vector options
1016
+ optionCount := 0
1017
+ if schema .VectorArgs .FlatOptions != nil {
1018
+ optionCount ++
1019
+ }
1020
+ if schema .VectorArgs .HNSWOptions != nil {
1021
+ optionCount ++
1022
+ }
1023
+ if schema .VectorArgs .VamanaOptions != nil {
1024
+ optionCount ++
988
1025
}
989
- if schema .VectorArgs .FlatOptions != nil && schema .VectorArgs .HNSWOptions != nil {
990
- panic ("FT.CREATE: SCHEMA VectorArgs FlatOptions and HNSWOptions are mutually exclusive" )
1026
+ if optionCount != 1 {
1027
+ cmd := NewStatusCmd (ctx , args ... )
1028
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: SCHEMA VectorArgs must have exactly one of FlatOptions, HNSWOptions, or VamanaOptions" ))
1029
+ return cmd
991
1030
}
992
1031
if schema .VectorArgs .FlatOptions != nil {
993
1032
args = append (args , "FLAT" )
994
1033
if schema .VectorArgs .FlatOptions .Type == "" || schema .VectorArgs .FlatOptions .Dim == 0 || schema .VectorArgs .FlatOptions .DistanceMetric == "" {
995
- panic ("FT.CREATE: Type, Dim and DistanceMetric are required for VECTOR FLAT" )
1034
+ cmd := NewStatusCmd (ctx , args ... )
1035
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: Type, Dim and DistanceMetric are required for VECTOR FLAT" ))
1036
+ return cmd
996
1037
}
997
1038
flatArgs := []interface {}{
998
1039
"TYPE" , schema .VectorArgs .FlatOptions .Type ,
@@ -1011,7 +1052,9 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
1011
1052
if schema .VectorArgs .HNSWOptions != nil {
1012
1053
args = append (args , "HNSW" )
1013
1054
if schema .VectorArgs .HNSWOptions .Type == "" || schema .VectorArgs .HNSWOptions .Dim == 0 || schema .VectorArgs .HNSWOptions .DistanceMetric == "" {
1014
- panic ("FT.CREATE: Type, Dim and DistanceMetric are required for VECTOR HNSW" )
1055
+ cmd := NewStatusCmd (ctx , args ... )
1056
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: Type, Dim and DistanceMetric are required for VECTOR HNSW" ))
1057
+ return cmd
1015
1058
}
1016
1059
hnswArgs := []interface {}{
1017
1060
"TYPE" , schema .VectorArgs .HNSWOptions .Type ,
@@ -1036,10 +1079,48 @@ func (c cmdable) FTCreate(ctx context.Context, index string, options *FTCreateOp
1036
1079
args = append (args , len (hnswArgs ))
1037
1080
args = append (args , hnswArgs ... )
1038
1081
}
1082
+ if schema .VectorArgs .VamanaOptions != nil {
1083
+ args = append (args , "SVS-VAMANA" )
1084
+ if schema .VectorArgs .VamanaOptions .Type == "" || schema .VectorArgs .VamanaOptions .Dim == 0 || schema .VectorArgs .VamanaOptions .DistanceMetric == "" {
1085
+ cmd := NewStatusCmd (ctx , args ... )
1086
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: Type, Dim and DistanceMetric are required for VECTOR VAMANA" ))
1087
+ return cmd
1088
+ }
1089
+ vamanaArgs := []interface {}{
1090
+ "TYPE" , schema .VectorArgs .VamanaOptions .Type ,
1091
+ "DIM" , schema .VectorArgs .VamanaOptions .Dim ,
1092
+ "DISTANCE_METRIC" , schema .VectorArgs .VamanaOptions .DistanceMetric ,
1093
+ }
1094
+ if schema .VectorArgs .VamanaOptions .Compression != "" {
1095
+ vamanaArgs = append (vamanaArgs , "COMPRESSION" , schema .VectorArgs .VamanaOptions .Compression )
1096
+ }
1097
+ if schema .VectorArgs .VamanaOptions .ConstructionWindowSize > 0 {
1098
+ vamanaArgs = append (vamanaArgs , "CONSTRUCTION_WINDOW_SIZE" , schema .VectorArgs .VamanaOptions .ConstructionWindowSize )
1099
+ }
1100
+ if schema .VectorArgs .VamanaOptions .GraphMaxDegree > 0 {
1101
+ vamanaArgs = append (vamanaArgs , "GRAPH_MAX_DEGREE" , schema .VectorArgs .VamanaOptions .GraphMaxDegree )
1102
+ }
1103
+ if schema .VectorArgs .VamanaOptions .SearchWindowSize > 0 {
1104
+ vamanaArgs = append (vamanaArgs , "SEARCH_WINDOW_SIZE" , schema .VectorArgs .VamanaOptions .SearchWindowSize )
1105
+ }
1106
+ if schema .VectorArgs .VamanaOptions .Epsilon > 0 {
1107
+ vamanaArgs = append (vamanaArgs , "EPSILON" , schema .VectorArgs .VamanaOptions .Epsilon )
1108
+ }
1109
+ if schema .VectorArgs .VamanaOptions .TrainingThreshold > 0 {
1110
+ vamanaArgs = append (vamanaArgs , "TRAINING_THRESHOLD" , schema .VectorArgs .VamanaOptions .TrainingThreshold )
1111
+ }
1112
+ if schema .VectorArgs .VamanaOptions .ReduceDim > 0 {
1113
+ vamanaArgs = append (vamanaArgs , "REDUCE" , schema .VectorArgs .VamanaOptions .ReduceDim )
1114
+ }
1115
+ args = append (args , len (vamanaArgs ))
1116
+ args = append (args , vamanaArgs ... )
1117
+ }
1039
1118
}
1040
1119
if schema .GeoShapeFieldType != "" {
1041
1120
if schema .FieldType != SearchFieldTypeGeoShape {
1042
- panic ("FT.CREATE: SCHEMA FieldType GEOSHAPE is required for GeoShapeFieldType" )
1121
+ cmd := NewStatusCmd (ctx , args ... )
1122
+ cmd .SetErr (fmt .Errorf ("FT.CREATE: SCHEMA FieldType GEOSHAPE is required for GeoShapeFieldType" ))
1123
+ return cmd
1043
1124
}
1044
1125
args = append (args , schema .GeoShapeFieldType )
1045
1126
}
@@ -1197,7 +1278,7 @@ func (c cmdable) FTExplainWithArgs(ctx context.Context, index string, query stri
1197
1278
// FTExplainCli - Returns the execution plan for a complex query. [Not Implemented]
1198
1279
// For more information, see https://redis.io/commands/ft.explaincli/
1199
1280
func (c cmdable ) FTExplainCli (ctx context.Context , key , path string ) error {
1200
- panic ( " not implemented" )
1281
+ return fmt . Errorf ( "FTExplainCli is not implemented" )
1201
1282
}
1202
1283
1203
1284
func parseFTInfo (data map [string ]interface {}) (FTInfoResult , error ) {
@@ -1758,7 +1839,7 @@ type SearchQuery []interface{}
1758
1839
// For more information, please refer to the Redis documentation about [FT.SEARCH].
1759
1840
//
1760
1841
// [FT.SEARCH]: (https://redis.io/commands/ft.search/)
1761
- func FTSearchQuery (query string , options * FTSearchOptions ) SearchQuery {
1842
+ func FTSearchQuery (query string , options * FTSearchOptions ) ( SearchQuery , error ) {
1762
1843
queryArgs := []interface {}{query }
1763
1844
if options != nil {
1764
1845
if options .NoContent {
@@ -1838,7 +1919,7 @@ func FTSearchQuery(query string, options *FTSearchOptions) SearchQuery {
1838
1919
for _ , sortBy := range options .SortBy {
1839
1920
queryArgs = append (queryArgs , sortBy .FieldName )
1840
1921
if sortBy .Asc && sortBy .Desc {
1841
- panic ("FT.SEARCH: ASC and DESC are mutually exclusive" )
1922
+ return nil , fmt . Errorf ("FT.SEARCH: ASC and DESC are mutually exclusive" )
1842
1923
}
1843
1924
if sortBy .Asc {
1844
1925
queryArgs = append (queryArgs , "ASC" )
@@ -1866,7 +1947,7 @@ func FTSearchQuery(query string, options *FTSearchOptions) SearchQuery {
1866
1947
queryArgs = append (queryArgs , "DIALECT" , 2 )
1867
1948
}
1868
1949
}
1869
- return queryArgs
1950
+ return queryArgs , nil
1870
1951
}
1871
1952
1872
1953
// FTSearchWithArgs - Executes a search query on an index with additional options.
@@ -1955,7 +2036,9 @@ func (c cmdable) FTSearchWithArgs(ctx context.Context, index string, query strin
1955
2036
for _ , sortBy := range options .SortBy {
1956
2037
args = append (args , sortBy .FieldName )
1957
2038
if sortBy .Asc && sortBy .Desc {
1958
- panic ("FT.SEARCH: ASC and DESC are mutually exclusive" )
2039
+ cmd := newFTSearchCmd (ctx , options , args ... )
2040
+ cmd .SetErr (fmt .Errorf ("FT.SEARCH: ASC and DESC are mutually exclusive" ))
2041
+ return cmd
1959
2042
}
1960
2043
if sortBy .Asc {
1961
2044
args = append (args , "ASC" )
0 commit comments