github.com/aldelo/common@v1.5.1/wrapper/redis/redis.go (about) 1 package redis 2 3 /* 4 * Copyright 2020-2023 Aldelo, LP 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 // ================================================================================================================= 20 // AWS CREDENTIAL: 21 // use $> aws configure (to set aws access key and secret to target machine) 22 // Store AWS Access ID and Secret Key into Default Profile Using '$ aws configure' cli 23 // 24 // To Install & Setup AWS CLI on Host: 25 // 1) https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2-linux.html 26 // On Ubuntu, if host does not have zip and unzip: 27 // $> sudo apt install zip 28 // $> sudo apt install unzip 29 // On Ubuntu, to install AWS CLI v2: 30 // $> curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" 31 // $> unzip awscliv2.zip 32 // $> sudo ./aws/install 33 // 2) $> aws configure set region awsRegionName --profile default 34 // 3) $> aws configure 35 // follow prompts to enter Access ID and Secret Key 36 // 37 // AWS Region Name Reference: 38 // us-west-2, us-east-1, ap-northeast-1, etc 39 // See: https://docs.aws.amazon.com/general/latest/gr/rande.html 40 // ================================================================================================================= 41 42 import ( 43 "github.com/aldelo/common/wrapper/redis/redisbitop" 44 "github.com/aldelo/common/wrapper/redis/redisdatatype" 45 "github.com/aldelo/common/wrapper/redis/rediskeytype" 46 "github.com/aldelo/common/wrapper/redis/redisradiusunit" 47 "github.com/aldelo/common/wrapper/redis/redissetcondition" 48 "github.com/aldelo/common/wrapper/xray" 49 "github.com/go-redis/redis/v8" 50 "strings" 51 52 "errors" 53 util "github.com/aldelo/common" 54 "time" 55 ) 56 57 // ================================================================================================================ 58 // STRUCTS 59 // ================================================================================================================ 60 61 // Redis defines wrapper struct to handle redis interactions with AWS ElasticCache Redis service (using go-redis package) 62 // 63 // IMPORTANT 64 // 65 // AWS ELASTICACHE REDIS lives within the VPC that the cluster is launched 66 // Access is allowed ONLY WITHIN EC2 in the same VPC 67 // There is no external public access since AWS Redis uses private IP only 68 // 69 // Dev Testing 70 // 71 // Test On AWS EC2 (via SSH into EC2) since elastic cache redis is deployed within vpc access only 72 // 73 // Reference Info 74 // 1. Redis Commands Documentation = https://redis.io/commands 75 // 2. Go-Redis Documentation = https://pkg.go.dev/github.com/go-redis/redis?tab=doc 76 type Redis struct { 77 // config fields 78 AwsRedisWriterEndpoint string 79 AwsRedisReaderEndpoint string 80 81 // client connection fields 82 cnWriter *redis.Client 83 cnReader *redis.Client 84 cnAreReady bool 85 86 // objects containing wrapped functions 87 BIT *BIT 88 LIST *LIST 89 HASH *HASH 90 SET *SET 91 SORTED_SET *SORTED_SET 92 GEO *GEO 93 STREAM *STREAM 94 PUBSUB *PUBSUB 95 PIPELINE *PIPELINE 96 TTL *TTL 97 UTILS *UTILS 98 99 _parentSegment *xray.XRayParentSegment 100 } 101 102 // BIT defines redis BIT operations 103 type BIT struct { 104 core *Redis 105 } 106 107 // SET defines redis SET operations 108 type SET struct { 109 core *Redis 110 } 111 112 // SORTED_SET defines SORTED SET operations 113 type SORTED_SET struct { 114 core *Redis 115 } 116 117 // LIST defines redis LIST operations 118 type LIST struct { 119 core *Redis 120 } 121 122 // HASH defines redis HASH operations 123 type HASH struct { 124 core *Redis 125 } 126 127 // GEO defines redis GEO operations 128 type GEO struct { 129 core *Redis 130 } 131 132 // STREAM defines redis STREAM operations 133 type STREAM struct { 134 core *Redis 135 } 136 137 // PUBSUB defines redis PUB SUB operations 138 type PUBSUB struct { 139 core *Redis 140 } 141 142 // PIPELINE defines batched pipeline patterns 143 type PIPELINE struct { 144 core *Redis 145 } 146 147 // TTL defines TTL and Persist related redis patterns 148 type TTL struct { 149 core *Redis 150 } 151 152 // UTILS defines redis helper functions 153 type UTILS struct { 154 core *Redis 155 } 156 157 // ================================================================================================================ 158 // STRUCTS FUNCTIONS 159 // ================================================================================================================ 160 161 // ---------------------------------------------------------------------------------------------------------------- 162 // connection functions 163 // ---------------------------------------------------------------------------------------------------------------- 164 165 // Connect will establish connection to aws elasticCache redis writer and reader endpoint connections. 166 func (r *Redis) Connect(parentSegment ...*xray.XRayParentSegment) (err error) { 167 if xray.XRayServiceOn() { 168 if len(parentSegment) > 0 { 169 r._parentSegment = parentSegment[0] 170 } 171 172 seg := xray.NewSegment("Redis-Connect", r._parentSegment) 173 defer seg.Close() 174 defer func() { 175 _ = seg.Seg.AddMetadata("Redis-Writer-Endpoint", r.AwsRedisWriterEndpoint) 176 _ = seg.Seg.AddMetadata("Redis-Reader-Endpoint", r.AwsRedisReaderEndpoint) 177 178 if err != nil { 179 _ = seg.Seg.AddError(err) 180 } 181 }() 182 183 err = r.connectInternal() 184 return err 185 } else { 186 return r.connectInternal() 187 } 188 } 189 190 // connectInternal performs the actual redis writer and reader connection 191 func (r *Redis) connectInternal() error { 192 // clean up prior cn reference 193 if r.BIT != nil { 194 r.BIT.core = nil 195 r.BIT = nil 196 } 197 198 if r.LIST != nil { 199 r.LIST.core = nil 200 r.LIST = nil 201 } 202 203 if r.HASH != nil { 204 r.HASH.core = nil 205 r.HASH = nil 206 } 207 208 if r.SET != nil { 209 r.SET.core = nil 210 r.SET = nil 211 } 212 213 if r.SORTED_SET != nil { 214 r.SORTED_SET.core = nil 215 r.SORTED_SET = nil 216 } 217 218 if r.GEO != nil { 219 r.GEO.core = nil 220 r.GEO = nil 221 } 222 223 if r.STREAM != nil { 224 r.STREAM.core = nil 225 r.STREAM = nil 226 } 227 228 if r.PUBSUB != nil { 229 r.PUBSUB.core = nil 230 r.PUBSUB = nil 231 } 232 233 if r.PIPELINE != nil { 234 r.PIPELINE.core = nil 235 r.PIPELINE = nil 236 } 237 238 if r.TTL != nil { 239 r.TTL.core = nil 240 r.TTL = nil 241 } 242 243 if r.UTILS != nil { 244 r.UTILS.core = nil 245 r.UTILS = nil 246 } 247 248 if r.cnWriter != nil { 249 _ = r.cnWriter.Close() 250 r.cnWriter = nil 251 } 252 253 if r.cnReader != nil { 254 _ = r.cnReader.Close() 255 r.cnReader = nil 256 } 257 258 // validate 259 if util.LenTrim(r.AwsRedisWriterEndpoint) <= 0 { 260 // writer endpoint works against the primary node 261 return errors.New("Connect To Redis Failed: " + "Writer Endpoint is Required") 262 } 263 264 if util.LenTrim(r.AwsRedisReaderEndpoint) <= 0 { 265 // reader endpoint is cluster level that works against all shards for read only access 266 return errors.New("Connect To Redis Failed: " + "Reader Endpoint is Required") 267 } 268 269 // establish new writer redis client 270 r.cnWriter = redis.NewClient(&redis.Options{ 271 Addr: r.AwsRedisWriterEndpoint, // redis endpoint url and port 272 Password: "", // no password set 273 DB: 0, // use default DB 274 ReadTimeout: 3 * time.Second, // time after read operation timeout 275 WriteTimeout: 3 * time.Second, // time after write operation timeout 276 PoolSize: 10, // 10 connections per every cpu 277 MinIdleConns: 3, // minimum number of idle connections to keep 278 }) 279 280 if r.cnWriter == nil { 281 return errors.New("Connect To Redis Failed: (Writer Endpoint) " + "Obtain Client Yielded Nil") 282 } 283 284 // establish new reader redis client 285 r.cnReader = redis.NewClient(&redis.Options{ 286 Addr: r.AwsRedisReaderEndpoint, // redis endpoint url and port 287 Password: "", // no password set 288 DB: 0, // use default DB 289 ReadTimeout: 3 * time.Second, // time after read operation timeout 290 WriteTimeout: 3 * time.Second, // time after write operation timeout 291 PoolSize: 10, // 10 connections per every cpu 292 MinIdleConns: 3, // minimum number of idle connections to keep 293 }) 294 295 if r.cnReader == nil { 296 return errors.New("Connect To Redis Failed: (Reader Endpoint) " + "Obtain Client Yielded Nil") 297 } 298 299 // once writer and readers are all connected, set reference to helper struct objects 300 r.BIT = new(BIT) 301 r.BIT.core = r 302 303 r.LIST = new(LIST) 304 r.LIST.core = r 305 306 r.HASH = new(HASH) 307 r.HASH.core = r 308 309 r.SET = new(SET) 310 r.SET.core = r 311 312 r.SORTED_SET = new(SORTED_SET) 313 r.SORTED_SET.core = r 314 315 r.GEO = new(GEO) 316 r.GEO.core = r 317 318 r.STREAM = new(STREAM) 319 r.STREAM.core = r 320 321 r.PUBSUB = new(PUBSUB) 322 r.PUBSUB.core = r 323 324 r.PIPELINE = new(PIPELINE) 325 r.PIPELINE.core = r 326 327 r.TTL = new(TTL) 328 r.TTL.core = r 329 330 r.UTILS = new(UTILS) 331 r.UTILS.core = r 332 333 // ready 334 r.cnAreReady = true 335 336 // success 337 return nil 338 } 339 340 // Disconnect will close aws redis writer and reader endpoints 341 func (r *Redis) Disconnect() { 342 // clean up prior cn reference 343 if r.BIT != nil { 344 r.BIT.core = nil 345 r.BIT = nil 346 } 347 348 if r.LIST != nil { 349 r.LIST.core = nil 350 r.LIST = nil 351 } 352 353 if r.HASH != nil { 354 r.HASH.core = nil 355 r.HASH = nil 356 } 357 358 if r.SET != nil { 359 r.SET.core = nil 360 r.SET = nil 361 } 362 363 if r.SORTED_SET != nil { 364 r.SORTED_SET.core = nil 365 r.SORTED_SET = nil 366 } 367 368 if r.GEO != nil { 369 r.GEO.core = nil 370 r.GEO = nil 371 } 372 373 if r.STREAM != nil { 374 r.STREAM.core = nil 375 r.STREAM = nil 376 } 377 378 if r.PUBSUB != nil { 379 r.PUBSUB.core = nil 380 r.PUBSUB = nil 381 } 382 383 if r.PIPELINE != nil { 384 r.PIPELINE.core = nil 385 r.PIPELINE = nil 386 } 387 388 if r.TTL != nil { 389 r.TTL.core = nil 390 r.TTL = nil 391 } 392 393 if r.UTILS != nil { 394 r.UTILS.core = nil 395 r.UTILS = nil 396 } 397 398 if r.cnWriter != nil { 399 _ = r.cnWriter.Close() 400 r.cnWriter = nil 401 } 402 403 if r.cnReader != nil { 404 _ = r.cnReader.Close() 405 r.cnReader = nil 406 } 407 408 r.cnAreReady = false 409 } 410 411 // UpdateParentSegment updates this struct's xray parent segment, if no parent segment, set nil 412 func (r *Redis) UpdateParentSegment(parentSegment *xray.XRayParentSegment) { 413 r._parentSegment = parentSegment 414 } 415 416 // ---------------------------------------------------------------------------------------------------------------- 417 // Cmd Result and Error Handling functions 418 // ---------------------------------------------------------------------------------------------------------------- 419 420 // handleStatusCmd evaluates redis StatusCmd struct, and returns error struct if applicable, 421 // error = nil indicates success 422 func (r *Redis) handleStatusCmd(statusCmd *redis.StatusCmd, errorTextPrefix ...string) error { 423 prefix := "" 424 425 if len(errorTextPrefix) > 0 { 426 prefix = errorTextPrefix[0] 427 } 428 429 if statusCmd == nil { 430 return errors.New(prefix + "Redis StatusCmd Result Yielded Nil") 431 } else { 432 if statusCmd.Err() != nil { 433 // has error encountered 434 return errors.New(prefix + statusCmd.Err().Error()) 435 } else { 436 // no error encountered 437 return nil 438 } 439 } 440 } 441 442 // handleStringStatusCmd evaluates redis StringStatusCmd struct, and returns error struct if applicable, 443 // error = nil indicates success 444 func (r *Redis) handleStringStatusCmd(statusCmd *redis.StatusCmd, errorTextPrefix ...string) (val string, notFound bool, err error) { 445 prefix := "" 446 447 if len(errorTextPrefix) > 0 { 448 prefix = errorTextPrefix[0] 449 } 450 451 if statusCmd == nil { 452 return "", false, errors.New(prefix + "Redis StatusCmd Result Yielded Nil") 453 } else { 454 if statusCmd.Err() != nil { 455 if statusCmd.Err() == redis.Nil { 456 // not found 457 return "", true, nil 458 } else { 459 // has error encountered 460 return "", false, errors.New(prefix + statusCmd.Err().Error()) 461 } 462 } else { 463 // no error encountered 464 if val, err = statusCmd.Result(); err != nil { 465 return "", false, errors.New(prefix + "[Result to String Errored] " + err.Error()) 466 } else { 467 return val, false, nil 468 } 469 } 470 } 471 } 472 473 // handleBoolCmd evaluates redis BoolCmd struct, and returns error struct if applicable, 474 // error = nil indicates success 475 func (r *Redis) handleBoolCmd(boolCmd *redis.BoolCmd, errorTextPrefix ...string) (val bool, err error) { 476 prefix := "" 477 478 if len(errorTextPrefix) > 0 { 479 prefix = errorTextPrefix[0] 480 } 481 482 if boolCmd == nil { 483 return false, errors.New(prefix + "Redis BoolCmd Result Yielded Nil") 484 } else { 485 if boolCmd.Err() != nil { 486 // has error encountered 487 return false, errors.New(prefix + boolCmd.Err().Error()) 488 } else { 489 // no error encountered 490 return boolCmd.Val(), nil 491 } 492 } 493 } 494 495 // handleIntCmd evaluates redis IntCmd struct, and returns error struct if applicable, 496 // error = nil indicates success 497 func (r *Redis) handleIntCmd(intCmd *redis.IntCmd, errorTextPrefix ...string) (val int64, notFound bool, err error) { 498 prefix := "" 499 500 if len(errorTextPrefix) > 0 { 501 prefix = errorTextPrefix[0] 502 } 503 504 if intCmd == nil { 505 return 0, false, errors.New(prefix + "Redis IntCmd Result Yielded Nil") 506 } else { 507 if intCmd.Err() != nil { 508 if intCmd.Err() == redis.Nil { 509 // not found 510 return 0, true, nil 511 } else { 512 // other error 513 return 0, false, errors.New(prefix + intCmd.Err().Error()) 514 } 515 } else { 516 // no error encountered 517 if val, err = intCmd.Result(); err != nil { 518 return 0, false, errors.New(prefix + "[Result to Int64 Errored] " + err.Error()) 519 } else { 520 return val, false, nil 521 } 522 } 523 } 524 } 525 526 // handleIntCmd2 evaluates redis IntCmd struct, and returns error struct if result is 0 or actual error 527 func (r *Redis) handleIntCmd2(intCmd *redis.IntCmd, errorTextPrefix ...string) error { 528 prefix := "" 529 530 if len(errorTextPrefix) > 0 { 531 prefix = errorTextPrefix[0] 532 } 533 534 if intCmd == nil { 535 return errors.New(prefix + "Redis IntCmd Result Yielded Nil") 536 } else { 537 if intCmd.Err() != nil { 538 return errors.New(prefix + intCmd.Err().Error()) 539 } else { 540 // no error encountered 541 if val, err := intCmd.Result(); err != nil { 542 return errors.New(prefix + "[Result to Int64 Errored] " + err.Error()) 543 } else { 544 if val == 0 { 545 // fail 546 return errors.New(prefix + "[No Records Affected] Action Yielded No Change") 547 } else { 548 // success 549 return nil 550 } 551 } 552 } 553 } 554 } 555 556 // handleFloatCmd evaluates redis FloatCmd struct, and returns error struct if applicable, 557 // error = nil indicates success 558 func (r *Redis) handleFloatCmd(floatCmd *redis.FloatCmd, errorTextPrefix ...string) (val float64, notFound bool, err error) { 559 prefix := "" 560 561 if len(errorTextPrefix) > 0 { 562 prefix = errorTextPrefix[0] 563 } 564 565 if floatCmd == nil { 566 return 0.00, false, errors.New(prefix + "Redis FloatCmd Result Yielded Nil") 567 } else { 568 if floatCmd.Err() != nil { 569 if floatCmd.Err() == redis.Nil { 570 // not found 571 return 0.00, true, nil 572 } else { 573 // other error 574 return 0.00, false, errors.New(prefix + floatCmd.Err().Error()) 575 } 576 } else { 577 // no error encountered 578 if val, err = floatCmd.Result(); err != nil { 579 return 0.00, false, errors.New(prefix + "[Result to Float64 Errored] " + err.Error()) 580 } else { 581 return val, false, nil 582 } 583 } 584 } 585 } 586 587 // handleTimeCmd evaluates redis TimeCmd struct, and returns error struct if applicable, 588 // error = nil indicates success 589 func (r *Redis) handleTimeCmd(timeCmd *redis.TimeCmd, errorTextPrefix ...string) (val time.Time, notFound bool, err error) { 590 prefix := "" 591 592 if len(errorTextPrefix) > 0 { 593 prefix = errorTextPrefix[0] 594 } 595 596 if timeCmd == nil { 597 return time.Time{}, false, errors.New(prefix + "Redis TimeCmd Result Yielded Nil") 598 } else { 599 if timeCmd.Err() != nil { 600 if timeCmd.Err() == redis.Nil { 601 // not found 602 return time.Time{}, true, nil 603 } else { 604 // other error 605 return time.Time{}, false, errors.New(prefix + timeCmd.Err().Error()) 606 } 607 } else { 608 // no error encountered 609 if val, err = timeCmd.Result(); err != nil { 610 return time.Time{}, false, errors.New(prefix + "[Result to Time Errored] " + err.Error()) 611 } else { 612 return val, false, nil 613 } 614 } 615 } 616 } 617 618 // handleDurationCmd evaluates redis DurationCmd struct, and returns error struct if applicable, 619 // error = nil indicates success 620 func (r *Redis) handleDurationCmd(durationCmd *redis.DurationCmd, errorTextPrefix ...string) (val time.Duration, notFound bool, err error) { 621 prefix := "" 622 623 if len(errorTextPrefix) > 0 { 624 prefix = errorTextPrefix[0] 625 } 626 627 if durationCmd == nil { 628 return 0, false, errors.New(prefix + "Redis DurationCmd Result Yielded Nil") 629 } else { 630 if durationCmd.Err() != nil { 631 if durationCmd.Err() == redis.Nil { 632 // not found 633 return 0, true, nil 634 } else { 635 // other error 636 return 0, false, errors.New(prefix + durationCmd.Err().Error()) 637 } 638 } else { 639 // no error encountered 640 if val, err = durationCmd.Result(); err != nil { 641 return 0, false, errors.New(prefix + "[Result to Duration Errored] " + err.Error()) 642 } else { 643 return val, false, nil 644 } 645 } 646 } 647 } 648 649 // handleStringCmd2 evaluates redis StringCmd struct, and returns error struct if applicable, 650 // error = nil indicates success 651 func (r *Redis) handleStringCmd2(stringCmd *redis.StringCmd, errorTextPrefix ...string) (val string, notFound bool, err error) { 652 prefix := "" 653 654 if len(errorTextPrefix) > 0 { 655 prefix = errorTextPrefix[0] 656 } 657 658 if stringCmd == nil { 659 return "", false, errors.New(prefix + "Redis StringCmd Result Yielded Nil") 660 } else { 661 if stringCmd.Err() != nil { 662 if stringCmd.Err() == redis.Nil { 663 // not found 664 return "", true, nil 665 } else { 666 // other error 667 return "", false, errors.New(prefix + stringCmd.Err().Error()) 668 } 669 } else { 670 // no error encountered 671 if val, err = stringCmd.Result(); err != nil { 672 return "", false, errors.New(prefix + "[Result to String Errored] " + err.Error()) 673 } else { 674 return val, false, nil 675 } 676 } 677 } 678 } 679 680 // handleStringCmd evaluates redis StringCmd struct, and related results and error if applicable 681 func (r *Redis) handleStringCmd(stringCmd *redis.StringCmd, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}, errorTextPrefix ...string) (notFound bool, err error) { 682 prefix := "" 683 684 if len(errorTextPrefix) > 0 { 685 prefix = errorTextPrefix[0] 686 } 687 688 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 689 return false, errors.New(prefix + "Result Output Data Type is Required") 690 } 691 692 if outputObjectPtr == nil { 693 return false, errors.New(prefix + "Result Output Data Object Pointer is Required") 694 } 695 696 if stringCmd == nil { 697 return false, errors.New(prefix + "Redis StringCmd Result Yielded Nil") 698 } else { 699 if stringCmd.Err() != nil { 700 // has error encountered 701 if stringCmd.Err() == redis.Nil { 702 // not found 703 return true, nil 704 } else { 705 // other error 706 return false, errors.New(prefix + stringCmd.Err().Error()) 707 } 708 } else { 709 // no error, evaluate result 710 switch outputDataType { 711 case redisdatatype.Bool: 712 // result to bool 713 if val, e := stringCmd.Result(); e != nil { 714 return false, errors.New(prefix + "[Result to Bool Errored] " + e.Error()) 715 } else { 716 // success 717 if output, success := util.ParseBool(val); !success { 718 return false, errors.New(prefix + "[Result to Bool Errored] Parse Str to Bool Not OK") 719 } else { 720 outputObjectPtr = output 721 return false, nil 722 } 723 } 724 case redisdatatype.Int: 725 // result to int 726 if val, e := stringCmd.Int(); e != nil { 727 return false, errors.New(prefix + "[Result to Int Errored] " + e.Error()) 728 } else { 729 // success 730 outputObjectPtr = val 731 return false, nil 732 } 733 case redisdatatype.Int64: 734 // result to int64 735 if val, e := stringCmd.Int64(); e != nil { 736 return false, errors.New(prefix + "[Result to Int64 Errored] " + e.Error()) 737 } else { 738 // success 739 outputObjectPtr = val 740 return false, nil 741 } 742 case redisdatatype.Float64: 743 // result to float64 744 if val, e := stringCmd.Float64(); e != nil { 745 return false, errors.New(prefix + "[Result to Float64 Errored] " + e.Error()) 746 } else { 747 // success 748 outputObjectPtr = val 749 return false, nil 750 } 751 case redisdatatype.Bytes: 752 // result to []byte 753 if val, e := stringCmd.Bytes(); e != nil { 754 return false, errors.New(prefix + "[Result to Bytes Errored] " + e.Error()) 755 } else { 756 // success 757 outputObjectPtr = val 758 return false, nil 759 } 760 case redisdatatype.Json: 761 // result to json 762 if str, e := stringCmd.Result(); e != nil { 763 return false, errors.New(prefix + "[Result to Json Errored] " + e.Error()) 764 } else { 765 // ready to unmarshal json to object 766 // found str value, 767 // unmarshal to json 768 if util.LenTrim(str) <= 0 { 769 return true, nil 770 } else { 771 if err = util.UnmarshalJSON(str, outputObjectPtr); err != nil { 772 // unmarshal error 773 return false, errors.New(prefix + "[Result to Json Errored] Unmarshal Json Failed " + err.Error()) 774 } else { 775 // unmarshal success 776 return false, nil 777 } 778 } 779 } 780 case redisdatatype.Time: 781 // result to int 782 if val, e := stringCmd.Time(); e != nil { 783 return false, errors.New(prefix + "[Result to Time Errored] " + e.Error()) 784 } else { 785 // success 786 outputObjectPtr = val 787 return false, nil 788 } 789 default: 790 // default is string 791 if str, e := stringCmd.Result(); e != nil { 792 return false, errors.New(prefix + "[Result to String Errored] " + e.Error()) 793 } else { 794 // success 795 outputObjectPtr = str 796 return false, nil 797 } 798 } 799 } 800 } 801 } 802 803 // handleSliceCmd evaluates redis SliceCmd struct, and related results and error if applicable 804 func (r *Redis) handleSliceCmd(sliceCmd *redis.SliceCmd, errorTextPrefix ...string) (outputSlice []interface{}, notFound bool, err error) { 805 prefix := "" 806 807 if len(errorTextPrefix) > 0 { 808 prefix = errorTextPrefix[0] 809 } 810 811 if sliceCmd == nil { 812 return nil, false, errors.New(prefix + "Redis SliceCmd Result Yielded Nil") 813 } else { 814 if sliceCmd.Err() != nil { 815 // has error encountered 816 if sliceCmd.Err() == redis.Nil { 817 // not found 818 return nil, true, nil 819 } else { 820 // other error 821 return nil, false, errors.New(prefix + sliceCmd.Err().Error()) 822 } 823 } else { 824 // no error, evaluate result 825 if outputSlice, err = sliceCmd.Result(); err != nil { 826 // error 827 return nil, false, errors.New(prefix + "[Result to Slice Errored] " + err.Error()) 828 } else { 829 // success 830 if len(outputSlice) > 0 { 831 return outputSlice, false, nil 832 } else { 833 return nil, true, nil 834 } 835 } 836 } 837 } 838 } 839 840 // handleStringSliceCmd evaluates redis StringSliceCmd struct, and related results and error if applicable 841 func (r *Redis) handleStringSliceCmd(stringSliceCmd *redis.StringSliceCmd, errorTextPrefix ...string) (outputSlice []string, notFound bool, err error) { 842 prefix := "" 843 844 if len(errorTextPrefix) > 0 { 845 prefix = errorTextPrefix[0] 846 } 847 848 if stringSliceCmd == nil { 849 return nil, false, errors.New(prefix + "Redis StringSliceCmd Result Yielded Nil") 850 } else { 851 if stringSliceCmd.Err() != nil { 852 // has error encountered 853 if stringSliceCmd.Err() == redis.Nil { 854 // not found 855 return nil, true, nil 856 } else { 857 // other error 858 return nil, false, errors.New(prefix + stringSliceCmd.Err().Error()) 859 } 860 } else { 861 // no error, evaluate result 862 if outputSlice, err = stringSliceCmd.Result(); err != nil { 863 // error 864 return nil, false, errors.New(prefix + "[Result to String Slice Errored] " + err.Error()) 865 } else { 866 // success 867 if len(outputSlice) > 0 { 868 return outputSlice, false, nil 869 } else { 870 return nil, true, nil 871 } 872 } 873 } 874 } 875 } 876 877 // handleIntSliceCmd evaluates redis IntSliceCmd struct, and related results and error if applicable 878 func (r *Redis) handleIntSliceCmd(intSliceCmd *redis.IntSliceCmd, errorTextPrefix ...string) (outputSlice []int64, notFound bool, err error) { 879 prefix := "" 880 881 if len(errorTextPrefix) > 0 { 882 prefix = errorTextPrefix[0] 883 } 884 885 if intSliceCmd == nil { 886 return nil, false, errors.New(prefix + "Redis IntSliceCmd Result Yielded Nil") 887 } else { 888 if intSliceCmd.Err() != nil { 889 // has error encountered 890 if intSliceCmd.Err() == redis.Nil { 891 // not found 892 return nil, true, nil 893 } else { 894 // other error 895 return nil, false, errors.New(prefix + intSliceCmd.Err().Error()) 896 } 897 } else { 898 // no error, evaluate result 899 if outputSlice, err = intSliceCmd.Result(); err != nil { 900 // error 901 return nil, false, errors.New(prefix + "[Result to Int64 Slice Errored] " + err.Error()) 902 } else { 903 // success 904 if len(outputSlice) > 0 { 905 return outputSlice, false, nil 906 } else { 907 return nil, true, nil 908 } 909 } 910 } 911 } 912 } 913 914 // handleBoolSliceCmd evaluates redis BoolSliceCmd struct, and related results and error if applicable 915 func (r *Redis) handleBoolSliceCmd(boolSliceCmd *redis.BoolSliceCmd, errorTextPrefix ...string) (outputSlice []bool, notFound bool, err error) { 916 prefix := "" 917 918 if len(errorTextPrefix) > 0 { 919 prefix = errorTextPrefix[0] 920 } 921 922 if boolSliceCmd == nil { 923 return nil, false, errors.New(prefix + "Redis BoolSliceCmd Result Yielded Nil") 924 } else { 925 if boolSliceCmd.Err() != nil { 926 // has error encountered 927 if boolSliceCmd.Err() == redis.Nil { 928 // not found 929 return nil, true, nil 930 } else { 931 // other error 932 return nil, false, errors.New(prefix + boolSliceCmd.Err().Error()) 933 } 934 } else { 935 // no error, evaluate result 936 if outputSlice, err = boolSliceCmd.Result(); err != nil { 937 // error 938 return nil, false, errors.New(prefix + "[Result to Bool Slice Errored] " + err.Error()) 939 } else { 940 // success 941 if len(outputSlice) > 0 { 942 return outputSlice, false, nil 943 } else { 944 return nil, true, nil 945 } 946 } 947 } 948 } 949 } 950 951 // handleZSliceCmd evaluates redis ZSliceCmd struct, and related results and error if applicable 952 func (r *Redis) handleZSliceCmd(zSliceCmd *redis.ZSliceCmd, errorTextPrefix ...string) (outputSlice []redis.Z, notFound bool, err error) { 953 prefix := "" 954 955 if len(errorTextPrefix) > 0 { 956 prefix = errorTextPrefix[0] 957 } 958 959 if zSliceCmd == nil { 960 return nil, false, errors.New(prefix + "Redis ZSliceCmd Result Yielded Nil") 961 } else { 962 if zSliceCmd.Err() != nil { 963 // has error encountered 964 if zSliceCmd.Err() == redis.Nil { 965 // not found 966 return nil, true, nil 967 } else { 968 // other error 969 return nil, false, errors.New(prefix + zSliceCmd.Err().Error()) 970 } 971 } else { 972 // no error, evaluate result 973 if outputSlice, err = zSliceCmd.Result(); err != nil { 974 // error 975 return nil, false, errors.New(prefix + "[Result to Z Slice Errored] " + err.Error()) 976 } else { 977 // success 978 if len(outputSlice) > 0 { 979 return outputSlice, false, nil 980 } else { 981 return nil, true, nil 982 } 983 } 984 } 985 } 986 } 987 988 // handleXMessageSliceCmd evaluates redis XMessageSliceCmd struct, and related results and error if applicable 989 func (r *Redis) handleXMessageSliceCmd(xmessageSliceCmd *redis.XMessageSliceCmd, errorTextPrefix ...string) (outputSlice []redis.XMessage, notFound bool, err error) { 990 prefix := "" 991 992 if len(errorTextPrefix) > 0 { 993 prefix = errorTextPrefix[0] 994 } 995 996 if xmessageSliceCmd == nil { 997 return nil, false, errors.New(prefix + "Redis XMessageSliceCmd Result Yielded Nil") 998 } else { 999 if xmessageSliceCmd.Err() != nil { 1000 // has error encountered 1001 if xmessageSliceCmd.Err() == redis.Nil { 1002 // not found 1003 return nil, true, nil 1004 } else { 1005 // other error 1006 return nil, false, errors.New(prefix + xmessageSliceCmd.Err().Error()) 1007 } 1008 } else { 1009 // no error, evaluate result 1010 if outputSlice, err = xmessageSliceCmd.Result(); err != nil { 1011 // error 1012 return nil, false, errors.New(prefix + "[Result to XMessage Slice Errored] " + err.Error()) 1013 } else { 1014 // success 1015 if len(outputSlice) > 0 { 1016 return outputSlice, false, nil 1017 } else { 1018 return nil, true, nil 1019 } 1020 } 1021 } 1022 } 1023 } 1024 1025 // handleXStreamSliceCmd evaluates redis XStreamSliceCmd struct, and related results and error if applicable 1026 func (r *Redis) handleXStreamSliceCmd(xstreamSliceCmd *redis.XStreamSliceCmd, errorTextPrefix ...string) (outputSlice []redis.XStream, notFound bool, err error) { 1027 prefix := "" 1028 1029 if len(errorTextPrefix) > 0 { 1030 prefix = errorTextPrefix[0] 1031 } 1032 1033 if xstreamSliceCmd == nil { 1034 return nil, false, errors.New(prefix + "Redis XStreamSliceCmd Result Yielded Nil") 1035 } else { 1036 if xstreamSliceCmd.Err() != nil { 1037 // has error encountered 1038 if xstreamSliceCmd.Err() == redis.Nil { 1039 // not found 1040 return nil, true, nil 1041 } else { 1042 // other error 1043 return nil, false, errors.New(prefix + xstreamSliceCmd.Err().Error()) 1044 } 1045 } else { 1046 // no error, evaluate result 1047 if outputSlice, err = xstreamSliceCmd.Result(); err != nil { 1048 // error 1049 return nil, false, errors.New(prefix + "[Result to XStream Slice Errored] " + err.Error()) 1050 } else { 1051 // success 1052 if len(outputSlice) > 0 { 1053 return outputSlice, false, nil 1054 } else { 1055 return nil, true, nil 1056 } 1057 } 1058 } 1059 } 1060 } 1061 1062 // handleXInfoGroupsCmd evaluates redis XInfoGroupsCmd struct, and related results and error if applicable 1063 func (r *Redis) handleXInfoGroupsCmd(xinfoGroupsCmd *redis.XInfoGroupsCmd, errorTextPrefix ...string) (outputSlice []redis.XInfoGroup, notFound bool, err error) { 1064 prefix := "" 1065 1066 if len(errorTextPrefix) > 0 { 1067 prefix = errorTextPrefix[0] 1068 } 1069 1070 if xinfoGroupsCmd == nil { 1071 return nil, false, errors.New(prefix + "Redis XInfoGroupsCmd Result Yielded Nil") 1072 } else { 1073 if xinfoGroupsCmd.Err() != nil { 1074 // has error encountered 1075 if xinfoGroupsCmd.Err() == redis.Nil { 1076 // not found 1077 return nil, true, nil 1078 } else { 1079 // other error 1080 return nil, false, errors.New(prefix + xinfoGroupsCmd.Err().Error()) 1081 } 1082 } else { 1083 // no error, evaluate result 1084 if outputSlice, err = xinfoGroupsCmd.Result(); err != nil { 1085 // error 1086 return nil, false, errors.New(prefix + "[Result to XInfoGroups Errored] " + err.Error()) 1087 } else { 1088 // success 1089 if len(outputSlice) > 0 { 1090 return outputSlice, false, nil 1091 } else { 1092 return nil, true, nil 1093 } 1094 } 1095 } 1096 } 1097 } 1098 1099 // handleScanCmd evaluates redis ScanCmd struct, and returns error struct if applicable, 1100 // error = nil indicates success 1101 func (r *Redis) handleScanCmd(scanCmd *redis.ScanCmd, errorTextPrefix ...string) (keys []string, cursor uint64, err error) { 1102 prefix := "" 1103 1104 if len(errorTextPrefix) > 0 { 1105 prefix = errorTextPrefix[0] 1106 } 1107 1108 if scanCmd == nil { 1109 return nil, 0, errors.New(prefix + "Redis ScanCmd Result Yielded Nil") 1110 } else { 1111 if scanCmd.Err() != nil { 1112 if scanCmd.Err() == redis.Nil { 1113 // not found 1114 return nil, 0, nil 1115 } else { 1116 // other error 1117 return nil, 0, errors.New(prefix + scanCmd.Err().Error()) 1118 } 1119 } else { 1120 // no error encountered 1121 return scanCmd.Result() 1122 } 1123 } 1124 } 1125 1126 // handleXPendingCmd evaluates redis XPendingCmd struct, and related results and error if applicable 1127 func (r *Redis) handleXPendingCmd(xpendingCmd *redis.XPendingCmd, errorTextPrefix ...string) (output *redis.XPending, notFound bool, err error) { 1128 prefix := "" 1129 1130 if len(errorTextPrefix) > 0 { 1131 prefix = errorTextPrefix[0] 1132 } 1133 1134 if xpendingCmd == nil { 1135 return nil, false, errors.New(prefix + "Redis XPendingCmd Result Yielded Nil") 1136 } else { 1137 if xpendingCmd.Err() != nil { 1138 // has error encountered 1139 if xpendingCmd.Err() == redis.Nil { 1140 // not found 1141 return nil, true, nil 1142 } else { 1143 // other error 1144 return nil, false, errors.New(prefix + xpendingCmd.Err().Error()) 1145 } 1146 } else { 1147 // no error, evaluate result 1148 if output, err = xpendingCmd.Result(); err != nil { 1149 // error 1150 return nil, false, errors.New(prefix + "[Result to XPending Errored] " + err.Error()) 1151 } else { 1152 // success 1153 if output != nil { 1154 return output, false, nil 1155 } else { 1156 return nil, true, nil 1157 } 1158 } 1159 } 1160 } 1161 } 1162 1163 // handleXPendingExtCmd evaluates redis XPendingExtCmd struct, and related results and error if applicable 1164 func (r *Redis) handleXPendingExtCmd(xpendingExtCmd *redis.XPendingExtCmd, errorTextPrefix ...string) (outputSlice []redis.XPendingExt, notFound bool, err error) { 1165 prefix := "" 1166 1167 if len(errorTextPrefix) > 0 { 1168 prefix = errorTextPrefix[0] 1169 } 1170 1171 if xpendingExtCmd == nil { 1172 return nil, false, errors.New(prefix + "Redis XPendingExtCmd Result Yielded Nil") 1173 } else { 1174 if xpendingExtCmd.Err() != nil { 1175 // has error encountered 1176 if xpendingExtCmd.Err() == redis.Nil { 1177 // not found 1178 return nil, true, nil 1179 } else { 1180 // other error 1181 return nil, false, errors.New(prefix + xpendingExtCmd.Err().Error()) 1182 } 1183 } else { 1184 // no error, evaluate result 1185 if outputSlice, err = xpendingExtCmd.Result(); err != nil { 1186 // error 1187 return nil, false, errors.New(prefix + "[Result to XPendingExt Errored] " + err.Error()) 1188 } else { 1189 // success 1190 if len(outputSlice) > 0 { 1191 return outputSlice, false, nil 1192 } else { 1193 return nil, true, nil 1194 } 1195 } 1196 } 1197 } 1198 } 1199 1200 // handleStringIntMapCmd evaluates redis StringIntMapCmd struct, and related results and error if applicable 1201 func (r *Redis) handleStringIntMapCmd(stringIntMapCmd *redis.StringIntMapCmd, errorTextPrefix ...string) (outputMap map[string]int64, notFound bool, err error) { 1202 prefix := "" 1203 1204 if len(errorTextPrefix) > 0 { 1205 prefix = errorTextPrefix[0] 1206 } 1207 1208 if stringIntMapCmd == nil { 1209 return nil, false, errors.New(prefix + "Redis String-Int-Map Result Yielded Nil") 1210 } else { 1211 if stringIntMapCmd.Err() != nil { 1212 // has error encountered 1213 if stringIntMapCmd.Err() == redis.Nil { 1214 // not found 1215 return nil, true, nil 1216 } else { 1217 // other error 1218 return nil, false, errors.New(prefix + stringIntMapCmd.Err().Error()) 1219 } 1220 } else { 1221 // no error, evaluate result 1222 if outputMap, err = stringIntMapCmd.Result(); err != nil { 1223 // error 1224 return nil, false, errors.New(prefix + "[Result to String-Int-Map Errored] " + err.Error()) 1225 } else { 1226 // success 1227 return outputMap, false, nil 1228 } 1229 } 1230 } 1231 } 1232 1233 // handleStringStringMapCmd evaluates redis StringStringMapCmd struct, and related results and error if applicable 1234 func (r *Redis) handleStringStringMapCmd(stringStringMapCmd *redis.StringStringMapCmd, errorTextPrefix ...string) (outputMap map[string]string, notFound bool, err error) { 1235 prefix := "" 1236 1237 if len(errorTextPrefix) > 0 { 1238 prefix = errorTextPrefix[0] 1239 } 1240 1241 if stringStringMapCmd == nil { 1242 return nil, false, errors.New(prefix + "Redis String-String-Map Result Yielded Nil") 1243 } else { 1244 if stringStringMapCmd.Err() != nil { 1245 // has error encountered 1246 if stringStringMapCmd.Err() == redis.Nil { 1247 // not found 1248 return nil, true, nil 1249 } else { 1250 // other error 1251 return nil, false, errors.New(prefix + stringStringMapCmd.Err().Error()) 1252 } 1253 } else { 1254 // no error, evaluate result 1255 if outputMap, err = stringStringMapCmd.Result(); err != nil { 1256 // error 1257 return nil, false, errors.New(prefix + "[Result to String-String-Map Errored] " + err.Error()) 1258 } else { 1259 // success 1260 return outputMap, false, nil 1261 } 1262 } 1263 } 1264 } 1265 1266 // handleStringStructMapCmd evaluates redis StringStructMapCmd struct, and related results and error if applicable 1267 func (r *Redis) handleStringStructMapCmd(stringStructMapCmd *redis.StringStructMapCmd, errorTextPrefix ...string) (outputMap map[string]struct{}, notFound bool, err error) { 1268 prefix := "" 1269 1270 if len(errorTextPrefix) > 0 { 1271 prefix = errorTextPrefix[0] 1272 } 1273 1274 if stringStructMapCmd == nil { 1275 return nil, false, errors.New(prefix + "Redis String-Struct-Map Result Yielded Nil") 1276 } else { 1277 if stringStructMapCmd.Err() != nil { 1278 // has error encountered 1279 if stringStructMapCmd.Err() == redis.Nil { 1280 // not found 1281 return nil, true, nil 1282 } else { 1283 // other error 1284 return nil, false, errors.New(prefix + stringStructMapCmd.Err().Error()) 1285 } 1286 } else { 1287 // no error, evaluate result 1288 if outputMap, err = stringStructMapCmd.Result(); err != nil { 1289 // error 1290 return nil, false, errors.New(prefix + "[Result to String-Struct-Map Errored] " + err.Error()) 1291 } else { 1292 // success 1293 return outputMap, false, nil 1294 } 1295 } 1296 } 1297 } 1298 1299 // ---------------------------------------------------------------------------------------------------------------- 1300 // Set and Get functions 1301 // ---------------------------------------------------------------------------------------------------------------- 1302 1303 // SetBase is helper to set value into redis by key. 1304 // 1305 // notes 1306 // 1307 // setCondition = support for SetNX and SetXX 1308 func (r *Redis) SetBase(key string, val interface{}, setCondition redissetcondition.RedisSetCondition, expires ...time.Duration) (err error) { 1309 // get new xray segment for tracing 1310 seg := xray.NewSegmentNullable("Redis-Set", r._parentSegment) 1311 1312 if seg != nil { 1313 defer seg.Close() 1314 defer func() { 1315 _ = seg.Seg.AddMetadata("Redis-Set-Key", key) 1316 _ = seg.Seg.AddMetadata("Redis-Set-Value", val) 1317 _ = seg.Seg.AddMetadata("Redis-Set-Condition", setCondition.Caption()) 1318 1319 if len(expires) > 0 { 1320 _ = seg.Seg.AddMetadata("Redis-Set-Expire-Seconds", expires[0].Seconds()) 1321 } else { 1322 _ = seg.Seg.AddMetadata("Redis-Set-Expire-Seconds", "Not Defined") 1323 } 1324 1325 if err != nil { 1326 _ = seg.Seg.AddError(err) 1327 } 1328 }() 1329 1330 err = r.setBaseInternal(key, val, setCondition, expires...) 1331 return err 1332 } else { 1333 return r.setBaseInternal(key, val, setCondition, expires...) 1334 } 1335 } 1336 1337 // setBaseInternal is helper to set value into redis by key 1338 // 1339 // notes 1340 // 1341 // setCondition = support for SetNX and SetXX 1342 func (r *Redis) setBaseInternal(key string, val interface{}, setCondition redissetcondition.RedisSetCondition, expires ...time.Duration) error { 1343 // validate 1344 if !r.cnAreReady { 1345 return errors.New("Redis Set Failed: " + "Endpoint Connections Not Ready") 1346 } 1347 1348 if util.LenTrim(key) <= 0 { 1349 return errors.New("Redis Set Failed: " + "Key is Required") 1350 } 1351 1352 // persist value to redis 1353 var expireDuration time.Duration 1354 1355 if len(expires) > 0 { 1356 expireDuration = expires[0] 1357 } 1358 1359 switch setCondition { 1360 case redissetcondition.Normal: 1361 cmd := r.cnWriter.Set(r.cnWriter.Context(), key, val, expireDuration) 1362 return r.handleStatusCmd(cmd, "Redis Set Failed: (Set Method) ") 1363 1364 case redissetcondition.SetIfExists: 1365 cmd := r.cnWriter.SetXX(r.cnWriter.Context(), key, val, expireDuration) 1366 if val, err := r.handleBoolCmd(cmd, "Redis Set Failed: (SetXX Method) "); err != nil { 1367 return err 1368 } else { 1369 if val { 1370 // success 1371 return nil 1372 } else { 1373 // not success 1374 return errors.New("Redis Set Failed: (SetXX Method) " + "Key Was Not Set") 1375 } 1376 } 1377 1378 case redissetcondition.SetIfNotExists: 1379 cmd := r.cnWriter.SetNX(r.cnWriter.Context(), key, val, expireDuration) 1380 if val, err := r.handleBoolCmd(cmd, "Redis Set Failed: (SetNX Method) "); err != nil { 1381 return err 1382 } else { 1383 if val { 1384 // success 1385 return nil 1386 } else { 1387 // not success 1388 return errors.New("Redis Set Failed: (SetNX Method) " + "Key Was Not Set") 1389 } 1390 } 1391 1392 default: 1393 return errors.New("Redis Set Failed: (Set Method) " + "SetCondition Not Expected") 1394 } 1395 } 1396 1397 // Set sets string value into redis by key 1398 func (r *Redis) Set(key string, val string, expires ...time.Duration) error { 1399 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1400 } 1401 1402 // SetBool sets boolean value into redis by key 1403 func (r *Redis) SetBool(key string, val bool, expires ...time.Duration) error { 1404 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1405 } 1406 1407 // SetInt sets int value into redis by key 1408 func (r *Redis) SetInt(key string, val int, expires ...time.Duration) error { 1409 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1410 } 1411 1412 // SetInt64 sets int64 value into redis by key 1413 func (r *Redis) SetInt64(key string, val int64, expires ...time.Duration) error { 1414 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1415 } 1416 1417 // SetFloat64 sets float64 value into redis by key 1418 func (r *Redis) SetFloat64(key string, val float64, expires ...time.Duration) error { 1419 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1420 } 1421 1422 // SetBytes sets []byte value into redis by key 1423 func (r *Redis) SetBytes(key string, val []byte, expires ...time.Duration) error { 1424 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1425 } 1426 1427 // SetJson sets Json object into redis by key (Json object is marshaled into string and then saved to redis) 1428 func (r *Redis) SetJson(key string, jsonObject interface{}, expires ...time.Duration) error { 1429 if val, err := util.MarshalJSONCompact(jsonObject); err != nil { 1430 return errors.New("Redis Set Failed: (Marshal Json) " + err.Error()) 1431 } else { 1432 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1433 } 1434 } 1435 1436 // SetTime sets time.Time value into redis by key 1437 func (r *Redis) SetTime(key string, val time.Time, expires ...time.Duration) error { 1438 return r.SetBase(key, val, redissetcondition.Normal, expires...) 1439 } 1440 1441 // GetBase is internal helper to get value from redis. 1442 func (r *Redis) GetBase(key string) (cmd *redis.StringCmd, notFound bool, err error) { 1443 // get new xray segment for tracing 1444 seg := xray.NewSegmentNullable("Redis-Get", r._parentSegment) 1445 1446 if seg != nil { 1447 defer seg.Close() 1448 defer func() { 1449 _ = seg.Seg.AddMetadata("Redis-Get-Key", key) 1450 _ = seg.Seg.AddMetadata("Redis-Get-Not-Found", notFound) 1451 _ = seg.Seg.AddMetadata("Redis-Get-Value-Cmd", cmd) 1452 1453 if err != nil { 1454 _ = seg.Seg.AddError(err) 1455 } 1456 }() 1457 1458 cmd, notFound, err = r.getBaseInternal(key) 1459 return cmd, notFound, err 1460 } else { 1461 return r.getBaseInternal(key) 1462 } 1463 } 1464 1465 // getBaseInternal is internal helper to get value from redis. 1466 func (r *Redis) getBaseInternal(key string) (cmd *redis.StringCmd, notFound bool, err error) { 1467 // validate 1468 if !r.cnAreReady { 1469 return nil, false, errors.New("Redis Get Failed: " + "Endpoint Connections Not Ready") 1470 } 1471 1472 if util.LenTrim(key) <= 0 { 1473 return nil, false, errors.New("Redis Get Failed: " + "Key is Required") 1474 } 1475 1476 // get value from redis 1477 cmd = r.cnReader.Get(r.cnReader.Context(), key) 1478 1479 if cmd.Err() != nil { 1480 if cmd.Err() == redis.Nil { 1481 // not found 1482 return nil, true, nil 1483 } else { 1484 // other error 1485 return nil, false, errors.New("Redis Get Failed: (Get Method) " + cmd.Err().Error()) 1486 } 1487 } else { 1488 // value found - return actual StringCmd 1489 return cmd, false, nil 1490 } 1491 } 1492 1493 // Get gets string value from redis by key 1494 func (r *Redis) Get(key string) (val string, notFound bool, err error) { 1495 var cmd *redis.StringCmd 1496 1497 if cmd, notFound, err = r.GetBase(key); err != nil { 1498 return "", notFound, err 1499 } else { 1500 if notFound { 1501 return "", notFound, err 1502 } else { 1503 if val, err = cmd.Result(); err != nil { 1504 return "", false, err 1505 } else { 1506 // found string value 1507 return val, false, nil 1508 } 1509 } 1510 } 1511 } 1512 1513 // GetBool gets bool value from redis by key 1514 func (r *Redis) GetBool(key string) (val bool, notFound bool, err error) { 1515 var cmd *redis.StringCmd 1516 1517 if cmd, notFound, err = r.GetBase(key); err != nil { 1518 return false, notFound, err 1519 } else { 1520 if notFound { 1521 return false, notFound, err 1522 } else { 1523 var valStr string 1524 1525 if valStr, err = cmd.Result(); err != nil { 1526 return false, false, err 1527 } else { 1528 // found string value, 1529 // convert to bool 1530 b, success := util.ParseBool(valStr) 1531 1532 if success { 1533 return b, false, nil 1534 } else { 1535 return false, true, nil 1536 } 1537 } 1538 } 1539 } 1540 } 1541 1542 // GetInt gets int value from redis by key 1543 func (r *Redis) GetInt(key string) (val int, notFound bool, err error) { 1544 var cmd *redis.StringCmd 1545 1546 if cmd, notFound, err = r.GetBase(key); err != nil { 1547 return 0, notFound, err 1548 } else { 1549 if notFound { 1550 return 0, notFound, err 1551 } else { 1552 if val, err = cmd.Int(); err != nil { 1553 return 0, false, err 1554 } else { 1555 // found int value, 1556 return val, false, nil 1557 } 1558 } 1559 } 1560 } 1561 1562 // GetInt64 gets int64 value from redis by key 1563 func (r *Redis) GetInt64(key string) (val int64, notFound bool, err error) { 1564 var cmd *redis.StringCmd 1565 1566 if cmd, notFound, err = r.GetBase(key); err != nil { 1567 return 0, notFound, err 1568 } else { 1569 if notFound { 1570 return 0, notFound, err 1571 } else { 1572 if val, err = cmd.Int64(); err != nil { 1573 return 0, false, err 1574 } else { 1575 // found int value, 1576 return val, false, nil 1577 } 1578 } 1579 } 1580 } 1581 1582 // GetFloat64 gets float64 value from redis by key 1583 func (r *Redis) GetFloat64(key string) (val float64, notFound bool, err error) { 1584 var cmd *redis.StringCmd 1585 1586 if cmd, notFound, err = r.GetBase(key); err != nil { 1587 return 0.00, notFound, err 1588 } else { 1589 if notFound { 1590 return 0.00, notFound, err 1591 } else { 1592 if val, err = cmd.Float64(); err != nil { 1593 return 0.00, false, err 1594 } else { 1595 // found int value, 1596 return val, false, nil 1597 } 1598 } 1599 } 1600 } 1601 1602 // GetBytes gets []byte value from redis by key 1603 func (r *Redis) GetBytes(key string) (val []byte, notFound bool, err error) { 1604 var cmd *redis.StringCmd 1605 1606 if cmd, notFound, err = r.GetBase(key); err != nil { 1607 return []byte{}, notFound, err 1608 } else { 1609 if notFound { 1610 return []byte{}, notFound, err 1611 } else { 1612 if val, err = cmd.Bytes(); err != nil { 1613 return []byte{}, false, err 1614 } else { 1615 // found int value, 1616 return val, false, nil 1617 } 1618 } 1619 } 1620 } 1621 1622 // GetJson gets Json object from redis by key (Json is stored as string in redis, unmarshaled to target object via get) 1623 func (r *Redis) GetJson(key string, resultObjectPtr interface{}) (notFound bool, err error) { 1624 if resultObjectPtr == nil { 1625 return false, errors.New("Redis Get Failed: (GetJson) " + "JSON Result Pointer Object is Required") 1626 } 1627 1628 var cmd *redis.StringCmd 1629 1630 if cmd, notFound, err = r.GetBase(key); err != nil { 1631 return notFound, err 1632 } else { 1633 if notFound { 1634 return notFound, err 1635 } else { 1636 var valStr string 1637 1638 if valStr, err = cmd.Result(); err != nil { 1639 return false, err 1640 } else { 1641 // found str value, 1642 // unmarshal to json 1643 if util.LenTrim(valStr) <= 0 { 1644 return true, nil 1645 } else { 1646 if err = util.UnmarshalJSON(valStr, resultObjectPtr); err != nil { 1647 // unmarshal error 1648 return false, err 1649 } else { 1650 // unmarshal success 1651 return false, nil 1652 } 1653 } 1654 } 1655 } 1656 } 1657 } 1658 1659 // GetTime gets time.Time value from redis by key 1660 func (r *Redis) GetTime(key string) (val time.Time, notFound bool, err error) { 1661 var cmd *redis.StringCmd 1662 1663 if cmd, notFound, err = r.GetBase(key); err != nil { 1664 return time.Time{}, notFound, err 1665 } else { 1666 if notFound { 1667 return time.Time{}, notFound, err 1668 } else { 1669 if val, err = cmd.Time(); err != nil { 1670 return time.Time{}, false, err 1671 } else { 1672 // found int value, 1673 return val, false, nil 1674 } 1675 } 1676 } 1677 } 1678 1679 // ---------------------------------------------------------------------------------------------------------------- 1680 // GetSet function 1681 // ---------------------------------------------------------------------------------------------------------------- 1682 1683 // GetSet will get old string value from redis by key, 1684 // and then set new string value into redis by the same key. 1685 func (r *Redis) GetSet(key string, val string) (oldValue string, notFound bool, err error) { 1686 // reg new xray segment for tracing 1687 seg := xray.NewSegmentNullable("Redis-GetSet", r._parentSegment) 1688 1689 if seg != nil { 1690 defer seg.Close() 1691 defer func() { 1692 _ = seg.Seg.AddMetadata("Redis-GetSet-Key", key) 1693 _ = seg.Seg.AddMetadata("Redis-GetSet-Not-Found", notFound) 1694 _ = seg.Seg.AddMetadata("Redis-GetSet-Old_Value", oldValue) 1695 _ = seg.Seg.AddMetadata("Redis-GetSet-New-Value", val) 1696 1697 if err != nil { 1698 _ = seg.Seg.AddError(err) 1699 } 1700 }() 1701 1702 oldValue, notFound, err = r.getSetInternal(key, val) 1703 return oldValue, notFound, err 1704 } else { 1705 return r.getSetInternal(key, val) 1706 } 1707 } 1708 1709 // getSetInternal will get old string value from redis by key, 1710 // and then set new string value into redis by the same key. 1711 func (r *Redis) getSetInternal(key string, val string) (oldValue string, notFound bool, err error) { 1712 // validate 1713 if !r.cnAreReady { 1714 return "", false, errors.New("Redis GetSet Failed: " + "Endpoint Connections Not Ready") 1715 } 1716 1717 if util.LenTrim(key) <= 0 { 1718 return "", false, errors.New("Redis GetSet Failed: " + "Key is Required") 1719 } 1720 1721 // persist value and get old value as return result 1722 cmd := r.cnWriter.GetSet(r.cnWriter.Context(), key, val) 1723 notFound, err = r.handleStringCmd(cmd, redisdatatype.String, &oldValue, "Redis GetSet Failed: ") 1724 1725 // return result 1726 return oldValue, notFound, err 1727 } 1728 1729 // ---------------------------------------------------------------------------------------------------------------- 1730 // MSet, MSetNX and MGet functions 1731 // ---------------------------------------------------------------------------------------------------------------- 1732 1733 // MSet is helper to set multiple values into redis by keys, 1734 // optional parameter setIfNotExists indicates if instead MSetNX is to be used 1735 // 1736 // notes 1737 // 1738 // kvMap = map of key string, and interface{} value 1739 func (r *Redis) MSet(kvMap map[string]interface{}, setIfNotExists ...bool) (err error) { 1740 // get new xray segment for tracing 1741 seg := xray.NewSegmentNullable("Redis-MSet", r._parentSegment) 1742 1743 if seg != nil { 1744 defer seg.Close() 1745 defer func() { 1746 _ = seg.Seg.AddMetadata("Redis-MSet-KeyValueMap", kvMap) 1747 1748 if err != nil { 1749 _ = seg.Seg.AddError(err) 1750 } 1751 }() 1752 1753 err = r.msetInternal(kvMap, setIfNotExists...) 1754 return err 1755 } else { 1756 return r.msetInternal(kvMap, setIfNotExists...) 1757 } 1758 } 1759 1760 // msetInternal is helper to set multiple values into redis by keys, 1761 // optional parameter setIfNotExists indicates if instead MSetNX is to be used 1762 // 1763 // notes 1764 // 1765 // kvMap = map of key string, and interface{} value 1766 func (r *Redis) msetInternal(kvMap map[string]interface{}, setIfNotExists ...bool) error { 1767 // validate 1768 if kvMap == nil { 1769 return errors.New("Redis MSet Failed: " + "KVMap is Required") 1770 } 1771 1772 if !r.cnAreReady { 1773 return errors.New("Redis MSet Failed: " + "Endpoint Connections Not Ready") 1774 } 1775 1776 // persist value to redis 1777 nx := false 1778 1779 if len(setIfNotExists) > 0 { 1780 nx = setIfNotExists[0] 1781 } 1782 1783 if !nx { 1784 // normal 1785 cmd := r.cnWriter.MSet(r.cnWriter.Context(), kvMap) 1786 return r.handleStatusCmd(cmd, "Redis MSet Failed: ") 1787 } else { 1788 // nx 1789 cmd := r.cnWriter.MSetNX(r.cnWriter.Context(), kvMap) 1790 if val, err := r.handleBoolCmd(cmd, "Redis MSetNX Failed: "); err != nil { 1791 return err 1792 } else { 1793 if val { 1794 // success 1795 return nil 1796 } else { 1797 // not success 1798 return errors.New("Redis MSetNX Failed: " + "Key Was Not Set") 1799 } 1800 } 1801 } 1802 } 1803 1804 // MGet is a helper to get values from redis based on one or more keys specified 1805 func (r *Redis) MGet(key ...string) (results []interface{}, notFound bool, err error) { 1806 // get new xray segment for tracing 1807 seg := xray.NewSegmentNullable("Redis-MGet", r._parentSegment) 1808 1809 if seg != nil { 1810 defer seg.Close() 1811 defer func() { 1812 _ = seg.Seg.AddMetadata("Redis-MGet-Keys", key) 1813 _ = seg.Seg.AddMetadata("Redis-MGet-Not-Found", notFound) 1814 _ = seg.Seg.AddMetadata("Redis-MGet-Results", results) 1815 1816 if err != nil { 1817 _ = seg.Seg.AddError(err) 1818 } 1819 }() 1820 1821 results, notFound, err = r.mgetInternal(key...) 1822 return results, notFound, err 1823 } else { 1824 return r.mgetInternal(key...) 1825 } 1826 } 1827 1828 // mgetInternal is a helper to get values from redis based on one or more keys specified 1829 func (r *Redis) mgetInternal(key ...string) (results []interface{}, notFound bool, err error) { 1830 // validate 1831 if len(key) <= 0 { 1832 return nil, false, errors.New("Redis MGet Failed: " + "Key is Required") 1833 } 1834 1835 if !r.cnAreReady { 1836 return nil, false, errors.New("Redis MGet Failed: " + "Endpoint Connections Not Ready") 1837 } 1838 1839 cmd := r.cnReader.MGet(r.cnWriter.Context(), key...) 1840 return r.handleSliceCmd(cmd, "Redis MGet Failed: ") 1841 } 1842 1843 // ---------------------------------------------------------------------------------------------------------------- 1844 // SetRange and GetRange functions 1845 // ---------------------------------------------------------------------------------------------------------------- 1846 1847 // SetRange sets val into key's stored value in redis, offset by the offset number 1848 // 1849 // example: 1850 // 1. "Hello World" 1851 // 2. Offset 6 = W 1852 // 3. Val "Xyz" replaces string from Offset Position 6 1853 // 4. End Result String = "Hello Xyzld" 1854 func (r *Redis) SetRange(key string, offset int64, val string) (err error) { 1855 // get new xray segment for tracing 1856 seg := xray.NewSegmentNullable("Redis-SetRange", r._parentSegment) 1857 1858 if seg != nil { 1859 defer seg.Close() 1860 defer func() { 1861 _ = seg.Seg.AddMetadata("Redis-SetRange-Key", key) 1862 _ = seg.Seg.AddMetadata("Redis-SetRange-Offset", offset) 1863 _ = seg.Seg.AddMetadata("Redis-SetRange-Value", val) 1864 1865 if err != nil { 1866 _ = seg.Seg.AddError(err) 1867 } 1868 }() 1869 1870 err = r.setRangeInternal(key, offset, val) 1871 return err 1872 } else { 1873 return r.setRangeInternal(key, offset, val) 1874 } 1875 } 1876 1877 // setRangeInternal sets val into key's stored value in redis, offset by the offset number 1878 // 1879 // example: 1880 // 1. "Hello World" 1881 // 2. Offset 6 = W 1882 // 3. Val "Xyz" replaces string from Offset Position 6 1883 // 4. End Result String = "Hello Xyzld" 1884 func (r *Redis) setRangeInternal(key string, offset int64, val string) error { 1885 // validate 1886 if len(key) <= 0 { 1887 return errors.New("Redis SetRange Failed: " + "Key is Required") 1888 } 1889 1890 if !r.cnAreReady { 1891 return errors.New("Redis SetRange Failed: " + "Endpoint Connections Not Ready") 1892 } 1893 1894 if offset < 0 { 1895 return errors.New("Redis SetRange Failed: " + "Offset Must Be 0 or Greater") 1896 } 1897 1898 cmd := r.cnWriter.SetRange(r.cnWriter.Context(), key, offset, val) 1899 1900 if _, _, err := r.handleIntCmd(cmd, "Redis SetRange Failed: "); err != nil { 1901 return err 1902 } else { 1903 return nil 1904 } 1905 } 1906 1907 // GetRange gets val between start and end positions from string value stored by key in redis 1908 func (r *Redis) GetRange(key string, start int64, end int64) (val string, notFound bool, err error) { 1909 // get new xray segment for tracing 1910 seg := xray.NewSegmentNullable("Redis-GetRange", r._parentSegment) 1911 1912 if seg != nil { 1913 defer seg.Close() 1914 defer func() { 1915 _ = seg.Seg.AddMetadata("Redis-GetRange-Key", key) 1916 _ = seg.Seg.AddMetadata("Redis-GetRange-Start-End", util.Int64ToString(start)+"-"+util.Int64ToString(end)) 1917 _ = seg.Seg.AddMetadata("Redis-GetRange-Not-Found", notFound) 1918 _ = seg.Seg.AddMetadata("Redis-GetRange-Value", val) 1919 1920 if err != nil { 1921 _ = seg.Seg.AddError(err) 1922 } 1923 }() 1924 1925 val, notFound, err = r.getRangeInternal(key, start, end) 1926 return val, notFound, err 1927 } else { 1928 return r.getRangeInternal(key, start, end) 1929 } 1930 } 1931 1932 // getRangeInternal gets val between start and end positions from string value stored by key in redis 1933 func (r *Redis) getRangeInternal(key string, start int64, end int64) (val string, notFound bool, err error) { 1934 // validate 1935 if len(key) <= 0 { 1936 return "", false, errors.New("Redis GetRange Failed: " + "Key is Required") 1937 } 1938 1939 if !r.cnAreReady { 1940 return "", false, errors.New("Redis GetRange Failed: " + "Endpoint Connections Not Ready") 1941 } 1942 1943 if start < 0 { 1944 return "", false, errors.New("Redis GetRange Failed: " + "Start Must Be 0 or Greater") 1945 } 1946 1947 if end < start { 1948 return "", false, errors.New("Redis GetRange Failed: " + "End Must Equal or Be Greater Than Start") 1949 } 1950 1951 cmd := r.cnReader.GetRange(r.cnReader.Context(), key, start, end) 1952 1953 if notFound, err = r.handleStringCmd(cmd, redisdatatype.String, &val, "Redis GetRange Failed: "); err != nil { 1954 return "", false, err 1955 } else { 1956 return val, false, nil 1957 } 1958 } 1959 1960 // ---------------------------------------------------------------------------------------------------------------- 1961 // Decr, DecrBy, Incr, IncrBy, and IncrByFloat functions 1962 // ---------------------------------------------------------------------------------------------------------------- 1963 1964 // Int64AddOrReduce will add or reduce int64 value against a key in redis, 1965 // and return the new value if found and performed 1966 func (r *Redis) Int64AddOrReduce(key string, val int64, isReduce ...bool) (newVal int64, notFound bool, err error) { 1967 // get new xray segment for tracing 1968 seg := xray.NewSegmentNullable("Redis-Int64AddOrReduce", r._parentSegment) 1969 1970 if seg != nil { 1971 defer seg.Close() 1972 defer func() { 1973 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-Key", key) 1974 1975 if len(isReduce) > 0 { 1976 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-IsReduce", isReduce[0]) 1977 } else { 1978 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-IsReduce", "false") 1979 } 1980 1981 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-Not-Found", notFound) 1982 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-Old-Value", val) 1983 _ = seg.Seg.AddMetadata("Redis-Int64AddOrReduce-New-Value", newVal) 1984 1985 if err != nil { 1986 _ = seg.Seg.AddError(err) 1987 } 1988 }() 1989 1990 newVal, notFound, err = r.int64AddOrReduceInternal(key, val, isReduce...) 1991 return newVal, notFound, err 1992 } else { 1993 return r.int64AddOrReduceInternal(key, val, isReduce...) 1994 } 1995 } 1996 1997 // int64AddOrReduceInternal will add or reduce int64 value against a key in redis, 1998 // and return the new value if found and performed 1999 func (r *Redis) int64AddOrReduceInternal(key string, val int64, isReduce ...bool) (newVal int64, notFound bool, err error) { 2000 // get reduce bool 2001 reduce := false 2002 2003 if len(isReduce) > 0 { 2004 reduce = isReduce[0] 2005 } 2006 2007 methodName := "" 2008 2009 if reduce { 2010 methodName = "Decr/DecrBy" 2011 } else { 2012 methodName = "Incr/IncrBy" 2013 } 2014 2015 // validate 2016 if len(key) <= 0 { 2017 return 0, false, errors.New("Redis " + methodName + " Failed: " + "Key is Required") 2018 } 2019 2020 if !r.cnAreReady { 2021 return 0, false, errors.New("Redis " + methodName + " Failed: " + "Endpoint Connections Not Ready") 2022 } 2023 2024 if val <= 0 { 2025 return 0, false, errors.New("Redis " + methodName + " Failed: " + "Value Must Be Greater Than 0") 2026 } 2027 2028 var cmd *redis.IntCmd 2029 2030 if !reduce { 2031 // increment 2032 if val == 1 { 2033 cmd = r.cnWriter.Incr(r.cnWriter.Context(), key) 2034 } else { 2035 cmd = r.cnWriter.IncrBy(r.cnWriter.Context(), key, val) 2036 } 2037 } else { 2038 // decrement 2039 if val == 1 { 2040 cmd = r.cnWriter.Decr(r.cnWriter.Context(), key) 2041 } else { 2042 cmd = r.cnWriter.DecrBy(r.cnWriter.Context(), key, val) 2043 } 2044 } 2045 2046 // evaluate cmd result 2047 return r.handleIntCmd(cmd, "Redis "+methodName+" Failed: ") 2048 } 2049 2050 // Float64AddOrReduce will add or reduce float64 value against a key in redis, 2051 // and return the new value if found and performed 2052 func (r *Redis) Float64AddOrReduce(key string, val float64) (newVal float64, notFound bool, err error) { 2053 // get new xray segment for tracing 2054 seg := xray.NewSegmentNullable("Redis-Float64AddOrReduce", r._parentSegment) 2055 2056 if seg != nil { 2057 defer seg.Close() 2058 defer func() { 2059 _ = seg.Seg.AddMetadata("Redis-Float64AddOrReduce-Key", key) 2060 _ = seg.Seg.AddMetadata("Redis-Float64AddOrReduce-Value", val) 2061 _ = seg.Seg.AddMetadata("Redis-Float64AddOrReduce-Not-Found", notFound) 2062 _ = seg.Seg.AddMetadata("Redis-Float64AddOrReduce-Result-NewValue", newVal) 2063 2064 if err != nil { 2065 _ = seg.Seg.AddError(err) 2066 } 2067 }() 2068 2069 newVal, notFound, err = r.float64AddOrReduceInternal(key, val) 2070 return newVal, notFound, err 2071 } else { 2072 return r.float64AddOrReduceInternal(key, val) 2073 } 2074 } 2075 2076 // float64AddOrReduceInternal will add or reduce float64 value against a key in redis, 2077 // and return the new value if found and performed 2078 func (r *Redis) float64AddOrReduceInternal(key string, val float64) (newVal float64, notFound bool, err error) { 2079 // validate 2080 if len(key) <= 0 { 2081 return 0.00, false, errors.New("Redis Float64AddOrReduce Failed: (IncrByFloat) " + "Key is Required") 2082 } 2083 2084 if !r.cnAreReady { 2085 return 0.00, false, errors.New("Redis Float64AddOrReduce Failed: (IncrByFloat) " + "Endpoint Connections Not Ready") 2086 } 2087 2088 cmd := r.cnWriter.IncrByFloat(r.cnWriter.Context(), key, val) 2089 return r.handleFloatCmd(cmd, "Redis Float64AddOrReduce Failed: (IncrByFloat)") 2090 } 2091 2092 // ---------------------------------------------------------------------------------------------------------------- 2093 // HyperLogLog functions 2094 // ---------------------------------------------------------------------------------------------------------------- 2095 2096 // PFAdd is a HyperLogLog function to uniquely accumulate the count of a specific value to redis, 2097 // such as email hit count, user hit count, ip address hit count etc, that is based on the unique occurences of such value 2098 func (r *Redis) PFAdd(key string, elements ...interface{}) (err error) { 2099 // get new xray segment for tracing 2100 seg := xray.NewSegmentNullable("Redis-PFAdd", r._parentSegment) 2101 2102 if seg != nil { 2103 defer seg.Close() 2104 defer func() { 2105 _ = seg.Seg.AddMetadata("Redis-PFAdd-Key", key) 2106 _ = seg.Seg.AddMetadata("Redis-PFAdd-Elements", elements) 2107 2108 if err != nil { 2109 _ = seg.Seg.AddError(err) 2110 } 2111 }() 2112 2113 err = r.pfAddInternal(key, elements...) 2114 return err 2115 } else { 2116 return r.pfAddInternal(key, elements...) 2117 } 2118 } 2119 2120 // pfAddInternal is a HyperLogLog function to uniquely accumulate the count of a specific value to redis, 2121 // such as email hit count, user hit count, ip address hit count etc, that is based on the unique occurences of such value 2122 func (r *Redis) pfAddInternal(key string, elements ...interface{}) error { 2123 // validate 2124 if len(key) <= 0 { 2125 return errors.New("Redis PFAdd Failed: " + "Key is Required") 2126 } 2127 2128 if !r.cnAreReady { 2129 return errors.New("Redis PFAdd Failed: " + "Endpoint Connections Not Ready") 2130 } 2131 2132 cmd := r.cnWriter.PFAdd(r.cnWriter.Context(), key, elements...) 2133 2134 if _, _, err := r.handleIntCmd(cmd, "Redis PFAdd Failed: "); err != nil { 2135 return err 2136 } else { 2137 return nil 2138 } 2139 } 2140 2141 // PFCount is a HyperLogLog function to retrieve the current count associated with the given unique value in redis, 2142 // Specify one or more keys, if multiple keys used, the result count is the union of all keys' unique value counts 2143 func (r *Redis) PFCount(key ...string) (val int64, notFound bool, err error) { 2144 // get new xray segment for tracing 2145 seg := xray.NewSegmentNullable("Redis-PFCount", r._parentSegment) 2146 2147 if seg != nil { 2148 defer seg.Close() 2149 defer func() { 2150 _ = seg.Seg.AddMetadata("Redis-PFCount-Keys", key) 2151 _ = seg.Seg.AddMetadata("Redis-PFCount-Not-Found", notFound) 2152 _ = seg.Seg.AddMetadata("Redis-PFCount-Result-Count", val) 2153 2154 if err != nil { 2155 _ = seg.Seg.AddError(err) 2156 } 2157 }() 2158 2159 val, notFound, err = r.pfCountInternal(key...) 2160 return val, notFound, err 2161 } else { 2162 return r.pfCountInternal(key...) 2163 } 2164 } 2165 2166 // pfCountInternal is a HyperLogLog function to retrieve the current count associated with the given unique value in redis, 2167 // Specify one or more keys, if multiple keys used, the result count is the union of all keys' unique value counts 2168 func (r *Redis) pfCountInternal(key ...string) (val int64, notFound bool, err error) { 2169 // validate 2170 if len(key) <= 0 { 2171 return 0, false, errors.New("Redis PFCount Failed: " + "Key is Required") 2172 } 2173 2174 if !r.cnAreReady { 2175 return 0, false, errors.New("Redis PFCount Failed: " + "Endpoint Connections Not Ready") 2176 } 2177 2178 cmd := r.cnReader.PFCount(r.cnReader.Context(), key...) 2179 return r.handleIntCmd(cmd, "Redis PFCount Failed: ") 2180 } 2181 2182 // PFMerge is a HyperLogLog function to merge two or more HyperLogLog as defined by keys together 2183 func (r *Redis) PFMerge(destKey string, sourceKey ...string) (err error) { 2184 // get new xray segment for tracing 2185 seg := xray.NewSegmentNullable("Redis-PFMerge", r._parentSegment) 2186 2187 if seg != nil { 2188 defer seg.Close() 2189 defer func() { 2190 _ = seg.Seg.AddMetadata("Redis-PFMerge-DestKey", destKey) 2191 _ = seg.Seg.AddMetadata("Redis-PFMerge-SourceKeys", sourceKey) 2192 2193 if err != nil { 2194 _ = seg.Seg.AddError(err) 2195 } 2196 }() 2197 2198 err = r.pfMergeInternal(destKey, sourceKey...) 2199 return err 2200 } else { 2201 return r.pfMergeInternal(destKey, sourceKey...) 2202 } 2203 } 2204 2205 // pfMergeInternal is a HyperLogLog function to merge two or more HyperLogLog as defined by keys together 2206 func (r *Redis) pfMergeInternal(destKey string, sourceKey ...string) error { 2207 // validate 2208 if len(destKey) <= 0 { 2209 return errors.New("Redis PFMerge Failed: " + "Destination Key is Required") 2210 } 2211 2212 if len(sourceKey) <= 0 { 2213 return errors.New("Redis PFMerge Failed: " + "Source Key is Required") 2214 } 2215 2216 if !r.cnAreReady { 2217 return errors.New("Redis PFMerge Failed: " + "Endpoint Connections Not Ready") 2218 } 2219 2220 cmd := r.cnWriter.PFMerge(r.cnWriter.Context(), destKey, sourceKey...) 2221 return r.handleStatusCmd(cmd, "Redis PFMerge Failed: ") 2222 } 2223 2224 // ---------------------------------------------------------------------------------------------------------------- 2225 // Other functions 2226 // ---------------------------------------------------------------------------------------------------------------- 2227 2228 // Exists checks if one or more keys exists in redis 2229 // 2230 // foundCount = 0 indicates not found; > 0 indicates found count 2231 func (r *Redis) Exists(key ...string) (foundCount int64, err error) { 2232 // get new xray segment for tracing 2233 seg := xray.NewSegmentNullable("Redis-Exists", r._parentSegment) 2234 2235 if seg != nil { 2236 defer seg.Close() 2237 defer func() { 2238 _ = seg.Seg.AddMetadata("Redis-Exists-Keys", key) 2239 _ = seg.Seg.AddMetadata("Redis-Exists-Result-Count", foundCount) 2240 2241 if err != nil { 2242 _ = seg.Seg.AddError(err) 2243 } 2244 }() 2245 2246 foundCount, err = r.existsInternal(key...) 2247 return foundCount, err 2248 } else { 2249 return r.existsInternal(key...) 2250 } 2251 } 2252 2253 // existsInternal checks if one or more keys exists in redis 2254 // 2255 // foundCount = 0 indicates not found; > 0 indicates found count 2256 func (r *Redis) existsInternal(key ...string) (foundCount int64, err error) { 2257 // validate 2258 if len(key) <= 0 { 2259 return 0, errors.New("Redis Exists Failed: " + "Key is Required") 2260 } 2261 2262 if !r.cnAreReady { 2263 return 0, errors.New("Redis Exists Failed: " + "Endpoint Connections Not Ready") 2264 } 2265 2266 cmd := r.cnReader.Exists(r.cnReader.Context(), key...) 2267 foundCount, _, err = r.handleIntCmd(cmd, "Redis Exists Failed: ") 2268 2269 return foundCount, err 2270 } 2271 2272 // StrLen gets the string length of the value stored by the key in redis 2273 func (r *Redis) StrLen(key string) (length int64, notFound bool, err error) { 2274 // get new xray segment for tracing 2275 seg := xray.NewSegmentNullable("Redis-StrLen", r._parentSegment) 2276 2277 if seg != nil { 2278 defer seg.Close() 2279 defer func() { 2280 _ = seg.Seg.AddMetadata("Redis-StrLen-Key", key) 2281 _ = seg.Seg.AddMetadata("Redis-StrLen-Not-Found", notFound) 2282 _ = seg.Seg.AddMetadata("Redis-StrLen-Result-Len", length) 2283 2284 if err != nil { 2285 _ = seg.Seg.AddError(err) 2286 } 2287 }() 2288 2289 length, notFound, err = r.strLenInternal(key) 2290 return length, notFound, err 2291 } else { 2292 return r.strLenInternal(key) 2293 } 2294 } 2295 2296 // strLenInternal gets the string length of the value stored by the key in redis 2297 func (r *Redis) strLenInternal(key string) (length int64, notFound bool, err error) { 2298 // validate 2299 if len(key) <= 0 { 2300 return 0, false, errors.New("Redis StrLen Failed: " + "Key is Required") 2301 } 2302 2303 if !r.cnAreReady { 2304 return 0, false, errors.New("Redis StrLen Failed: " + "Endpoint Connections Not Ready") 2305 } 2306 2307 cmd := r.cnReader.StrLen(r.cnReader.Context(), key) 2308 return r.handleIntCmd(cmd, "Redis StrLen Failed: ") 2309 } 2310 2311 // Append will append a value to the existing value under the given key in redis, 2312 // if key does not exist, a new key based on the given key is created 2313 func (r *Redis) Append(key string, valToAppend string) (err error) { 2314 // get new xray segment for tracing 2315 seg := xray.NewSegmentNullable("Redis-Append", r._parentSegment) 2316 2317 if seg != nil { 2318 defer seg.Close() 2319 defer func() { 2320 _ = seg.Seg.AddMetadata("Redis-Append-Key", key) 2321 _ = seg.Seg.AddMetadata("Redis-Append-Value", valToAppend) 2322 2323 if err != nil { 2324 _ = seg.Seg.AddError(err) 2325 } 2326 }() 2327 2328 err = r.appendInternal(key, valToAppend) 2329 return err 2330 } else { 2331 return r.appendInternal(key, valToAppend) 2332 } 2333 } 2334 2335 // appendInternal will append a value to the existing value under the given key in redis, 2336 // if key does not exist, a new key based on the given key is created 2337 func (r *Redis) appendInternal(key string, valToAppend string) error { 2338 // validate 2339 if len(key) <= 0 { 2340 return errors.New("Redis Append Failed: " + "Key is Required") 2341 } 2342 2343 if !r.cnAreReady { 2344 return errors.New("Redis Append Failed: " + "Endpoint Connections Not Ready") 2345 } 2346 2347 cmd := r.cnWriter.Append(r.cnWriter.Context(), key, valToAppend) 2348 _, _, err := r.handleIntCmd(cmd) 2349 return err 2350 } 2351 2352 // Del will delete one or more keys specified from redis 2353 func (r *Redis) Del(key ...string) (deletedCount int64, err error) { 2354 // get new xray segment for tracing 2355 seg := xray.NewSegmentNullable("Redis-Del", r._parentSegment) 2356 2357 if seg != nil { 2358 defer seg.Close() 2359 defer func() { 2360 _ = seg.Seg.AddMetadata("Redis-Del-Keys", key) 2361 _ = seg.Seg.AddMetadata("Redis-Del-Result-Deleted-Count", deletedCount) 2362 2363 if err != nil { 2364 _ = seg.Seg.AddError(err) 2365 } 2366 }() 2367 2368 deletedCount, err = r.delInternal(key...) 2369 return deletedCount, err 2370 } else { 2371 return r.delInternal(key...) 2372 } 2373 } 2374 2375 // delInternal will delete one or more keys specified from redis 2376 func (r *Redis) delInternal(key ...string) (deletedCount int64, err error) { 2377 // validate 2378 if len(key) <= 0 { 2379 return 0, errors.New("Redis Del Failed: " + "Key is Required") 2380 } 2381 2382 if !r.cnAreReady { 2383 return 0, errors.New("Redis Del Failed: " + "Endpoint Connections Not Ready") 2384 } 2385 2386 cmd := r.cnWriter.Del(r.cnWriter.Context(), key...) 2387 deletedCount, _, err = r.handleIntCmd(cmd, "Redis Del Failed: ") 2388 return deletedCount, err 2389 } 2390 2391 // Unlink is similar to Del where it removes one or more keys specified from redis, 2392 // however, unlink performs the delete asynchronously and is faster than Del 2393 func (r *Redis) Unlink(key ...string) (unlinkedCount int64, err error) { 2394 // get new xray segment for tracing 2395 seg := xray.NewSegmentNullable("Redis-Unlink", r._parentSegment) 2396 2397 if seg != nil { 2398 defer seg.Close() 2399 defer func() { 2400 _ = seg.Seg.AddMetadata("Redis-Unlink-Keys", key) 2401 _ = seg.Seg.AddMetadata("Redis-Unlink-Result-Unlinked-Count", unlinkedCount) 2402 2403 if err != nil { 2404 _ = seg.Seg.AddError(err) 2405 } 2406 }() 2407 2408 unlinkedCount, err = r.unlinkInternal(key...) 2409 return unlinkedCount, err 2410 } else { 2411 return r.unlinkInternal(key...) 2412 } 2413 } 2414 2415 // unlinkInternal is similar to Del where it removes one or more keys specified from redis, 2416 // however, unlink performs the delete asynchronously and is faster than Del 2417 func (r *Redis) unlinkInternal(key ...string) (unlinkedCount int64, err error) { 2418 // validate 2419 if len(key) <= 0 { 2420 return 0, errors.New("Redis Unlink Failed: " + "Key is Required") 2421 } 2422 2423 if !r.cnAreReady { 2424 return 0, errors.New("Redis Unlink Failed: " + "Endpoint Connections Not Ready") 2425 } 2426 2427 cmd := r.cnWriter.Unlink(r.cnWriter.Context(), key...) 2428 unlinkedCount, _, err = r.handleIntCmd(cmd, "Redis Unlink Failed: ") 2429 return unlinkedCount, err 2430 } 2431 2432 // ---------------------------------------------------------------------------------------------------------------- 2433 // BIT functions 2434 // ---------------------------------------------------------------------------------------------------------------- 2435 2436 // SetBit will set or clear (1 or 0) the bit at offset in the string value stored by the key in redis, 2437 // If the key doesn't exist, a new key with the key defined is created, 2438 // The string holding bit value will grow as needed when offset exceeds the string, grown value defaults with bit 0 2439 // 2440 // bit range = left 0 -> right 8 = byte 2441 func (b *BIT) SetBit(key string, offset int64, bitValue bool) (err error) { 2442 // get new xray segment for tracing 2443 seg := xray.NewSegmentNullable("Redis-SetBit", b.core._parentSegment) 2444 2445 if seg != nil { 2446 defer seg.Close() 2447 defer func() { 2448 _ = seg.Seg.AddMetadata("Redis-SetBit-Key", key) 2449 _ = seg.Seg.AddMetadata("Redis-SetBit-Offset", offset) 2450 _ = seg.Seg.AddMetadata("Redis-SetBit-Bit-Value", bitValue) 2451 2452 if err != nil { 2453 _ = seg.Seg.AddError(err) 2454 } 2455 }() 2456 2457 err = b.setBitInternal(key, offset, bitValue) 2458 return err 2459 } else { 2460 return b.setBitInternal(key, offset, bitValue) 2461 } 2462 } 2463 2464 // setBitInternal will set or clear (1 or 0) the bit at offset in the string value stored by the key in redis, 2465 // If the key doesn't exist, a new key with the key defined is created, 2466 // The string holding bit value will grow as needed when offset exceeds the string, grown value defaults with bit 0 2467 // 2468 // bit range = left 0 -> right 8 = byte 2469 func (b *BIT) setBitInternal(key string, offset int64, bitValue bool) error { 2470 // validate 2471 if b.core == nil { 2472 return errors.New("Redis SetBit Failed: " + "Base is Nil") 2473 } 2474 2475 if !b.core.cnAreReady { 2476 return errors.New("Redis SetBit Failed: " + "Endpoint Connections Not Ready") 2477 } 2478 2479 if len(key) <= 0 { 2480 return errors.New("Redis SetBit Failed: " + "Key is Required") 2481 } 2482 2483 if offset < 0 { 2484 return errors.New("Redis SetBit Failed: " + "Offset is 0 or Greater") 2485 } 2486 2487 v := 0 2488 2489 if bitValue { 2490 v = 1 2491 } 2492 2493 cmd := b.core.cnWriter.SetBit(b.core.cnWriter.Context(), key, offset, v) 2494 _, _, err := b.core.handleIntCmd(cmd, "Redis SetBit Failed: ") 2495 return err 2496 } 2497 2498 // GetBit will return the bit value (1 or 0) at offset position of the value for the key in redis 2499 // If key is not found or offset is greater than key's value, then blank string is assumed and bit 0 is returned 2500 func (b *BIT) GetBit(key string, offset int64) (val int, err error) { 2501 // get new xray segment for tracing 2502 seg := xray.NewSegmentNullable("Redis-GetBit", b.core._parentSegment) 2503 2504 if seg != nil { 2505 defer seg.Close() 2506 defer func() { 2507 _ = seg.Seg.AddMetadata("Redis-GetBit-Key", key) 2508 _ = seg.Seg.AddMetadata("Redis-GetBit-Offset", offset) 2509 _ = seg.Seg.AddMetadata("Redis-GetBit-Result", val) 2510 2511 if err != nil { 2512 _ = seg.Seg.AddError(err) 2513 } 2514 }() 2515 2516 val, err = b.getBitInternal(key, offset) 2517 return val, err 2518 } else { 2519 return b.getBitInternal(key, offset) 2520 } 2521 } 2522 2523 // getBitInternal will return the bit value (1 or 0) at offset position of the value for the key in redis 2524 // If key is not found or offset is greater than key's value, then blank string is assumed and bit 0 is returned 2525 func (b *BIT) getBitInternal(key string, offset int64) (val int, err error) { 2526 // validate 2527 if b.core == nil { 2528 return 0, errors.New("Redis GetBit Failed: " + "Base is Nil") 2529 } 2530 2531 if !b.core.cnAreReady { 2532 return 0, errors.New("Redis GetBit Failed: " + "Endpoint Connections Not Ready") 2533 } 2534 2535 if len(key) <= 0 { 2536 return 0, errors.New("Redis GetBit Failed: " + "Key is Required") 2537 } 2538 2539 if offset < 0 { 2540 return 0, errors.New("Redis GetBit Failed: " + "Offset is 0 or Greater") 2541 } 2542 2543 cmd := b.core.cnReader.GetBit(b.core.cnReader.Context(), key, offset) 2544 v, _, e := b.core.handleIntCmd(cmd, "Redis GetBit Failed: ") 2545 val = int(v) 2546 return val, e 2547 } 2548 2549 // BitCount counts the number of set bits (population counting of bits that are 1) in a string, 2550 // 2551 // offsetFrom = evaluate bitcount begin at offsetFrom position 2552 // offsetTo = evaluate bitcount until offsetTo position 2553 func (b *BIT) BitCount(key string, offsetFrom int64, offsetTo int64) (valCount int64, err error) { 2554 // get new xray segment for tracing 2555 seg := xray.NewSegmentNullable("Redis-BitCount", b.core._parentSegment) 2556 2557 if seg != nil { 2558 defer seg.Close() 2559 defer func() { 2560 _ = seg.Seg.AddMetadata("Redis-BitCount-Key", key) 2561 _ = seg.Seg.AddMetadata("Redis-BitCount-Offset-From", offsetFrom) 2562 _ = seg.Seg.AddMetadata("Redis-BitCount-Offset-To", offsetTo) 2563 _ = seg.Seg.AddMetadata("Redis-BitCount-Result-Count", valCount) 2564 2565 if err != nil { 2566 _ = seg.Seg.AddError(err) 2567 } 2568 }() 2569 2570 valCount, err = b.bitCountInternal(key, offsetFrom, offsetTo) 2571 return valCount, err 2572 } else { 2573 return b.bitCountInternal(key, offsetFrom, offsetTo) 2574 } 2575 } 2576 2577 // bitCountInternal counts the number of set bits (population counting of bits that are 1) in a string, 2578 // 2579 // offsetFrom = evaluate bitcount begin at offsetFrom position 2580 // offsetTo = evaluate bitcount until offsetTo position 2581 func (b *BIT) bitCountInternal(key string, offsetFrom int64, offsetTo int64) (valCount int64, err error) { 2582 // validate 2583 if b.core == nil { 2584 return 0, errors.New("Redis BitCount Failed: " + "Base is Nil") 2585 } 2586 2587 if !b.core.cnAreReady { 2588 return 0, errors.New("Redis BitCount Failed: " + "Endpoint Connections Not Ready") 2589 } 2590 2591 bc := new(redis.BitCount) 2592 2593 bc.Start = offsetFrom 2594 bc.End = offsetTo 2595 2596 cmd := b.core.cnReader.BitCount(b.core.cnReader.Context(), key, bc) 2597 valCount, _, err = b.core.handleIntCmd(cmd, "Redis BitCount Failed: ") 2598 return valCount, err 2599 } 2600 2601 // BitField treats redis string as array of bits 2602 // See detail at https://redis.io/commands/bitfield 2603 // 2604 // Supported Sub Commands: 2605 // 2606 // GET <type> <offset> -- returns the specified bit field 2607 // SET <type> <offset> <value> -- sets the specified bit field and returns its old value 2608 // INCRBY <type> <offset> <increment> -- increments or decrements (if negative) the specified bit field and returns the new value 2609 // 2610 // Notes: 2611 // 2612 // i = if integer type, i can be preceeded to indicate signed integer, such as i5 = signed integer 5 2613 // u = if integer type, u can be preceeded to indicate unsigned integer, such as u5 = unsigned integer 5 2614 // # = if offset is preceeded with #, the specified offset is multiplied by the type width, such as #0 = 0, #1 = 8 when type if 8-bit byte 2615 func (b *BIT) BitField(key string, args ...interface{}) (valBits []int64, err error) { 2616 // get new xray segment for tracing 2617 seg := xray.NewSegmentNullable("Redis-BitField", b.core._parentSegment) 2618 2619 if seg != nil { 2620 defer seg.Close() 2621 defer func() { 2622 _ = seg.Seg.AddMetadata("Redis-BitField-Key", key) 2623 _ = seg.Seg.AddMetadata("Redis-BitField-Input-Args", args) 2624 _ = seg.Seg.AddMetadata("Redis-BitField-Input-Result", valBits) 2625 2626 if err != nil { 2627 _ = seg.Seg.AddError(err) 2628 } 2629 }() 2630 2631 valBits, err = b.bitFieldInternal(key, args...) 2632 return valBits, err 2633 } else { 2634 return b.bitFieldInternal(key, args...) 2635 } 2636 } 2637 2638 // bitFieldInternal treats redis string as array of bits 2639 // See detail at https://redis.io/commands/bitfield 2640 // 2641 // Supported Sub Commands: 2642 // 2643 // GET <type> <offset> -- returns the specified bit field 2644 // SET <type> <offset> <value> -- sets the specified bit field and returns its old value 2645 // INCRBY <type> <offset> <increment> -- increments or decrements (if negative) the specified bit field and returns the new value 2646 // 2647 // Notes: 2648 // 2649 // i = if integer type, i can be preceeded to indicate signed integer, such as i5 = signed integer 5 2650 // u = if integer type, u can be preceeded to indicate unsigned integer, such as u5 = unsigned integer 5 2651 // # = if offset is preceeded with #, the specified offset is multiplied by the type width, such as #0 = 0, #1 = 8 when type if 8-bit byte 2652 func (b *BIT) bitFieldInternal(key string, args ...interface{}) (valBits []int64, err error) { 2653 // validate 2654 if b.core == nil { 2655 return nil, errors.New("Redis BitField Failed: " + "Base is Nil") 2656 } 2657 2658 if !b.core.cnAreReady { 2659 return nil, errors.New("Redis BitField Failed: " + "Endpoint Connections Not Ready") 2660 } 2661 2662 if len(key) <= 0 { 2663 return nil, errors.New("Redis BitField Failed: " + "Key is Required") 2664 } 2665 2666 if len(args) <= 0 { 2667 return nil, errors.New("Redis BitField Failed: " + "Args is Required") 2668 } 2669 2670 cmd := b.core.cnWriter.BitField(b.core.cnWriter.Context(), key, args...) 2671 valBits, _, err = b.core.handleIntSliceCmd(cmd, "Redis BitField Failed: ") 2672 return valBits, err 2673 } 2674 2675 // BitOpAnd performs bitwise operation between multiple keys (containing string value), 2676 // stores the result in the destination key, 2677 // if operation failed, error is returned, if success, nil is returned 2678 // 2679 // Supported: 2680 // 2681 // And, Or, XOr, Not 2682 func (b *BIT) BitOp(keyDest string, bitOpType redisbitop.RedisBitop, keySource ...string) (err error) { 2683 // get new xray segment for tracing 2684 seg := xray.NewSegmentNullable("Redis-BitOp", b.core._parentSegment) 2685 2686 if seg != nil { 2687 defer seg.Close() 2688 defer func() { 2689 _ = seg.Seg.AddMetadata("Redis-BitOp-KeyDest", keyDest) 2690 _ = seg.Seg.AddMetadata("Redis-BitOp-OpType", bitOpType) 2691 _ = seg.Seg.AddMetadata("Redis-BitOp-KeySource", keySource) 2692 2693 if err != nil { 2694 _ = seg.Seg.AddError(err) 2695 } 2696 }() 2697 2698 err = b.bitOpInternal(keyDest, bitOpType, keySource...) 2699 return err 2700 } else { 2701 return b.bitOpInternal(keyDest, bitOpType, keySource...) 2702 } 2703 } 2704 2705 // bitOpInternal performs bitwise operation between multiple keys (containing string value), 2706 // stores the result in the destination key, 2707 // if operation failed, error is returned, if success, nil is returned 2708 // 2709 // Supported: 2710 // 2711 // And, Or, XOr, Not 2712 func (b *BIT) bitOpInternal(keyDest string, bitOpType redisbitop.RedisBitop, keySource ...string) error { 2713 // validate 2714 if b.core == nil { 2715 return errors.New("Redis BitOp Failed: " + "Base is Nil") 2716 } 2717 2718 if !b.core.cnAreReady { 2719 return errors.New("Redis BitOp Failed: " + "Endpoint Connections Not Ready") 2720 } 2721 2722 if len(keyDest) <= 0 { 2723 return errors.New("Redis BitOp Failed: " + "Key Destination is Required") 2724 } 2725 2726 if !bitOpType.Valid() || bitOpType == redisbitop.UNKNOWN { 2727 return errors.New("Redis BitOp Failed: " + "BitOp Type Not Valid") 2728 } 2729 2730 if bitOpType != redisbitop.NOT { 2731 if len(keySource) <= 1 { 2732 return errors.New("Redis BitOp Failed: " + "Key Source Must Be 2 Or More") 2733 } 2734 } else { 2735 if len(keySource) != 1 { 2736 return errors.New("Redis BitOp-Not Failed: " + "Key Source Must Be Singular") 2737 } 2738 } 2739 2740 var cmd *redis.IntCmd 2741 2742 switch bitOpType { 2743 case redisbitop.And: 2744 cmd = b.core.cnWriter.BitOpAnd(b.core.cnWriter.Context(), keyDest, keySource...) 2745 case redisbitop.Or: 2746 cmd = b.core.cnWriter.BitOpOr(b.core.cnWriter.Context(), keyDest, keySource...) 2747 case redisbitop.XOr: 2748 cmd = b.core.cnWriter.BitOpXor(b.core.cnWriter.Context(), keyDest, keySource...) 2749 case redisbitop.NOT: 2750 cmd = b.core.cnWriter.BitOpNot(b.core.cnWriter.Context(), keyDest, keySource[0]) 2751 default: 2752 return errors.New("Redis BitOp Failed: " + "BitOp Type Not Expected") 2753 } 2754 2755 _, _, err := b.core.handleIntCmd(cmd, "Redis BitOp Failed: ") 2756 return err 2757 } 2758 2759 // BitPos returns the position of the first bit set to 1 or 0 (as requested via input query) in a string, 2760 // position of bit is returned from left to right, 2761 // first byte most significant bit is 0 on left most, 2762 // second byte most significant bit is at position 8 (after the first byte right most bit 7), and so on 2763 // 2764 // bitValue = 1 or 0 2765 // startPosition = bit pos start from this bit offset position 2766 func (b *BIT) BitPos(key string, bitValue int64, startPosition ...int64) (valPosition int64, err error) { 2767 // get new xray segment for tracing 2768 seg := xray.NewSegmentNullable("Redis-BitPos", b.core._parentSegment) 2769 2770 if seg != nil { 2771 defer seg.Close() 2772 defer func() { 2773 _ = seg.Seg.AddMetadata("Redis-BitPos-Key", key) 2774 _ = seg.Seg.AddMetadata("Redis-BitPos-BitValue", bitValue) 2775 _ = seg.Seg.AddMetadata("Redis-BitPos-Start-Position", startPosition) 2776 _ = seg.Seg.AddMetadata("Redis-BitPos-Result-Position", valPosition) 2777 2778 if err != nil { 2779 _ = seg.Seg.AddError(err) 2780 } 2781 }() 2782 2783 valPosition, err = b.bitPosInternal(key, bitValue, startPosition...) 2784 return valPosition, err 2785 } else { 2786 return b.bitPosInternal(key, bitValue, startPosition...) 2787 } 2788 } 2789 2790 // bitPosInternal returns the position of the first bit set to 1 or 0 (as requested via input query) in a string, 2791 // position of bit is returned from left to right, 2792 // first byte most significant bit is 0 on left most, 2793 // second byte most significant bit is at position 8 (after the first byte right most bit 7), and so on 2794 // 2795 // bitValue = 1 or 0 2796 // startPosition = bit pos start from this bit offset position 2797 func (b *BIT) bitPosInternal(key string, bitValue int64, startPosition ...int64) (valPosition int64, err error) { 2798 // validate 2799 if b.core == nil { 2800 return 0, errors.New("Redis BitPos Failed: " + "Base is Nil") 2801 } 2802 2803 if !b.core.cnAreReady { 2804 return 0, errors.New("Redis BitPos Failed: " + "Endpoint Connections Not Ready") 2805 } 2806 2807 if len(key) <= 0 { 2808 return 0, errors.New("Redis BitPos Failed: " + "Key is Required") 2809 } 2810 2811 if bitValue != 0 && bitValue != 1 { 2812 return 0, errors.New("Redis BitPos Failed: " + "Bit Value Must Be 1 or 0") 2813 } 2814 2815 cmd := b.core.cnReader.BitPos(b.core.cnReader.Context(), key, bitValue, startPosition...) 2816 valPosition, _, err = b.core.handleIntCmd(cmd, "Redis BitPos Failed: ") 2817 return valPosition, err 2818 } 2819 2820 // ---------------------------------------------------------------------------------------------------------------- 2821 // LIST functions 2822 // ---------------------------------------------------------------------------------------------------------------- 2823 2824 // LSet will set element to the list index 2825 func (l *LIST) LSet(key string, index int64, value interface{}) (err error) { 2826 // get new xray segment for tracing 2827 seg := xray.NewSegmentNullable("Redis-LSet", l.core._parentSegment) 2828 2829 if seg != nil { 2830 defer seg.Close() 2831 defer func() { 2832 _ = seg.Seg.AddMetadata("Redis-LSet-Key", key) 2833 _ = seg.Seg.AddMetadata("Redis-LSet-Index", index) 2834 _ = seg.Seg.AddMetadata("Redis-LSet-value", value) 2835 2836 if err != nil { 2837 _ = seg.Seg.AddError(err) 2838 } 2839 }() 2840 2841 err = l.lsetInternal(key, index, value) 2842 return err 2843 } else { 2844 return l.lsetInternal(key, index, value) 2845 } 2846 } 2847 2848 // lsetInternal will set element to the list index 2849 func (l *LIST) lsetInternal(key string, index int64, value interface{}) error { 2850 // validate 2851 if l.core == nil { 2852 return errors.New("Redis LSet Failed: " + "Base is Nil") 2853 } 2854 2855 if !l.core.cnAreReady { 2856 return errors.New("Redis LSet Failed: " + "Endpoint Connections Not Ready") 2857 } 2858 2859 if len(key) <= 0 { 2860 return errors.New("Redis LSet Failed: " + "Key is Required") 2861 } 2862 2863 if value == nil { 2864 return errors.New("Redis LSet Failed: " + "Value is Required") 2865 } 2866 2867 cmd := l.core.cnWriter.LSet(l.core.cnWriter.Context(), key, index, value) 2868 return l.core.handleStatusCmd(cmd, "Redis LSet Failed: ") 2869 } 2870 2871 // LInsert will insert a value either before or after the pivot element 2872 func (l *LIST) LInsert(key string, bBefore bool, pivot interface{}, value interface{}) (err error) { 2873 // get new xray segment for tracing 2874 seg := xray.NewSegmentNullable("Redis-LInsert", l.core._parentSegment) 2875 2876 if seg != nil { 2877 defer seg.Close() 2878 defer func() { 2879 _ = seg.Seg.AddMetadata("Redis-LInsert-Key", key) 2880 _ = seg.Seg.AddMetadata("Redis-LInsert-Insert-Before", bBefore) 2881 _ = seg.Seg.AddMetadata("Redis-LInsert-Pivot-Element", pivot) 2882 _ = seg.Seg.AddMetadata("Redis-LInsert-Insert-Value", value) 2883 2884 if err != nil { 2885 _ = seg.Seg.AddError(err) 2886 } 2887 }() 2888 2889 err = l.linsertInternal(key, bBefore, pivot, value) 2890 return err 2891 } else { 2892 return l.linsertInternal(key, bBefore, pivot, value) 2893 } 2894 } 2895 2896 // linsertInternal will insert a value either before or after the pivot element 2897 func (l *LIST) linsertInternal(key string, bBefore bool, pivot interface{}, value interface{}) error { 2898 // validate 2899 if l.core == nil { 2900 return errors.New("Redis LInsert Failed: " + "Base is Nil") 2901 } 2902 2903 if !l.core.cnAreReady { 2904 return errors.New("Redis LInsert Failed: " + "Endpoint Connections Not Ready") 2905 } 2906 2907 if len(key) <= 0 { 2908 return errors.New("Redis LInsert Failed: " + "Key is Required") 2909 } 2910 2911 if pivot == nil { 2912 return errors.New("Redis LInsert Failed: " + "Pivot is Required") 2913 } 2914 2915 if value == nil { 2916 return errors.New("Redis LInsert Failed: " + "Value is Required") 2917 } 2918 2919 var cmd *redis.IntCmd 2920 2921 if bBefore { 2922 cmd = l.core.cnWriter.LInsertBefore(l.core.cnWriter.Context(), key, pivot, value) 2923 } else { 2924 cmd = l.core.cnWriter.LInsertAfter(l.core.cnWriter.Context(), key, pivot, value) 2925 } 2926 2927 _, _, err := l.core.handleIntCmd(cmd, "Redis LInsert Failed: ") 2928 return err 2929 } 2930 2931 // LPush stores all the specified values at the head of the list as defined by the key, 2932 // if key does not exist, then empty list is created before performing the push operation (unless keyMustExist bit is set) 2933 // 2934 // Elements are inserted one after the other to the head of the list, from the leftmost to the rightmost, 2935 // for example, LPush mylist a b c will result in a list containing c as first element, b as second element, and a as third element 2936 // 2937 // error is returned if the key is not holding a value of type list 2938 func (l *LIST) LPush(key string, keyMustExist bool, value ...interface{}) (err error) { 2939 // get new xray segment for tracing 2940 seg := xray.NewSegmentNullable("Redis-LPush", l.core._parentSegment) 2941 2942 if seg != nil { 2943 defer seg.Close() 2944 defer func() { 2945 _ = seg.Seg.AddMetadata("Redis-LPush-Key", key) 2946 _ = seg.Seg.AddMetadata("Redis-LPush-Key-Must-Exist", keyMustExist) 2947 _ = seg.Seg.AddMetadata("Redis-LPush-Values", value) 2948 2949 if err != nil { 2950 _ = seg.Seg.AddError(err) 2951 } 2952 }() 2953 2954 err = l.lpushInternal(key, keyMustExist, value...) 2955 return err 2956 } else { 2957 return l.lpushInternal(key, keyMustExist, value...) 2958 } 2959 } 2960 2961 // lpushInternal stores all the specified values at the head of the list as defined by the key, 2962 // if key does not exist, then empty list is created before performing the push operation (unless keyMustExist bit is set) 2963 // 2964 // Elements are inserted one after the other to the head of the list, from the leftmost to the rightmost, 2965 // for example, LPush mylist a b c will result in a list containing c as first element, b as second element, and a as third element 2966 // 2967 // error is returned if the key is not holding a value of type list 2968 func (l *LIST) lpushInternal(key string, keyMustExist bool, value ...interface{}) error { 2969 // validate 2970 if l.core == nil { 2971 return errors.New("Redis LPush Failed: " + "Base is Nil") 2972 } 2973 2974 if !l.core.cnAreReady { 2975 return errors.New("Redis LPush Failed: " + "Endpoint Connections Not Ready") 2976 } 2977 2978 if len(key) <= 0 { 2979 return errors.New("Redis LPush Failed: " + "Key is Required") 2980 } 2981 2982 if len(value) <= 0 { 2983 return errors.New("Redis LPush Failed: " + "At Least 1 Value is Required") 2984 } 2985 2986 var cmd *redis.IntCmd 2987 2988 if !keyMustExist { 2989 cmd = l.core.cnWriter.LPush(l.core.cnWriter.Context(), key, value...) 2990 } else { 2991 cmd = l.core.cnWriter.LPushX(l.core.cnWriter.Context(), key, value...) 2992 } 2993 2994 _, _, err := l.core.handleIntCmd(cmd, "Redis LPush Failed: ") 2995 return err 2996 } 2997 2998 // RPush stores all the specified values at the tail of the list as defined by the key, 2999 // if key does not exist, then empty list is created before performing the push operation (unless keyMustExist bit is set) 3000 // 3001 // Elements are inserted one after the other to the tail of the list, from the leftmost to the rightmost, 3002 // for example, RPush mylist a b c will result in a list containing a as first element, b as second element, and c as third element 3003 // 3004 // error is returned if the key is not holding a value of type list 3005 func (l *LIST) RPush(key string, keyMustExist bool, value ...interface{}) (err error) { 3006 // get new xray segment for tracing 3007 seg := xray.NewSegmentNullable("Redis-RPush", l.core._parentSegment) 3008 3009 if seg != nil { 3010 defer seg.Close() 3011 defer func() { 3012 _ = seg.Seg.AddMetadata("Redis-RPush-Key", key) 3013 _ = seg.Seg.AddMetadata("Redis-RPush-Key-Must-Exist", keyMustExist) 3014 _ = seg.Seg.AddMetadata("Redis-RPush-Values", value) 3015 3016 if err != nil { 3017 _ = seg.Seg.AddError(err) 3018 } 3019 }() 3020 3021 err = l.rpushInternal(key, keyMustExist, value...) 3022 return err 3023 } else { 3024 return l.rpushInternal(key, keyMustExist, value...) 3025 } 3026 } 3027 3028 // rpushInternal stores all the specified values at the tail of the list as defined by the key, 3029 // if key does not exist, then empty list is created before performing the push operation (unless keyMustExist bit is set) 3030 // 3031 // Elements are inserted one after the other to the tail of the list, from the leftmost to the rightmost, 3032 // for example, RPush mylist a b c will result in a list containing a as first element, b as second element, and c as third element 3033 // 3034 // error is returned if the key is not holding a value of type list 3035 func (l *LIST) rpushInternal(key string, keyMustExist bool, value ...interface{}) error { 3036 // validate 3037 if l.core == nil { 3038 return errors.New("Redis RPush Failed: " + "Base is Nil") 3039 } 3040 3041 if !l.core.cnAreReady { 3042 return errors.New("Redis RPush Failed: " + "Endpoint Connections Not Ready") 3043 } 3044 3045 if len(key) <= 0 { 3046 return errors.New("Redis RPush Failed: " + "Key is Required") 3047 } 3048 3049 if len(value) <= 0 { 3050 return errors.New("Redis RPush Failed: " + "At Least 1 Value is Required") 3051 } 3052 3053 var cmd *redis.IntCmd 3054 3055 if !keyMustExist { 3056 cmd = l.core.cnWriter.RPush(l.core.cnWriter.Context(), key, value...) 3057 } else { 3058 cmd = l.core.cnWriter.RPushX(l.core.cnWriter.Context(), key, value...) 3059 } 3060 3061 _, _, err := l.core.handleIntCmd(cmd, "Redis RPush Failed: ") 3062 return err 3063 } 3064 3065 // LPop will remove and return the first element from the list stored at key 3066 func (l *LIST) LPop(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3067 // get new xray segment for tracing 3068 seg := xray.NewSegmentNullable("Redis-LPop", l.core._parentSegment) 3069 3070 if seg != nil { 3071 defer seg.Close() 3072 defer func() { 3073 _ = seg.Seg.AddMetadata("Redis-LPop-Key", key) 3074 _ = seg.Seg.AddMetadata("Redis-LPop-Output-Data-Type", outputDataType) 3075 _ = seg.Seg.AddMetadata("Redis-LPop-Not-Found", notFound) 3076 _ = seg.Seg.AddMetadata("Redis-LPop-Output-Object", outputObjectPtr) 3077 3078 if err != nil { 3079 _ = seg.Seg.AddError(err) 3080 } 3081 }() 3082 3083 notFound, err = l.lpopInternal(key, outputDataType, outputObjectPtr) 3084 return notFound, err 3085 } else { 3086 return l.lpopInternal(key, outputDataType, outputObjectPtr) 3087 } 3088 } 3089 3090 // lpopInternal will remove and return the first element from the list stored at key 3091 func (l *LIST) lpopInternal(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3092 // validate 3093 if l.core == nil { 3094 return false, errors.New("Redis LPop Failed: " + "Base is Nil") 3095 } 3096 3097 if !l.core.cnAreReady { 3098 return false, errors.New("Redis LPop Failed: " + "Endpoint Connections Not Ready") 3099 } 3100 3101 if len(key) <= 0 { 3102 return false, errors.New("Redis LPop Failed: " + "Key is Required") 3103 } 3104 3105 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 3106 return false, errors.New("Redis LPop Failed: " + "Output Data Type is Required") 3107 } 3108 3109 if outputObjectPtr == nil { 3110 return false, errors.New("Redis LPop Failed: " + "Output Object Pointer is Required") 3111 } 3112 3113 cmd := l.core.cnWriter.LPop(l.core.cnWriter.Context(), key) 3114 return l.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis LPop Failed: ") 3115 } 3116 3117 // RPop removes and returns the last element of the list stored at key 3118 func (l *LIST) RPop(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3119 // get new xray segment for tracing 3120 seg := xray.NewSegmentNullable("Redis-RPop", l.core._parentSegment) 3121 3122 if seg != nil { 3123 defer seg.Close() 3124 defer func() { 3125 _ = seg.Seg.AddMetadata("Redis-RPop-Key", key) 3126 _ = seg.Seg.AddMetadata("Redis-RPop-Output-Data-Type", outputDataType) 3127 _ = seg.Seg.AddMetadata("Redis-RPop-Not-Found", notFound) 3128 _ = seg.Seg.AddMetadata("Redis-RPop-Output-Object", outputObjectPtr) 3129 3130 if err != nil { 3131 _ = seg.Seg.AddError(err) 3132 } 3133 }() 3134 3135 notFound, err = l.rpopInternal(key, outputDataType, outputObjectPtr) 3136 return notFound, err 3137 } else { 3138 return l.rpopInternal(key, outputDataType, outputObjectPtr) 3139 } 3140 } 3141 3142 // rpopInternal removes and returns the last element of the list stored at key 3143 func (l *LIST) rpopInternal(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3144 // validate 3145 if l.core == nil { 3146 return false, errors.New("Redis RPop Failed: " + "Base is Nil") 3147 } 3148 3149 if !l.core.cnAreReady { 3150 return false, errors.New("Redis RPop Failed: " + "Endpoint Connections Not Ready") 3151 } 3152 3153 if len(key) <= 0 { 3154 return false, errors.New("Redis RPop Failed: " + "Key is Required") 3155 } 3156 3157 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 3158 return false, errors.New("Redis RPop Failed: " + "Output Data Type is Required") 3159 } 3160 3161 if outputObjectPtr == nil { 3162 return false, errors.New("Redis RPop Failed: " + "Output Object Pointer is Required") 3163 } 3164 3165 cmd := l.core.cnWriter.RPop(l.core.cnWriter.Context(), key) 3166 return l.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis RPop Failed: ") 3167 } 3168 3169 // RPopLPush will atomically remove and return last element of the list stored at keySource, 3170 // and then push the returned element at first element position (head) of the list stored at keyDest 3171 func (l *LIST) RPopLPush(keySource string, keyDest string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3172 // get new xray segment for tracing 3173 seg := xray.NewSegmentNullable("Redis-RPopLPush", l.core._parentSegment) 3174 3175 if seg != nil { 3176 defer seg.Close() 3177 defer func() { 3178 _ = seg.Seg.AddMetadata("Redis-RPopLPush-KeySource", keySource) 3179 _ = seg.Seg.AddMetadata("Redis-RPopLPush-KeyDest", keyDest) 3180 _ = seg.Seg.AddMetadata("Redis-RPopLPush-Output-Data-Type", outputDataType) 3181 _ = seg.Seg.AddMetadata("Redis-RPopLPush-Not-Found", notFound) 3182 _ = seg.Seg.AddMetadata("Redis-RPopLPush-Output-Object", outputObjectPtr) 3183 3184 if err != nil { 3185 _ = seg.Seg.AddError(err) 3186 } 3187 }() 3188 3189 notFound, err = l.rpopLPushInternal(keySource, keyDest, outputDataType, outputObjectPtr) 3190 return notFound, err 3191 } else { 3192 return l.rpopLPushInternal(keySource, keyDest, outputDataType, outputObjectPtr) 3193 } 3194 } 3195 3196 // rpopLPushInternal will atomically remove and return last element of the list stored at keySource, 3197 // and then push the returned element at first element position (head) of the list stored at keyDest 3198 func (l *LIST) rpopLPushInternal(keySource string, keyDest string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3199 // validate 3200 if l.core == nil { 3201 return false, errors.New("Redis RPopLPush Failed: " + "Base is Nil") 3202 } 3203 3204 if !l.core.cnAreReady { 3205 return false, errors.New("Redis RPopLPush Failed: " + "Endpoint Connections Not Ready") 3206 } 3207 3208 if len(keySource) <= 0 { 3209 return false, errors.New("Redis RPopLPush Failed: " + "Key Source is Required") 3210 } 3211 3212 if len(keyDest) <= 0 { 3213 return false, errors.New("Redis RPopLPush Failed: " + "Key Destination is Required") 3214 } 3215 3216 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 3217 return false, errors.New("Redis RPopLPush Failed: " + "Output Data Type is Required") 3218 } 3219 3220 if outputObjectPtr == nil { 3221 return false, errors.New("Redis RPopLPush Failed: " + "Output Object Pointer is Required") 3222 } 3223 3224 cmd := l.core.cnWriter.RPopLPush(l.core.cnWriter.Context(), keySource, keyDest) 3225 return l.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis RPopLPush Failed: ") 3226 } 3227 3228 // LIndex returns the element by list index position, for the value stored in list by key, 3229 // Index is zero-based, 3230 // Negative Index can be used to denote reverse order, 3231 // 3232 // such as -1 = last element 3233 // such as -2 = second to last element, and so on 3234 // 3235 // Error is returned if value at key is not a list 3236 func (l *LIST) LIndex(key string, index int64, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3237 // get new xray segment for tracing 3238 seg := xray.NewSegmentNullable("Redis-LIndex", l.core._parentSegment) 3239 3240 if seg != nil { 3241 defer seg.Close() 3242 defer func() { 3243 _ = seg.Seg.AddMetadata("Redis-LIndex-Key", key) 3244 _ = seg.Seg.AddMetadata("Redis-LIndex-Index", index) 3245 _ = seg.Seg.AddMetadata("Redis-LIndex-Output-Data-Type", outputDataType) 3246 _ = seg.Seg.AddMetadata("Redis-LIndex-Output-Not-Found", notFound) 3247 _ = seg.Seg.AddMetadata("Redis-LIndex-Output-Object", outputObjectPtr) 3248 3249 if err != nil { 3250 _ = seg.Seg.AddError(err) 3251 } 3252 }() 3253 3254 notFound, err = l.lindexInternal(key, index, outputDataType, outputObjectPtr) 3255 return notFound, err 3256 } else { 3257 return l.lindexInternal(key, index, outputDataType, outputObjectPtr) 3258 } 3259 } 3260 3261 // lindexInternal returns the element by list index position, for the value stored in list by key, 3262 // Index is zero-based, 3263 // Negative Index can be used to denote reverse order, 3264 // 3265 // such as -1 = last element 3266 // such as -2 = second to last element, and so on 3267 // 3268 // Error is returned if value at key is not a list 3269 func (l *LIST) lindexInternal(key string, index int64, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3270 // validate 3271 if l.core == nil { 3272 return false, errors.New("Redis LIndex Failed: " + "Base is Nil") 3273 } 3274 3275 if !l.core.cnAreReady { 3276 return false, errors.New("Redis LIndex Failed: " + "Endpoint Connections Not Ready") 3277 } 3278 3279 if len(key) <= 0 { 3280 return false, errors.New("Redis LIndex Failed: " + "Key is Required") 3281 } 3282 3283 cmd := l.core.cnReader.LIndex(l.core.cnReader.Context(), key, index) 3284 return l.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis LIndex Failed: ") 3285 } 3286 3287 // LLen returns the length of the list stored at key, 3288 // if key does not exist, it is treated as empty list and 0 is returned, 3289 // 3290 // Error is returned if value at key is not a list 3291 func (l *LIST) LLen(key string) (val int64, notFound bool, err error) { 3292 // get new xray segment for tracing 3293 seg := xray.NewSegmentNullable("Redis-LLen", l.core._parentSegment) 3294 3295 if seg != nil { 3296 defer seg.Close() 3297 defer func() { 3298 _ = seg.Seg.AddMetadata("Redis-LLen-Key", key) 3299 _ = seg.Seg.AddMetadata("Redis-LLen-Not-Found", notFound) 3300 _ = seg.Seg.AddMetadata("Redis-LLen-Result", val) 3301 3302 if err != nil { 3303 _ = seg.Seg.AddError(err) 3304 } 3305 }() 3306 3307 val, notFound, err = l.llenInternal(key) 3308 return val, notFound, err 3309 } else { 3310 return l.llenInternal(key) 3311 } 3312 } 3313 3314 // llenInternal returns the length of the list stored at key, 3315 // if key does not exist, it is treated as empty list and 0 is returned, 3316 // 3317 // Error is returned if value at key is not a list 3318 func (l *LIST) llenInternal(key string) (val int64, notFound bool, err error) { 3319 // validate 3320 if l.core == nil { 3321 return 0, false, errors.New("Redis LLen Failed: " + "Base is Nil") 3322 } 3323 3324 if !l.core.cnAreReady { 3325 return 0, false, errors.New("Redis LLen Failed: " + "Endpoint Connections Not Ready") 3326 } 3327 3328 if len(key) <= 0 { 3329 return 0, false, errors.New("Redis LLen Failed: " + "Key is Required") 3330 } 3331 3332 cmd := l.core.cnReader.LLen(l.core.cnReader.Context(), key) 3333 return l.core.handleIntCmd(cmd, "Redis LLen Failed: ") 3334 } 3335 3336 // LRange returns the specified elements of the list stored at key, 3337 // Offsets start and stop are zero based indexes, 3338 // Offsets can be negative, where -1 is the last element, while -2 is next to last element, and so on, 3339 // 3340 // Offsets start > stop, empty list is returned, 3341 // Offsets stop > last element, stop uses last element instead 3342 // 3343 // Example: 3344 // 3345 // start top = 0 - 10 = returns 11 elements (0 to 10 = 11) 3346 func (l *LIST) LRange(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 3347 // get new xray segment for tracing 3348 seg := xray.NewSegmentNullable("Redis-LRange", l.core._parentSegment) 3349 3350 if seg != nil { 3351 defer seg.Close() 3352 defer func() { 3353 _ = seg.Seg.AddMetadata("Redis-LRange-Key", key) 3354 _ = seg.Seg.AddMetadata("Redis-LRange-Start", start) 3355 _ = seg.Seg.AddMetadata("Redis-LRange-Stop", stop) 3356 _ = seg.Seg.AddMetadata("Redis-LRange-Not-Found", notFound) 3357 _ = seg.Seg.AddMetadata("Redis-LRange-Result", outputSlice) 3358 3359 if err != nil { 3360 _ = seg.Seg.AddError(err) 3361 } 3362 }() 3363 3364 outputSlice, notFound, err = l.lrangeInternal(key, start, stop) 3365 return outputSlice, notFound, err 3366 } else { 3367 return l.lrangeInternal(key, start, stop) 3368 } 3369 } 3370 3371 // lrangeInternal returns the specified elements of the list stored at key, 3372 // Offsets start and stop are zero based indexes, 3373 // Offsets can be negative, where -1 is the last element, while -2 is next to last element, and so on, 3374 // 3375 // Offsets start > stop, empty list is returned, 3376 // Offsets stop > last element, stop uses last element instead 3377 // 3378 // Example: 3379 // 3380 // start top = 0 - 10 = returns 11 elements (0 to 10 = 11) 3381 func (l *LIST) lrangeInternal(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 3382 // validate 3383 if l.core == nil { 3384 return nil, false, errors.New("Redis LRange Failed: " + "Base is Nil") 3385 } 3386 3387 if !l.core.cnAreReady { 3388 return nil, false, errors.New("Redis LRange Failed: " + "Endpoint Connections Not Ready") 3389 } 3390 3391 if len(key) <= 0 { 3392 return nil, false, errors.New("Redis LRange Failed: " + "Key is Required") 3393 } 3394 3395 cmd := l.core.cnReader.LRange(l.core.cnReader.Context(), key, start, stop) 3396 return l.core.handleStringSliceCmd(cmd, "Redis LRange Failed: ") 3397 } 3398 3399 // LRem removes the first count occurrences of elements equal to 'element value' from list stored at key 3400 // count indicates number of occurrences 3401 // 3402 // count > 0 = removes elements equal to 'element value' moving from head to tail 3403 // count < 0 = removes elements equal to 'element value' moving from tail to head 3404 // count = 0 = removes all elements equal to 'element value' 3405 // 3406 // Example: 3407 // 3408 // LREM list 02 "hello" = removes the last two occurrences of "hello" in the list stored at key named 'list' 3409 func (l *LIST) LRem(key string, count int64, value interface{}) (err error) { 3410 // get new xray segment for tracing 3411 seg := xray.NewSegmentNullable("Redis-LRem", l.core._parentSegment) 3412 3413 if seg != nil { 3414 defer seg.Close() 3415 defer func() { 3416 _ = seg.Seg.AddMetadata("Redis-LRem-Key", key) 3417 _ = seg.Seg.AddMetadata("Redis-LRem-Count", count) 3418 _ = seg.Seg.AddMetadata("Redis-LRem-Value", value) 3419 3420 if err != nil { 3421 _ = seg.Seg.AddError(err) 3422 } 3423 }() 3424 3425 err = l.lremInternal(key, count, value) 3426 return err 3427 } else { 3428 return l.lremInternal(key, count, value) 3429 } 3430 } 3431 3432 // lremInternal removes the first count occurrences of elements equal to 'element value' from list stored at key 3433 // count indicates number of occurrences 3434 // 3435 // count > 0 = removes elements equal to 'element value' moving from head to tail 3436 // count < 0 = removes elements equal to 'element value' moving from tail to head 3437 // count = 0 = removes all elements equal to 'element value' 3438 // 3439 // Example: 3440 // 3441 // LREM list 02 "hello" = removes the last two occurrences of "hello" in the list stored at key named 'list' 3442 func (l *LIST) lremInternal(key string, count int64, value interface{}) error { 3443 // validate 3444 if l.core == nil { 3445 return errors.New("Redis LRem Failed: " + "Base is Nil") 3446 } 3447 3448 if !l.core.cnAreReady { 3449 return errors.New("Redis LRem Failed: " + "Endpoint Connections Not Ready") 3450 } 3451 3452 if len(key) <= 0 { 3453 return errors.New("Redis LRem Failed: " + "Key is Required") 3454 } 3455 3456 if value == nil { 3457 return errors.New("Redis LRem Failed: " + "Value is Required") 3458 } 3459 3460 cmd := l.core.cnWriter.LRem(l.core.cnWriter.Context(), key, count, value) 3461 return l.core.handleIntCmd2(cmd, "Redis LRem Failed: ") 3462 } 3463 3464 // LTrim will trim an existing list so that it will contian only the specified range of elements specified, 3465 // Both start and stop are zero-based indexes, 3466 // Both start and stop can be negative, where -1 is the last element, while -2 is the second to last element 3467 // 3468 // Example: 3469 // 3470 // LTRIM foobar 0 2 = modifies the list store at key named 'foobar' so that only the first 3 elements of the list will remain 3471 func (l *LIST) LTrim(key string, start int64, stop int64) (err error) { 3472 // get new xray segment for tracing 3473 seg := xray.NewSegmentNullable("Redis-LTrim", l.core._parentSegment) 3474 3475 if seg != nil { 3476 defer seg.Close() 3477 defer func() { 3478 _ = seg.Seg.AddMetadata("Redis-LTrim-Key", key) 3479 _ = seg.Seg.AddMetadata("Redis-LTrim-Start", start) 3480 _ = seg.Seg.AddMetadata("Redis-LTrim-Stop", stop) 3481 3482 if err != nil { 3483 _ = seg.Seg.AddError(err) 3484 } 3485 }() 3486 3487 err = l.ltrimInternal(key, start, stop) 3488 return err 3489 } else { 3490 return l.ltrimInternal(key, start, stop) 3491 } 3492 } 3493 3494 // ltrimInternal will trim an existing list so that it will contian only the specified range of elements specified, 3495 // Both start and stop are zero-based indexes, 3496 // Both start and stop can be negative, where -1 is the last element, while -2 is the second to last element 3497 // 3498 // Example: 3499 // 3500 // LTRIM foobar 0 2 = modifies the list store at key named 'foobar' so that only the first 3 elements of the list will remain 3501 func (l *LIST) ltrimInternal(key string, start int64, stop int64) error { 3502 // validate 3503 if l.core == nil { 3504 return errors.New("Redis LTrim Failed: " + "Base is Nil") 3505 } 3506 3507 if !l.core.cnAreReady { 3508 return errors.New("Redis LTrim Failed: " + "Endpoint Connections Not Ready") 3509 } 3510 3511 if len(key) <= 0 { 3512 return errors.New("Redis LTrim Failed: " + "Key is Required") 3513 } 3514 3515 cmd := l.core.cnWriter.LTrim(l.core.cnWriter.Context(), key, start, stop) 3516 return l.core.handleStatusCmd(cmd, "Redis LTrim Failed: ") 3517 } 3518 3519 // ---------------------------------------------------------------------------------------------------------------- 3520 // HASH functions 3521 // ---------------------------------------------------------------------------------------------------------------- 3522 3523 // HExists returns if field is an existing field in the hash stored at key 3524 // 3525 // 1 = exists; 0 = not exist or key not exist 3526 func (h *HASH) HExists(key string, field string) (valExists bool, err error) { 3527 // get new xray segment for tracing 3528 seg := xray.NewSegmentNullable("Redis-HExists", h.core._parentSegment) 3529 3530 if seg != nil { 3531 defer seg.Close() 3532 defer func() { 3533 _ = seg.Seg.AddMetadata("Redis-HExists-Key", key) 3534 _ = seg.Seg.AddMetadata("Redis-HExists-Field", field) 3535 _ = seg.Seg.AddMetadata("Redis-HExists-Result-Exists", valExists) 3536 3537 if err != nil { 3538 _ = seg.Seg.AddError(err) 3539 } 3540 }() 3541 3542 valExists, err = h.hexistsInternal(key, field) 3543 return valExists, err 3544 } else { 3545 return h.hexistsInternal(key, field) 3546 } 3547 } 3548 3549 // hexistsInternal returns if field is an existing field in the hash stored at key 3550 // 3551 // 1 = exists; 0 = not exist or key not exist 3552 func (h *HASH) hexistsInternal(key string, field string) (valExists bool, err error) { 3553 // validate 3554 if h.core == nil { 3555 return false, errors.New("Redis HExists Failed: " + "Base is Nil") 3556 } 3557 3558 if !h.core.cnAreReady { 3559 return false, errors.New("Redis HExists Failed: " + "Endpoint Connections Not Ready") 3560 } 3561 3562 if len(key) <= 0 { 3563 return false, errors.New("Redis HExists Failed: " + "Key is Required") 3564 } 3565 3566 if len(field) <= 0 { 3567 return false, errors.New("Redis HExists Failed: " + "Field is Required") 3568 } 3569 3570 cmd := h.core.cnReader.HExists(h.core.cnReader.Context(), key, field) 3571 return h.core.handleBoolCmd(cmd, "Redis HExists Failed: ") 3572 } 3573 3574 // HLen returns the number of fields contained in the hash stored at key 3575 func (h *HASH) HLen(key string) (valLen int64, notFound bool, err error) { 3576 // get new xray segment for tracing 3577 seg := xray.NewSegmentNullable("Redis-HLen", h.core._parentSegment) 3578 3579 if seg != nil { 3580 defer seg.Close() 3581 defer func() { 3582 _ = seg.Seg.AddMetadata("Redis-HLen-Key", key) 3583 _ = seg.Seg.AddMetadata("Redis-HLen-Not-Found", notFound) 3584 _ = seg.Seg.AddMetadata("Redis-HLen-Result-Length", valLen) 3585 3586 if err != nil { 3587 _ = seg.Seg.AddError(err) 3588 } 3589 }() 3590 3591 valLen, notFound, err = h.hlenInternal(key) 3592 return valLen, notFound, err 3593 } else { 3594 return h.hlenInternal(key) 3595 } 3596 } 3597 3598 // hlenInternal returns the number of fields contained in the hash stored at key 3599 func (h *HASH) hlenInternal(key string) (valLen int64, notFound bool, err error) { 3600 // validate 3601 if h.core == nil { 3602 return 0, false, errors.New("Redis HLen Failed: " + "Base is Nil") 3603 } 3604 3605 if !h.core.cnAreReady { 3606 return 0, false, errors.New("Redis HLen Failed: " + "Endpoint Connections Not Ready") 3607 } 3608 3609 if len(key) <= 0 { 3610 return 0, false, errors.New("Redis HLen Failed: " + "Key is Required") 3611 } 3612 3613 cmd := h.core.cnReader.HLen(h.core.cnReader.Context(), key) 3614 return h.core.handleIntCmd(cmd, "Redis HLen Failed: ") 3615 } 3616 3617 // HSet will set 'field' in hash stored at key to 'value', 3618 // if key does not exist, a new key holding a hash is created, 3619 // 3620 // if 'field' already exists in the hash, it will be overridden 3621 // if 'field' does not exist, it will be added 3622 func (h *HASH) HSet(key string, value ...interface{}) (err error) { 3623 // get new xray segment for tracing 3624 seg := xray.NewSegmentNullable("Redis-HSet", h.core._parentSegment) 3625 3626 if seg != nil { 3627 defer seg.Close() 3628 defer func() { 3629 _ = seg.Seg.AddMetadata("Redis-HSet-Key", key) 3630 _ = seg.Seg.AddMetadata("Redis-HSet-Values", value) 3631 3632 if err != nil { 3633 _ = seg.Seg.AddError(err) 3634 } 3635 }() 3636 3637 err = h.hsetInternal(key, value...) 3638 return err 3639 } else { 3640 return h.hsetInternal(key, value...) 3641 } 3642 } 3643 3644 // hsetInternal will set 'field' in hash stored at key to 'value', 3645 // if key does not exist, a new key holding a hash is created, 3646 // 3647 // if 'field' already exists in the hash, it will be overridden 3648 // if 'field' does not exist, it will be added 3649 func (h *HASH) hsetInternal(key string, value ...interface{}) error { 3650 // validate 3651 if h.core == nil { 3652 return errors.New("Redis HSet Failed: " + "Base is Nil") 3653 } 3654 3655 if !h.core.cnAreReady { 3656 return errors.New("Redis HSet Failed: " + "Endpoint Connections Not Ready") 3657 } 3658 3659 if len(key) <= 0 { 3660 return errors.New("Redis HSet Failed: " + "Key is Required") 3661 } 3662 3663 if len(value) <= 0 { 3664 return errors.New("Redis HSet Failed: " + "At Least 1 Value is Required") 3665 } 3666 3667 cmd := h.core.cnWriter.HSet(h.core.cnWriter.Context(), key, value...) 3668 return h.core.handleIntCmd2(cmd, "Redis HSet Failed: ") 3669 } 3670 3671 // HSetNX will set 'field' in hash stored at key to 'value', 3672 // if 'field' does not currently existing in hash 3673 // 3674 // note: 3675 // 3676 // 'field' must not yet exist in hash, otherwise will not add 3677 func (h *HASH) HSetNX(key string, field string, value interface{}) (err error) { 3678 // get new xray segment for tracing 3679 seg := xray.NewSegmentNullable("Redis-HSetNX", h.core._parentSegment) 3680 3681 if seg != nil { 3682 defer seg.Close() 3683 defer func() { 3684 _ = seg.Seg.AddMetadata("Redis-HSetNX-Key", key) 3685 _ = seg.Seg.AddMetadata("Redis-HSetNX-Field", field) 3686 _ = seg.Seg.AddMetadata("Redis-HSetNX-Value", value) 3687 3688 if err != nil { 3689 _ = seg.Seg.AddError(err) 3690 } 3691 }() 3692 3693 err = h.hsetNXInternal(key, field, value) 3694 return err 3695 } else { 3696 return h.hsetNXInternal(key, field, value) 3697 } 3698 } 3699 3700 // hsetNXInternal will set 'field' in hash stored at key to 'value', 3701 // if 'field' does not currently existing in hash 3702 // 3703 // note: 3704 // 3705 // 'field' must not yet exist in hash, otherwise will not add 3706 func (h *HASH) hsetNXInternal(key string, field string, value interface{}) error { 3707 // validate 3708 if h.core == nil { 3709 return errors.New("Redis HSetNX Failed: " + "Base is Nil") 3710 } 3711 3712 if !h.core.cnAreReady { 3713 return errors.New("Redis HSetNX Failed: " + "Endpoint Connections Not Ready") 3714 } 3715 3716 if len(key) <= 0 { 3717 return errors.New("Redis HSetNX Failed: " + "Key is Required") 3718 } 3719 3720 if len(field) <= 0 { 3721 return errors.New("Redis HSetNX Failed: " + "Field is Required") 3722 } 3723 3724 if value == nil { 3725 return errors.New("Redis HSetNX Failed: " + "Value is Required") 3726 } 3727 3728 cmd := h.core.cnWriter.HSetNX(h.core.cnWriter.Context(), key, field, value) 3729 3730 if val, err := h.core.handleBoolCmd(cmd, "Redis HSetNX Failed: "); err != nil { 3731 return err 3732 } else { 3733 if val { 3734 // success 3735 return nil 3736 } else { 3737 // error 3738 return errors.New("Redis HSetNX Failed: " + "Action Result Yielded False") 3739 } 3740 } 3741 } 3742 3743 // HGet returns the value associated with 'field' in the hash stored at key 3744 func (h *HASH) HGet(key string, field string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3745 // get new xray segment for tracing 3746 seg := xray.NewSegmentNullable("Redis-HGet", h.core._parentSegment) 3747 3748 if seg != nil { 3749 defer seg.Close() 3750 defer func() { 3751 _ = seg.Seg.AddMetadata("Redis-HGet-Key", key) 3752 _ = seg.Seg.AddMetadata("Redis-HGet-Field", field) 3753 _ = seg.Seg.AddMetadata("Redis-HGet-Output-Data-Type", outputDataType) 3754 _ = seg.Seg.AddMetadata("Redis-HGet-Not-Found", notFound) 3755 _ = seg.Seg.AddMetadata("Redis-HGet-Output-Object", outputObjectPtr) 3756 3757 if err != nil { 3758 _ = seg.Seg.AddError(err) 3759 } 3760 }() 3761 3762 notFound, err = h.hgetInternal(key, field, outputDataType, outputObjectPtr) 3763 return notFound, err 3764 } else { 3765 return h.hgetInternal(key, field, outputDataType, outputObjectPtr) 3766 } 3767 } 3768 3769 // hgetInternal returns the value associated with 'field' in the hash stored at key 3770 func (h *HASH) hgetInternal(key string, field string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 3771 // validate 3772 if h.core == nil { 3773 return false, errors.New("Redis HGet Failed: " + "Base is Nil") 3774 } 3775 3776 if !h.core.cnAreReady { 3777 return false, errors.New("Redis HGet Failed: " + "Endpoint Connections Not Ready") 3778 } 3779 3780 if len(key) <= 0 { 3781 return false, errors.New("Redis HGet Failed: " + "Key is Required") 3782 } 3783 3784 if len(field) <= 0 { 3785 return false, errors.New("Redis HGet Failed: " + "Field is Required") 3786 } 3787 3788 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 3789 return false, errors.New("Redis HGet Failed: " + "Output Data Type is Required") 3790 } 3791 3792 if outputObjectPtr == nil { 3793 return false, errors.New("Redis HGet Failed: " + "Output Object Pointer is Required") 3794 } 3795 3796 cmd := h.core.cnReader.HGet(h.core.cnReader.Context(), key, field) 3797 return h.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis HGet Failed: ") 3798 } 3799 3800 // HGetAll returns all fields and values of the hash store at key, 3801 // in the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash 3802 func (h *HASH) HGetAll(key string) (outputMap map[string]string, notFound bool, err error) { 3803 // get new xray segment for tracing 3804 seg := xray.NewSegmentNullable("Redis-HGetAll", h.core._parentSegment) 3805 3806 if seg != nil { 3807 defer seg.Close() 3808 defer func() { 3809 _ = seg.Seg.AddMetadata("Redis-HGetAll-Key", key) 3810 _ = seg.Seg.AddMetadata("Redis-HGetAll-Not-Found", notFound) 3811 _ = seg.Seg.AddMetadata("Redis-HGetAll-Result", outputMap) 3812 3813 if err != nil { 3814 _ = seg.Seg.AddError(err) 3815 } 3816 }() 3817 3818 outputMap, notFound, err = h.hgetAllInternal(key) 3819 return outputMap, notFound, err 3820 } else { 3821 return h.hgetAllInternal(key) 3822 } 3823 } 3824 3825 // hgetAllInternal returns all fields and values of the hash store at key, 3826 // in the returned value, every field name is followed by its value, so the length of the reply is twice the size of the hash 3827 func (h *HASH) hgetAllInternal(key string) (outputMap map[string]string, notFound bool, err error) { 3828 // validate 3829 if h.core == nil { 3830 return nil, false, errors.New("Redis HGetAll Failed: " + "Base is Nil") 3831 } 3832 3833 if !h.core.cnAreReady { 3834 return nil, false, errors.New("Redis HGetAll Failed: " + "Endpoint Connections Not Ready") 3835 } 3836 3837 if len(key) <= 0 { 3838 return nil, false, errors.New("Redis HGetAll Failed: " + "Key is Required") 3839 } 3840 3841 cmd := h.core.cnReader.HGetAll(h.core.cnReader.Context(), key) 3842 return h.core.handleStringStringMapCmd(cmd, "Redis HGetAll Failed: ") 3843 } 3844 3845 // HMSet will set the specified 'fields' to their respective values in the hash stored by key, 3846 // This command overrides any specified 'fields' already existing in the hash, 3847 // If key does not exist, a new key holding a hash is created 3848 func (h *HASH) HMSet(key string, value ...interface{}) (err error) { 3849 // get new xray segment for tracing 3850 seg := xray.NewSegmentNullable("Redis-HMSet", h.core._parentSegment) 3851 3852 if seg != nil { 3853 defer seg.Close() 3854 defer func() { 3855 _ = seg.Seg.AddMetadata("Redis-HMSet-Key", key) 3856 _ = seg.Seg.AddMetadata("Redis-HMSet-Values", value) 3857 3858 if err != nil { 3859 _ = seg.Seg.AddError(err) 3860 } 3861 }() 3862 3863 err = h.hmsetInternal(key, value...) 3864 return err 3865 } else { 3866 return h.hmsetInternal(key, value...) 3867 } 3868 } 3869 3870 // hmsetInternal will set the specified 'fields' to their respective values in the hash stored by key, 3871 // This command overrides any specified 'fields' already existing in the hash, 3872 // If key does not exist, a new key holding a hash is created 3873 func (h *HASH) hmsetInternal(key string, value ...interface{}) error { 3874 // validate 3875 if h.core == nil { 3876 return errors.New("Redis HMSet Failed: " + "Base is Nil") 3877 } 3878 3879 if !h.core.cnAreReady { 3880 return errors.New("Redis HMSet Failed: " + "Endpoint Connections Not Ready") 3881 } 3882 3883 if len(key) <= 0 { 3884 return errors.New("Redis HMSet Failed: " + "Key is Required") 3885 } 3886 3887 if len(value) <= 0 { 3888 return errors.New("Redis HMSet Failed: " + "At Least 1 Value is Required") 3889 } 3890 3891 cmd := h.core.cnWriter.HMSet(h.core.cnWriter.Context(), key, value...) 3892 3893 if val, err := h.core.handleBoolCmd(cmd, "Redis HMSet Failed: "); err != nil { 3894 return err 3895 } else { 3896 if val { 3897 // success 3898 return nil 3899 } else { 3900 // not success 3901 return errors.New("Redis HMSet Failed: " + "Action Result Yielded False") 3902 } 3903 } 3904 } 3905 3906 // HMGet will return the values associated with the specified 'fields' in the hash stored at key, 3907 // For every 'field' that does not exist in the hash, a nil value is returned, 3908 // If key is not existent, then nil is returned for all values 3909 func (h *HASH) HMGet(key string, field ...string) (outputSlice []interface{}, notFound bool, err error) { 3910 // get new xray segment for tracing 3911 seg := xray.NewSegmentNullable("Redis-HMGet", h.core._parentSegment) 3912 3913 if seg != nil { 3914 defer seg.Close() 3915 defer func() { 3916 _ = seg.Seg.AddMetadata("Redis-HMGet-Key", key) 3917 _ = seg.Seg.AddMetadata("Redis-HMGet-Fields", field) 3918 _ = seg.Seg.AddMetadata("Redis-HMGet-Not-Found", notFound) 3919 _ = seg.Seg.AddMetadata("Redis-HMGet-Result", outputSlice) 3920 3921 if err != nil { 3922 _ = seg.Seg.AddError(err) 3923 } 3924 }() 3925 3926 outputSlice, notFound, err = h.hmgetInternal(key, field...) 3927 return outputSlice, notFound, err 3928 } else { 3929 return h.hmgetInternal(key, field...) 3930 } 3931 } 3932 3933 // hmgetInternal will return the values associated with the specified 'fields' in the hash stored at key, 3934 // For every 'field' that does not exist in the hash, a nil value is returned, 3935 // If key is not existent, then nil is returned for all values 3936 func (h *HASH) hmgetInternal(key string, field ...string) (outputSlice []interface{}, notFound bool, err error) { 3937 // validate 3938 if h.core == nil { 3939 return nil, false, errors.New("Redis HMGet Failed: " + "Base is Nil") 3940 } 3941 3942 if !h.core.cnAreReady { 3943 return nil, false, errors.New("Redis HMGet Failed: " + "Endpoint Connections Not Ready") 3944 } 3945 3946 if len(key) <= 0 { 3947 return nil, false, errors.New("Redis HMGet Failed: " + "Key is Required") 3948 } 3949 3950 if len(field) <= 0 { 3951 return nil, false, errors.New("Redis HMGet Failed: " + "At Least 1 Field is Required") 3952 } 3953 3954 cmd := h.core.cnReader.HMGet(h.core.cnReader.Context(), key, field...) 3955 return h.core.handleSliceCmd(cmd, "Redis HMGet Failed: ") 3956 } 3957 3958 // HDel removes the specified 'fields' from the hash stored at key, 3959 // any specified 'fields' that do not exist in the hash are ignored, 3960 // if key does not exist, it is treated as an empty hash, and 0 is returned 3961 func (h *HASH) HDel(key string, field ...string) (deletedCount int64, err error) { 3962 // get new xray segment for tracing 3963 seg := xray.NewSegmentNullable("Redis-HDel", h.core._parentSegment) 3964 3965 if seg != nil { 3966 defer seg.Close() 3967 defer func() { 3968 _ = seg.Seg.AddMetadata("Redis-HDel-Key", key) 3969 _ = seg.Seg.AddMetadata("Redis-HDel-Fields", field) 3970 _ = seg.Seg.AddMetadata("Redis-HDel-Result-Deleted-Count", deletedCount) 3971 3972 if err != nil { 3973 _ = seg.Seg.AddError(err) 3974 } 3975 }() 3976 3977 deletedCount, err = h.hdelInternal(key, field...) 3978 return deletedCount, err 3979 } else { 3980 return h.hdelInternal(key, field...) 3981 } 3982 } 3983 3984 // hdelInternal removes the specified 'fields' from the hash stored at key, 3985 // any specified 'fields' that do not exist in the hash are ignored, 3986 // if key does not exist, it is treated as an empty hash, and 0 is returned 3987 func (h *HASH) hdelInternal(key string, field ...string) (deletedCount int64, err error) { 3988 // validate 3989 if h.core == nil { 3990 return 0, errors.New("Redis HDel Failed: " + "Base is Nil") 3991 } 3992 3993 if !h.core.cnAreReady { 3994 return 0, errors.New("Redis HDel Failed: " + "Endpoint Connections Not Ready") 3995 } 3996 3997 if len(key) <= 0 { 3998 return 0, errors.New("Redis HDel Failed: " + "Key is Required") 3999 } 4000 4001 if len(field) <= 0 { 4002 return 0, errors.New("Redis HDel Failed: " + "At Least 1 Field is Required") 4003 } 4004 4005 cmd := h.core.cnWriter.HDel(h.core.cnWriter.Context(), key, field...) 4006 deletedCount, _, err = h.core.handleIntCmd(cmd, "Redis HDel Failed: ") 4007 return deletedCount, err 4008 } 4009 4010 // HKeys returns all field names in the hash stored at key, 4011 // field names are the element keys 4012 func (h *HASH) HKeys(key string) (outputSlice []string, notFound bool, err error) { 4013 // get new xray segment for tracing 4014 seg := xray.NewSegmentNullable("Redis-HKeys", h.core._parentSegment) 4015 4016 if seg != nil { 4017 defer seg.Close() 4018 defer func() { 4019 _ = seg.Seg.AddMetadata("Redis-HKeys-Key", key) 4020 _ = seg.Seg.AddMetadata("Redis-HKeys-Not-Found", notFound) 4021 _ = seg.Seg.AddMetadata("Redis-HKeys-Results", outputSlice) 4022 4023 if err != nil { 4024 _ = seg.Seg.AddError(err) 4025 } 4026 }() 4027 4028 outputSlice, notFound, err = h.hkeysInternal(key) 4029 return outputSlice, notFound, err 4030 } else { 4031 return h.hkeysInternal(key) 4032 } 4033 } 4034 4035 // hkeysInternal returns all field names in the hash stored at key, 4036 // field names are the element keys 4037 func (h *HASH) hkeysInternal(key string) (outputSlice []string, notFound bool, err error) { 4038 // validate 4039 if h.core == nil { 4040 return nil, false, errors.New("Redis HKeys Failed: " + "Base is Nil") 4041 } 4042 4043 if !h.core.cnAreReady { 4044 return nil, false, errors.New("Redis HKeys Failed: " + "Endpoint Connections Not Ready") 4045 } 4046 4047 if len(key) <= 0 { 4048 return nil, false, errors.New("Redis HKeys Failed: " + "Key is Required") 4049 } 4050 4051 cmd := h.core.cnReader.HKeys(h.core.cnReader.Context(), key) 4052 return h.core.handleStringSliceCmd(cmd, "Redis HKeys Failed: ") 4053 } 4054 4055 // HVals returns all values in the hash stored at key 4056 func (h *HASH) HVals(key string) (outputSlice []string, notFound bool, err error) { 4057 // get new xray segment for tracing 4058 seg := xray.NewSegmentNullable("Redis-HVals", h.core._parentSegment) 4059 4060 if seg != nil { 4061 defer seg.Close() 4062 defer func() { 4063 _ = seg.Seg.AddMetadata("Redis-HVals-Key", key) 4064 _ = seg.Seg.AddMetadata("Redis-HVals-Not-Found", notFound) 4065 _ = seg.Seg.AddMetadata("Redis-HVals-Results", outputSlice) 4066 4067 if err != nil { 4068 _ = seg.Seg.AddError(err) 4069 } 4070 }() 4071 4072 outputSlice, notFound, err = h.hvalsInternal(key) 4073 return outputSlice, notFound, err 4074 } else { 4075 return h.hvalsInternal(key) 4076 } 4077 } 4078 4079 // hvalsInternal returns all values in the hash stored at key 4080 func (h *HASH) hvalsInternal(key string) (outputSlice []string, notFound bool, err error) { 4081 // validate 4082 if h.core == nil { 4083 return nil, false, errors.New("Redis HVals Failed: " + "Base is Nil") 4084 } 4085 4086 if !h.core.cnAreReady { 4087 return nil, false, errors.New("Redis HVals Failed: " + "Endpoint Connections Not Ready") 4088 } 4089 4090 if len(key) <= 0 { 4091 return nil, false, errors.New("Redis HVals Failed: " + "Key is Required") 4092 } 4093 4094 cmd := h.core.cnReader.HVals(h.core.cnReader.Context(), key) 4095 return h.core.handleStringSliceCmd(cmd, "Redis HVals Failed: ") 4096 } 4097 4098 // HScan is used to incrementally iterate over a set of fields for hash stored at key, 4099 // HScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 4100 // 4101 // start iteration = cursor set to 0 4102 // stop iteration = when redis returns cursor value of 0 4103 // 4104 // match = filters elements based on match filter, for elements retrieved from redis before return to client 4105 // 4106 // glob-style patterns: 4107 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 4108 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 4109 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 4110 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 4111 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 4112 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 4113 // 7) Use \ to escape special characters if needing to match verbatim 4114 // 4115 // count = hint to redis count of elements to retrieve in the call 4116 func (h *HASH) HScan(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 4117 // get new xray segment for tracing 4118 seg := xray.NewSegmentNullable("Redis-HScan", h.core._parentSegment) 4119 4120 if seg != nil { 4121 defer seg.Close() 4122 defer func() { 4123 _ = seg.Seg.AddMetadata("Redis-HScan-Key", key) 4124 _ = seg.Seg.AddMetadata("Redis-HScan-Cursor", cursor) 4125 _ = seg.Seg.AddMetadata("Redis-HScan-Match", match) 4126 _ = seg.Seg.AddMetadata("Redis-HScan-Count", count) 4127 _ = seg.Seg.AddMetadata("Redis-HScan-Result-Keys", outputKeys) 4128 _ = seg.Seg.AddMetadata("Redis-HScan-Result-Cursor", outputCursor) 4129 4130 if err != nil { 4131 _ = seg.Seg.AddError(err) 4132 } 4133 }() 4134 4135 outputKeys, outputCursor, err = h.hscanInternal(key, cursor, match, count) 4136 return outputKeys, outputCursor, err 4137 } else { 4138 return h.hscanInternal(key, cursor, match, count) 4139 } 4140 } 4141 4142 // hscanInternal is used to incrementally iterate over a set of fields for hash stored at key, 4143 // HScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 4144 // 4145 // start iteration = cursor set to 0 4146 // stop iteration = when redis returns cursor value of 0 4147 // 4148 // match = filters elements based on match filter, for elements retrieved from redis before return to client 4149 // 4150 // glob-style patterns: 4151 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 4152 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 4153 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 4154 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 4155 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 4156 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 4157 // 7) Use \ to escape special characters if needing to match verbatim 4158 // 4159 // count = hint to redis count of elements to retrieve in the call 4160 func (h *HASH) hscanInternal(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 4161 // validate 4162 if h.core == nil { 4163 return nil, 0, errors.New("Redis HScan Failed: " + "Base is Nil") 4164 } 4165 4166 if !h.core.cnAreReady { 4167 return nil, 0, errors.New("Redis HScan Failed: " + "Endpoint Connections Not Ready") 4168 } 4169 4170 if len(key) <= 0 { 4171 return nil, 0, errors.New("Redis HScan Failed: " + "Key is Required") 4172 } 4173 4174 if len(match) <= 0 { 4175 return nil, 0, errors.New("Redis HScan Failed: " + "Match is Required") 4176 } 4177 4178 if count < 0 { 4179 return nil, 0, errors.New("Redis HScan Failed: " + "Count Must Be Zero or Greater") 4180 } 4181 4182 cmd := h.core.cnReader.HScan(h.core.cnReader.Context(), key, cursor, match, count) 4183 return h.core.handleScanCmd(cmd, "Redis HScan Failed: ") 4184 } 4185 4186 // HIncrBy increments or decrements the number (int64) value at 'field' in the hash stored at key, 4187 // if key does not exist, a new key holding a hash is created, 4188 // if 'field' does not exist then the value is set to 0 before operation is performed 4189 // 4190 // this function supports both increment and decrement (although name of function is increment) 4191 func (h *HASH) HIncrBy(key string, field string, incrValue int64) (err error) { 4192 // get new xray segment for tracing 4193 seg := xray.NewSegmentNullable("Redis-HIncrBy", h.core._parentSegment) 4194 4195 if seg != nil { 4196 defer seg.Close() 4197 defer func() { 4198 _ = seg.Seg.AddMetadata("Redis-HIncrBy-Key", key) 4199 _ = seg.Seg.AddMetadata("Redis-HIncrBy-Field", field) 4200 _ = seg.Seg.AddMetadata("Redis-HIncrBy-Increment-Value", incrValue) 4201 4202 if err != nil { 4203 _ = seg.Seg.AddError(err) 4204 } 4205 }() 4206 4207 err = h.hincrByInternal(key, field, incrValue) 4208 return err 4209 } else { 4210 return h.hincrByInternal(key, field, incrValue) 4211 } 4212 } 4213 4214 // hincrByInternal increments or decrements the number (int64) value at 'field' in the hash stored at key, 4215 // if key does not exist, a new key holding a hash is created, 4216 // if 'field' does not exist then the value is set to 0 before operation is performed 4217 // 4218 // this function supports both increment and decrement (although name of function is increment) 4219 func (h *HASH) hincrByInternal(key string, field string, incrValue int64) error { 4220 // validate 4221 if h.core == nil { 4222 return errors.New("Redis HIncrBy Failed: " + "Base is Nil") 4223 } 4224 4225 if !h.core.cnAreReady { 4226 return errors.New("Redis HIncrBy Failed: " + "Endpoint Connections Not Ready") 4227 } 4228 4229 if len(key) <= 0 { 4230 return errors.New("Redis HIncrBy Failed: " + "Key is Required") 4231 } 4232 4233 if len(field) <= 0 { 4234 return errors.New("Redis HIncrBy Failed: " + "Field is Required") 4235 } 4236 4237 if incrValue == 0 { 4238 return errors.New("Redis HIncrBy Failed: " + "Increment Value Must Not Be Zero") 4239 } 4240 4241 cmd := h.core.cnWriter.HIncrBy(h.core.cnWriter.Context(), key, field, incrValue) 4242 4243 if _, _, err := h.core.handleIntCmd(cmd, "Redis HIncrBy Failed: "); err != nil { 4244 return err 4245 } else { 4246 return nil 4247 } 4248 } 4249 4250 // HIncrByFloat increments or decrements the number (float64) value at 'field' in the hash stored at key, 4251 // if key does not exist, a new key holding a hash is created, 4252 // if 'field' does not exist then the value is set to 0 before operation is performed 4253 // 4254 // this function supports both increment and decrement (although name of function is increment) 4255 func (h *HASH) HIncrByFloat(key string, field string, incrValue float64) (err error) { 4256 // get new xray segment for tracing 4257 seg := xray.NewSegmentNullable("Redis-HIncrByFloat", h.core._parentSegment) 4258 4259 if seg != nil { 4260 defer seg.Close() 4261 defer func() { 4262 _ = seg.Seg.AddMetadata("Redis-HIncrByFloat-Key", key) 4263 _ = seg.Seg.AddMetadata("Redis-HIncrByFloat-Field", field) 4264 _ = seg.Seg.AddMetadata("Redis-HIncrByFloat-Increment-Value", incrValue) 4265 4266 if err != nil { 4267 _ = seg.Seg.AddError(err) 4268 } 4269 }() 4270 4271 err = h.hincrByFloatInternal(key, field, incrValue) 4272 return err 4273 } else { 4274 return h.hincrByFloatInternal(key, field, incrValue) 4275 } 4276 } 4277 4278 // hincrByFloatInternal increments or decrements the number (float64) value at 'field' in the hash stored at key, 4279 // if key does not exist, a new key holding a hash is created, 4280 // if 'field' does not exist then the value is set to 0 before operation is performed 4281 // 4282 // this function supports both increment and decrement (although name of function is increment) 4283 func (h *HASH) hincrByFloatInternal(key string, field string, incrValue float64) error { 4284 // validate 4285 if h.core == nil { 4286 return errors.New("Redis HIncrByFloat Failed: " + "Base is Nil") 4287 } 4288 4289 if !h.core.cnAreReady { 4290 return errors.New("Redis HIncrByFloat Failed: " + "Endpoint Connections Not Ready") 4291 } 4292 4293 if len(key) <= 0 { 4294 return errors.New("Redis HIncrByFloat Failed: " + "Key is Required") 4295 } 4296 4297 if len(field) <= 0 { 4298 return errors.New("Redis HIncrByFloat Failed: " + "Field is Required") 4299 } 4300 4301 if incrValue == 0.00 { 4302 return errors.New("Redis HIncrByFloat Failed: " + "Increment Value Must Not Be Zero") 4303 } 4304 4305 cmd := h.core.cnWriter.HIncrByFloat(h.core.cnWriter.Context(), key, field, incrValue) 4306 4307 if _, _, err := h.core.handleFloatCmd(cmd, "Redis HIncrByFloat Failed: "); err != nil { 4308 return err 4309 } else { 4310 return nil 4311 } 4312 } 4313 4314 // ---------------------------------------------------------------------------------------------------------------- 4315 // SET functions 4316 // ---------------------------------------------------------------------------------------------------------------- 4317 4318 // SAdd adds the specified members to the set stored at key, 4319 // Specified members that are already a member of this set are ignored, 4320 // If key does not exist, a new set is created before adding the specified members 4321 // 4322 // Error is returned when the value stored at key is not a set 4323 func (s *SET) SAdd(key string, member ...interface{}) (err error) { 4324 // get new xray segment for tracing 4325 seg := xray.NewSegmentNullable("Redis-SAdd", s.core._parentSegment) 4326 4327 if seg != nil { 4328 defer seg.Close() 4329 defer func() { 4330 _ = seg.Seg.AddMetadata("Redis-SAdd-Key", key) 4331 _ = seg.Seg.AddMetadata("Redis-SAdd-Members", member) 4332 4333 if err != nil { 4334 _ = seg.Seg.AddError(err) 4335 } 4336 }() 4337 4338 err = s.saddInternal(key, member...) 4339 return err 4340 } else { 4341 return s.saddInternal(key, member...) 4342 } 4343 } 4344 4345 // saddInternal adds the specified members to the set stored at key, 4346 // Specified members that are already a member of this set are ignored, 4347 // If key does not exist, a new set is created before adding the specified members 4348 // 4349 // Error is returned when the value stored at key is not a set 4350 func (s *SET) saddInternal(key string, member ...interface{}) error { 4351 // validate 4352 if s.core == nil { 4353 return errors.New("Redis SAdd Failed: " + "Base is Nil") 4354 } 4355 4356 if !s.core.cnAreReady { 4357 return errors.New("Redis SAdd Failed: " + "Endpoint Connections Not Ready") 4358 } 4359 4360 if len(key) <= 0 { 4361 return errors.New("Redis SAdd Failed: " + "Key is Required") 4362 } 4363 4364 if len(member) <= 0 { 4365 return errors.New("Redis SAdd Failed: " + "At Least 1 Member is Required") 4366 } 4367 4368 cmd := s.core.cnWriter.SAdd(s.core.cnWriter.Context(), key, member...) 4369 return s.core.handleIntCmd2(cmd, "Redis SAdd Failed: ") 4370 } 4371 4372 // SCard returns the set cardinality (number of elements) of the set stored at key 4373 func (s *SET) SCard(key string) (val int64, notFound bool, err error) { 4374 // get new xray segment for tracing 4375 seg := xray.NewSegmentNullable("Redis-SCard", s.core._parentSegment) 4376 4377 if seg != nil { 4378 defer seg.Close() 4379 defer func() { 4380 _ = seg.Seg.AddMetadata("Redis-SCard-Key", key) 4381 _ = seg.Seg.AddMetadata("Redis-SCard-Not-Found", notFound) 4382 _ = seg.Seg.AddMetadata("Redis-SCard-Result-Count", val) 4383 4384 if err != nil { 4385 _ = seg.Seg.AddError(err) 4386 } 4387 }() 4388 4389 val, notFound, err = s.scardInternal(key) 4390 return val, notFound, err 4391 } else { 4392 return s.scardInternal(key) 4393 } 4394 } 4395 4396 // scardInternal returns the set cardinality (number of elements) of the set stored at key 4397 func (s *SET) scardInternal(key string) (val int64, notFound bool, err error) { 4398 // validate 4399 if s.core == nil { 4400 return 0, false, errors.New("Redis SCard Failed: " + "Base is Nil") 4401 } 4402 4403 if !s.core.cnAreReady { 4404 return 0, false, errors.New("Redis SCard Failed: " + "Endpoint Connections Not Ready") 4405 } 4406 4407 if len(key) <= 0 { 4408 return 0, false, errors.New("Redis SCard Failed: " + "Key is Required") 4409 } 4410 4411 cmd := s.core.cnReader.SCard(s.core.cnReader.Context(), key) 4412 return s.core.handleIntCmd(cmd, "Redis SCard Failed: ") 4413 } 4414 4415 // SDiff returns the members of the set resulting from the difference between the first set and all the successive sets 4416 // 4417 // Example: 4418 // 4419 // key1 = { a, b, c, d } 4420 // key2 = { c } 4421 // key3 = { a, c, e } 4422 // SDIFF key1, key2, key3 = { b, d } 4423 // { b, d } is returned because this is the difference delta 4424 func (s *SET) SDiff(key ...string) (outputSlice []string, notFound bool, err error) { 4425 // get new xray segment for tracing 4426 seg := xray.NewSegmentNullable("Redis-SDiff", s.core._parentSegment) 4427 4428 if seg != nil { 4429 defer seg.Close() 4430 defer func() { 4431 _ = seg.Seg.AddMetadata("Redis-SDiff-Keys", key) 4432 _ = seg.Seg.AddMetadata("Redis-SDiff-Not-Found", notFound) 4433 _ = seg.Seg.AddMetadata("Redis-SDiff-Results", outputSlice) 4434 4435 if err != nil { 4436 _ = seg.Seg.AddError(err) 4437 } 4438 }() 4439 4440 outputSlice, notFound, err = s.sdiffInternal(key...) 4441 return outputSlice, notFound, err 4442 } else { 4443 return s.sdiffInternal(key...) 4444 } 4445 } 4446 4447 // sdiffInternal returns the members of the set resulting from the difference between the first set and all the successive sets 4448 // 4449 // Example: 4450 // 4451 // key1 = { a, b, c, d } 4452 // key2 = { c } 4453 // key3 = { a, c, e } 4454 // SDIFF key1, key2, key3 = { b, d } 4455 // { b, d } is returned because this is the difference delta 4456 func (s *SET) sdiffInternal(key ...string) (outputSlice []string, notFound bool, err error) { 4457 // validate 4458 if s.core == nil { 4459 return nil, false, errors.New("Redis SDiff Failed: " + "Base is Nil") 4460 } 4461 4462 if !s.core.cnAreReady { 4463 return nil, false, errors.New("Redis SDiff Failed: " + "Endpoint Connections Not Ready") 4464 } 4465 4466 if len(key) <= 1 { 4467 return nil, false, errors.New("Redis SDiff Failed: " + "At Least 2 Keys Are Required") 4468 } 4469 4470 cmd := s.core.cnReader.SDiff(s.core.cnReader.Context(), key...) 4471 return s.core.handleStringSliceCmd(cmd, "Redis SDiff Failed: ") 4472 } 4473 4474 // SDiffStore will store the set differential to destination, 4475 // if destination already exists, it is overwritten 4476 // 4477 // Example: 4478 // 4479 // key1 = { a, b, c, d } 4480 // key2 = { c } 4481 // key3 = { a, c, e } 4482 // SDIFF key1, key2, key3 = { b, d } 4483 // { b, d } is stored because this is the difference delta 4484 func (s *SET) SDiffStore(keyDest string, keySource ...string) (err error) { 4485 // get new xray segment for tracing 4486 seg := xray.NewSegmentNullable("Redis-SDiffStore", s.core._parentSegment) 4487 4488 if seg != nil { 4489 defer seg.Close() 4490 defer func() { 4491 _ = seg.Seg.AddMetadata("Redis-SDiffStore-KeyDest", keyDest) 4492 _ = seg.Seg.AddMetadata("Redis-SDiffStore-KeySources", keySource) 4493 4494 if err != nil { 4495 _ = seg.Seg.AddError(err) 4496 } 4497 }() 4498 4499 err = s.sdiffStoreInternal(keyDest, keySource...) 4500 return err 4501 } else { 4502 return s.sdiffStoreInternal(keyDest, keySource...) 4503 } 4504 } 4505 4506 // sdiffStoreInternal will store the set differential to destination, 4507 // if destination already exists, it is overwritten 4508 // 4509 // Example: 4510 // 4511 // key1 = { a, b, c, d } 4512 // key2 = { c } 4513 // key3 = { a, c, e } 4514 // SDIFF key1, key2, key3 = { b, d } 4515 // { b, d } is stored because this is the difference delta 4516 func (s *SET) sdiffStoreInternal(keyDest string, keySource ...string) error { 4517 // validate 4518 if s.core == nil { 4519 return errors.New("Redis SDiffStore Failed: " + "Base is Nil") 4520 } 4521 4522 if !s.core.cnAreReady { 4523 return errors.New("Redis SDiffStore Failed: " + "Endpoint Connections Not Ready") 4524 } 4525 4526 if len(keyDest) <= 0 { 4527 return errors.New("Redis SDiffStore Failed: " + "Key Destination is Required") 4528 } 4529 4530 if len(keySource) <= 1 { 4531 return errors.New("Redis SDiffStore Failed: " + "At Least 2 Key Sources are Required") 4532 } 4533 4534 cmd := s.core.cnWriter.SDiffStore(s.core.cnWriter.Context(), keyDest, keySource...) 4535 return s.core.handleIntCmd2(cmd, "Redis SDiffStore Failed: ") 4536 } 4537 4538 // SInter returns the members of the set resulting from the intersection of all the given sets 4539 // 4540 // Example: 4541 // 4542 // Key1 = { a, b, c, d } 4543 // Key2 = { c } 4544 // Key3 = { a, c, e } 4545 // SINTER key1 key2 key3 = { c } 4546 // { c } is returned because this is the intersection on all keys (appearing in all keys) 4547 func (s *SET) SInter(key ...string) (outputSlice []string, notFound bool, err error) { 4548 // get new xray segment for tracing 4549 seg := xray.NewSegmentNullable("Redis-SInter", s.core._parentSegment) 4550 4551 if seg != nil { 4552 defer seg.Close() 4553 defer func() { 4554 _ = seg.Seg.AddMetadata("Redis-SInter-Keys", key) 4555 _ = seg.Seg.AddMetadata("Redis-SInter-Not-Found", notFound) 4556 _ = seg.Seg.AddMetadata("Redis-SInter-Results", outputSlice) 4557 4558 if err != nil { 4559 _ = seg.Seg.AddError(err) 4560 } 4561 }() 4562 4563 outputSlice, notFound, err = s.sinterInternal(key...) 4564 return outputSlice, notFound, err 4565 } else { 4566 return s.sinterInternal(key...) 4567 } 4568 } 4569 4570 // sinterInternal returns the members of the set resulting from the intersection of all the given sets 4571 // 4572 // Example: 4573 // 4574 // Key1 = { a, b, c, d } 4575 // Key2 = { c } 4576 // Key3 = { a, c, e } 4577 // SINTER key1 key2 key3 = { c } 4578 // { c } is returned because this is the intersection on all keys (appearing in all keys) 4579 func (s *SET) sinterInternal(key ...string) (outputSlice []string, notFound bool, err error) { 4580 // validate 4581 if s.core == nil { 4582 return nil, false, errors.New("Redis SInter Failed: " + "Base is Nil") 4583 } 4584 4585 if !s.core.cnAreReady { 4586 return nil, false, errors.New("Redis SInter Failed: " + "Endpoint Connections Not Ready") 4587 } 4588 4589 if len(key) <= 1 { 4590 return nil, false, errors.New("Redis SInter Failed: " + "At Least 2 Keys Are Required") 4591 } 4592 4593 cmd := s.core.cnReader.SInter(s.core.cnReader.Context(), key...) 4594 return s.core.handleStringSliceCmd(cmd, "Redis SInter Failed: ") 4595 } 4596 4597 // SInterStore stores the members of the set resulting from the intersection of all the given sets to destination, 4598 // if destination already exists, it is overwritten 4599 // 4600 // Example: 4601 // 4602 // Key1 = { a, b, c, d } 4603 // Key2 = { c } 4604 // Key3 = { a, c, e } 4605 // SINTER key1 key2 key3 = { c } 4606 // { c } is stored because this is the intersection on all keys (appearing in all keys) 4607 func (s *SET) SInterStore(keyDest string, keySource ...string) (err error) { 4608 // get new xray segment for tracing 4609 seg := xray.NewSegmentNullable("Redis-SInterStore", s.core._parentSegment) 4610 4611 if seg != nil { 4612 defer seg.Close() 4613 defer func() { 4614 _ = seg.Seg.AddMetadata("Redis-SInterStore-KeyDest", keyDest) 4615 _ = seg.Seg.AddMetadata("Redis-SInterStore-KeySources", keySource) 4616 4617 if err != nil { 4618 _ = seg.Seg.AddError(err) 4619 } 4620 }() 4621 4622 err = s.sinterStoreInternal(keyDest, keySource...) 4623 return err 4624 } else { 4625 return s.sinterStoreInternal(keyDest, keySource...) 4626 } 4627 } 4628 4629 // sinterStoreInternal stores the members of the set resulting from the intersection of all the given sets to destination, 4630 // if destination already exists, it is overwritten 4631 // 4632 // Example: 4633 // 4634 // Key1 = { a, b, c, d } 4635 // Key2 = { c } 4636 // Key3 = { a, c, e } 4637 // SINTER key1 key2 key3 = { c } 4638 // { c } is stored because this is the intersection on all keys (appearing in all keys) 4639 func (s *SET) sinterStoreInternal(keyDest string, keySource ...string) error { 4640 // validate 4641 if s.core == nil { 4642 return errors.New("Redis SInterStore Failed: " + "Base is Nil") 4643 } 4644 4645 if !s.core.cnAreReady { 4646 return errors.New("Redis SInterStore Failed: " + "Endpoint Connections Not Ready") 4647 } 4648 4649 if len(keyDest) <= 0 { 4650 return errors.New("Redis SInterStore Failed: " + "Key Destination is Required") 4651 } 4652 4653 if len(keySource) <= 1 { 4654 return errors.New("Redis SInterStore Failed: " + "At Least 2 Key Sources are Required") 4655 } 4656 4657 cmd := s.core.cnWriter.SInterStore(s.core.cnWriter.Context(), keyDest, keySource...) 4658 return s.core.handleIntCmd2(cmd, "Redis SInterStore Failed: ") 4659 } 4660 4661 // SIsMember returns status if 'member' is a member of the set stored at key 4662 func (s *SET) SIsMember(key string, member interface{}) (val bool, err error) { 4663 // get new xray segment for tracing 4664 seg := xray.NewSegmentNullable("Redis-SIsMember", s.core._parentSegment) 4665 4666 if seg != nil { 4667 defer seg.Close() 4668 defer func() { 4669 _ = seg.Seg.AddMetadata("Redis-SIsMember-Key", key) 4670 _ = seg.Seg.AddMetadata("Redis-SIsMember-Member", member) 4671 _ = seg.Seg.AddMetadata("Redis-SIsMember-Result-IsMember", val) 4672 4673 if err != nil { 4674 _ = seg.Seg.AddError(err) 4675 } 4676 }() 4677 4678 val, err = s.sisMemberInternal(key, member) 4679 return val, err 4680 } else { 4681 return s.sisMemberInternal(key, member) 4682 } 4683 } 4684 4685 // sisMemberInternal returns status if 'member' is a member of the set stored at key 4686 func (s *SET) sisMemberInternal(key string, member interface{}) (val bool, err error) { 4687 // validate 4688 if s.core == nil { 4689 return false, errors.New("Redis SIsMember Failed: " + "Base is Nil") 4690 } 4691 4692 if !s.core.cnAreReady { 4693 return false, errors.New("Redis SIsMember Failed: " + "Endpoint Connections Not Ready") 4694 } 4695 4696 if len(key) <= 0 { 4697 return false, errors.New("Redis SIsMember Failed: " + "Key is Required") 4698 } 4699 4700 if member == nil { 4701 return false, errors.New("Redis SIsMember Failed: " + "Member is Required") 4702 } 4703 4704 cmd := s.core.cnReader.SIsMember(s.core.cnReader.Context(), key, member) 4705 return s.core.handleBoolCmd(cmd, "Redis SIsMember Failed: ") 4706 } 4707 4708 // SMembers returns all the members of the set value stored at key 4709 func (s *SET) SMembers(key string) (outputSlice []string, notFound bool, err error) { 4710 // get new xray segment for tracing 4711 seg := xray.NewSegmentNullable("Redis-SMembers", s.core._parentSegment) 4712 4713 if seg != nil { 4714 defer seg.Close() 4715 defer func() { 4716 _ = seg.Seg.AddMetadata("Redis-SMember-Key", key) 4717 _ = seg.Seg.AddMetadata("Redis-SMember-Not-Found", notFound) 4718 _ = seg.Seg.AddMetadata("Redis-SMember-Results", outputSlice) 4719 4720 if err != nil { 4721 _ = seg.Seg.AddError(err) 4722 } 4723 }() 4724 4725 outputSlice, notFound, err = s.smembersInternal(key) 4726 return outputSlice, notFound, err 4727 } else { 4728 return s.smembersInternal(key) 4729 } 4730 } 4731 4732 // smembersInternal returns all the members of the set value stored at key 4733 func (s *SET) smembersInternal(key string) (outputSlice []string, notFound bool, err error) { 4734 // validate 4735 if s.core == nil { 4736 return nil, false, errors.New("Redis SMembers Failed: " + "Base is Nil") 4737 } 4738 4739 if !s.core.cnAreReady { 4740 return nil, false, errors.New("Redis SMembers Failed: " + "Endpoint Connections Not Ready") 4741 } 4742 4743 if len(key) <= 0 { 4744 return nil, false, errors.New("Redis SMembers Failed: " + "Key is Required") 4745 } 4746 4747 cmd := s.core.cnReader.SMembers(s.core.cnReader.Context(), key) 4748 return s.core.handleStringSliceCmd(cmd, "Redis SMember Failed: ") 4749 } 4750 4751 // SMembersMap returns all the members of the set value stored at key, via map 4752 func (s *SET) SMembersMap(key string) (outputMap map[string]struct{}, notFound bool, err error) { 4753 // get new xray segment for tracing 4754 seg := xray.NewSegmentNullable("Redis-SMembersMap", s.core._parentSegment) 4755 4756 if seg != nil { 4757 defer seg.Close() 4758 defer func() { 4759 _ = seg.Seg.AddMetadata("Redis-SMembersMap-Key", key) 4760 _ = seg.Seg.AddMetadata("Redis-SMembersMap-Not-Found", notFound) 4761 _ = seg.Seg.AddMetadata("Redis-SMembersMap-Result", outputMap) 4762 4763 if err != nil { 4764 _ = seg.Seg.AddError(err) 4765 } 4766 }() 4767 4768 outputMap, notFound, err = s.smembersMapInternal(key) 4769 return outputMap, notFound, err 4770 } else { 4771 return s.smembersMapInternal(key) 4772 } 4773 } 4774 4775 // smembersMapInternal returns all the members of the set value stored at key, via map 4776 func (s *SET) smembersMapInternal(key string) (outputMap map[string]struct{}, notFound bool, err error) { 4777 // validate 4778 if s.core == nil { 4779 return nil, false, errors.New("Redis SMembersMap Failed: " + "Base is Nil") 4780 } 4781 4782 if !s.core.cnAreReady { 4783 return nil, false, errors.New("Redis SMembersMap Failed: " + "Endpoint Connections Not Ready") 4784 } 4785 4786 if len(key) <= 0 { 4787 return nil, false, errors.New("Redis SMembersMap Failed: " + "Key is Required") 4788 } 4789 4790 cmd := s.core.cnReader.SMembersMap(s.core.cnReader.Context(), key) 4791 return s.core.handleStringStructMapCmd(cmd, "Redis SMembersMap Failed: ") 4792 } 4793 4794 // SScan is used to incrementally iterate over a set of fields for set stored at key, 4795 // SScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 4796 // 4797 // start iteration = cursor set to 0 4798 // stop iteration = when redis returns cursor value of 0 4799 // 4800 // match = filters elements based on match filter, for elements retrieved from redis before return to client 4801 // 4802 // glob-style patterns: 4803 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 4804 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 4805 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 4806 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 4807 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 4808 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 4809 // 7) Use \ to escape special characters if needing to match verbatim 4810 // 4811 // count = hint to redis count of elements to retrieve in the call 4812 func (s *SET) SScan(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 4813 // get new xray segment for tracing 4814 seg := xray.NewSegmentNullable("Redis-SScan", s.core._parentSegment) 4815 4816 if seg != nil { 4817 defer seg.Close() 4818 defer func() { 4819 _ = seg.Seg.AddMetadata("Redis-SScan-Key", key) 4820 _ = seg.Seg.AddMetadata("Redis-SScan-Cursor", cursor) 4821 _ = seg.Seg.AddMetadata("Redis-SScan-Match", match) 4822 _ = seg.Seg.AddMetadata("Redis-SScan-Count", count) 4823 _ = seg.Seg.AddMetadata("Redis-SScan-Result-Keys", outputKeys) 4824 _ = seg.Seg.AddMetadata("Redis-SScan-Result-Cursor", outputCursor) 4825 4826 if err != nil { 4827 _ = seg.Seg.AddError(err) 4828 } 4829 }() 4830 4831 outputKeys, outputCursor, err = s.sscanInternal(key, cursor, match, count) 4832 return outputKeys, outputCursor, err 4833 } else { 4834 return s.sscanInternal(key, cursor, match, count) 4835 } 4836 } 4837 4838 // sscanInternal is used to incrementally iterate over a set of fields for set stored at key, 4839 // SScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 4840 // 4841 // start iteration = cursor set to 0 4842 // stop iteration = when redis returns cursor value of 0 4843 // 4844 // match = filters elements based on match filter, for elements retrieved from redis before return to client 4845 // 4846 // glob-style patterns: 4847 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 4848 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 4849 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 4850 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 4851 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 4852 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 4853 // 7) Use \ to escape special characters if needing to match verbatim 4854 // 4855 // count = hint to redis count of elements to retrieve in the call 4856 func (s *SET) sscanInternal(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 4857 // validate 4858 if s.core == nil { 4859 return nil, 0, errors.New("Redis SScan Failed: " + "Base is Nil") 4860 } 4861 4862 if !s.core.cnAreReady { 4863 return nil, 0, errors.New("Redis SScan Failed: " + "Endpoint Connections Not Ready") 4864 } 4865 4866 if len(key) <= 0 { 4867 return nil, 0, errors.New("Redis SScan Failed: " + "Key is Required") 4868 } 4869 4870 if len(match) <= 0 { 4871 return nil, 0, errors.New("Redis SScan Failed: " + "Match is Required") 4872 } 4873 4874 if count < 0 { 4875 return nil, 0, errors.New("Redis SScan Failed: " + "Count Must Be 0 or Greater") 4876 } 4877 4878 cmd := s.core.cnReader.SScan(s.core.cnReader.Context(), key, cursor, match, count) 4879 return s.core.handleScanCmd(cmd, "Redis SScan Failed: ") 4880 } 4881 4882 // SRandMember returns a random element from the set value stored at key 4883 func (s *SET) SRandMember(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 4884 // get new xray segment for tracing 4885 seg := xray.NewSegmentNullable("Redis-SRandMember", s.core._parentSegment) 4886 4887 if seg != nil { 4888 defer seg.Close() 4889 defer func() { 4890 _ = seg.Seg.AddMetadata("Redis-SRandMember-Key", key) 4891 _ = seg.Seg.AddMetadata("Redis-SRandMember-Output-Data-Type", outputDataType) 4892 _ = seg.Seg.AddMetadata("Redis-SRandMember-Not-Found", notFound) 4893 _ = seg.Seg.AddMetadata("Redis-SRandMember-Output-Object", outputObjectPtr) 4894 4895 if err != nil { 4896 _ = seg.Seg.AddError(err) 4897 } 4898 }() 4899 4900 notFound, err = s.srandMemberInternal(key, outputDataType, outputObjectPtr) 4901 return notFound, err 4902 } else { 4903 return s.srandMemberInternal(key, outputDataType, outputObjectPtr) 4904 } 4905 } 4906 4907 // srandMemberInternal returns a random element from the set value stored at key 4908 func (s *SET) srandMemberInternal(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 4909 // validate 4910 if s.core == nil { 4911 return false, errors.New("Redis SRandMember Failed: " + "Base is Nil") 4912 } 4913 4914 if !s.core.cnAreReady { 4915 return false, errors.New("Redis SRandMember Failed: " + "Endpoint Connections Not Ready") 4916 } 4917 4918 if len(key) <= 0 { 4919 return false, errors.New("Redis SRandMember Failed: " + "Key is Required") 4920 } 4921 4922 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 4923 return false, errors.New("Redis SRandMember Failed: " + "Output Data Type is Required") 4924 } 4925 4926 if outputObjectPtr == nil { 4927 return false, errors.New("Redis SRandMember Failed: " + "Output Object Pointer is Required") 4928 } 4929 4930 cmd := s.core.cnReader.SRandMember(s.core.cnReader.Context(), key) 4931 return s.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis SRandMember Failed: ") 4932 } 4933 4934 // SRandMemberN returns one or more random elements from the set value stored at key, with count indicating return limit 4935 // 4936 // count > 0 = returns an array of count distinct elements (non-repeating), up to the set elements size 4937 // count < 0 = returns an array of count elements (may be repeating), and up to the count size (selected members may still be part of the subsequent selection process) 4938 func (s *SET) SRandMemberN(key string, count int64) (outputSlice []string, notFound bool, err error) { 4939 // get new xray segment for tracing 4940 seg := xray.NewSegmentNullable("Redis-SRandMemberN", s.core._parentSegment) 4941 4942 if seg != nil { 4943 defer seg.Close() 4944 defer func() { 4945 _ = seg.Seg.AddMetadata("Redis-SRandMemberN-Key", key) 4946 _ = seg.Seg.AddMetadata("Redis-SRandMemberN-Count", count) 4947 _ = seg.Seg.AddMetadata("Redis-SRandMemberN-Not-Found", notFound) 4948 _ = seg.Seg.AddMetadata("Redis-SRandMemberN-Results", outputSlice) 4949 4950 if err != nil { 4951 _ = seg.Seg.AddError(err) 4952 } 4953 }() 4954 4955 outputSlice, notFound, err = s.srandMemberNInternal(key, count) 4956 return outputSlice, notFound, err 4957 } else { 4958 return s.srandMemberNInternal(key, count) 4959 } 4960 } 4961 4962 // srandMemberNInternal returns one or more random elements from the set value stored at key, with count indicating return limit 4963 // 4964 // count > 0 = returns an array of count distinct elements (non-repeating), up to the set elements size 4965 // count < 0 = returns an array of count elements (may be repeating), and up to the count size (selected members may still be part of the subsequent selection process) 4966 func (s *SET) srandMemberNInternal(key string, count int64) (outputSlice []string, notFound bool, err error) { 4967 // validate 4968 if s.core == nil { 4969 return nil, false, errors.New("Redis SRandMemberN Failed: " + "Base is Nil") 4970 } 4971 4972 if !s.core.cnAreReady { 4973 return nil, false, errors.New("Redis SRandMemberN Failed: " + "Endpoint Connections Not Ready") 4974 } 4975 4976 if len(key) <= 0 { 4977 return nil, false, errors.New("Redis SRandMemberN Failed: " + "Key is Required") 4978 } 4979 4980 if count == 0 { 4981 return nil, false, errors.New("Redis SRandMemberN Failed: " + "Count Must Not Be Zero") 4982 } 4983 4984 cmd := s.core.cnReader.SRandMemberN(s.core.cnReader.Context(), key, count) 4985 return s.core.handleStringSliceCmd(cmd, "Redis SRandMemberN Failed: ") 4986 } 4987 4988 // SRem removes the specified members from the set stored at key, 4989 // Specified members that are not a member of this set are ignored, 4990 // If key does not exist, it is treated as an empty set and this command returns 0 4991 // 4992 // Error is returned if the value stored at key is not a set 4993 func (s *SET) SRem(key string, member ...interface{}) (err error) { 4994 // get new xray segment for tracing 4995 seg := xray.NewSegmentNullable("Redis-SRem", s.core._parentSegment) 4996 4997 if seg != nil { 4998 defer seg.Close() 4999 defer func() { 5000 _ = seg.Seg.AddMetadata("Redis-SRem-Key", key) 5001 _ = seg.Seg.AddMetadata("Redis-SRem-Members", member) 5002 5003 if err != nil { 5004 _ = seg.Seg.AddError(err) 5005 } 5006 }() 5007 5008 err = s.sremInternal(key, member...) 5009 return err 5010 } else { 5011 return s.sremInternal(key, member...) 5012 } 5013 } 5014 5015 // sremInternal removes the specified members from the set stored at key, 5016 // Specified members that are not a member of this set are ignored, 5017 // If key does not exist, it is treated as an empty set and this command returns 0 5018 // 5019 // Error is returned if the value stored at key is not a set 5020 func (s *SET) sremInternal(key string, member ...interface{}) error { 5021 // validate 5022 if s.core == nil { 5023 return errors.New("Redis SRem Failed: " + "Base is Nil") 5024 } 5025 5026 if !s.core.cnAreReady { 5027 return errors.New("Redis SRem Failed: " + "Endpoint Connections Not Ready") 5028 } 5029 5030 if len(key) <= 0 { 5031 return errors.New("Redis SRem Failed: " + "Key is Required") 5032 } 5033 5034 if len(member) <= 0 { 5035 return errors.New("Redis SRem Failed: " + "At Least 1 Member is Required") 5036 } 5037 5038 cmd := s.core.cnWriter.SRem(s.core.cnWriter.Context(), key, member...) 5039 return s.core.handleIntCmd2(cmd, "Redis SRem Failed: ") 5040 } 5041 5042 // SMove will move a member from the set at 'source' to the set at 'destination' atomically, 5043 // The element will appear to be a member of source or destination for other clients 5044 // 5045 // If source set does not exist, or does not contain the specified element, no operation is performed and 0 is returned, 5046 // Otherwise, the element is removed from the source set and added to the destination set 5047 // 5048 // # If the specified element already exist in the destination set, it is only removed from the source set 5049 // 5050 // Error is returned if the source or destination does not hold a set value 5051 func (s *SET) SMove(keySource string, keyDest string, member interface{}) (err error) { 5052 // get new xray segment for tracing 5053 seg := xray.NewSegmentNullable("Redis-SMove", s.core._parentSegment) 5054 5055 if seg != nil { 5056 defer seg.Close() 5057 defer func() { 5058 _ = seg.Seg.AddMetadata("Redis-SMove-KeySource", keySource) 5059 _ = seg.Seg.AddMetadata("Redis-SMove-KeyDest", keyDest) 5060 _ = seg.Seg.AddMetadata("Redis-SMove-Member", member) 5061 5062 if err != nil { 5063 _ = seg.Seg.AddError(err) 5064 } 5065 }() 5066 5067 err = s.smoveInternal(keySource, keyDest, member) 5068 return err 5069 } else { 5070 return s.smoveInternal(keySource, keyDest, member) 5071 } 5072 } 5073 5074 // smoveInternal will move a member from the set at 'source' to the set at 'destination' atomically, 5075 // The element will appear to be a member of source or destination for other clients 5076 // 5077 // If source set does not exist, or does not contain the specified element, no operation is performed and 0 is returned, 5078 // Otherwise, the element is removed from the source set and added to the destination set 5079 // 5080 // # If the specified element already exist in the destination set, it is only removed from the source set 5081 // 5082 // Error is returned if the source or destination does not hold a set value 5083 func (s *SET) smoveInternal(keySource string, keyDest string, member interface{}) error { 5084 // validate 5085 if s.core == nil { 5086 return errors.New("Redis SMove Failed: " + "Base is Nil") 5087 } 5088 5089 if !s.core.cnAreReady { 5090 return errors.New("Redis SMove Failed: " + "Endpoint Connections Not Ready") 5091 } 5092 5093 if len(keySource) <= 0 { 5094 return errors.New("Redis SMove Failed: " + "Key Source is Required") 5095 } 5096 5097 if len(keyDest) <= 0 { 5098 return errors.New("Redis SMove Failed: " + "Key Destination is Required") 5099 } 5100 5101 if member == nil { 5102 return errors.New("Redis SMove Failed: " + "Member is Required") 5103 } 5104 5105 cmd := s.core.cnWriter.SMove(s.core.cnWriter.Context(), keySource, keyDest, member) 5106 5107 if val, err := s.core.handleBoolCmd(cmd, "Redis SMove Failed: "); err != nil { 5108 return err 5109 } else { 5110 if val { 5111 // success 5112 return nil 5113 } else { 5114 // false 5115 return errors.New("Redis SMove Failed: " + "Action Result Yielded False") 5116 } 5117 } 5118 } 5119 5120 // SPop removes and returns one random element from the set value stored at key 5121 func (s *SET) SPop(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 5122 // get new xray segment for tracing 5123 seg := xray.NewSegmentNullable("Redis-SPop", s.core._parentSegment) 5124 5125 if seg != nil { 5126 defer seg.Close() 5127 defer func() { 5128 _ = seg.Seg.AddMetadata("Redis-SPop-Key", key) 5129 _ = seg.Seg.AddMetadata("Redis-SPop-Output-Data-Type", outputDataType) 5130 _ = seg.Seg.AddMetadata("Redis-SPop-Output-Not-Found", notFound) 5131 _ = seg.Seg.AddMetadata("Redis-SPop-Output-Object", outputObjectPtr) 5132 5133 if err != nil { 5134 _ = seg.Seg.AddError(err) 5135 } 5136 }() 5137 5138 notFound, err = s.spopInternal(key, outputDataType, outputObjectPtr) 5139 return notFound, err 5140 } else { 5141 return s.spopInternal(key, outputDataType, outputObjectPtr) 5142 } 5143 } 5144 5145 // spopInternal removes and returns one random element from the set value stored at key 5146 func (s *SET) spopInternal(key string, outputDataType redisdatatype.RedisDataType, outputObjectPtr interface{}) (notFound bool, err error) { 5147 // validate 5148 if s.core == nil { 5149 return false, errors.New("Redis SPop Failed: " + "Base is Nil") 5150 } 5151 5152 if !s.core.cnAreReady { 5153 return false, errors.New("Redis SPop Failed: " + "Endpoint Connections Not Ready") 5154 } 5155 5156 if len(key) <= 0 { 5157 return false, errors.New("Redis SPop Failed: " + "Key is Required") 5158 } 5159 5160 if !outputDataType.Valid() || outputDataType == redisdatatype.UNKNOWN { 5161 return false, errors.New("Redis SPop Failed: " + "Output Data Type is Required") 5162 } 5163 5164 if outputObjectPtr == nil { 5165 return false, errors.New("Redis SPop Failed: " + "Output Object Pointer is Required") 5166 } 5167 5168 cmd := s.core.cnWriter.SPop(s.core.cnWriter.Context(), key) 5169 return s.core.handleStringCmd(cmd, outputDataType, outputObjectPtr, "Redis SPop Failed: ") 5170 } 5171 5172 // SPopN removes and returns one or more random element from the set value stored at key 5173 // 5174 // count > 0 = returns an array of count distinct elements (non-repeating), up to the set elements size 5175 // count < 0 = returns an array of count elements (may be repeating), and up to the count size (selected members may still be part of the subsequent selection process) 5176 func (s *SET) SPopN(key string, count int64) (outputSlice []string, notFound bool, err error) { 5177 // get new xray segment for tracing 5178 seg := xray.NewSegmentNullable("Redis-SPopN", s.core._parentSegment) 5179 5180 if seg != nil { 5181 defer seg.Close() 5182 defer func() { 5183 _ = seg.Seg.AddMetadata("Redis-SPopN-Key", key) 5184 _ = seg.Seg.AddMetadata("Redis-SPopN-Count", count) 5185 _ = seg.Seg.AddMetadata("Redis-SPopN-Not-Found", notFound) 5186 _ = seg.Seg.AddMetadata("Redis-SPopN-Results", outputSlice) 5187 5188 if err != nil { 5189 _ = seg.Seg.AddError(err) 5190 } 5191 }() 5192 5193 outputSlice, notFound, err = s.spopNInternal(key, count) 5194 return outputSlice, notFound, err 5195 } else { 5196 return s.spopNInternal(key, count) 5197 } 5198 } 5199 5200 // spopNInternal removes and returns one or more random element from the set value stored at key 5201 // 5202 // count > 0 = returns an array of count distinct elements (non-repeating), up to the set elements size 5203 // count < 0 = returns an array of count elements (may be repeating), and up to the count size (selected members may still be part of the subsequent selection process) 5204 func (s *SET) spopNInternal(key string, count int64) (outputSlice []string, notFound bool, err error) { 5205 // validate 5206 if s.core == nil { 5207 return nil, false, errors.New("Redis SPopN Failed: " + "Base is Nil") 5208 } 5209 5210 if !s.core.cnAreReady { 5211 return nil, false, errors.New("Redis SPopN Failed: " + "Endpoint Connections Not Ready") 5212 } 5213 5214 if len(key) <= 0 { 5215 return nil, false, errors.New("Redis SPopN Failed: " + "Key is Required") 5216 } 5217 5218 if count == 0 { 5219 return nil, false, errors.New("Redis SPopN Failed: " + "Count Must Not Be Zero") 5220 } 5221 5222 cmd := s.core.cnWriter.SPopN(s.core.cnWriter.Context(), key, count) 5223 return s.core.handleStringSliceCmd(cmd, "Redis SPopN Failed: ") 5224 } 5225 5226 // SUnion returns the members of the set resulting from the union of all the given sets, 5227 // if a key is not existent, it is treated as a empty set 5228 // 5229 // Example: 5230 // 5231 // key1 = { a, b, c } 5232 // key2 = { c } 5233 // key3 = { a, c, e } 5234 // SUNION key1 key2 key3 = { a, b, c, d, e } 5235 func (s *SET) SUnion(key ...string) (outputSlice []string, notFound bool, err error) { 5236 // get new xray segment for tracing 5237 seg := xray.NewSegmentNullable("Redis-SUnion", s.core._parentSegment) 5238 5239 if seg != nil { 5240 defer seg.Close() 5241 defer func() { 5242 _ = seg.Seg.AddMetadata("Redis-SUnion-Keys", key) 5243 _ = seg.Seg.AddMetadata("Redis-SUnion-Not-Found", notFound) 5244 _ = seg.Seg.AddMetadata("Redis-SUnion-Results", outputSlice) 5245 5246 if err != nil { 5247 _ = seg.Seg.AddError(err) 5248 } 5249 }() 5250 5251 outputSlice, notFound, err = s.sunionInternal(key...) 5252 return outputSlice, notFound, err 5253 } else { 5254 return s.sunionInternal(key...) 5255 } 5256 } 5257 5258 // sunionInternal returns the members of the set resulting from the union of all the given sets, 5259 // if a key is not existent, it is treated as a empty set 5260 // 5261 // Example: 5262 // 5263 // key1 = { a, b, c } 5264 // key2 = { c } 5265 // key3 = { a, c, e } 5266 // SUNION key1 key2 key3 = { a, b, c, d, e } 5267 func (s *SET) sunionInternal(key ...string) (outputSlice []string, notFound bool, err error) { 5268 // validate 5269 if s.core == nil { 5270 return nil, false, errors.New("Redis SUnion Failed: " + "Base is Nil") 5271 } 5272 5273 if !s.core.cnAreReady { 5274 return nil, false, errors.New("Redis SUnion Failed: " + "Endpoint Connections Not Ready") 5275 } 5276 5277 if len(key) <= 1 { 5278 return nil, false, errors.New("Redis SUnion Failed: " + "At Least 2 Keys Are Required") 5279 } 5280 5281 cmd := s.core.cnReader.SUnion(s.core.cnReader.Context(), key...) 5282 return s.core.handleStringSliceCmd(cmd, "Redis SUnion Failed: ") 5283 } 5284 5285 // SUnionStore will store the members of the set resulting from the union of all the given sets to 'destination' 5286 // if a key is not existent, it is treated as a empty set, 5287 // if 'destination' already exists, it is overwritten 5288 // 5289 // Example: 5290 // 5291 // key1 = { a, b, c } 5292 // key2 = { c } 5293 // key3 = { a, c, e } 5294 // SUNION key1 key2 key3 = { a, b, c, d, e } 5295 func (s *SET) SUnionStore(keyDest string, keySource ...string) (err error) { 5296 // get new xray segment for tracing 5297 seg := xray.NewSegmentNullable("Redis-SUnionStore", s.core._parentSegment) 5298 5299 if seg != nil { 5300 defer seg.Close() 5301 defer func() { 5302 _ = seg.Seg.AddMetadata("Redis-SUnionStore-KeyDest", keyDest) 5303 _ = seg.Seg.AddMetadata("Redis-SUnionStore-KeySources", keySource) 5304 5305 if err != nil { 5306 _ = seg.Seg.AddError(err) 5307 } 5308 }() 5309 5310 err = s.sunionStoreInternal(keyDest, keySource...) 5311 return err 5312 } else { 5313 return s.sunionStoreInternal(keyDest, keySource...) 5314 } 5315 } 5316 5317 // sunionStoreInternal will store the members of the set resulting from the union of all the given sets to 'destination' 5318 // if a key is not existent, it is treated as a empty set, 5319 // if 'destination' already exists, it is overwritten 5320 // 5321 // Example: 5322 // 5323 // key1 = { a, b, c } 5324 // key2 = { c } 5325 // key3 = { a, c, e } 5326 // SUNION key1 key2 key3 = { a, b, c, d, e } 5327 func (s *SET) sunionStoreInternal(keyDest string, keySource ...string) error { 5328 // validate 5329 if s.core == nil { 5330 return errors.New("Redis SUnionStore Failed: " + "Base is Nil") 5331 } 5332 5333 if !s.core.cnAreReady { 5334 return errors.New("Redis SUnionStore Failed: " + "Endpoint Connections Not Ready") 5335 } 5336 5337 if len(keyDest) <= 0 { 5338 return errors.New("Redis SUnionStore Failed: " + "Key Destination is Required") 5339 } 5340 5341 if len(keySource) <= 1 { 5342 return errors.New("Redis SUnionStore Failed: " + "At Least 2 Key Sources are Required") 5343 } 5344 5345 cmd := s.core.cnWriter.SUnionStore(s.core.cnWriter.Context(), keyDest, keySource...) 5346 return s.core.handleIntCmd2(cmd, "Redis SUnionStore Failed: ") 5347 } 5348 5349 // ---------------------------------------------------------------------------------------------------------------- 5350 // SORTED_SET functions 5351 // ---------------------------------------------------------------------------------------------------------------- 5352 5353 // ZAdd will add all the specified members with the specified scores to the sorted set stored at key, 5354 // If a specified member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering 5355 // 5356 // # If key does not exist, a new sorted set with the specified members is created as if the set was empty 5357 // 5358 // # If value at key is not a sorted set, then error is returned 5359 // 5360 // Score Values: 5361 // 1. Should be string representation of a double precision floating point number 5362 // 5363 // Other ZAdd Options: 5364 // 1. ZAdd XX / XXCH = only update elements that already exists, never add elements 5365 // 2. ZAdd NX / NXCH = don't update already existing elements, always add new elements 5366 // 3. ZAdd CH = modify the return value from the number of new or updated elements added, CH = Changed 5367 func (z *SORTED_SET) ZAdd(key string, setCondition redissetcondition.RedisSetCondition, getChanged bool, member ...*redis.Z) (err error) { 5368 // get new xray segment for tracing 5369 seg := xray.NewSegmentNullable("Redis-ZAdd", z.core._parentSegment) 5370 5371 if seg != nil { 5372 defer seg.Close() 5373 defer func() { 5374 _ = seg.Seg.AddMetadata("Redis-ZAdd-Key", key) 5375 _ = seg.Seg.AddMetadata("Redis-ZAdd-Condition", setCondition) 5376 _ = seg.Seg.AddMetadata("Redis-ZAdd-Get-Changed", getChanged) 5377 _ = seg.Seg.AddMetadata("Redis-ZAdd-Member", member) 5378 5379 if err != nil { 5380 _ = seg.Seg.AddError(err) 5381 } 5382 }() 5383 5384 err = z.zaddInternal(key, setCondition, getChanged, member...) 5385 return err 5386 } else { 5387 return z.zaddInternal(key, setCondition, getChanged, member...) 5388 } 5389 } 5390 5391 // zaddInternal will add all the specified members with the specified scores to the sorted set stored at key, 5392 // If a specified member is already a member of the sorted set, the score is updated and the element reinserted at the right position to ensure the correct ordering 5393 // 5394 // # If key does not exist, a new sorted set with the specified members is created as if the set was empty 5395 // 5396 // # If value at key is not a sorted set, then error is returned 5397 // 5398 // Score Values: 5399 // 1. Should be string representation of a double precision floating point number 5400 // 5401 // Other ZAdd Options: 5402 // 1. ZAdd XX / XXCH = only update elements that already exists, never add elements 5403 // 2. ZAdd NX / NXCH = don't update already existing elements, always add new elements 5404 // 3. ZAdd CH = modify the return value from the number of new or updated elements added, CH = Changed 5405 func (z *SORTED_SET) zaddInternal(key string, setCondition redissetcondition.RedisSetCondition, getChanged bool, member ...*redis.Z) error { 5406 // validate 5407 if z.core == nil { 5408 return errors.New("Redis ZAdd Failed: " + "Base is Nil") 5409 } 5410 5411 if !z.core.cnAreReady { 5412 return errors.New("Redis ZAdd Failed: " + "Endpoint Connections Not Ready") 5413 } 5414 5415 if len(key) <= 0 { 5416 return errors.New("Redis ZAdd Failed: " + "Key is Required") 5417 } 5418 5419 if !setCondition.Valid() || setCondition == redissetcondition.UNKNOWN { 5420 return errors.New("Redis ZAdd Failed: " + "Set Condition is Required") 5421 } 5422 5423 if len(member) <= 0 { 5424 return errors.New("Redis ZAdd Failed: " + "At Least 1 Member is Required") 5425 } 5426 5427 var cmd *redis.IntCmd 5428 5429 switch setCondition { 5430 case redissetcondition.Normal: 5431 if !getChanged { 5432 cmd = z.core.cnWriter.ZAdd(z.core.cnWriter.Context(), key, member...) 5433 } else { 5434 cmd = z.core.cnWriter.ZAddCh(z.core.cnWriter.Context(), key, member...) 5435 } 5436 case redissetcondition.SetIfNotExists: 5437 if !getChanged { 5438 cmd = z.core.cnWriter.ZAddNX(z.core.cnWriter.Context(), key, member...) 5439 } else { 5440 cmd = z.core.cnWriter.ZAddNXCh(z.core.cnWriter.Context(), key, member...) 5441 } 5442 case redissetcondition.SetIfExists: 5443 if !getChanged { 5444 cmd = z.core.cnWriter.ZAddXX(z.core.cnWriter.Context(), key, member...) 5445 } else { 5446 cmd = z.core.cnWriter.ZAddXXCh(z.core.cnWriter.Context(), key, member...) 5447 } 5448 default: 5449 return errors.New("Redis ZAdd Failed: " + "Set Condition is Required") 5450 } 5451 5452 return z.core.handleIntCmd2(cmd, "Redis ZAdd Failed: ") 5453 } 5454 5455 // ZCard returns the sorted set cardinality (number of elements) of the sorted set stored at key 5456 func (z *SORTED_SET) ZCard(key string) (val int64, notFound bool, err error) { 5457 // get new xray segment for tracing 5458 seg := xray.NewSegmentNullable("Redis-ZCard", z.core._parentSegment) 5459 5460 if seg != nil { 5461 defer seg.Close() 5462 defer func() { 5463 _ = seg.Seg.AddMetadata("Redis-ZCard-Key", key) 5464 _ = seg.Seg.AddMetadata("Redis-ZCard-Not-Found", notFound) 5465 _ = seg.Seg.AddMetadata("Redis-ZCard-Not-Result-Count", val) 5466 5467 if err != nil { 5468 _ = seg.Seg.AddError(err) 5469 } 5470 }() 5471 5472 val, notFound, err = z.zcardInternal(key) 5473 return val, notFound, err 5474 } else { 5475 return z.zcardInternal(key) 5476 } 5477 } 5478 5479 // zcardInternal returns the sorted set cardinality (number of elements) of the sorted set stored at key 5480 func (z *SORTED_SET) zcardInternal(key string) (val int64, notFound bool, err error) { 5481 // validate 5482 if z.core == nil { 5483 return 0, false, errors.New("Redis ZCard Failed: " + "Base is Nil") 5484 } 5485 5486 if !z.core.cnAreReady { 5487 return 0, false, errors.New("Redis ZCard Failed: " + "Endpoint Connections Not Ready") 5488 } 5489 5490 if len(key) <= 0 { 5491 return 0, false, errors.New("Redis ZCard Failed: " + "Key is Required") 5492 } 5493 5494 cmd := z.core.cnReader.ZCard(z.core.cnReader.Context(), key) 5495 return z.core.handleIntCmd(cmd, "Redis ZCard Failed: ") 5496 } 5497 5498 // ZCount returns the number of elements in the sorted set at key with a score between min and max 5499 func (z *SORTED_SET) ZCount(key string, min string, max string) (val int64, notFound bool, err error) { 5500 // get new xray segment for tracing 5501 seg := xray.NewSegmentNullable("Redis-ZCount", z.core._parentSegment) 5502 5503 if seg != nil { 5504 defer seg.Close() 5505 defer func() { 5506 _ = seg.Seg.AddMetadata("Redis-ZCount-Key", key) 5507 _ = seg.Seg.AddMetadata("Redis-ZCount-Min", min) 5508 _ = seg.Seg.AddMetadata("Redis-ZCount-Max", max) 5509 _ = seg.Seg.AddMetadata("Redis-ZCount-Not-Found", notFound) 5510 _ = seg.Seg.AddMetadata("Redis-ZCount-Result-Count", val) 5511 5512 if err != nil { 5513 _ = seg.Seg.AddError(err) 5514 } 5515 }() 5516 5517 val, notFound, err = z.zcountInternal(key, min, max) 5518 return val, notFound, err 5519 } else { 5520 return z.zcountInternal(key, min, max) 5521 } 5522 } 5523 5524 // zcountInternal returns the number of elements in the sorted set at key with a score between min and max 5525 func (z *SORTED_SET) zcountInternal(key string, min string, max string) (val int64, notFound bool, err error) { 5526 // validate 5527 if z.core == nil { 5528 return 0, false, errors.New("Redis ZCount Failed: " + "Base is Nil") 5529 } 5530 5531 if !z.core.cnAreReady { 5532 return 0, false, errors.New("Redis ZCount Failed: " + "Endpoint Connections Not Ready") 5533 } 5534 5535 if len(key) <= 0 { 5536 return 0, false, errors.New("Redis ZCount Failed: " + "Key is Required") 5537 } 5538 5539 if len(min) <= 0 { 5540 return 0, false, errors.New("Redis ZCount Failed: " + "Min is Required") 5541 } 5542 5543 if len(max) <= 0 { 5544 return 0, false, errors.New("Redis ZCount Failed: " + "Max is Required") 5545 } 5546 5547 cmd := z.core.cnReader.ZCount(z.core.cnReader.Context(), key, min, max) 5548 return z.core.handleIntCmd(cmd, "Redis ZCount Failed: ") 5549 } 5550 5551 // ZIncr will increment the score of member in sorted set at key 5552 // 5553 // Also support for ZIncrXX (member must exist), ZIncrNX (member must not exist) 5554 func (z *SORTED_SET) ZIncr(key string, setCondition redissetcondition.RedisSetCondition, member *redis.Z) (err error) { 5555 // get new xray segment for tracing 5556 seg := xray.NewSegmentNullable("Redis-ZIncr", z.core._parentSegment) 5557 5558 if seg != nil { 5559 defer seg.Close() 5560 defer func() { 5561 _ = seg.Seg.AddMetadata("Redis-ZIncr-Key", key) 5562 _ = seg.Seg.AddMetadata("Redis-ZIncr-Condition", setCondition) 5563 _ = seg.Seg.AddMetadata("Redis-ZIncr-Member", member) 5564 5565 if err != nil { 5566 _ = seg.Seg.AddError(err) 5567 } 5568 }() 5569 5570 err = z.zincrInternal(key, setCondition, member) 5571 return err 5572 } else { 5573 return z.zincrInternal(key, setCondition, member) 5574 } 5575 } 5576 5577 // zincrInternal will increment the score of member in sorted set at key 5578 // 5579 // Also support for ZIncrXX (member must exist), ZIncrNX (member must not exist) 5580 func (z *SORTED_SET) zincrInternal(key string, setCondition redissetcondition.RedisSetCondition, member *redis.Z) error { 5581 // validate 5582 if z.core == nil { 5583 return errors.New("Redis ZIncr Failed: " + "Base is Nil") 5584 } 5585 5586 if !z.core.cnAreReady { 5587 return errors.New("Redis ZIncr Failed: " + "Endpoint Connections Not Ready") 5588 } 5589 5590 if len(key) <= 0 { 5591 return errors.New("Redis ZIncr Failed: " + "Key is Required") 5592 } 5593 5594 if !setCondition.Valid() || setCondition == redissetcondition.UNKNOWN { 5595 return errors.New("Redis ZIncr Failed: " + "Set Condition is Required") 5596 } 5597 5598 if member == nil { 5599 return errors.New("Redis ZIncr Failed: " + "Member is Required") 5600 } 5601 5602 var cmd *redis.FloatCmd 5603 5604 switch setCondition { 5605 case redissetcondition.Normal: 5606 cmd = z.core.cnWriter.ZIncr(z.core.cnWriter.Context(), key, member) 5607 case redissetcondition.SetIfNotExists: 5608 cmd = z.core.cnWriter.ZIncrNX(z.core.cnWriter.Context(), key, member) 5609 case redissetcondition.SetIfExists: 5610 cmd = z.core.cnWriter.ZIncrXX(z.core.cnWriter.Context(), key, member) 5611 default: 5612 return errors.New("Redis ZIncr Failed: " + "Set Condition is Required") 5613 } 5614 5615 if _, _, err := z.core.handleFloatCmd(cmd, "Redis ZIncr Failed: "); err != nil { 5616 return err 5617 } else { 5618 return nil 5619 } 5620 } 5621 5622 // ZIncrBy increments or decrements the score of member in the sorted set stored at key, with custom increment value, 5623 // If member does not exist in the sorted set, it is added with increment value as its score, 5624 // If key does not exist, a new sorted set with the specified member as its sole member is created 5625 // 5626 // # Error is returned if the value stored at key is not a sorted set 5627 // 5628 // Score should be string representation of a numeric value, and accepts double precision floating point numbers 5629 // To decrement, use negative value 5630 func (z *SORTED_SET) ZIncrBy(key string, increment float64, member string) (err error) { 5631 // get new xray segment for tracing 5632 seg := xray.NewSegmentNullable("Redis-ZIncrBy", z.core._parentSegment) 5633 5634 if seg != nil { 5635 defer seg.Close() 5636 defer func() { 5637 _ = seg.Seg.AddMetadata("Redis-ZIncrBy-Key", key) 5638 _ = seg.Seg.AddMetadata("Redis-ZIncrBy-Increment", increment) 5639 _ = seg.Seg.AddMetadata("Redis-ZIncrBy-Member", member) 5640 5641 if err != nil { 5642 _ = seg.Seg.AddError(err) 5643 } 5644 }() 5645 5646 err = z.zincrByInternal(key, increment, member) 5647 return err 5648 } else { 5649 return z.zincrByInternal(key, increment, member) 5650 } 5651 } 5652 5653 // zincrByInternal increments or decrements the score of member in the sorted set stored at key, with custom increment value, 5654 // If member does not exist in the sorted set, it is added with increment value as its score, 5655 // If key does not exist, a new sorted set with the specified member as its sole member is created 5656 // 5657 // # Error is returned if the value stored at key is not a sorted set 5658 // 5659 // Score should be string representation of a numeric value, and accepts double precision floating point numbers 5660 // To decrement, use negative value 5661 func (z *SORTED_SET) zincrByInternal(key string, increment float64, member string) error { 5662 // validate 5663 if z.core == nil { 5664 return errors.New("Redis ZIncrBy Failed: " + "Base is Nil") 5665 } 5666 5667 if !z.core.cnAreReady { 5668 return errors.New("Redis ZIncrBy Failed: " + "Endpoint Connections Not Ready") 5669 } 5670 5671 if len(key) <= 0 { 5672 return errors.New("Redis ZIncrBy Failed: " + "Key is Required") 5673 } 5674 5675 if increment == 0.00 { 5676 return errors.New("Redis ZIncrBy Failed: " + "Increment is Required") 5677 } 5678 5679 if len(member) <= 0 { 5680 return errors.New("Redis ZIncrBy Failed: " + "Member is Required") 5681 } 5682 5683 cmd := z.core.cnWriter.ZIncrBy(z.core.cnWriter.Context(), key, increment, member) 5684 if _, _, err := z.core.handleFloatCmd(cmd, "Redis ZIncrBy Failed: "); err != nil { 5685 return err 5686 } else { 5687 return nil 5688 } 5689 } 5690 5691 // ZInterStore computes the intersection of numKeys sorted set given by the specified keys, 5692 // and stores the result in 'destination' 5693 // 5694 // numKeys (input keys) are required 5695 // 5696 // If 'destination' already exists, it is overwritten 5697 // 5698 // Default Logic: 5699 // 5700 // Resulting score of an element is the sum of its scores in the sorted set where it exists 5701 func (z *SORTED_SET) ZInterStore(keyDest string, store *redis.ZStore) (err error) { 5702 // get new xray segment for tracing 5703 seg := xray.NewSegmentNullable("Redis-ZInterStore", z.core._parentSegment) 5704 5705 if seg != nil { 5706 defer seg.Close() 5707 defer func() { 5708 _ = seg.Seg.AddMetadata("Redis-ZInterStore-KeyDest", keyDest) 5709 _ = seg.Seg.AddMetadata("Redis-ZInterStore-Input-Args", store) 5710 5711 if err != nil { 5712 _ = seg.Seg.AddError(err) 5713 } 5714 }() 5715 5716 err = z.zinterStoreInternal(keyDest, store) 5717 return err 5718 } else { 5719 return z.zinterStoreInternal(keyDest, store) 5720 } 5721 } 5722 5723 // zinterStoreInternal computes the intersection of numKeys sorted set given by the specified keys, 5724 // and stores the result in 'destination' 5725 // 5726 // numKeys (input keys) are required 5727 // 5728 // If 'destination' already exists, it is overwritten 5729 // 5730 // Default Logic: 5731 // 5732 // Resulting score of an element is the sum of its scores in the sorted set where it exists 5733 func (z *SORTED_SET) zinterStoreInternal(keyDest string, store *redis.ZStore) error { 5734 // validate 5735 if z.core == nil { 5736 return errors.New("Redis ZInterStore Failed: " + "Base is Nil") 5737 } 5738 5739 if !z.core.cnAreReady { 5740 return errors.New("Redis ZInterStore Failed: " + "Endpoint Connections Not Ready") 5741 } 5742 5743 if len(keyDest) <= 0 { 5744 return errors.New("Redis ZInterStore Failed: " + "Key Destination is Required") 5745 } 5746 5747 if store == nil { 5748 return errors.New("Redis ZInterStore Failed: " + "Store is Required") 5749 } 5750 5751 cmd := z.core.cnWriter.ZInterStore(z.core.cnWriter.Context(), keyDest, store) 5752 return z.core.handleIntCmd2(cmd, "Redis ZInterStore Failed: ") 5753 } 5754 5755 // ZLexCount returns the number of elements in the sorted set at key, with a value between min and max 5756 func (z *SORTED_SET) ZLexCount(key string, min string, max string) (val int64, notFound bool, err error) { 5757 // get new xray segment for tracing 5758 seg := xray.NewSegmentNullable("Redis-ZLexCount", z.core._parentSegment) 5759 5760 if seg != nil { 5761 defer seg.Close() 5762 defer func() { 5763 _ = seg.Seg.AddMetadata("Redis-ZLexCount-Key", key) 5764 _ = seg.Seg.AddMetadata("Redis-ZLexCount-Min", min) 5765 _ = seg.Seg.AddMetadata("Redis-ZLexCount-Max", max) 5766 _ = seg.Seg.AddMetadata("Redis-ZLexCount-Not-Found", notFound) 5767 _ = seg.Seg.AddMetadata("Redis-ZLexCount-Result", val) 5768 5769 if err != nil { 5770 _ = seg.Seg.AddError(err) 5771 } 5772 }() 5773 5774 val, notFound, err = z.zlexCountInternal(key, min, max) 5775 return val, notFound, err 5776 } else { 5777 return z.zlexCountInternal(key, min, max) 5778 } 5779 } 5780 5781 // zlexCountInternal returns the number of elements in the sorted set at key, with a value between min and max 5782 func (z *SORTED_SET) zlexCountInternal(key string, min string, max string) (val int64, notFound bool, err error) { 5783 // validate 5784 if z.core == nil { 5785 return 0, false, errors.New("Redis ZLexCount Failed: " + "Base is Nil") 5786 } 5787 5788 if !z.core.cnAreReady { 5789 return 0, false, errors.New("Redis ZLexCount Failed: " + "Endpoint Connections Not Ready") 5790 } 5791 5792 if len(key) <= 0 { 5793 return 0, false, errors.New("Redis ZLexCount Failed: " + "Key is Required") 5794 } 5795 5796 if len(min) <= 0 { 5797 return 0, false, errors.New("Redis ZLexCount Failed: " + "Min is Required") 5798 } 5799 5800 if len(max) <= 0 { 5801 return 0, false, errors.New("Redis ZLexCount Failed: " + "Max is Required") 5802 } 5803 5804 cmd := z.core.cnReader.ZLexCount(z.core.cnReader.Context(), key, min, max) 5805 return z.core.handleIntCmd(cmd, "Redis ZLexCount Failed: ") 5806 } 5807 5808 // ZPopMax removes and returns up to the count of members with the highest scores in the sorted set stored at key, 5809 // Specifying more count than members will not cause error, rather given back smaller result set, 5810 // Returning elements ordered with highest score first, then subsequent and so on 5811 func (z *SORTED_SET) ZPopMax(key string, count ...int64) (outputSlice []redis.Z, notFound bool, err error) { 5812 // get new xray segment for tracing 5813 seg := xray.NewSegmentNullable("Redis-ZPopMax", z.core._parentSegment) 5814 5815 if seg != nil { 5816 defer seg.Close() 5817 defer func() { 5818 _ = seg.Seg.AddMetadata("Redis-ZPopMax-Key", key) 5819 _ = seg.Seg.AddMetadata("Redis-ZPopMax-Count", count) 5820 _ = seg.Seg.AddMetadata("Redis-ZPopMax-Not-Found", notFound) 5821 _ = seg.Seg.AddMetadata("Redis-ZPopMax-Results", outputSlice) 5822 5823 if err != nil { 5824 _ = seg.Seg.AddError(err) 5825 } 5826 }() 5827 5828 outputSlice, notFound, err = z.zpopMaxInternal(key, count...) 5829 return outputSlice, notFound, err 5830 } else { 5831 return z.zpopMaxInternal(key, count...) 5832 } 5833 } 5834 5835 // zpopMaxInternal removes and returns up to the count of members with the highest scores in the sorted set stored at key, 5836 // Specifying more count than members will not cause error, rather given back smaller result set, 5837 // Returning elements ordered with highest score first, then subsequent and so on 5838 func (z *SORTED_SET) zpopMaxInternal(key string, count ...int64) (outputSlice []redis.Z, notFound bool, err error) { 5839 // validate 5840 if z.core == nil { 5841 return nil, false, errors.New("Redis ZPopMax Failed: " + "Base is Nil") 5842 } 5843 5844 if !z.core.cnAreReady { 5845 return nil, false, errors.New("Redis ZPopMax Failed: " + "Endpoint Connections Not Ready") 5846 } 5847 5848 if len(key) <= 0 { 5849 return nil, false, errors.New("Redis ZPopMax Failed: " + "Key is Required") 5850 } 5851 5852 var cmd *redis.ZSliceCmd 5853 5854 if len(count) <= 0 { 5855 cmd = z.core.cnWriter.ZPopMax(z.core.cnWriter.Context(), key) 5856 } else { 5857 cmd = z.core.cnWriter.ZPopMax(z.core.cnWriter.Context(), key, count...) 5858 } 5859 5860 return z.core.handleZSliceCmd(cmd, "Redis ZPopMax Failed: ") 5861 } 5862 5863 // ZPopMin removes and returns up to the count of members with the lowest scores in the sorted set stored at key, 5864 // Specifying more count than members will not cause error, rather given back smaller result set, 5865 // Returning elements ordered with lowest score first, then subsequently higher score, and so on 5866 func (z *SORTED_SET) ZPopMin(key string, count ...int64) (outputSlice []redis.Z, notFound bool, err error) { 5867 // get new xray segment for tracing 5868 seg := xray.NewSegmentNullable("Redis-ZPopMin", z.core._parentSegment) 5869 5870 if seg != nil { 5871 defer seg.Close() 5872 defer func() { 5873 _ = seg.Seg.AddMetadata("Redis-ZPopMin-Key", key) 5874 _ = seg.Seg.AddMetadata("Redis-ZPopMin-Count", count) 5875 _ = seg.Seg.AddMetadata("Redis-ZPopMin-Not-Found", notFound) 5876 _ = seg.Seg.AddMetadata("Redis-ZPopMin-Results", outputSlice) 5877 5878 if err != nil { 5879 _ = seg.Seg.AddError(err) 5880 } 5881 }() 5882 5883 outputSlice, notFound, err = z.zpopMinInternal(key, count...) 5884 return outputSlice, notFound, err 5885 } else { 5886 return z.zpopMinInternal(key, count...) 5887 } 5888 } 5889 5890 // zpopMinInternal removes and returns up to the count of members with the lowest scores in the sorted set stored at key, 5891 // Specifying more count than members will not cause error, rather given back smaller result set, 5892 // Returning elements ordered with lowest score first, then subsequently higher score, and so on 5893 func (z *SORTED_SET) zpopMinInternal(key string, count ...int64) (outputSlice []redis.Z, notFound bool, err error) { 5894 // validate 5895 if z.core == nil { 5896 return nil, false, errors.New("Redis ZPopMin Failed: " + "Base is Nil") 5897 } 5898 5899 if !z.core.cnAreReady { 5900 return nil, false, errors.New("Redis ZPopMin Failed: " + "Endpoint Connections Not Ready") 5901 } 5902 5903 if len(key) <= 0 { 5904 return nil, false, errors.New("Redis ZPopMin Failed: " + "Key is Required") 5905 } 5906 5907 var cmd *redis.ZSliceCmd 5908 5909 if len(count) <= 0 { 5910 z.core.cnWriter.ZPopMin(z.core.cnWriter.Context(), key) 5911 } else { 5912 z.core.cnWriter.ZPopMin(z.core.cnWriter.Context(), key, count...) 5913 } 5914 5915 return z.core.handleZSliceCmd(cmd, "Redis ZPopMin Failed: ") 5916 } 5917 5918 // ZRange returns the specified range of elements in the sorted set stored at key, 5919 // The elements are considered to be ordered form lowest to the highest score, 5920 // Lexicographical order is used for elements with equal score 5921 // 5922 // start and stop are both zero-based indexes, 5923 // start and stop may be negative, where -1 is the last index, and -2 is the second to the last index, 5924 // start and stop are inclusive range 5925 func (z *SORTED_SET) ZRange(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 5926 // get new xray segment for tracing 5927 seg := xray.NewSegmentNullable("Redis-ZRange", z.core._parentSegment) 5928 5929 if seg != nil { 5930 defer seg.Close() 5931 defer func() { 5932 _ = seg.Seg.AddMetadata("Redis-ZRange-Key", key) 5933 _ = seg.Seg.AddMetadata("Redis-ZRange-Start", start) 5934 _ = seg.Seg.AddMetadata("Redis-ZRange-Stop", stop) 5935 _ = seg.Seg.AddMetadata("Redis-ZRange-Not-Found", notFound) 5936 _ = seg.Seg.AddMetadata("Redis-ZRange-Results", outputSlice) 5937 5938 if err != nil { 5939 _ = seg.Seg.AddError(err) 5940 } 5941 }() 5942 5943 outputSlice, notFound, err = z.zrangeInternal(key, start, stop) 5944 return outputSlice, notFound, err 5945 } else { 5946 return z.zrangeInternal(key, start, stop) 5947 } 5948 } 5949 5950 // zrangeInternal returns the specified range of elements in the sorted set stored at key, 5951 // The elements are considered to be ordered form lowest to the highest score, 5952 // Lexicographical order is used for elements with equal score 5953 // 5954 // start and stop are both zero-based indexes, 5955 // start and stop may be negative, where -1 is the last index, and -2 is the second to the last index, 5956 // start and stop are inclusive range 5957 func (z *SORTED_SET) zrangeInternal(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 5958 // validate 5959 if z.core == nil { 5960 return nil, false, errors.New("Redis ZRange Failed: " + "Base is Nil") 5961 } 5962 5963 if !z.core.cnAreReady { 5964 return nil, false, errors.New("Redis ZRange Failed: " + "Endpoint Connections Not Ready") 5965 } 5966 5967 if len(key) <= 0 { 5968 return nil, false, errors.New("Redis ZRange Failed: " + "Key is Required") 5969 } 5970 5971 cmd := z.core.cnReader.ZRange(z.core.cnReader.Context(), key, start, stop) 5972 return z.core.handleStringSliceCmd(cmd, "Redis ZRange Failed: ") 5973 } 5974 5975 // ZRangeByLex returns all the elements in the sorted set at key with a value between min and max 5976 func (z *SORTED_SET) ZRangeByLex(key string, opt *redis.ZRangeBy) (outputSlice []string, notFound bool, err error) { 5977 // get new xray segment for tracing 5978 seg := xray.NewSegmentNullable("Redis-ZRangeByLex", z.core._parentSegment) 5979 5980 if seg != nil { 5981 defer seg.Close() 5982 defer func() { 5983 _ = seg.Seg.AddMetadata("Redis-ZRangeByLex-Key", key) 5984 _ = seg.Seg.AddMetadata("Redis-ZRangeByLex-Input-Args", opt) 5985 _ = seg.Seg.AddMetadata("Redis-ZRangeByLex-Not-Found", notFound) 5986 _ = seg.Seg.AddMetadata("Redis-ZRangeByLex-Results", outputSlice) 5987 5988 if err != nil { 5989 _ = seg.Seg.AddError(err) 5990 } 5991 }() 5992 5993 outputSlice, notFound, err = z.zrangeByLexInternal(key, opt) 5994 return outputSlice, notFound, err 5995 } else { 5996 return z.zrangeByLexInternal(key, opt) 5997 } 5998 } 5999 6000 // zrangeByLexInternal returns all the elements in the sorted set at key with a value between min and max 6001 func (z *SORTED_SET) zrangeByLexInternal(key string, opt *redis.ZRangeBy) (outputSlice []string, notFound bool, err error) { 6002 // validate 6003 if z.core == nil { 6004 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Base is Nil") 6005 } 6006 6007 if !z.core.cnAreReady { 6008 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Endpoint Connections Not Ready") 6009 } 6010 6011 if len(key) <= 0 { 6012 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Key is Required") 6013 } 6014 6015 if opt == nil { 6016 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Opt is Required") 6017 } 6018 6019 cmd := z.core.cnReader.ZRangeByLex(z.core.cnReader.Context(), key, opt) 6020 return z.core.handleStringSliceCmd(cmd, "Redis ZRangeByLex Failed: ") 6021 } 6022 6023 // ZRangeByScore returns all the elements in the sorted set at key with a score between min and max, 6024 // Elements are considered to be ordered from low to high scores 6025 func (z *SORTED_SET) ZRangeByScore(key string, opt *redis.ZRangeBy) (outputSlice []string, notFound bool, err error) { 6026 // get new xray segment for tracing 6027 seg := xray.NewSegmentNullable("Redis-ZRangeByScore", z.core._parentSegment) 6028 6029 if seg != nil { 6030 defer seg.Close() 6031 defer func() { 6032 _ = seg.Seg.AddMetadata("Redis-ZRangeByScore-Key", key) 6033 _ = seg.Seg.AddMetadata("Redis-ZRangeByScore-Input-Args", opt) 6034 _ = seg.Seg.AddMetadata("Redis-ZRangeByScore-Not-Found", notFound) 6035 _ = seg.Seg.AddMetadata("Redis-ZRangeByScore-Results", outputSlice) 6036 6037 if err != nil { 6038 _ = seg.Seg.AddError(err) 6039 } 6040 }() 6041 6042 outputSlice, notFound, err = z.zrangeByScoreInternal(key, opt) 6043 return outputSlice, notFound, err 6044 } else { 6045 return z.zrangeByScoreInternal(key, opt) 6046 } 6047 } 6048 6049 // zrangeByScoreInternal returns all the elements in the sorted set at key with a score between min and max, 6050 // Elements are considered to be ordered from low to high scores 6051 func (z *SORTED_SET) zrangeByScoreInternal(key string, opt *redis.ZRangeBy) (outputSlice []string, notFound bool, err error) { 6052 // validate 6053 if z.core == nil { 6054 return nil, false, errors.New("Redis ZRangeByScore Failed: " + "Base is Nil") 6055 } 6056 6057 if !z.core.cnAreReady { 6058 return nil, false, errors.New("Redis ZRangeByScore Failed: " + "Endpoint Connections Not Ready") 6059 } 6060 6061 if len(key) <= 0 { 6062 return nil, false, errors.New("Redis ZRangeByScore Failed: " + "Key is Required") 6063 } 6064 6065 if opt == nil { 6066 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Opt is Required") 6067 } 6068 6069 cmd := z.core.cnReader.ZRangeByScore(z.core.cnReader.Context(), key, opt) 6070 return z.core.handleStringSliceCmd(cmd, "Redis ZRangeByScore Failed: ") 6071 } 6072 6073 // ZRangeByScoreWithScores returns all the elements in the sorted set at key with a score between min and max, 6074 // Elements are considered to be ordered from low to high scores 6075 func (z *SORTED_SET) ZRangeByScoreWithScores(key string, opt *redis.ZRangeBy) (outputSlice []redis.Z, notFound bool, err error) { 6076 // get new xray segment for tracing 6077 seg := xray.NewSegmentNullable("Redis-ZRangeByScoreWithScores", z.core._parentSegment) 6078 6079 if seg != nil { 6080 defer seg.Close() 6081 defer func() { 6082 _ = seg.Seg.AddMetadata("Redis-ZRangeByScoreWithScores-Key", key) 6083 _ = seg.Seg.AddMetadata("Redis-ZRangeByScoreWithScores-Input-Args", opt) 6084 _ = seg.Seg.AddMetadata("Redis-ZRangeByScoreWithScores-Not-Found", notFound) 6085 _ = seg.Seg.AddMetadata("Redis-ZRangeByScoreWithScores-Results", outputSlice) 6086 6087 if err != nil { 6088 _ = seg.Seg.AddError(err) 6089 } 6090 }() 6091 6092 outputSlice, notFound, err = z.zrangeByScoreWithScoresInternal(key, opt) 6093 return outputSlice, notFound, err 6094 } else { 6095 return z.zrangeByScoreWithScoresInternal(key, opt) 6096 } 6097 } 6098 6099 // zrangeByScoreWithScoresInternal returns all the elements in the sorted set at key with a score between min and max, 6100 // Elements are considered to be ordered from low to high scores 6101 func (z *SORTED_SET) zrangeByScoreWithScoresInternal(key string, opt *redis.ZRangeBy) (outputSlice []redis.Z, notFound bool, err error) { 6102 // validate 6103 if z.core == nil { 6104 return nil, false, errors.New("Redis ZRangeByScoreWithScores Failed: " + "Base is Nil") 6105 } 6106 6107 if !z.core.cnAreReady { 6108 return nil, false, errors.New("Redis ZRangeByScoreWithScores Failed: " + "Endpoint Connections Not Ready") 6109 } 6110 6111 if len(key) <= 0 { 6112 return nil, false, errors.New("Redis ZRangeByScoreWithScores Failed: " + "Key is Required") 6113 } 6114 6115 if opt == nil { 6116 return nil, false, errors.New("Redis ZRangeByLex Failed: " + "Opt is Required") 6117 } 6118 6119 cmd := z.core.cnReader.ZRangeByScoreWithScores(z.core.cnReader.Context(), key, opt) 6120 return z.core.handleZSliceCmd(cmd, "ZRangeByLex") 6121 } 6122 6123 // ZRank returns the rank of member in the sorted set stored at key, with the scores ordered from low to high, 6124 // The rank (or index) is zero-based, where lowest member is index 0 (or rank 0) 6125 func (z *SORTED_SET) ZRank(key string, member string) (val int64, notFound bool, err error) { 6126 // get new xray segment for tracing 6127 seg := xray.NewSegmentNullable("Redis-ZRank", z.core._parentSegment) 6128 6129 if seg != nil { 6130 defer seg.Close() 6131 defer func() { 6132 _ = seg.Seg.AddMetadata("Redis-ZRank-Key", key) 6133 _ = seg.Seg.AddMetadata("Redis-ZRank-Member", member) 6134 _ = seg.Seg.AddMetadata("Redis-ZRank-Not-Found", notFound) 6135 _ = seg.Seg.AddMetadata("Redis-ZRank-Result", val) 6136 6137 if err != nil { 6138 _ = seg.Seg.AddError(err) 6139 } 6140 }() 6141 6142 val, notFound, err = z.zrankInternal(key, member) 6143 return val, notFound, err 6144 } else { 6145 return z.zrankInternal(key, member) 6146 } 6147 } 6148 6149 // zrankInternal returns the rank of member in the sorted set stored at key, with the scores ordered from low to high, 6150 // The rank (or index) is zero-based, where lowest member is index 0 (or rank 0) 6151 func (z *SORTED_SET) zrankInternal(key string, member string) (val int64, notFound bool, err error) { 6152 // validate 6153 if z.core == nil { 6154 return 0, false, errors.New("Redis ZRank Failed: " + "Base is Nil") 6155 } 6156 6157 if !z.core.cnAreReady { 6158 return 0, false, errors.New("Redis ZRank Failed: " + "Endpoint Connections Not Ready") 6159 } 6160 6161 if len(key) <= 0 { 6162 return 0, false, errors.New("Redis ZRank Failed: " + "Key is Required") 6163 } 6164 6165 if len(member) <= 0 { 6166 return 0, false, errors.New("Redis ZRank Failed: " + "Member is Required") 6167 } 6168 6169 cmd := z.core.cnReader.ZRank(z.core.cnReader.Context(), key, member) 6170 return z.core.handleIntCmd(cmd, "Redis ZRank Failed: ") 6171 } 6172 6173 // ZRem removes the specified members from the stored set stored at key, 6174 // Non-existing members are ignored 6175 // 6176 // Error is returned if the value at key is not a sorted set 6177 func (z *SORTED_SET) ZRem(key string, member ...interface{}) (err error) { 6178 // get new xray segment for tracing 6179 seg := xray.NewSegmentNullable("Redis-ZRem", z.core._parentSegment) 6180 6181 if seg != nil { 6182 defer seg.Close() 6183 defer func() { 6184 _ = seg.Seg.AddMetadata("Redis-ZRem-Key", key) 6185 _ = seg.Seg.AddMetadata("Redis-ZRem-Members", member) 6186 6187 if err != nil { 6188 _ = seg.Seg.AddError(err) 6189 } 6190 }() 6191 6192 err = z.zremInternal(key, member...) 6193 return err 6194 } else { 6195 return z.zremInternal(key, member...) 6196 } 6197 } 6198 6199 // zremInternal removes the specified members from the stored set stored at key, 6200 // Non-existing members are ignored 6201 // 6202 // Error is returned if the value at key is not a sorted set 6203 func (z *SORTED_SET) zremInternal(key string, member ...interface{}) error { 6204 // validate 6205 if z.core == nil { 6206 return errors.New("Redis ZRem Failed: " + "Base is Nil") 6207 } 6208 6209 if !z.core.cnAreReady { 6210 return errors.New("Redis ZRem Failed: " + "Endpoint Connections Not Ready") 6211 } 6212 6213 if len(key) <= 0 { 6214 return errors.New("Redis ZRem Failed: " + "Key is Required") 6215 } 6216 6217 if len(member) <= 0 { 6218 return errors.New("Redis ZRem Failed: " + "Member is Required") 6219 } 6220 6221 cmd := z.core.cnWriter.ZRem(z.core.cnWriter.Context(), key, member...) 6222 return z.core.handleIntCmd2(cmd, "Redis ZRem Failed: ") 6223 } 6224 6225 // ZRemRangeByLex removes all elements in the sorted set stored at key, between the lexicographical range specified by min and max 6226 func (z *SORTED_SET) ZRemRangeByLex(key string, min string, max string) (err error) { 6227 // get new xray segment for tracing 6228 seg := xray.NewSegmentNullable("Redis-ZRemRangeByLex", z.core._parentSegment) 6229 6230 if seg != nil { 6231 defer seg.Close() 6232 defer func() { 6233 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByLex-Key", key) 6234 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByLex-Min", min) 6235 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByLex-Max", max) 6236 6237 if err != nil { 6238 _ = seg.Seg.AddError(err) 6239 } 6240 }() 6241 6242 err = z.zremRangeByLexInternal(key, min, max) 6243 return err 6244 } else { 6245 return z.zremRangeByLexInternal(key, min, max) 6246 } 6247 } 6248 6249 // zremRangeByLexInternal removes all elements in the sorted set stored at key, between the lexicographical range specified by min and max 6250 func (z *SORTED_SET) zremRangeByLexInternal(key string, min string, max string) error { 6251 // validate 6252 if z.core == nil { 6253 return errors.New("Redis ZRemRangeByLex Failed: " + "Base is Nil") 6254 } 6255 6256 if !z.core.cnAreReady { 6257 return errors.New("Redis ZRemRangeByLex Failed: " + "Endpoint Connections Not Ready") 6258 } 6259 6260 if len(key) <= 0 { 6261 return errors.New("Redis ZRemRangeByLex Failed: " + "Key is Required") 6262 } 6263 6264 if len(min) <= 0 { 6265 return errors.New("Redis ZRemRangeByLex Failed: " + "Min is Required") 6266 } 6267 6268 if len(max) <= 0 { 6269 return errors.New("Redis ZRemRangeByLex Failed: " + "Max is Required") 6270 } 6271 6272 cmd := z.core.cnWriter.ZRemRangeByLex(z.core.cnWriter.Context(), key, min, max) 6273 return z.core.handleIntCmd2(cmd, "Redis ZRemRangeByLex Failed: ") 6274 } 6275 6276 // ZRemRangeByScore removes all elements in the sorted set stored at key, with a score between min and max (inclusive) 6277 func (z *SORTED_SET) ZRemRangeByScore(key string, min string, max string) (err error) { 6278 // get new xray segment for tracing 6279 seg := xray.NewSegmentNullable("Redis-ZRemRangeByScore", z.core._parentSegment) 6280 6281 if seg != nil { 6282 defer seg.Close() 6283 defer func() { 6284 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByScore-Key", key) 6285 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByScore-Min", min) 6286 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByScore-Max", max) 6287 6288 if err != nil { 6289 _ = seg.Seg.AddError(err) 6290 } 6291 }() 6292 6293 err = z.zremRangeByScoreInternal(key, min, max) 6294 return err 6295 } else { 6296 return z.zremRangeByScoreInternal(key, min, max) 6297 } 6298 } 6299 6300 // zremRangeByScoreInternal removes all elements in the sorted set stored at key, with a score between min and max (inclusive) 6301 func (z *SORTED_SET) zremRangeByScoreInternal(key string, min string, max string) error { 6302 // validate 6303 if z.core == nil { 6304 return errors.New("Redis ZRemRangeByScore Failed: " + "Base is Nil") 6305 } 6306 6307 if !z.core.cnAreReady { 6308 return errors.New("Redis ZRemRangeByScore Failed: " + "Endpoint Connections Not Ready") 6309 } 6310 6311 if len(key) <= 0 { 6312 return errors.New("Redis ZRemRangeByScore Failed: " + "Key is Required") 6313 } 6314 6315 if len(min) <= 0 { 6316 return errors.New("Redis ZRemRangeByScore Failed: " + "Min is Required") 6317 } 6318 6319 if len(max) <= 0 { 6320 return errors.New("Redis ZRemRangeByScore Failed: " + "Max is Required") 6321 } 6322 6323 cmd := z.core.cnWriter.ZRemRangeByScore(z.core.cnWriter.Context(), key, min, max) 6324 return z.core.handleIntCmd2(cmd, "Redis ZRemRangeByScore Failed: ") 6325 } 6326 6327 // ZRemRangeByRank removes all elements in the sorted set stored at key, with rank between start and stop 6328 // 6329 // Both start and stop are zero-based, 6330 // Both start and stop can be negative, where -1 is the element with highest score, -2 is the element with next to highest score, and so on 6331 func (z *SORTED_SET) ZRemRangeByRank(key string, start int64, stop int64) (err error) { 6332 // get new xray segment for tracing 6333 seg := xray.NewSegmentNullable("Redis-ZRemRangeByRank", z.core._parentSegment) 6334 6335 if seg != nil { 6336 defer seg.Close() 6337 defer func() { 6338 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByRank-Key", key) 6339 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByRank-Start", start) 6340 _ = seg.Seg.AddMetadata("Redis-ZRemRangeByRank-Stop", stop) 6341 6342 if err != nil { 6343 _ = seg.Seg.AddError(err) 6344 } 6345 }() 6346 6347 err = z.zremRangeByRankInternal(key, start, stop) 6348 return err 6349 } else { 6350 return z.zremRangeByRankInternal(key, start, stop) 6351 } 6352 } 6353 6354 // zremRangeByRankInternal removes all elements in the sorted set stored at key, with rank between start and stop 6355 // 6356 // Both start and stop are zero-based, 6357 // Both start and stop can be negative, where -1 is the element with highest score, -2 is the element with next to highest score, and so on 6358 func (z *SORTED_SET) zremRangeByRankInternal(key string, start int64, stop int64) error { 6359 // validate 6360 if z.core == nil { 6361 return errors.New("Redis ZRemRangeByRank Failed: " + "Base is Nil") 6362 } 6363 6364 if !z.core.cnAreReady { 6365 return errors.New("Redis ZRemRangeByRank Failed: " + "Endpoint Connections Not Ready") 6366 } 6367 6368 if len(key) <= 0 { 6369 return errors.New("Redis ZRemRangeByRank Failed: " + "Key is Required") 6370 } 6371 6372 cmd := z.core.cnWriter.ZRemRangeByRank(z.core.cnWriter.Context(), key, start, stop) 6373 return z.core.handleIntCmd2(cmd, "Redis ZRemRangeByRank Failed: ") 6374 } 6375 6376 // ZRevRange returns the specified range of elements in the sorted set stored at key, 6377 // With elements ordered from highest to the lowest score, 6378 // Descending lexicographical order is used for elements with equal score 6379 func (z *SORTED_SET) ZRevRange(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 6380 // get new xray segment for tracing 6381 seg := xray.NewSegmentNullable("Redis-ZRevRange", z.core._parentSegment) 6382 6383 if seg != nil { 6384 defer seg.Close() 6385 defer func() { 6386 _ = seg.Seg.AddMetadata("Redis-ZRevRange-Key", key) 6387 _ = seg.Seg.AddMetadata("Redis-ZRevRange-Start", start) 6388 _ = seg.Seg.AddMetadata("Redis-ZRevRange-Stop", stop) 6389 _ = seg.Seg.AddMetadata("Redis-ZRevRange-Not-Found", notFound) 6390 _ = seg.Seg.AddMetadata("Redis-ZRevRange-Results", outputSlice) 6391 6392 if err != nil { 6393 _ = seg.Seg.AddError(err) 6394 } 6395 }() 6396 6397 outputSlice, notFound, err = z.zrevRangeInternal(key, start, stop) 6398 return outputSlice, notFound, err 6399 } else { 6400 return z.zrevRangeInternal(key, start, stop) 6401 } 6402 } 6403 6404 // zrevRangeInternal returns the specified range of elements in the sorted set stored at key, 6405 // With elements ordered from highest to the lowest score, 6406 // Descending lexicographical order is used for elements with equal score 6407 func (z *SORTED_SET) zrevRangeInternal(key string, start int64, stop int64) (outputSlice []string, notFound bool, err error) { 6408 // validate 6409 if z.core == nil { 6410 return nil, false, errors.New("Redis ZRevRange Failed: " + "Base is Nil") 6411 } 6412 6413 if !z.core.cnAreReady { 6414 return nil, false, errors.New("Redis ZRevRange Failed: " + "Endpoint Connections Not Ready") 6415 } 6416 6417 if len(key) <= 0 { 6418 return nil, false, errors.New("Redis ZRevRange Failed: " + "Key is Required") 6419 } 6420 6421 cmd := z.core.cnReader.ZRevRange(z.core.cnReader.Context(), key, start, stop) 6422 return z.core.handleStringSliceCmd(cmd, "Redis ZRevRange Failed: ") 6423 } 6424 6425 // ZRevRangeWithScores returns the specified range of elements (with scores) in the sorted set stored at key, 6426 // With elements ordered from highest to the lowest score, 6427 // Descending lexicographical order is used for elements with equal score 6428 func (z *SORTED_SET) ZRevRangeWithScores(key string, start int64, stop int64) (outputSlice []redis.Z, notFound bool, err error) { 6429 // get new xray segment for tracing 6430 seg := xray.NewSegmentNullable("Redis-ZRevRangeWithScores", z.core._parentSegment) 6431 6432 if seg != nil { 6433 defer seg.Close() 6434 defer func() { 6435 _ = seg.Seg.AddMetadata("Redis-ZRevRangeWithScores-Key", key) 6436 _ = seg.Seg.AddMetadata("Redis-ZRevRangeWithScores-Start", start) 6437 _ = seg.Seg.AddMetadata("Redis-ZRevRangeWithScores-Stop", stop) 6438 _ = seg.Seg.AddMetadata("Redis-ZRevRangeWithScores-Not-Found", notFound) 6439 _ = seg.Seg.AddMetadata("Redis-ZRevRangeWithScores-Results", outputSlice) 6440 6441 if err != nil { 6442 _ = seg.Seg.AddError(err) 6443 } 6444 }() 6445 6446 outputSlice, notFound, err = z.zrevRangeWithScoresInternal(key, start, stop) 6447 return outputSlice, notFound, err 6448 } else { 6449 return z.zrevRangeWithScoresInternal(key, start, stop) 6450 } 6451 } 6452 6453 // zrevRangeWithScoresInternal returns the specified range of elements (with scores) in the sorted set stored at key, 6454 // With elements ordered from highest to the lowest score, 6455 // Descending lexicographical order is used for elements with equal score 6456 func (z *SORTED_SET) zrevRangeWithScoresInternal(key string, start int64, stop int64) (outputSlice []redis.Z, notFound bool, err error) { 6457 // validate 6458 if z.core == nil { 6459 return nil, false, errors.New("Redis ZRevRangeWithScores Failed: " + "Base is Nil") 6460 } 6461 6462 if !z.core.cnAreReady { 6463 return nil, false, errors.New("Redis ZRevRangeWithScores Failed: " + "Endpoint Connections Not Ready") 6464 } 6465 6466 if len(key) <= 0 { 6467 return nil, false, errors.New("Redis ZRevRangeWithScores Failed: " + "Key is Required") 6468 } 6469 6470 cmd := z.core.cnReader.ZRevRangeWithScores(z.core.cnReader.Context(), key, start, stop) 6471 return z.core.handleZSliceCmd(cmd, "Redis ZRevRangeWithScores Failed: ") 6472 } 6473 6474 // ZRevRangeByScoreWithScores returns all the elements (with scores) in the sorted set at key, with a score between max and min (inclusive), 6475 // With elements ordered from highest to lowest scores, 6476 // Descending lexicographical order is used for elements with equal score 6477 func (z *SORTED_SET) ZRevRangeByScoreWithScores(key string, opt *redis.ZRangeBy) (outputSlice []redis.Z, notFound bool, err error) { 6478 // get new xray segment for tracing 6479 seg := xray.NewSegmentNullable("Redis-ZRevRangeByScoreWithScores", z.core._parentSegment) 6480 6481 if seg != nil { 6482 defer seg.Close() 6483 defer func() { 6484 _ = seg.Seg.AddMetadata("Redis-ZRevRangeByScoreWithScores-Key", key) 6485 _ = seg.Seg.AddMetadata("Redis-ZRevRangeByScoreWithScores-Input-Args", opt) 6486 _ = seg.Seg.AddMetadata("Redis-ZRevRangeByScoreWithScores-Not-Found", notFound) 6487 _ = seg.Seg.AddMetadata("Redis-ZRevRangeByScoreWithScores-Results", outputSlice) 6488 6489 if err != nil { 6490 _ = seg.Seg.AddError(err) 6491 } 6492 }() 6493 6494 outputSlice, notFound, err = z.zrevRangeByScoreWithScoresInternal(key, opt) 6495 return outputSlice, notFound, err 6496 } else { 6497 return z.zrevRangeByScoreWithScoresInternal(key, opt) 6498 } 6499 } 6500 6501 // zrevRangeByScoreWithScoresInternal returns all the elements (with scores) in the sorted set at key, with a score between max and min (inclusive), 6502 // With elements ordered from highest to lowest scores, 6503 // Descending lexicographical order is used for elements with equal score 6504 func (z *SORTED_SET) zrevRangeByScoreWithScoresInternal(key string, opt *redis.ZRangeBy) (outputSlice []redis.Z, notFound bool, err error) { 6505 // validate 6506 if z.core == nil { 6507 return nil, false, errors.New("Redis ZRevRangeByScoreWithScores Failed: " + "Base is Nil") 6508 } 6509 6510 if !z.core.cnAreReady { 6511 return nil, false, errors.New("Redis ZRevRangeByScoreWithScores Failed: " + "Endpoint Connections Not Ready") 6512 } 6513 6514 if len(key) <= 0 { 6515 return nil, false, errors.New("Redis ZRevRangeByScoreWithScores Failed: " + "Key is Required") 6516 } 6517 6518 if opt == nil { 6519 return nil, false, errors.New("Redis ZRevRangeByScoreWithScores Failed: " + "Opt is Required") 6520 } 6521 6522 cmd := z.core.cnReader.ZRevRangeByScoreWithScores(z.core.cnReader.Context(), key, opt) 6523 return z.core.handleZSliceCmd(cmd, "Redis ZRevRangeByScoreWithScores Failed: ") 6524 } 6525 6526 // ZRevRank returns the rank of member in the sorted set stored at key, with the scores ordered from high to low, 6527 // Rank (index) is ordered from high to low, and is zero-based, where 0 is the highest rank (index) 6528 // ZRevRank is opposite of ZRank 6529 func (z *SORTED_SET) ZRevRank(key string, member string) (val int64, notFound bool, err error) { 6530 // get new xray segment for tracing 6531 seg := xray.NewSegmentNullable("Redis-ZRevRank", z.core._parentSegment) 6532 6533 if seg != nil { 6534 defer seg.Close() 6535 defer func() { 6536 _ = seg.Seg.AddMetadata("Redis-ZRevRank-Key", key) 6537 _ = seg.Seg.AddMetadata("Redis-ZRevRank-Member", member) 6538 _ = seg.Seg.AddMetadata("Redis-ZRevRank-Not-Found", notFound) 6539 _ = seg.Seg.AddMetadata("Redis-ZRevRank-Result-Rank", val) 6540 6541 if err != nil { 6542 _ = seg.Seg.AddError(err) 6543 } 6544 }() 6545 6546 val, notFound, err = z.zrevRankInternal(key, member) 6547 return val, notFound, err 6548 } else { 6549 return z.zrevRankInternal(key, member) 6550 } 6551 } 6552 6553 // zrevRankInternal returns the rank of member in the sorted set stored at key, with the scores ordered from high to low, 6554 // Rank (index) is ordered from high to low, and is zero-based, where 0 is the highest rank (index) 6555 // ZRevRank is opposite of ZRank 6556 func (z *SORTED_SET) zrevRankInternal(key string, member string) (val int64, notFound bool, err error) { 6557 // validate 6558 if z.core == nil { 6559 return 0, false, errors.New("Redis ZRevRank Failed: " + "Base is Nil") 6560 } 6561 6562 if !z.core.cnAreReady { 6563 return 0, false, errors.New("Redis ZRevRank Failed: " + "Endpoint Connections Not Ready") 6564 } 6565 6566 if len(key) <= 0 { 6567 return 0, false, errors.New("Redis ZRevRank Failed: " + "Key is Required") 6568 } 6569 6570 if len(member) <= 0 { 6571 return 0, false, errors.New("Redis ZRevRank Failed: " + "Member is Required") 6572 } 6573 6574 cmd := z.core.cnReader.ZRevRank(z.core.cnReader.Context(), key, member) 6575 return z.core.handleIntCmd(cmd, "Redis ZRevRank Failed: ") 6576 } 6577 6578 // ZScan is used to incrementally iterate over a sorted set of fields stored at key, 6579 // ZScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 6580 // 6581 // start iteration = cursor set to 0 6582 // stop iteration = when redis returns cursor value of 0 6583 // 6584 // match = filters elements based on match filter, for elements retrieved from redis before return to client 6585 // 6586 // glob-style patterns: 6587 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 6588 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 6589 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 6590 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 6591 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 6592 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 6593 // 7) Use \ to escape special characters if needing to match verbatim 6594 // 6595 // count = hint to redis count of elements to retrieve in the call 6596 func (z *SORTED_SET) ZScan(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 6597 // get new xray segment for tracing 6598 seg := xray.NewSegmentNullable("Redis-ZScan", z.core._parentSegment) 6599 6600 if seg != nil { 6601 defer seg.Close() 6602 defer func() { 6603 _ = seg.Seg.AddMetadata("Redis-ZScan-Key", key) 6604 _ = seg.Seg.AddMetadata("Redis-ZScan-Cursor", cursor) 6605 _ = seg.Seg.AddMetadata("Redis-ZScan-Match", match) 6606 _ = seg.Seg.AddMetadata("Redis-ZScan-Count", count) 6607 _ = seg.Seg.AddMetadata("Redis-ZScan-Result-Keys", outputKeys) 6608 _ = seg.Seg.AddMetadata("Redis-ZScan-Result-Cursor", outputCursor) 6609 6610 if err != nil { 6611 _ = seg.Seg.AddError(err) 6612 } 6613 }() 6614 6615 outputKeys, outputCursor, err = z.zscanInternal(key, cursor, match, count) 6616 return outputKeys, outputCursor, err 6617 } else { 6618 return z.zscanInternal(key, cursor, match, count) 6619 } 6620 } 6621 6622 // zscanInternal is used to incrementally iterate over a sorted set of fields stored at key, 6623 // ZScan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 6624 // 6625 // start iteration = cursor set to 0 6626 // stop iteration = when redis returns cursor value of 0 6627 // 6628 // match = filters elements based on match filter, for elements retrieved from redis before return to client 6629 // 6630 // glob-style patterns: 6631 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 6632 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 6633 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 6634 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 6635 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 6636 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 6637 // 7) Use \ to escape special characters if needing to match verbatim 6638 // 6639 // count = hint to redis count of elements to retrieve in the call 6640 func (z *SORTED_SET) zscanInternal(key string, cursor uint64, match string, count int64) (outputKeys []string, outputCursor uint64, err error) { 6641 // validate 6642 if z.core == nil { 6643 return nil, 0, errors.New("Redis ZScan Failed: " + "Base is Nil") 6644 } 6645 6646 if !z.core.cnAreReady { 6647 return nil, 0, errors.New("Redis ZScan Failed: " + "Endpoint Connections Not Ready") 6648 } 6649 6650 if len(key) <= 0 { 6651 return nil, 0, errors.New("Redis ZScan Failed: " + "Key is Required") 6652 } 6653 6654 if len(match) <= 0 { 6655 return nil, 0, errors.New("Redis ZScan Failed: " + "Match is Required") 6656 } 6657 6658 if count < 0 { 6659 return nil, 0, errors.New("Redis ZScan Failed: " + "Count Must Be Zero or Greater") 6660 } 6661 6662 cmd := z.core.cnReader.ZScan(z.core.cnReader.Context(), key, cursor, match, count) 6663 return z.core.handleScanCmd(cmd, "Redis ZScan Failed: ") 6664 } 6665 6666 // ZScore returns the score of member in the sorted set at key, 6667 // if member is not existent in the sorted set, or key does not exist, nil is returned 6668 func (z *SORTED_SET) ZScore(key string, member string) (val float64, notFound bool, err error) { 6669 // get new xray segment for tracing 6670 seg := xray.NewSegmentNullable("Redis-ZScore", z.core._parentSegment) 6671 6672 if seg != nil { 6673 defer seg.Close() 6674 defer func() { 6675 _ = seg.Seg.AddMetadata("Redis-ZScore-Key", key) 6676 _ = seg.Seg.AddMetadata("Redis-ZScore-Member", member) 6677 _ = seg.Seg.AddMetadata("Redis-ZScore-Not-Found", notFound) 6678 _ = seg.Seg.AddMetadata("Redis-ZScore-Result", val) 6679 6680 if err != nil { 6681 _ = seg.Seg.AddError(err) 6682 } 6683 }() 6684 6685 val, notFound, err = z.zscoreInternal(key, member) 6686 return val, notFound, err 6687 } else { 6688 return z.zscoreInternal(key, member) 6689 } 6690 } 6691 6692 // zscoreInternal returns the score of member in the sorted set at key, 6693 // if member is not existent in the sorted set, or key does not exist, nil is returned 6694 func (z *SORTED_SET) zscoreInternal(key string, member string) (val float64, notFound bool, err error) { 6695 // validate 6696 if z.core == nil { 6697 return 0, false, errors.New("Redis ZScore Failed: " + "Base is Nil") 6698 } 6699 6700 if !z.core.cnAreReady { 6701 return 0, false, errors.New("Redis ZScore Failed: " + "Endpoint Connections Not Ready") 6702 } 6703 6704 if len(key) <= 0 { 6705 return 0, false, errors.New("Redis ZScore Failed: " + "Key is Required") 6706 } 6707 6708 if len(member) <= 0 { 6709 return 0, false, errors.New("Redis ZScore Failed: " + "Member is Required") 6710 } 6711 6712 cmd := z.core.cnReader.ZScore(z.core.cnReader.Context(), key, member) 6713 return z.core.handleFloatCmd(cmd, "Redis ZScore Failed: ") 6714 } 6715 6716 // ZUnionStore computes the union of numKeys sorted set given by the specified keys, 6717 // and stores the result in 'destination' 6718 // 6719 // numKeys (input keys) are required 6720 func (z *SORTED_SET) ZUnionStore(keyDest string, store *redis.ZStore) (err error) { 6721 // get new xray segment for tracing 6722 seg := xray.NewSegmentNullable("Redis-ZUnionStore", z.core._parentSegment) 6723 6724 if seg != nil { 6725 defer seg.Close() 6726 defer func() { 6727 _ = seg.Seg.AddMetadata("Redis-ZUnionStore-KeyDest", keyDest) 6728 _ = seg.Seg.AddMetadata("Redis-ZUnionStore-Input-Keys", store) 6729 6730 if err != nil { 6731 _ = seg.Seg.AddError(err) 6732 } 6733 }() 6734 6735 err = z.zunionStoreInternal(keyDest, store) 6736 return err 6737 } else { 6738 return z.zunionStoreInternal(keyDest, store) 6739 } 6740 } 6741 6742 // zunionStoreInternal computes the union of numKeys sorted set given by the specified keys, 6743 // and stores the result in 'destination' 6744 // 6745 // numKeys (input keys) are required 6746 func (z *SORTED_SET) zunionStoreInternal(keyDest string, store *redis.ZStore) error { 6747 // validate 6748 if z.core == nil { 6749 return errors.New("Redis ZUnionStore Failed: " + "Base is Nil") 6750 } 6751 6752 if !z.core.cnAreReady { 6753 return errors.New("Redis ZUnionStore Failed: " + "Endpoint Connections Not Ready") 6754 } 6755 6756 if len(keyDest) <= 0 { 6757 return errors.New("Redis ZUnionStore Failed: " + "Key Destination is Required") 6758 } 6759 6760 if store == nil { 6761 return errors.New("Redis ZUnionStore Failed: " + "Store is Required") 6762 } 6763 6764 cmd := z.core.cnWriter.ZUnionStore(z.core.cnWriter.Context(), keyDest, store) 6765 return z.core.handleIntCmd2(cmd, "Redis ZUnionStore Failed: ") 6766 } 6767 6768 // ---------------------------------------------------------------------------------------------------------------- 6769 // GEO functions 6770 // ---------------------------------------------------------------------------------------------------------------- 6771 6772 // GeoAdd will add geospatial info (lat, lon, name) to the specified key, 6773 // data is stored into the key as a sorted set, 6774 // supports later query by radius with GeoRadius or GeoRadiusByMember commands 6775 // 6776 // valid longitude = -180 to 180 degrees 6777 // valid latitude = -85.05112878 to 85.05112878 degrees 6778 // 6779 // Use ZREM to remove Geo Key (since there is no GEODEL Command) 6780 func (g *GEO) GeoAdd(key string, geoLocation *redis.GeoLocation) (err error) { 6781 // get new xray segment for tracing 6782 seg := xray.NewSegmentNullable("Redis-GeoAdd", g.core._parentSegment) 6783 6784 if seg != nil { 6785 defer seg.Close() 6786 defer func() { 6787 _ = seg.Seg.AddMetadata("Redis-GeoAdd-Key", key) 6788 _ = seg.Seg.AddMetadata("Redis-GeoAdd-Location", geoLocation) 6789 6790 if err != nil { 6791 _ = seg.Seg.AddError(err) 6792 } 6793 }() 6794 6795 err = g.geoAddInternal(key, geoLocation) 6796 return err 6797 } else { 6798 return g.geoAddInternal(key, geoLocation) 6799 } 6800 } 6801 6802 // geoAddInternal will add geospatial info (lat, lon, name) to the specified key, 6803 // data is stored into the key as a sorted set, 6804 // supports later query by radius with GeoRadius or GeoRadiusByMember commands 6805 // 6806 // valid longitude = -180 to 180 degrees 6807 // valid latitude = -85.05112878 to 85.05112878 degrees 6808 // 6809 // Use ZREM to remove Geo Key (since there is no GEODEL Command) 6810 func (g *GEO) geoAddInternal(key string, geoLocation *redis.GeoLocation) error { 6811 // validate 6812 if g.core == nil { 6813 return errors.New("Redis GeoAdd Failed: " + "Base is Nil") 6814 } 6815 6816 if !g.core.cnAreReady { 6817 return errors.New("Redis GeoAdd Failed: " + "Endpoint Connections Not Ready") 6818 } 6819 6820 if len(key) <= 0 { 6821 return errors.New("Redis GeoAdd Failed: " + "Key is Required") 6822 } 6823 6824 if geoLocation == nil { 6825 return errors.New("Redis GeoAdd Failed: " + "Geo Location is Required") 6826 } 6827 6828 cmd := g.core.cnWriter.GeoAdd(g.core.cnWriter.Context(), key, geoLocation) 6829 _, _, err := g.core.handleIntCmd(cmd, "Redis GeoAdd Failed: ") 6830 return err 6831 } 6832 6833 // GeoDist returns the distance between two members in the geospatial index represented by the sorted set 6834 // 6835 // unit = m (meters), km (kilometers), mi (miles), ft (feet) 6836 func (g *GEO) GeoDist(key string, member1 string, member2 string, unit redisradiusunit.RedisRadiusUnit) (valDist float64, notFound bool, err error) { 6837 // get new xray segment for tracing 6838 seg := xray.NewSegmentNullable("Redis-GeoDist", g.core._parentSegment) 6839 6840 if seg != nil { 6841 defer seg.Close() 6842 defer func() { 6843 _ = seg.Seg.AddMetadata("Redis-GeoDist-Key", key) 6844 _ = seg.Seg.AddMetadata("Redis-GeoDist-Member1", member1) 6845 _ = seg.Seg.AddMetadata("Redis-GeoDist-Member2", member2) 6846 _ = seg.Seg.AddMetadata("Redis-GeoDist-Radius-Unit", unit) 6847 _ = seg.Seg.AddMetadata("Redis-GeoDist-Not-Found", notFound) 6848 _ = seg.Seg.AddMetadata("Redis-GeoDist-Result-Distance", valDist) 6849 6850 if err != nil { 6851 _ = seg.Seg.AddError(err) 6852 } 6853 }() 6854 6855 valDist, notFound, err = g.geoDistInternal(key, member1, member2, unit) 6856 return valDist, notFound, err 6857 } else { 6858 return g.geoDistInternal(key, member1, member2, unit) 6859 } 6860 } 6861 6862 // geoDistInternal returns the distance between two members in the geospatial index represented by the sorted set 6863 // 6864 // unit = m (meters), km (kilometers), mi (miles), ft (feet) 6865 func (g *GEO) geoDistInternal(key string, member1 string, member2 string, unit redisradiusunit.RedisRadiusUnit) (valDist float64, notFound bool, err error) { 6866 // validate 6867 if g.core == nil { 6868 return 0.00, false, errors.New("Redis GeoDist Failed: " + "Base is Nil") 6869 } 6870 6871 if !g.core.cnAreReady { 6872 return 0.00, false, errors.New("Redis GeoDist Failed: " + "Endpoint Connections Not Ready") 6873 } 6874 6875 if len(key) <= 0 { 6876 return 0.00, false, errors.New("Redis GeoDist Failed: " + "Key is Required") 6877 } 6878 6879 if len(member1) <= 0 { 6880 return 0.00, false, errors.New("Redis GeoDist Failed: " + "Member 1 is Required") 6881 } 6882 6883 if len(member2) <= 0 { 6884 return 0.00, false, errors.New("Redis GeoDist Failed: " + "Member 2 is Required") 6885 } 6886 6887 if !unit.Valid() || unit == redisradiusunit.UNKNOWN { 6888 return 0.00, false, errors.New("Radius GeoDist Failed: " + "Radius Unit is Required") 6889 } 6890 6891 cmd := g.core.cnReader.GeoDist(g.core.cnReader.Context(), key, member1, member2, unit.Key()) 6892 return g.core.handleFloatCmd(cmd, "Redis GeoDist Failed: ") 6893 } 6894 6895 // GeoHash returns valid GeoHash string representing the position of one or more elements in a sorted set (added by GeoAdd) 6896 // This function returns a STANDARD GEOHASH as described on geohash.org site 6897 func (g *GEO) GeoHash(key string, member ...string) (geoHashSlice []string, notFound bool, err error) { 6898 // get new xray segment for tracing 6899 seg := xray.NewSegmentNullable("Redis-GeoHash", g.core._parentSegment) 6900 6901 if seg != nil { 6902 defer seg.Close() 6903 defer func() { 6904 _ = seg.Seg.AddMetadata("Redis-GeoHash-Key", key) 6905 _ = seg.Seg.AddMetadata("Redis-GeoHash-Members", member) 6906 _ = seg.Seg.AddMetadata("Redis-GeoHash-Not-Found", notFound) 6907 _ = seg.Seg.AddMetadata("Redis-GeoHash-Result-Positions", geoHashSlice) 6908 6909 if err != nil { 6910 _ = seg.Seg.AddError(err) 6911 } 6912 }() 6913 6914 geoHashSlice, notFound, err = g.geoHashInternal(key, member...) 6915 return geoHashSlice, notFound, err 6916 } else { 6917 return g.geoHashInternal(key, member...) 6918 } 6919 } 6920 6921 // geoHashInternal returns valid GeoHash string representing the position of one or more elements in a sorted set (added by GeoAdd) 6922 // This function returns a STANDARD GEOHASH as described on geohash.org site 6923 func (g *GEO) geoHashInternal(key string, member ...string) (geoHashSlice []string, notFound bool, err error) { 6924 // validate 6925 if g.core == nil { 6926 return nil, false, errors.New("Redis GeoHash Failed: " + "Base is Nil") 6927 } 6928 6929 if !g.core.cnAreReady { 6930 return nil, false, errors.New("Redis GeoHash Failed: " + "Endpoint Connections Not Ready") 6931 } 6932 6933 if len(key) <= 0 { 6934 return nil, false, errors.New("Redis GeoHash Failed: " + "Key is Required") 6935 } 6936 6937 if len(member) <= 0 { 6938 return nil, false, errors.New("Redis GeoHash Failed: " + "At Least 1 Member is Required") 6939 } 6940 6941 cmd := g.core.cnReader.GeoHash(g.core.cnReader.Context(), key, member...) 6942 return g.core.handleStringSliceCmd(cmd, "Redis GeoHash Failed: ") 6943 } 6944 6945 // GeoPos returns the position (longitude and latitude) of all the specified members of the geospatial index represented by the sorted set at key 6946 func (g *GEO) GeoPos(key string, member ...string) (cmd *redis.GeoPosCmd, err error) { 6947 // get new xray segment for tracing 6948 seg := xray.NewSegmentNullable("Redis-GeoPos", g.core._parentSegment) 6949 6950 if seg != nil { 6951 defer seg.Close() 6952 defer func() { 6953 _ = seg.Seg.AddMetadata("Redis-GeoPos-Key", key) 6954 _ = seg.Seg.AddMetadata("Redis-GeoPos-Members", member) 6955 _ = seg.Seg.AddMetadata("Redis-GeoPos-Result-Position", cmd) 6956 6957 if err != nil { 6958 _ = seg.Seg.AddError(err) 6959 } 6960 }() 6961 6962 cmd, err = g.geoPosInternal(key, member...) 6963 return cmd, err 6964 } else { 6965 return g.geoPosInternal(key, member...) 6966 } 6967 } 6968 6969 // geoPosInternal returns the position (longitude and latitude) of all the specified members of the geospatial index represented by the sorted set at key 6970 func (g *GEO) geoPosInternal(key string, member ...string) (*redis.GeoPosCmd, error) { 6971 // validate 6972 if g.core == nil { 6973 return nil, errors.New("Redis GeoPos Failed: " + "Base is Nil") 6974 } 6975 6976 if !g.core.cnAreReady { 6977 return nil, errors.New("Redis GeoPos Failed: " + "Endpoint Connections Not Ready") 6978 } 6979 6980 if len(key) <= 0 { 6981 return nil, errors.New("Redis GeoPos Failed: " + "Key is Required") 6982 } 6983 6984 if len(member) <= 0 { 6985 return nil, errors.New("Redis GeoPos Failed: " + "At Least 1 Member is Required") 6986 } 6987 6988 return g.core.cnReader.GeoPos(g.core.cnReader.Context(), key, member...), nil 6989 } 6990 6991 // GeoRadius returns the members of a sorted set populated with geospatial information using GeoAdd, 6992 // which are within the borders of the area specified with the center location and the maximum distance from the center (the radius) 6993 // 6994 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 6995 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 6996 // withCoord = return the longitude and latitude coordinates of the matching items 6997 // 6998 // asc = sort returned items from the nearest to the farthest, relative to the center 6999 // desc = sort returned items from the farthest to the nearest, relative to the center 7000 // 7001 // count = optional limit of return items; default is return all items found, use count to limit the list 7002 // 7003 // store = store the items in a sorted set populated with their geospatial information 7004 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7005 func (g *GEO) GeoRadius(key string, longitude float64, latitude float64, query *redis.GeoRadiusQuery) (cmd *redis.GeoLocationCmd, err error) { 7006 // get new xray segment for tracing 7007 seg := xray.NewSegmentNullable("Redis-GeoRadius", g.core._parentSegment) 7008 7009 if seg != nil { 7010 defer seg.Close() 7011 defer func() { 7012 _ = seg.Seg.AddMetadata("Redis-GeoRadius-Key", key) 7013 _ = seg.Seg.AddMetadata("Redis-GeoRadius-Longitude", longitude) 7014 _ = seg.Seg.AddMetadata("Redis-GeoRadius-Latitude", latitude) 7015 _ = seg.Seg.AddMetadata("Redis-GeoRadius-Query", query) 7016 _ = seg.Seg.AddMetadata("Redis-GeoRadius-Result-Location", cmd) 7017 7018 if err != nil { 7019 _ = seg.Seg.AddError(err) 7020 } 7021 }() 7022 7023 cmd, err = g.geoRadiusInternal(key, longitude, latitude, query) 7024 return cmd, err 7025 } else { 7026 return g.geoRadiusInternal(key, longitude, latitude, query) 7027 } 7028 } 7029 7030 // geoRadiusInternal returns the members of a sorted set populated with geospatial information using GeoAdd, 7031 // which are within the borders of the area specified with the center location and the maximum distance from the center (the radius) 7032 // 7033 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7034 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7035 // withCoord = return the longitude and latitude coordinates of the matching items 7036 // 7037 // asc = sort returned items from the nearest to the farthest, relative to the center 7038 // desc = sort returned items from the farthest to the nearest, relative to the center 7039 // 7040 // count = optional limit of return items; default is return all items found, use count to limit the list 7041 // 7042 // store = store the items in a sorted set populated with their geospatial information 7043 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7044 func (g *GEO) geoRadiusInternal(key string, longitude float64, latitude float64, query *redis.GeoRadiusQuery) (*redis.GeoLocationCmd, error) { 7045 // validate 7046 if g.core == nil { 7047 return nil, errors.New("Redis GeoRadius Failed: " + "Base is Nil") 7048 } 7049 7050 if !g.core.cnAreReady { 7051 return nil, errors.New("Redis GeoRadius Failed: " + "Endpoint Connections Not Ready") 7052 } 7053 7054 if len(key) <= 0 { 7055 return nil, errors.New("Redis GeoRadius Failed: " + "Key is Required") 7056 } 7057 7058 if query == nil { 7059 return nil, errors.New("Redis GeoRadius Failed: " + "Query is Required") 7060 } 7061 7062 // remove invalid query fields 7063 if util.LenTrim(query.Sort) > 0 { 7064 switch strings.ToUpper(query.Sort) { 7065 case "ASC": 7066 // valid 7067 case "DESC": 7068 // valid 7069 default: 7070 // not valid 7071 query.Sort = "" 7072 } 7073 } 7074 7075 if util.LenTrim(query.Store) > 0 { 7076 // this function is read only 7077 query.Store = "" 7078 } 7079 7080 if util.LenTrim(query.StoreDist) > 0 { 7081 // this function is read only 7082 query.StoreDist = "" 7083 } 7084 7085 if util.LenTrim(query.Unit) > 0 { 7086 switch strings.ToUpper(query.Unit) { 7087 case "M": 7088 case "KM": 7089 case "MI": 7090 case "FT": 7091 // valid 7092 default: 7093 // not valid 7094 query.Unit = "mi" 7095 } 7096 } 7097 7098 return g.core.cnReader.GeoRadius(g.core.cnReader.Context(), key, longitude, latitude, query), nil 7099 } 7100 7101 // GeoRadiusStore will store the members of a sorted set populated with geospatial information using GeoAdd, 7102 // which are within the borders of the area specified with the center location and the maximum distance from the center (the radius) 7103 // 7104 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7105 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7106 // withCoord = return the longitude and latitude coordinates of the matching items 7107 // 7108 // asc = sort returned items from the nearest to the farthest, relative to the center 7109 // desc = sort returned items from the farthest to the nearest, relative to the center 7110 // 7111 // count = optional limit of return items; default is return all items found, use count to limit the list 7112 // 7113 // store = store the items in a sorted set populated with their geospatial information 7114 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7115 func (g *GEO) GeoRadiusStore(key string, longitude float64, latitude float64, query *redis.GeoRadiusQuery) (err error) { 7116 // get new xray segment for tracing 7117 seg := xray.NewSegmentNullable("Redis-GeoRadiusStore", g.core._parentSegment) 7118 7119 if seg != nil { 7120 defer seg.Close() 7121 defer func() { 7122 _ = seg.Seg.AddMetadata("Redis-GeoRadiusStore-Key", key) 7123 _ = seg.Seg.AddMetadata("Redis-GeoRadiusStore-Longitude", longitude) 7124 _ = seg.Seg.AddMetadata("Redis-GeoRadiusStore-Latitude", latitude) 7125 _ = seg.Seg.AddMetadata("Redis-GeoRadiusStore-Query", query) 7126 7127 if err != nil { 7128 _ = seg.Seg.AddError(err) 7129 } 7130 }() 7131 7132 err = g.geoRadiusStoreInternal(key, longitude, latitude, query) 7133 return err 7134 } else { 7135 return g.geoRadiusStoreInternal(key, longitude, latitude, query) 7136 } 7137 } 7138 7139 // geoRadiusStoreInternal will store the members of a sorted set populated with geospatial information using GeoAdd, 7140 // which are within the borders of the area specified with the center location and the maximum distance from the center (the radius) 7141 // 7142 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7143 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7144 // withCoord = return the longitude and latitude coordinates of the matching items 7145 // 7146 // asc = sort returned items from the nearest to the farthest, relative to the center 7147 // desc = sort returned items from the farthest to the nearest, relative to the center 7148 // 7149 // count = optional limit of return items; default is return all items found, use count to limit the list 7150 // 7151 // store = store the items in a sorted set populated with their geospatial information 7152 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7153 func (g *GEO) geoRadiusStoreInternal(key string, longitude float64, latitude float64, query *redis.GeoRadiusQuery) error { 7154 // validate 7155 if g.core == nil { 7156 return errors.New("Redis GeoRadiusStore Failed: " + "Base is Nil") 7157 } 7158 7159 if !g.core.cnAreReady { 7160 return errors.New("Redis GeoRadiusStore Failed: " + "Endpoint Connections Not Ready") 7161 } 7162 7163 if len(key) <= 0 { 7164 return errors.New("Redis GeoRadiusStore Failed: " + "Key is Required") 7165 } 7166 7167 if query == nil { 7168 return errors.New("Redis GeoRadiusStore Failed: " + "Query is Required") 7169 } 7170 7171 // remove invalid query fields 7172 if util.LenTrim(query.Sort) > 0 { 7173 switch strings.ToUpper(query.Sort) { 7174 case "ASC": 7175 // valid 7176 case "DESC": 7177 // valid 7178 default: 7179 // not valid 7180 query.Sort = "" 7181 } 7182 } 7183 7184 if util.LenTrim(query.Unit) > 0 { 7185 switch strings.ToUpper(query.Unit) { 7186 case "M": 7187 case "KM": 7188 case "MI": 7189 case "FT": 7190 // valid 7191 default: 7192 // not valid 7193 query.Unit = "mi" 7194 } 7195 } 7196 7197 cmd := g.core.cnWriter.GeoRadiusStore(g.core.cnWriter.Context(), key, longitude, latitude, query) 7198 _, _, err := g.core.handleIntCmd(cmd, "Redis GeoRadiusStore Failed: ") 7199 return err 7200 } 7201 7202 // GeoRadiusByMember is same as GeoRadius, except instead of taking as the center of the area to query (long lat), 7203 // this takes the name of a member already existing inside the geospatial index represented by the sorted set 7204 // 7205 // # The position of the specified member is used as the center of the query 7206 // 7207 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7208 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7209 // withCoord = return the longitude and latitude coordinates of the matching items 7210 // 7211 // asc = sort returned items from the nearest to the farthest, relative to the center 7212 // desc = sort returned items from the farthest to the nearest, relative to the center 7213 // 7214 // count = optional limit of return items; default is return all items found, use count to limit the list 7215 // 7216 // store = store the items in a sorted set populated with their geospatial information 7217 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7218 func (g *GEO) GeoRadiusByMember(key string, member string, query *redis.GeoRadiusQuery) (cmd *redis.GeoLocationCmd, err error) { 7219 // get new xray segment for tracing 7220 seg := xray.NewSegmentNullable("Redis-GeoRadiusByMember", g.core._parentSegment) 7221 7222 if seg != nil { 7223 defer seg.Close() 7224 defer func() { 7225 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMember-Key", key) 7226 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMember-Member", member) 7227 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMember-Query", query) 7228 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMember-Result-Location", cmd) 7229 7230 if err != nil { 7231 _ = seg.Seg.AddError(err) 7232 } 7233 }() 7234 7235 cmd, err = g.geoRadiusByMemberInternal(key, member, query) 7236 return cmd, err 7237 } else { 7238 return g.geoRadiusByMemberInternal(key, member, query) 7239 } 7240 } 7241 7242 // geoRadiusByMemberInternal is same as GeoRadius, except instead of taking as the center of the area to query (long lat), 7243 // this takes the name of a member already existing inside the geospatial index represented by the sorted set 7244 // 7245 // # The position of the specified member is used as the center of the query 7246 // 7247 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7248 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7249 // withCoord = return the longitude and latitude coordinates of the matching items 7250 // 7251 // asc = sort returned items from the nearest to the farthest, relative to the center 7252 // desc = sort returned items from the farthest to the nearest, relative to the center 7253 // 7254 // count = optional limit of return items; default is return all items found, use count to limit the list 7255 // 7256 // store = store the items in a sorted set populated with their geospatial information 7257 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7258 func (g *GEO) geoRadiusByMemberInternal(key string, member string, query *redis.GeoRadiusQuery) (*redis.GeoLocationCmd, error) { 7259 // validate 7260 if g.core == nil { 7261 return nil, errors.New("Redis GeoRadiusByMember Failed: " + "Base is Nil") 7262 } 7263 7264 if !g.core.cnAreReady { 7265 return nil, errors.New("Redis GeoRadiusByMember Failed: " + "Endpoint Connections Not Ready") 7266 } 7267 7268 if len(key) <= 0 { 7269 return nil, errors.New("Redis GeoRadiusByMember Failed: " + "Key is Required") 7270 } 7271 7272 if len(member) <= 0 { 7273 return nil, errors.New("Redis GeoRadiusByMember Failed: " + "Member is Required") 7274 } 7275 7276 if query == nil { 7277 return nil, errors.New("Redis GeoRadiusByMember Failed: " + "Query is Required") 7278 } 7279 7280 // remove invalid query fields 7281 if util.LenTrim(query.Sort) > 0 { 7282 switch strings.ToUpper(query.Sort) { 7283 case "ASC": 7284 // valid 7285 case "DESC": 7286 // valid 7287 default: 7288 // not valid 7289 query.Sort = "" 7290 } 7291 } 7292 7293 if util.LenTrim(query.Store) > 0 { 7294 // this function is read only 7295 query.Store = "" 7296 } 7297 7298 if util.LenTrim(query.StoreDist) > 0 { 7299 // this function is read only 7300 query.StoreDist = "" 7301 } 7302 7303 if util.LenTrim(query.Unit) > 0 { 7304 switch strings.ToUpper(query.Unit) { 7305 case "M": 7306 case "KM": 7307 case "MI": 7308 case "FT": 7309 // valid 7310 default: 7311 // not valid 7312 query.Unit = "mi" 7313 } 7314 } 7315 7316 return g.core.cnReader.GeoRadiusByMember(g.core.cnReader.Context(), key, member, query), nil 7317 } 7318 7319 // GeoRadiusByMemberStore is same as GeoRadiusStore, except instead of taking as the center of the area to query (long lat), 7320 // this takes the name of a member already existing inside the geospatial index represented by the sorted set 7321 // 7322 // # The position of the specified member is used as the center of the query 7323 // 7324 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7325 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7326 // withCoord = return the longitude and latitude coordinates of the matching items 7327 // 7328 // asc = sort returned items from the nearest to the farthest, relative to the center 7329 // desc = sort returned items from the farthest to the nearest, relative to the center 7330 // 7331 // count = optional limit of return items; default is return all items found, use count to limit the list 7332 // 7333 // store = store the items in a sorted set populated with their geospatial information 7334 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7335 func (g *GEO) GeoRadiusByMemberStore(key string, member string, query *redis.GeoRadiusQuery) (err error) { 7336 // get new xray segment for tracing 7337 seg := xray.NewSegmentNullable("Redis-GeoRadiusByMemberStore", g.core._parentSegment) 7338 7339 if seg != nil { 7340 defer seg.Close() 7341 defer func() { 7342 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMemberStore-Key", key) 7343 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMemberStore-Member", member) 7344 _ = seg.Seg.AddMetadata("Redis-GeoRadiusByMemberStore-Query", query) 7345 7346 if err != nil { 7347 _ = seg.Seg.AddError(err) 7348 } 7349 }() 7350 7351 err = g.geoRadiusByMemberStoreInternal(key, member, query) 7352 return err 7353 } else { 7354 return g.geoRadiusByMemberStoreInternal(key, member, query) 7355 } 7356 } 7357 7358 // geoRadiusByMemberStoreInternal is same as GeoRadiusStore, except instead of taking as the center of the area to query (long lat), 7359 // this takes the name of a member already existing inside the geospatial index represented by the sorted set 7360 // 7361 // # The position of the specified member is used as the center of the query 7362 // 7363 // radius = units are: m (meters), km (kilometers), mi (miles), ft (feet) 7364 // withDist = return the distance of returned items from the specified center (using same unit as units specified in the radius) 7365 // withCoord = return the longitude and latitude coordinates of the matching items 7366 // 7367 // asc = sort returned items from the nearest to the farthest, relative to the center 7368 // desc = sort returned items from the farthest to the nearest, relative to the center 7369 // 7370 // count = optional limit of return items; default is return all items found, use count to limit the list 7371 // 7372 // store = store the items in a sorted set populated with their geospatial information 7373 // storeDist = store the items in a sorted set populated with their distance from the center as a floating point number, in the same unit specified in the radius 7374 func (g *GEO) geoRadiusByMemberStoreInternal(key string, member string, query *redis.GeoRadiusQuery) error { 7375 // validate 7376 if g.core == nil { 7377 return errors.New("Redis GeoRadiusByMemberStore Failed: " + "Base is Nil") 7378 } 7379 7380 if !g.core.cnAreReady { 7381 return errors.New("Redis GeoRadiusByMemberStore Failed: " + "Endpoint Connections Not Ready") 7382 } 7383 7384 if len(key) <= 0 { 7385 return errors.New("Redis GeoRadiusByMemberStore Failed: " + "Key is Required") 7386 } 7387 7388 if len(member) <= 0 { 7389 return errors.New("Redis GeoRadiusByMemberStore Failed: " + "Member is Required") 7390 } 7391 7392 if query == nil { 7393 return errors.New("Redis GeoRadiusByMemberStore Failed: " + "Query is Required") 7394 } 7395 7396 // remove invalid query fields 7397 if util.LenTrim(query.Sort) > 0 { 7398 switch strings.ToUpper(query.Sort) { 7399 case "ASC": 7400 // valid 7401 case "DESC": 7402 // valid 7403 default: 7404 // not valid 7405 query.Sort = "" 7406 } 7407 } 7408 7409 if util.LenTrim(query.Unit) > 0 { 7410 switch strings.ToUpper(query.Unit) { 7411 case "M": 7412 case "KM": 7413 case "MI": 7414 case "FT": 7415 // valid 7416 default: 7417 // not valid 7418 query.Unit = "mi" 7419 } 7420 } 7421 7422 cmd := g.core.cnWriter.GeoRadiusByMemberStore(g.core.cnWriter.Context(), key, member, query) 7423 _, _, err := g.core.handleIntCmd(cmd, "Redis GeoRadiusByMemberStore Failed: ") 7424 return err 7425 } 7426 7427 // ---------------------------------------------------------------------------------------------------------------- 7428 // STREAM functions 7429 // ---------------------------------------------------------------------------------------------------------------- 7430 7431 // 7432 // *** REDIS STREAM INTRODUCTION = https://redis.io/topics/streams-intro *** 7433 // 7434 7435 // XAck removes one or multiple messages from the 'pending entries list (PEL)' of a stream consumer group 7436 // 7437 // # A message is pending, and as such stored inside the PEL, when it was delivered to some consumer 7438 // 7439 // Once a consumer successfully processes a message, it should call XAck to remove the message so it does not get processed again (and releases message from memory in redis) 7440 func (x *STREAM) XAck(stream string, group string, id ...string) (err error) { 7441 // get new xray segment for tracing 7442 seg := xray.NewSegmentNullable("Redis-XAck", x.core._parentSegment) 7443 7444 if seg != nil { 7445 defer seg.Close() 7446 defer func() { 7447 _ = seg.Seg.AddMetadata("Redis-XAck-Stream", stream) 7448 _ = seg.Seg.AddMetadata("Redis-XAck-Group", group) 7449 _ = seg.Seg.AddMetadata("Redis-XAck-IDs", id) 7450 7451 if err != nil { 7452 _ = seg.Seg.AddError(err) 7453 } 7454 }() 7455 7456 err = x.xackInternal(stream, group, id...) 7457 return err 7458 } else { 7459 return x.xackInternal(stream, group, id...) 7460 } 7461 } 7462 7463 // xackInternal removes one or multiple messages from the 'pending entries list (PEL)' of a stream consumer group 7464 // 7465 // # A message is pending, and as such stored inside the PEL, when it was delivered to some consumer 7466 // 7467 // Once a consumer successfully processes a message, it should call XAck to remove the message so it does not get processed again (and releases message from memory in redis) 7468 func (x *STREAM) xackInternal(stream string, group string, id ...string) error { 7469 // validate 7470 if x.core == nil { 7471 return errors.New("Redis XAck Failed: " + "Base is Nil") 7472 } 7473 7474 if !x.core.cnAreReady { 7475 return errors.New("Redis XAck Failed: " + "Endpoint Connections Not Ready") 7476 } 7477 7478 if len(stream) <= 0 { 7479 return errors.New("Redis XAck Failed: " + "Stream is Required") 7480 } 7481 7482 if len(group) <= 0 { 7483 return errors.New("Redis XAck Failed: " + "Group is Required") 7484 } 7485 7486 if len(id) <= 0 { 7487 return errors.New("Redis XAck Failed: " + "At Least 1 ID is Required") 7488 } 7489 7490 cmd := x.core.cnWriter.XAck(x.core.cnWriter.Context(), stream, group, id...) 7491 return x.core.handleIntCmd2(cmd, "Redis XAck Failed: ") 7492 } 7493 7494 // XAdd appends the specified stream entry to the stream at the specified key, 7495 // If the key does not exist, as a side effect of running this command the key is created with a stream value 7496 func (x *STREAM) XAdd(addArgs *redis.XAddArgs) (err error) { 7497 // get new xray segment for tracing 7498 seg := xray.NewSegmentNullable("Redis-XAdd", x.core._parentSegment) 7499 7500 if seg != nil { 7501 defer seg.Close() 7502 defer func() { 7503 _ = seg.Seg.AddMetadata("Redis-XAdd-Input-Args", addArgs) 7504 7505 if err != nil { 7506 _ = seg.Seg.AddError(err) 7507 } 7508 }() 7509 7510 err = x.xaddInternal(addArgs) 7511 return err 7512 } else { 7513 return x.xaddInternal(addArgs) 7514 } 7515 } 7516 7517 // xaddInternal appends the specified stream entry to the stream at the specified key, 7518 // If the key does not exist, as a side effect of running this command the key is created with a stream value 7519 func (x *STREAM) xaddInternal(addArgs *redis.XAddArgs) error { 7520 // validate 7521 if x.core == nil { 7522 return errors.New("Redis XAdd Failed: " + "Base is Nil") 7523 } 7524 7525 if !x.core.cnAreReady { 7526 return errors.New("Redis XAdd Failed: " + "Endpoint Connections Not Ready") 7527 } 7528 7529 if addArgs == nil { 7530 return errors.New("Redis XAdd Failed: " + "AddArgs is Required") 7531 } 7532 7533 cmd := x.core.cnWriter.XAdd(x.core.cnWriter.Context(), addArgs) 7534 7535 if _, _, err := x.core.handleStringCmd2(cmd, "Redis XAdd Failed: "); err != nil { 7536 return err 7537 } else { 7538 return nil 7539 } 7540 } 7541 7542 // XClaim in the context of stream consumer group, this function changes the ownership of a pending message, 7543 // so that the new owner is the consumer specified as the command argument 7544 func (x *STREAM) XClaim(claimArgs *redis.XClaimArgs) (valMessages []redis.XMessage, notFound bool, err error) { 7545 // get new xray segment for tracing 7546 seg := xray.NewSegmentNullable("Redis-XClaim", x.core._parentSegment) 7547 7548 if seg != nil { 7549 defer seg.Close() 7550 defer func() { 7551 _ = seg.Seg.AddMetadata("Redis-XClaim-Input-Args", claimArgs) 7552 _ = seg.Seg.AddMetadata("Redis-XClaim-Not-Found", notFound) 7553 _ = seg.Seg.AddMetadata("Redis-XClaim-Results", valMessages) 7554 7555 if err != nil { 7556 _ = seg.Seg.AddError(err) 7557 } 7558 }() 7559 7560 valMessages, notFound, err = x.xclaimInternal(claimArgs) 7561 return valMessages, notFound, err 7562 } else { 7563 return x.xclaimInternal(claimArgs) 7564 } 7565 } 7566 7567 // xclaimInternal in the context of stream consumer group, this function changes the ownership of a pending message, 7568 // so that the new owner is the consumer specified as the command argument 7569 func (x *STREAM) xclaimInternal(claimArgs *redis.XClaimArgs) (valMessages []redis.XMessage, notFound bool, err error) { 7570 // validate 7571 if x.core == nil { 7572 return nil, false, errors.New("Redis XClaim Failed: " + "Base is Nil") 7573 } 7574 7575 if !x.core.cnAreReady { 7576 return nil, false, errors.New("Redis XClaim Failed: " + "Endpoint Connections Not Ready") 7577 } 7578 7579 if claimArgs == nil { 7580 return nil, false, errors.New("Redis XClaim Failed: " + "ClaimArgs is Required") 7581 } 7582 7583 cmd := x.core.cnWriter.XClaim(x.core.cnWriter.Context(), claimArgs) 7584 return x.core.handleXMessageSliceCmd(cmd, "Redis XClaim Failed: ") 7585 } 7586 7587 // XClaimJustID in the context of stream consumer group, this function changes the ownership of a pending message, 7588 // so that the new owner is the consumer specified as the command argument 7589 func (x *STREAM) XClaimJustID(claimArgs *redis.XClaimArgs) (outputSlice []string, notFound bool, err error) { 7590 // get new xray segment for tracing 7591 seg := xray.NewSegmentNullable("Redis-XClaimJustID", x.core._parentSegment) 7592 7593 if seg != nil { 7594 defer seg.Close() 7595 defer func() { 7596 _ = seg.Seg.AddMetadata("Redis-XClaimJustID-Input-Args", claimArgs) 7597 _ = seg.Seg.AddMetadata("Redis-XClaimJustID-Not-Found", notFound) 7598 _ = seg.Seg.AddMetadata("Redis-XClaimJustID-Results", outputSlice) 7599 7600 if err != nil { 7601 _ = seg.Seg.AddError(err) 7602 } 7603 }() 7604 7605 outputSlice, notFound, err = x.xclaimJustIDInternal(claimArgs) 7606 return outputSlice, notFound, err 7607 } else { 7608 return x.xclaimJustIDInternal(claimArgs) 7609 } 7610 } 7611 7612 // xclaimJustIDInternal in the context of stream consumer group, this function changes the ownership of a pending message, 7613 // so that the new owner is the consumer specified as the command argument 7614 func (x *STREAM) xclaimJustIDInternal(claimArgs *redis.XClaimArgs) (outputSlice []string, notFound bool, err error) { 7615 // validate 7616 if x.core == nil { 7617 return nil, false, errors.New("Redis XClaim Failed: " + "Base is Nil") 7618 } 7619 7620 if !x.core.cnAreReady { 7621 return nil, false, errors.New("Redis XClaim Failed: " + "Endpoint Connections Not Ready") 7622 } 7623 7624 if claimArgs == nil { 7625 return nil, false, errors.New("Redis XClaim Failed: " + "ClaimArgs is Required") 7626 } 7627 7628 cmd := x.core.cnWriter.XClaimJustID(x.core.cnWriter.Context(), claimArgs) 7629 return x.core.handleStringSliceCmd(cmd, "Redis XClaim Failed: ") 7630 } 7631 7632 // XDel removes the specified entries from a stream 7633 func (x *STREAM) XDel(stream string, id ...string) (err error) { 7634 // get new xray segment for tracing 7635 seg := xray.NewSegmentNullable("Redis-XDel", x.core._parentSegment) 7636 7637 if seg != nil { 7638 defer seg.Close() 7639 defer func() { 7640 _ = seg.Seg.AddMetadata("Redis-XDel-Stream", stream) 7641 _ = seg.Seg.AddMetadata("Redis-XDel-IDs", id) 7642 7643 if err != nil { 7644 _ = seg.Seg.AddError(err) 7645 } 7646 }() 7647 7648 err = x.xdelInternal(stream, id...) 7649 return err 7650 } else { 7651 return x.xdelInternal(stream, id...) 7652 } 7653 } 7654 7655 // xdelInternal removes the specified entries from a stream 7656 func (x *STREAM) xdelInternal(stream string, id ...string) error { 7657 // validate 7658 if x.core == nil { 7659 return errors.New("Redis XDel Failed: " + "Base is Nil") 7660 } 7661 7662 if !x.core.cnAreReady { 7663 return errors.New("Redis XDel Failed: " + "Endpoint Connections Not Ready") 7664 } 7665 7666 if len(stream) <= 0 { 7667 return errors.New("Redis XDel Failed: " + "Stream is Required") 7668 } 7669 7670 if len(id) <= 0 { 7671 return errors.New("Redis XDel Failed: " + "At Least 1 ID is Required") 7672 } 7673 7674 cmd := x.core.cnWriter.XDel(x.core.cnWriter.Context(), stream, id...) 7675 return x.core.handleIntCmd2(cmd, "Redis XDel Failed: ") 7676 } 7677 7678 // XGroupCreate will create a new consumer group associated with a stream 7679 func (x *STREAM) XGroupCreate(stream string, group string, start string) (err error) { 7680 // get new xray segment for tracing 7681 seg := xray.NewSegmentNullable("Redis-XGroupCreate", x.core._parentSegment) 7682 7683 if seg != nil { 7684 defer seg.Close() 7685 defer func() { 7686 _ = seg.Seg.AddMetadata("Redis-XGroupCreate-Stream", stream) 7687 _ = seg.Seg.AddMetadata("Redis-XGroupCreate-Group", group) 7688 _ = seg.Seg.AddMetadata("Redis-XGroupCreate-Start", start) 7689 7690 if err != nil { 7691 _ = seg.Seg.AddError(err) 7692 } 7693 }() 7694 7695 err = x.xgroupCreateInternal(stream, group, start) 7696 return err 7697 } else { 7698 return x.xgroupCreateInternal(stream, group, start) 7699 } 7700 } 7701 7702 // xgroupCreateInternal will create a new consumer group associated with a stream 7703 func (x *STREAM) xgroupCreateInternal(stream string, group string, start string) error { 7704 // validate 7705 if x.core == nil { 7706 return errors.New("Redis XGroupCreate Failed: " + "Base is Nil") 7707 } 7708 7709 if !x.core.cnAreReady { 7710 return errors.New("Redis XGroupCreate Failed: " + "Endpoint Connections Not Ready") 7711 } 7712 7713 if len(stream) <= 0 { 7714 return errors.New("Redis XGroupCreate Failed: " + "Stream is Required") 7715 } 7716 7717 if len(group) <= 0 { 7718 return errors.New("Redis XGroupCreate Failed: " + "Group is Required") 7719 } 7720 7721 if len(start) <= 0 { 7722 return errors.New("Redis XGroupCreate Failed: " + "Start is Required") 7723 } 7724 7725 cmd := x.core.cnWriter.XGroupCreate(x.core.cnWriter.Context(), stream, group, start) 7726 return x.core.handleStatusCmd(cmd, "Redis XGroupCreate Failed: ") 7727 } 7728 7729 // XGroupCreateMkStream will create a new consumer group, and create a stream if stream doesn't exist 7730 func (x *STREAM) XGroupCreateMkStream(stream string, group string, start string) (err error) { 7731 // get new xray segment for tracing 7732 seg := xray.NewSegmentNullable("Redis-XGroupCreateMkStream", x.core._parentSegment) 7733 7734 if seg != nil { 7735 defer seg.Close() 7736 defer func() { 7737 _ = seg.Seg.AddMetadata("Redis-XGroupCreateMkStream-Stream", stream) 7738 _ = seg.Seg.AddMetadata("Redis-XGroupCreateMkStream-Group", group) 7739 _ = seg.Seg.AddMetadata("Redis-XGroupCreateMkStream-Start", start) 7740 7741 if err != nil { 7742 _ = seg.Seg.AddError(err) 7743 } 7744 }() 7745 7746 err = x.xgroupCreateMkStreamInternal(stream, group, start) 7747 return err 7748 } else { 7749 return x.xgroupCreateMkStreamInternal(stream, group, start) 7750 } 7751 } 7752 7753 // xgroupCreateMkStreamInternal will create a new consumer group, and create a stream if stream doesn't exist 7754 func (x *STREAM) xgroupCreateMkStreamInternal(stream string, group string, start string) error { 7755 // validate 7756 if x.core == nil { 7757 return errors.New("Redis XGroupCreateMkStream Failed: " + "Base is Nil") 7758 } 7759 7760 if !x.core.cnAreReady { 7761 return errors.New("Redis XGroupCreateMkStream Failed: " + "Endpoint Connections Not Ready") 7762 } 7763 7764 if len(stream) <= 0 { 7765 return errors.New("Redis XGroupCreateMkStream Failed: " + "Stream is Required") 7766 } 7767 7768 if len(group) <= 0 { 7769 return errors.New("Redis XGroupCreateMkStream Failed: " + "Group is Required") 7770 } 7771 7772 if len(start) <= 0 { 7773 return errors.New("Redis XGroupCreateMkStream Failed: " + "Start is Required") 7774 } 7775 7776 cmd := x.core.cnWriter.XGroupCreateMkStream(x.core.cnWriter.Context(), stream, group, start) 7777 return x.core.handleStatusCmd(cmd, "Redis XGroupCreateMkStream Failed: ") 7778 } 7779 7780 // XGroupDelConsumer removes a given consumer from a consumer group 7781 func (x *STREAM) XGroupDelConsumer(stream string, group string, consumer string) (err error) { 7782 // get new xray segment for tracing 7783 seg := xray.NewSegmentNullable("Redis-XGroupDelConsumer", x.core._parentSegment) 7784 7785 if seg != nil { 7786 defer seg.Close() 7787 defer func() { 7788 _ = seg.Seg.AddMetadata("Redis-XGroupDelConsumer-Stream", stream) 7789 _ = seg.Seg.AddMetadata("Redis-XGroupDelConsumer-Group", group) 7790 _ = seg.Seg.AddMetadata("Redis-XGroupDelConsumer-Consumer", consumer) 7791 7792 if err != nil { 7793 _ = seg.Seg.AddError(err) 7794 } 7795 }() 7796 7797 err = x.xgroupDelConsumerInternal(stream, group, consumer) 7798 return err 7799 } else { 7800 return x.xgroupDelConsumerInternal(stream, group, consumer) 7801 } 7802 } 7803 7804 // xgroupDelConsumerInternal removes a given consumer from a consumer group 7805 func (x *STREAM) xgroupDelConsumerInternal(stream string, group string, consumer string) error { 7806 // validate 7807 if x.core == nil { 7808 return errors.New("Redis XGroupDelConsumer Failed: " + "Base is Nil") 7809 } 7810 7811 if !x.core.cnAreReady { 7812 return errors.New("Redis XGroupDelConsumer Failed: " + "Endpoint Connections Not Ready") 7813 } 7814 7815 if len(stream) <= 0 { 7816 return errors.New("Redis XGroupDelConsumer Failed: " + "Stream is Required") 7817 } 7818 7819 if len(group) <= 0 { 7820 return errors.New("Redis XGroupDelConsumer Failed: " + "Group is Required") 7821 } 7822 7823 if len(consumer) <= 0 { 7824 return errors.New("Redis XGroupDelConsumer Failed: " + "Consumer is Required") 7825 } 7826 7827 cmd := x.core.cnWriter.XGroupDelConsumer(x.core.cnWriter.Context(), stream, group, consumer) 7828 return x.core.handleIntCmd2(cmd, "Redis XGroupDelConsumer Failed: ") 7829 } 7830 7831 // XGroupDestroy will destroy a consumer group even if there are active consumers and pending messages 7832 func (x *STREAM) XGroupDestroy(stream string, group string) (err error) { 7833 // get new xray segment for tracing 7834 seg := xray.NewSegmentNullable("Redis-XGroupDestroy", x.core._parentSegment) 7835 7836 if seg != nil { 7837 defer seg.Close() 7838 defer func() { 7839 _ = seg.Seg.AddMetadata("Redis-XGroupDestroy-Stream", stream) 7840 _ = seg.Seg.AddMetadata("Redis-XGroupDestroy-Group", group) 7841 7842 if err != nil { 7843 _ = seg.Seg.AddError(err) 7844 } 7845 }() 7846 7847 err = x.xgroupDestroyInternal(stream, group) 7848 return err 7849 } else { 7850 return x.xgroupDestroyInternal(stream, group) 7851 } 7852 } 7853 7854 // xgroupDestroyInternal will destroy a consumer group even if there are active consumers and pending messages 7855 func (x *STREAM) xgroupDestroyInternal(stream string, group string) error { 7856 // validate 7857 if x.core == nil { 7858 return errors.New("Redis XGroupDestroy Failed: " + "Base is Nil") 7859 } 7860 7861 if !x.core.cnAreReady { 7862 return errors.New("Redis XGroupDestroy Failed: " + "Endpoint Connections Not Ready") 7863 } 7864 7865 if len(stream) <= 0 { 7866 return errors.New("Redis XGroupDestroy Failed: " + "Stream is Required") 7867 } 7868 7869 if len(group) <= 0 { 7870 return errors.New("Redis XGroupDestroy Failed: " + "Group is Required") 7871 } 7872 7873 cmd := x.core.cnWriter.XGroupDestroy(x.core.cnWriter.Context(), stream, group) 7874 return x.core.handleIntCmd2(cmd, "Redis XGroupDestroy Failed: ") 7875 } 7876 7877 // XGroupSetID will set the next message to deliver, 7878 // Normally the next ID is set when the consumer is created, as the last argument to XGroupCreate, 7879 // However, using XGroupSetID resets the next message ID in case prior message needs to be reprocessed 7880 func (x *STREAM) XGroupSetID(stream string, group string, start string) (err error) { 7881 // get new xray segment for tracing 7882 seg := xray.NewSegmentNullable("Redis-XGroupSetID", x.core._parentSegment) 7883 7884 if seg != nil { 7885 defer seg.Close() 7886 defer func() { 7887 _ = seg.Seg.AddMetadata("Redis-XGroupSetID-Stream", stream) 7888 _ = seg.Seg.AddMetadata("Redis-XGroupSetID-Group", group) 7889 _ = seg.Seg.AddMetadata("Redis-XGroupSetID-Start", start) 7890 7891 if err != nil { 7892 _ = seg.Seg.AddError(err) 7893 } 7894 }() 7895 7896 err = x.xgroupSetIDInternal(stream, group, start) 7897 return err 7898 } else { 7899 return x.xgroupSetIDInternal(stream, group, start) 7900 } 7901 } 7902 7903 // xgroupSetIDInternal will set the next message to deliver, 7904 // Normally the next ID is set when the consumer is created, as the last argument to XGroupCreate, 7905 // However, using XGroupSetID resets the next message ID in case prior message needs to be reprocessed 7906 func (x *STREAM) xgroupSetIDInternal(stream string, group string, start string) error { 7907 // validate 7908 if x.core == nil { 7909 return errors.New("Redis XGroupSetID Failed: " + "Base is Nil") 7910 } 7911 7912 if !x.core.cnAreReady { 7913 return errors.New("Redis XGroupSetID Failed: " + "Endpoint Connections Not Ready") 7914 } 7915 7916 if len(stream) <= 0 { 7917 return errors.New("Redis XGroupSetID Failed: " + "Stream is Required") 7918 } 7919 7920 if len(group) <= 0 { 7921 return errors.New("Redis XGroupSetID Failed: " + "Group is Required") 7922 } 7923 7924 if len(start) <= 0 { 7925 return errors.New("Redis XGroupSetID Failed: " + "Start is Required") 7926 } 7927 7928 cmd := x.core.cnWriter.XGroupSetID(x.core.cnWriter.Context(), stream, group, start) 7929 return x.core.handleStatusCmd(cmd, "Redis XGroupSetID Failed: ") 7930 } 7931 7932 // XInfoGroups retrieves different information about the streams, and associated consumer groups 7933 func (x *STREAM) XInfoGroups(key string) (outputSlice []redis.XInfoGroup, notFound bool, err error) { 7934 // get new xray segment for tracing 7935 seg := xray.NewSegmentNullable("Redis-XInfoGroups", x.core._parentSegment) 7936 7937 if seg != nil { 7938 defer seg.Close() 7939 defer func() { 7940 _ = seg.Seg.AddMetadata("Redis-XInfoGroups-Key", key) 7941 _ = seg.Seg.AddMetadata("Redis-XInfoGroups-Not-Found", notFound) 7942 _ = seg.Seg.AddMetadata("Redis-XInfoGroups-Results", outputSlice) 7943 7944 if err != nil { 7945 _ = seg.Seg.AddError(err) 7946 } 7947 }() 7948 7949 outputSlice, notFound, err = x.xinfoGroupsInternal(key) 7950 return outputSlice, notFound, err 7951 } else { 7952 return x.xinfoGroupsInternal(key) 7953 } 7954 } 7955 7956 // xinfoGroupsInternal retrieves different information about the streams, and associated consumer groups 7957 func (x *STREAM) xinfoGroupsInternal(key string) (outputSlice []redis.XInfoGroup, notFound bool, err error) { 7958 // validate 7959 if x.core == nil { 7960 return nil, false, errors.New("Redis XInfoGroups Failed: " + "Base is Nil") 7961 } 7962 7963 if !x.core.cnAreReady { 7964 return nil, false, errors.New("Redis XInfoGroups Failed: " + "Endpoint Connections Not Ready") 7965 } 7966 7967 if len(key) <= 0 { 7968 return nil, false, errors.New("Redis XInfoGroups Failed: " + "Key is Required") 7969 } 7970 7971 cmd := x.core.cnReader.XInfoGroups(x.core.cnReader.Context(), key) 7972 return x.core.handleXInfoGroupsCmd(cmd, "Redis XInfoGroups Failed: ") 7973 } 7974 7975 // XLen returns the number of entries inside a stream 7976 func (x *STREAM) XLen(stream string) (val int64, notFound bool, err error) { 7977 // get new xray segment for tracing 7978 seg := xray.NewSegmentNullable("Redis-XLen", x.core._parentSegment) 7979 7980 if seg != nil { 7981 defer seg.Close() 7982 defer func() { 7983 _ = seg.Seg.AddMetadata("Redis-XLen-Stream", stream) 7984 _ = seg.Seg.AddMetadata("Redis-XLen-Not-Found", notFound) 7985 _ = seg.Seg.AddMetadata("Redis-XLen-Result", val) 7986 7987 if err != nil { 7988 _ = seg.Seg.AddError(err) 7989 } 7990 }() 7991 7992 val, notFound, err = x.xlenInternal(stream) 7993 return val, notFound, err 7994 } else { 7995 return x.xlenInternal(stream) 7996 } 7997 } 7998 7999 // xlenInternal returns the number of entries inside a stream 8000 func (x *STREAM) xlenInternal(stream string) (val int64, notFound bool, err error) { 8001 // validate 8002 if x.core == nil { 8003 return 0, false, errors.New("Redis XLen Failed: " + "Base is Nil") 8004 } 8005 8006 if !x.core.cnAreReady { 8007 return 0, false, errors.New("Redis XLen Failed: " + "Endpoint Connections Not Ready") 8008 } 8009 8010 if len(stream) <= 0 { 8011 return 0, false, errors.New("Redis XLen Failed: " + "Stream is Required") 8012 } 8013 8014 cmd := x.core.cnReader.XLen(x.core.cnReader.Context(), stream) 8015 return x.core.handleIntCmd(cmd, "Redis XLen Failed: ") 8016 } 8017 8018 // XPending fetches data from a stream via a consumer group, and not acknowledging such data, its like creating pending entries 8019 func (x *STREAM) XPending(stream string, group string) (val *redis.XPending, notFound bool, err error) { 8020 // get new xray segment for tracing 8021 seg := xray.NewSegmentNullable("Redis-XPending", x.core._parentSegment) 8022 8023 if seg != nil { 8024 defer seg.Close() 8025 defer func() { 8026 _ = seg.Seg.AddMetadata("Redis-XPending-Stream", stream) 8027 _ = seg.Seg.AddMetadata("Redis-XPending-Group", group) 8028 _ = seg.Seg.AddMetadata("Redis-XPending-Not-Found", notFound) 8029 _ = seg.Seg.AddMetadata("Redis-XPending-Results", val) 8030 8031 if err != nil { 8032 _ = seg.Seg.AddError(err) 8033 } 8034 }() 8035 8036 val, notFound, err = x.xpendingInternal(stream, group) 8037 return val, notFound, err 8038 } else { 8039 return x.xpendingInternal(stream, group) 8040 } 8041 } 8042 8043 // xpendingInternal fetches data from a stream via a consumer group, and not acknowledging such data, its like creating pending entries 8044 func (x *STREAM) xpendingInternal(stream string, group string) (val *redis.XPending, notFound bool, err error) { 8045 // validate 8046 if x.core == nil { 8047 return nil, false, errors.New("Redis XPending Failed: " + "Base is Nil") 8048 } 8049 8050 if !x.core.cnAreReady { 8051 return nil, false, errors.New("Redis XPending Failed: " + "Endpoint Connections Not Ready") 8052 } 8053 8054 if len(stream) <= 0 { 8055 return nil, false, errors.New("Redis XPending Failed: " + "Stream is Required") 8056 } 8057 8058 if len(group) <= 0 { 8059 return nil, false, errors.New("Redis XPending Failed: " + "Group is Required") 8060 } 8061 8062 cmd := x.core.cnWriter.XPending(x.core.cnWriter.Context(), stream, group) 8063 return x.core.handleXPendingCmd(cmd, "Redis XPending Failed: ") 8064 } 8065 8066 // XPendingExt fetches data from a stream via a consumer group, and not acknowledging such data, its like creating pending entries 8067 func (x *STREAM) XPendingExt(pendingArgs *redis.XPendingExtArgs) (outputSlice []redis.XPendingExt, notFound bool, err error) { 8068 // get new xray segment for tracing 8069 seg := xray.NewSegmentNullable("Redis-XPendingExt", x.core._parentSegment) 8070 8071 if seg != nil { 8072 defer seg.Close() 8073 defer func() { 8074 _ = seg.Seg.AddMetadata("Redis-XPendingExt-Input-Args", pendingArgs) 8075 _ = seg.Seg.AddMetadata("Redis-XPendingExt-Not-Found", notFound) 8076 _ = seg.Seg.AddMetadata("Redis-XPendingExt-Results", outputSlice) 8077 8078 if err != nil { 8079 _ = seg.Seg.AddError(err) 8080 } 8081 }() 8082 8083 outputSlice, notFound, err = x.xpendingExtInternal(pendingArgs) 8084 return outputSlice, notFound, err 8085 } else { 8086 return x.xpendingExtInternal(pendingArgs) 8087 } 8088 } 8089 8090 // xpendingExtInternal fetches data from a stream via a consumer group, and not acknowledging such data, its like creating pending entries 8091 func (x *STREAM) xpendingExtInternal(pendingArgs *redis.XPendingExtArgs) (outputSlice []redis.XPendingExt, notFound bool, err error) { 8092 // validate 8093 if x.core == nil { 8094 return nil, false, errors.New("Redis XPendingExt Failed: " + "Base is Nil") 8095 } 8096 8097 if !x.core.cnAreReady { 8098 return nil, false, errors.New("Redis XPendingExt Failed: " + "Endpoint Connections Not Ready") 8099 } 8100 8101 if pendingArgs == nil { 8102 return nil, false, errors.New("Redis XPendingExt Failed: " + "PendingArgs is Required") 8103 } 8104 8105 cmd := x.core.cnWriter.XPendingExt(x.core.cnWriter.Context(), pendingArgs) 8106 return x.core.handleXPendingExtCmd(cmd, "Redis XPendingExt Failed: ") 8107 } 8108 8109 // XRange returns the stream entries matching a given range of IDs, 8110 // Range is specified by a minimum and maximum ID, 8111 // Ordering is lowest to highest 8112 func (x *STREAM) XRange(stream string, start string, stop string, count ...int64) (outputSlice []redis.XMessage, notFound bool, err error) { 8113 // get new xray segment for tracing 8114 seg := xray.NewSegmentNullable("Redis-XRange", x.core._parentSegment) 8115 8116 if seg != nil { 8117 defer seg.Close() 8118 defer func() { 8119 _ = seg.Seg.AddMetadata("Redis-XRange-Stream", stream) 8120 _ = seg.Seg.AddMetadata("Redis-XRange-Start", start) 8121 _ = seg.Seg.AddMetadata("Redis-XRange-Stop", stop) 8122 8123 if len(count) > 0 { 8124 _ = seg.Seg.AddMetadata("Redis-XRange-Limit-Count", count[0]) 8125 } else { 8126 _ = seg.Seg.AddMetadata("Redis-XRange-Limit-Count", "None") 8127 } 8128 8129 _ = seg.Seg.AddMetadata("Redis-XRange-Not-Found", notFound) 8130 _ = seg.Seg.AddMetadata("Redis-XRange-Results", outputSlice) 8131 8132 if err != nil { 8133 _ = seg.Seg.AddError(err) 8134 } 8135 }() 8136 8137 outputSlice, notFound, err = x.xrangeInternal(stream, start, stop, count...) 8138 return outputSlice, notFound, err 8139 } else { 8140 return x.xrangeInternal(stream, start, stop, count...) 8141 } 8142 } 8143 8144 // xrangeInternal returns the stream entries matching a given range of IDs, 8145 // Range is specified by a minimum and maximum ID, 8146 // Ordering is lowest to highest 8147 func (x *STREAM) xrangeInternal(stream string, start string, stop string, count ...int64) (outputSlice []redis.XMessage, notFound bool, err error) { 8148 // validate 8149 if x.core == nil { 8150 return nil, false, errors.New("Redis XRange Failed: " + "Base is Nil") 8151 } 8152 8153 if !x.core.cnAreReady { 8154 return nil, false, errors.New("Redis XRange Failed: " + "Endpoint Connections Not Ready") 8155 } 8156 8157 if len(stream) <= 0 { 8158 return nil, false, errors.New("Redis XRange Failed: " + "Stream is Required") 8159 } 8160 8161 if len(start) <= 0 { 8162 return nil, false, errors.New("Redis XRange Failed: " + "Start is Required") 8163 } 8164 8165 if len(stop) <= 0 { 8166 return nil, false, errors.New("Redis XRange Failed: " + "Stop is Required") 8167 } 8168 8169 var cmd *redis.XMessageSliceCmd 8170 8171 if len(count) <= 0 { 8172 cmd = x.core.cnReader.XRange(x.core.cnReader.Context(), stream, start, stop) 8173 } else { 8174 cmd = x.core.cnReader.XRangeN(x.core.cnReader.Context(), stream, start, stop, count[0]) 8175 } 8176 8177 return x.core.handleXMessageSliceCmd(cmd, "Redis XRange Failed: ") 8178 } 8179 8180 // XRevRange returns the stream entries matching a given range of IDs, 8181 // Range is specified by a maximum and minimum ID, 8182 // Ordering is highest to lowest 8183 func (x *STREAM) XRevRange(stream string, start string, stop string, count ...int64) (outputSlice []redis.XMessage, notFound bool, err error) { 8184 // get new xray segment for tracing 8185 seg := xray.NewSegmentNullable("Redis-XRevRange", x.core._parentSegment) 8186 8187 if seg != nil { 8188 defer seg.Close() 8189 defer func() { 8190 _ = seg.Seg.AddMetadata("Redis-XRevRange-Stream", stream) 8191 _ = seg.Seg.AddMetadata("Redis-XRevRange-Start", start) 8192 _ = seg.Seg.AddMetadata("Redis-XRevRange-Stop", stop) 8193 8194 if len(count) > 0 { 8195 _ = seg.Seg.AddMetadata("Redis-XRevRange-Limit-Count", count[0]) 8196 } else { 8197 _ = seg.Seg.AddMetadata("Redis-XRevRange-Limit-Count", "None") 8198 } 8199 8200 _ = seg.Seg.AddMetadata("Redis-XRevRange-Not-Found", notFound) 8201 _ = seg.Seg.AddMetadata("Redis-XRevRange-Results", outputSlice) 8202 8203 if err != nil { 8204 _ = seg.Seg.AddError(err) 8205 } 8206 }() 8207 8208 outputSlice, notFound, err = x.xrevRangeInternal(stream, start, stop, count...) 8209 return outputSlice, notFound, err 8210 } else { 8211 return x.xrevRangeInternal(stream, start, stop, count...) 8212 } 8213 } 8214 8215 // xrevRangeInternal returns the stream entries matching a given range of IDs, 8216 // Range is specified by a maximum and minimum ID, 8217 // Ordering is highest to lowest 8218 func (x *STREAM) xrevRangeInternal(stream string, start string, stop string, count ...int64) (outputSlice []redis.XMessage, notFound bool, err error) { 8219 // validate 8220 if x.core == nil { 8221 return nil, false, errors.New("Redis XRevRange Failed: " + "Base is Nil") 8222 } 8223 8224 if !x.core.cnAreReady { 8225 return nil, false, errors.New("Redis XRevRange Failed: " + "Endpoint Connections Not Ready") 8226 } 8227 8228 if len(stream) <= 0 { 8229 return nil, false, errors.New("Redis XRevRange Failed: " + "Stream is Required") 8230 } 8231 8232 if len(start) <= 0 { 8233 return nil, false, errors.New("Redis XRevRange Failed: " + "Start is Required") 8234 } 8235 8236 if len(stop) <= 0 { 8237 return nil, false, errors.New("Redis XRevRange Failed: " + "Stop is Required") 8238 } 8239 8240 var cmd *redis.XMessageSliceCmd 8241 8242 if len(count) <= 0 { 8243 cmd = x.core.cnReader.XRevRange(x.core.cnReader.Context(), stream, start, stop) 8244 } else { 8245 cmd = x.core.cnReader.XRevRangeN(x.core.cnReader.Context(), stream, start, stop, count[0]) 8246 } 8247 8248 return x.core.handleXMessageSliceCmd(cmd, "Redis XRevRange Failed: ") 8249 } 8250 8251 // XRead will read data from one or multiple streams, 8252 // only returning entries with an ID greater than the last received ID reported by the caller 8253 func (x *STREAM) XRead(readArgs *redis.XReadArgs) (outputSlice []redis.XStream, notFound bool, err error) { 8254 // get new xray segment for tracing 8255 seg := xray.NewSegmentNullable("Redis-XRead", x.core._parentSegment) 8256 8257 if seg != nil { 8258 defer seg.Close() 8259 defer func() { 8260 _ = seg.Seg.AddMetadata("Redis-XRead-Input-Args", readArgs) 8261 _ = seg.Seg.AddMetadata("Redis-XRead-Input-Not-Found", notFound) 8262 _ = seg.Seg.AddMetadata("Redis-XRead-Results", outputSlice) 8263 8264 if err != nil { 8265 _ = seg.Seg.AddError(err) 8266 } 8267 }() 8268 8269 outputSlice, notFound, err = x.xreadInternal(readArgs) 8270 return outputSlice, notFound, err 8271 } else { 8272 return x.xreadInternal(readArgs) 8273 } 8274 } 8275 8276 // xreadInternal will read data from one or multiple streams, 8277 // only returning entries with an ID greater than the last received ID reported by the caller 8278 func (x *STREAM) xreadInternal(readArgs *redis.XReadArgs) (outputSlice []redis.XStream, notFound bool, err error) { 8279 // validate 8280 if x.core == nil { 8281 return nil, false, errors.New("Redis XRead Failed: " + "Base is Nil") 8282 } 8283 8284 if !x.core.cnAreReady { 8285 return nil, false, errors.New("Redis XRead Failed: " + "Endpoint Connections Not Ready") 8286 } 8287 8288 if readArgs == nil { 8289 return nil, false, errors.New("Redis XRead Failed: " + "ReadArgs is Required") 8290 } 8291 8292 cmd := x.core.cnReader.XRead(x.core.cnReader.Context(), readArgs) 8293 return x.core.handleXStreamSliceCmd(cmd, "Redis XRead Failed: ") 8294 } 8295 8296 // XReadStreams is a special version of XRead command for streams 8297 func (x *STREAM) XReadStreams(stream ...string) (outputSlice []redis.XStream, notFound bool, err error) { 8298 // get new xray segment for tracing 8299 seg := xray.NewSegmentNullable("Redis-XReadStreams", x.core._parentSegment) 8300 8301 if seg != nil { 8302 defer seg.Close() 8303 defer func() { 8304 _ = seg.Seg.AddMetadata("Redis-XReadStreams-Streams", stream) 8305 _ = seg.Seg.AddMetadata("Redis-XReadStreams-Not-Found", notFound) 8306 _ = seg.Seg.AddMetadata("Redis-XReadStreams-Results", outputSlice) 8307 8308 if err != nil { 8309 _ = seg.Seg.AddError(err) 8310 } 8311 }() 8312 8313 outputSlice, notFound, err = x.xreadStreamsInternal(stream...) 8314 return outputSlice, notFound, err 8315 } else { 8316 return x.xreadStreamsInternal(stream...) 8317 } 8318 } 8319 8320 // xreadStreamsInternal is a special version of XRead command for streams 8321 func (x *STREAM) xreadStreamsInternal(stream ...string) (outputSlice []redis.XStream, notFound bool, err error) { 8322 // validate 8323 if x.core == nil { 8324 return nil, false, errors.New("Redis XReadStreams Failed: " + "Base is Nil") 8325 } 8326 8327 if !x.core.cnAreReady { 8328 return nil, false, errors.New("Redis XReadStreams Failed: " + "Endpoint Connections Not Ready") 8329 } 8330 8331 if len(stream) <= 0 { 8332 return nil, false, errors.New("Redis XReadStreams Failed: " + "At Least 1 Stream is Required") 8333 } 8334 8335 cmd := x.core.cnReader.XReadStreams(x.core.cnReader.Context(), stream...) 8336 return x.core.handleXStreamSliceCmd(cmd, "Redis XReadStream Failed: ") 8337 } 8338 8339 // XReadGroup is a special version of XRead command with support for consumer groups 8340 func (x *STREAM) XReadGroup(readGroupArgs *redis.XReadGroupArgs) (outputSlice []redis.XStream, notFound bool, err error) { 8341 // get new xray segment for tracing 8342 seg := xray.NewSegmentNullable("Redis-XReadGroup", x.core._parentSegment) 8343 8344 if seg != nil { 8345 defer seg.Close() 8346 defer func() { 8347 _ = seg.Seg.AddMetadata("Redis-XReadGroup-ReadGroup", readGroupArgs) 8348 _ = seg.Seg.AddMetadata("Redis-XReadGroup-Not-Found", notFound) 8349 _ = seg.Seg.AddMetadata("Redis-XReadGroup-Result", outputSlice) 8350 8351 if err != nil { 8352 _ = seg.Seg.AddError(err) 8353 } 8354 }() 8355 8356 outputSlice, notFound, err = x.xreadGroupInternal(readGroupArgs) 8357 return outputSlice, notFound, err 8358 } else { 8359 return x.xreadGroupInternal(readGroupArgs) 8360 } 8361 } 8362 8363 // xreadGroupInternal is a special version of XRead command with support for consumer groups 8364 func (x *STREAM) xreadGroupInternal(readGroupArgs *redis.XReadGroupArgs) (outputSlice []redis.XStream, notFound bool, err error) { 8365 // validate 8366 if x.core == nil { 8367 return nil, false, errors.New("Redis XReadGroup Failed: " + "Base is Nil") 8368 } 8369 8370 if !x.core.cnAreReady { 8371 return nil, false, errors.New("Redis XReadGroup Failed: " + "Endpoint Connections Not Ready") 8372 } 8373 8374 if readGroupArgs == nil { 8375 return nil, false, errors.New("Redis XReadGroup Failed: " + "ReadGroupArgs is Required") 8376 } 8377 8378 cmd := x.core.cnReader.XReadGroup(x.core.cnReader.Context(), readGroupArgs) 8379 return x.core.handleXStreamSliceCmd(cmd, "Redis XReadGroup Failed: ") 8380 } 8381 8382 // XTrim trims the stream to a given number of items, evicting older items (items with lower IDs) if needed 8383 func (x *STREAM) XTrim(key string, maxLen int64) (err error) { 8384 // get new xray segment for tracing 8385 seg := xray.NewSegmentNullable("Redis-XTrim", x.core._parentSegment) 8386 8387 if seg != nil { 8388 defer seg.Close() 8389 defer func() { 8390 _ = seg.Seg.AddMetadata("Redis-XTrim-Key", key) 8391 _ = seg.Seg.AddMetadata("Redis-XTrim-MaxLen", maxLen) 8392 8393 if err != nil { 8394 _ = seg.Seg.AddError(err) 8395 } 8396 }() 8397 8398 err = x.xtrimInternal(key, maxLen) 8399 return err 8400 } else { 8401 return x.xtrimInternal(key, maxLen) 8402 } 8403 } 8404 8405 // xtrimInternal trims the stream to a given number of items, evicting older items (items with lower IDs) if needed 8406 func (x *STREAM) xtrimInternal(key string, maxLen int64) error { 8407 // validate 8408 if x.core == nil { 8409 return errors.New("Redis XTrim Failed: " + "Base is Nil") 8410 } 8411 8412 if !x.core.cnAreReady { 8413 return errors.New("Redis XTrim Failed: " + "Endpoint Connections Not Ready") 8414 } 8415 8416 if len(key) <= 0 { 8417 return errors.New("Redis XTrim Failed: " + "Key is Required") 8418 } 8419 8420 if maxLen < 0 { 8421 return errors.New("Redis XTrim Failed: " + "MaxLen Must Not Be Negative") 8422 } 8423 8424 cmd := x.core.cnWriter.XTrim(x.core.cnWriter.Context(), key, maxLen) 8425 return x.core.handleIntCmd2(cmd, "Redis XTrim Failed: ") 8426 } 8427 8428 // XTrimApprox trims the stream to a given number of items, evicting older items (items with lower IDs) if needed 8429 func (x *STREAM) XTrimApprox(key string, maxLen int64) (err error) { 8430 // get new xray segment for tracing 8431 seg := xray.NewSegmentNullable("Redis-XTrimApprox", x.core._parentSegment) 8432 8433 if seg != nil { 8434 defer seg.Close() 8435 defer func() { 8436 _ = seg.Seg.AddMetadata("Redis-XTrimApprox-Key", key) 8437 _ = seg.Seg.AddMetadata("Redis-XTrimApprox-MaxLen", maxLen) 8438 8439 if err != nil { 8440 _ = seg.Seg.AddError(err) 8441 } 8442 }() 8443 8444 err = x.xtrimApproxInternal(key, maxLen) 8445 return err 8446 } else { 8447 return x.xtrimApproxInternal(key, maxLen) 8448 } 8449 } 8450 8451 // xtrimApproxInternal trims the stream to a given number of items, evicting older items (items with lower IDs) if needed 8452 func (x *STREAM) xtrimApproxInternal(key string, maxLen int64) error { 8453 // validate 8454 if x.core == nil { 8455 return errors.New("Redis XTrimApprox Failed: " + "Base is Nil") 8456 } 8457 8458 if !x.core.cnAreReady { 8459 return errors.New("Redis XTrimApprox Failed: " + "Endpoint Connections Not Ready") 8460 } 8461 8462 if len(key) <= 0 { 8463 return errors.New("Redis XTrimApprox Failed: " + "Key is Required") 8464 } 8465 8466 if maxLen < 0 { 8467 return errors.New("Redis XTrimApprox Failed: " + "MaxLen Must Not Be Negative") 8468 } 8469 8470 cmd := x.core.cnWriter.XTrimApprox(x.core.cnWriter.Context(), key, maxLen) 8471 return x.core.handleIntCmd2(cmd, "Redis XTrimApprox Failed: ") 8472 } 8473 8474 // ---------------------------------------------------------------------------------------------------------------- 8475 // PUBSUB functions 8476 // ---------------------------------------------------------------------------------------------------------------- 8477 8478 // 8479 // *** REDIS PUB/SUB INTRODUCTION = https://redis.io/topics/pubsub *** 8480 // 8481 8482 // PSubscribe (Pattern Subscribe) will subscribe client to the given pattern channels (glob-style), 8483 // a pointer to redis PubSub object is returned upon successful subscribe 8484 // 8485 // Once client is subscribed, do not call other redis actions, other than Subscribe, PSubscribe, Ping, Unsubscribe, PUnsubscribe, and Quit (Per Redis Doc) 8486 // 8487 // glob-style patterns: 8488 // 1. h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 8489 // 2. h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 8490 // 3. h*llo = * represents any single or more char match (hllo, heeeelo match) 8491 // 4. h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 8492 // 5. h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 8493 // 6. h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 8494 // 7. Use \ to escape special characters if needing to match verbatim 8495 func (ps *PUBSUB) PSubscribe(channel ...string) (psObj *redis.PubSub, err error) { 8496 // get new xray segment for tracing 8497 seg := xray.NewSegmentNullable("Redis-PSubscribe", ps.core._parentSegment) 8498 8499 if seg != nil { 8500 defer seg.Close() 8501 defer func() { 8502 _ = seg.Seg.AddMetadata("Redis-PSubscribe-Channels", channel) 8503 8504 if err != nil { 8505 _ = seg.Seg.AddError(err) 8506 } 8507 }() 8508 8509 psObj, err = ps.psubscribeInternal(channel...) 8510 return psObj, err 8511 } else { 8512 return ps.psubscribeInternal(channel...) 8513 } 8514 } 8515 8516 // psubscribeInternal (Pattern Subscribe) will subscribe client to the given pattern channels (glob-style), 8517 // a pointer to redis PubSub object is returned upon successful subscribe 8518 // 8519 // Once client is subscribed, do not call other redis actions, other than Subscribe, PSubscribe, Ping, Unsubscribe, PUnsubscribe, and Quit (Per Redis Doc) 8520 // 8521 // glob-style patterns: 8522 // 1. h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 8523 // 2. h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 8524 // 3. h*llo = * represents any single or more char match (hllo, heeeelo match) 8525 // 4. h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 8526 // 5. h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 8527 // 6. h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 8528 // 7. Use \ to escape special characters if needing to match verbatim 8529 func (ps *PUBSUB) psubscribeInternal(channel ...string) (*redis.PubSub, error) { 8530 // validate 8531 if ps.core == nil { 8532 return nil, errors.New("Redis PSubscribe Failed: " + "Base is Nil") 8533 } 8534 8535 if !ps.core.cnAreReady { 8536 return nil, errors.New("Redis PSubscribe Failed: " + "Endpoint Connections Not Ready") 8537 } 8538 8539 if len(channel) <= 0 { 8540 return nil, errors.New("Redis PSubscribe Failed: " + "At Least 1 Channel is Required") 8541 } 8542 8543 return ps.core.cnWriter.PSubscribe(ps.core.cnWriter.Context(), channel...), nil 8544 } 8545 8546 // Subscribe (Non-Pattern Subscribe) will subscribe client to the given channels, 8547 // a pointer to redis PubSub object is returned upon successful subscribe 8548 // 8549 // Once client is subscribed, do not call other redis actions, other than Subscribe, PSubscribe, Ping, Unsubscribe, PUnsubscribe, and Quit (Per Redis Doc) 8550 func (ps *PUBSUB) Subscribe(channel ...string) (psObj *redis.PubSub, err error) { 8551 // get new xray segment for tracing 8552 seg := xray.NewSegmentNullable("Redis-Subscribe", ps.core._parentSegment) 8553 8554 if seg != nil { 8555 defer seg.Close() 8556 defer func() { 8557 _ = seg.Seg.AddMetadata("Redis-Subscribe-Channels", channel) 8558 8559 if err != nil { 8560 _ = seg.Seg.AddError(err) 8561 } 8562 }() 8563 8564 psObj, err = ps.subscribeInternal(channel...) 8565 return psObj, err 8566 } else { 8567 return ps.subscribeInternal(channel...) 8568 } 8569 } 8570 8571 // subscribeInternal (Non-Pattern Subscribe) will subscribe client to the given channels, 8572 // a pointer to redis PubSub object is returned upon successful subscribe 8573 // 8574 // Once client is subscribed, do not call other redis actions, other than Subscribe, PSubscribe, Ping, Unsubscribe, PUnsubscribe, and Quit (Per Redis Doc) 8575 func (ps *PUBSUB) subscribeInternal(channel ...string) (*redis.PubSub, error) { 8576 // validate 8577 if ps.core == nil { 8578 return nil, errors.New("Redis Subscribe Failed: " + "Base is Nil") 8579 } 8580 8581 if !ps.core.cnAreReady { 8582 return nil, errors.New("Redis Subscribe Failed: " + "Endpoint Connections Not Ready") 8583 } 8584 8585 if len(channel) <= 0 { 8586 return nil, errors.New("Redis Subscribe Failed: " + "At Least 1 Channel is Required") 8587 } 8588 8589 return ps.core.cnWriter.Subscribe(ps.core.cnWriter.Context(), channel...), nil 8590 } 8591 8592 // Publish will post a message to a given channel, 8593 // returns number of clients that received the message 8594 func (ps *PUBSUB) Publish(channel string, message interface{}) (valReceived int64, err error) { 8595 // get new xray segment for tracing 8596 seg := xray.NewSegmentNullable("Redis-Publish", ps.core._parentSegment) 8597 8598 if seg != nil { 8599 defer seg.Close() 8600 defer func() { 8601 _ = seg.Seg.AddMetadata("Redis-Publish-Channel", channel) 8602 _ = seg.Seg.AddMetadata("Redis-Publish-Message", message) 8603 _ = seg.Seg.AddMetadata("Redis-Publish-Received-Clients-Count", valReceived) 8604 8605 if err != nil { 8606 _ = seg.Seg.AddError(err) 8607 } 8608 }() 8609 8610 valReceived, err = ps.publishInternal(channel, message) 8611 return valReceived, err 8612 } else { 8613 return ps.publishInternal(channel, message) 8614 } 8615 } 8616 8617 // publishInternal will post a message to a given channel, 8618 // returns number of clients that received the message 8619 func (ps *PUBSUB) publishInternal(channel string, message interface{}) (valReceived int64, err error) { 8620 // validate 8621 if ps.core == nil { 8622 return 0, errors.New("Redis Publish Failed: " + "Base is Nil") 8623 } 8624 8625 if !ps.core.cnAreReady { 8626 return 0, errors.New("Redis Publish Failed: " + "Endpoint Connections Not Ready") 8627 } 8628 8629 cmd := ps.core.cnWriter.Publish(ps.core.cnWriter.Context(), channel, message) 8630 valReceived, _, err = ps.core.handleIntCmd(cmd, "Redis Publish Failed: ") 8631 return valReceived, err 8632 } 8633 8634 // PubSubChannels lists currently active channels, 8635 // active channel = pub/sub channel with one or more subscribers (excluding clients subscribed to patterns), 8636 // pattern = optional, channels matching specific glob-style pattern are listed; otherwise, all channels listed 8637 // 8638 // glob-style patterns: 8639 // 1. h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 8640 // 2. h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 8641 // 3. h*llo = * represents any single or more char match (hllo, heeeelo match) 8642 // 4. h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 8643 // 5. h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 8644 // 6. h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 8645 // 7. Use \ to escape special characters if needing to match verbatim 8646 func (ps *PUBSUB) PubSubChannels(pattern string) (valChannels []string, err error) { 8647 // get new xray segment for tracing 8648 seg := xray.NewSegmentNullable("Redis-PubSubChannels", ps.core._parentSegment) 8649 8650 if seg != nil { 8651 defer seg.Close() 8652 defer func() { 8653 _ = seg.Seg.AddMetadata("Redis-PubSubChannels-Pattern", pattern) 8654 _ = seg.Seg.AddMetadata("Redis-PubSubChannels-Result", valChannels) 8655 8656 if err != nil { 8657 _ = seg.Seg.AddError(err) 8658 } 8659 }() 8660 8661 valChannels, err = ps.pubSubChannelsInternal(pattern) 8662 return valChannels, err 8663 } else { 8664 return ps.pubSubChannelsInternal(pattern) 8665 } 8666 } 8667 8668 // pubSubChannelsInternal lists currently active channels, 8669 // active channel = pub/sub channel with one or more subscribers (excluding clients subscribed to patterns), 8670 // pattern = optional, channels matching specific glob-style pattern are listed; otherwise, all channels listed 8671 // 8672 // glob-style patterns: 8673 // 1. h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 8674 // 2. h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 8675 // 3. h*llo = * represents any single or more char match (hllo, heeeelo match) 8676 // 4. h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 8677 // 5. h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 8678 // 6. h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 8679 // 7. Use \ to escape special characters if needing to match verbatim 8680 func (ps *PUBSUB) pubSubChannelsInternal(pattern string) (valChannels []string, err error) { 8681 // validate 8682 if ps.core == nil { 8683 return nil, errors.New("Redis PubSubChannels Failed: " + "Base is Nil") 8684 } 8685 8686 if !ps.core.cnAreReady { 8687 return nil, errors.New("Redis PubSubChannels Failed: " + "Endpoint Connections Not Ready") 8688 } 8689 8690 cmd := ps.core.cnReader.PubSubChannels(ps.core.cnReader.Context(), pattern) 8691 valChannels, _, err = ps.core.handleStringSliceCmd(cmd, "Redis PubSubChannels Failed: ") 8692 return valChannels, err 8693 } 8694 8695 // PubSubNumPat (Pub/Sub Number of Patterns) returns the number of subscriptions to patterns (that were using PSubscribe Command), 8696 // This counts both clients subscribed to patterns, and also total number of patterns all the clients are subscribed to 8697 func (ps *PUBSUB) PubSubNumPat() (valPatterns int64, err error) { 8698 // get new xray segment for tracing 8699 seg := xray.NewSegmentNullable("Redis-PubSubNumPat", ps.core._parentSegment) 8700 8701 if seg != nil { 8702 defer seg.Close() 8703 defer func() { 8704 _ = seg.Seg.AddMetadata("Redis-PubSubNumPat-Result", valPatterns) 8705 8706 if err != nil { 8707 _ = seg.Seg.AddError(err) 8708 } 8709 }() 8710 8711 valPatterns, err = ps.pubSubNumPatInternal() 8712 return valPatterns, err 8713 } else { 8714 return ps.pubSubNumPatInternal() 8715 } 8716 } 8717 8718 // pubSubNumPatInternal (Pub/Sub Number of Patterns) returns the number of subscriptions to patterns (that were using PSubscribe Command), 8719 // This counts both clients subscribed to patterns, and also total number of patterns all the clients are subscribed to 8720 func (ps *PUBSUB) pubSubNumPatInternal() (valPatterns int64, err error) { 8721 // validate 8722 if ps.core == nil { 8723 return 0, errors.New("Redis PubSubNumPat Failed: " + "Base is Nil") 8724 } 8725 8726 if !ps.core.cnAreReady { 8727 return 0, errors.New("Redis PubSubNumPat Failed: " + "Endpoint Connections Not Ready") 8728 } 8729 8730 cmd := ps.core.cnReader.PubSubNumPat(ps.core.cnReader.Context()) 8731 valPatterns, _, err = ps.core.handleIntCmd(cmd, "Redis PubSubNumPat Failed: ") 8732 return valPatterns, err 8733 } 8734 8735 // PubSubNumSub (Pub/Sub Number of Subscribers) returns number of subscribers (not counting clients subscribed to patterns) for the specific channels 8736 func (ps *PUBSUB) PubSubNumSub(channel ...string) (val map[string]int64, err error) { 8737 // get new xray segment for tracing 8738 seg := xray.NewSegmentNullable("Redis-PubSubNumSub", ps.core._parentSegment) 8739 8740 if seg != nil { 8741 defer seg.Close() 8742 defer func() { 8743 _ = seg.Seg.AddMetadata("Redis-PubSubNumSub-Channels", channel) 8744 _ = seg.Seg.AddMetadata("Redis-PubSubNumSub-Result", val) 8745 8746 if err != nil { 8747 _ = seg.Seg.AddError(err) 8748 } 8749 }() 8750 8751 val, err = ps.pubSubNumSubInternal(channel...) 8752 return val, err 8753 } else { 8754 return ps.pubSubNumSubInternal(channel...) 8755 } 8756 } 8757 8758 // pubSubNumSubInternal (Pub/Sub Number of Subscribers) returns number of subscribers (not counting clients subscribed to patterns) for the specific channels 8759 func (ps *PUBSUB) pubSubNumSubInternal(channel ...string) (val map[string]int64, err error) { 8760 // validate 8761 if ps.core == nil { 8762 return nil, errors.New("Redis PubSubNumSub Failed: " + "Base is Nil") 8763 } 8764 8765 if !ps.core.cnAreReady { 8766 return nil, errors.New("Redis PubSubNumSub Failed: " + "Endpoint Connections Not Ready") 8767 } 8768 8769 cmd := ps.core.cnReader.PubSubNumSub(ps.core.cnReader.Context(), channel...) 8770 val, _, err = ps.core.handleStringIntMapCmd(cmd, "Redis PubSubNumSub Failed: ") 8771 return val, err 8772 } 8773 8774 // ---------------------------------------------------------------------------------------------------------------- 8775 // PIPELINE functions 8776 // ---------------------------------------------------------------------------------------------------------------- 8777 8778 // 8779 // *** REDIS PIPELINING INTRODUCTION = https://redis.io/topics/pipelining *** 8780 // 8781 8782 // Pipeline allows actions against redis to be handled in a batched fashion 8783 func (p *PIPELINE) Pipeline() (result redis.Pipeliner, err error) { 8784 // get new xray segment for tracing 8785 seg := xray.NewSegmentNullable("Redis-Pipeline", p.core._parentSegment) 8786 8787 if seg != nil { 8788 defer seg.Close() 8789 defer func() { 8790 _ = seg.Seg.AddMetadata("Redis-Pipeline-Result", result) 8791 8792 if err != nil { 8793 _ = seg.Seg.AddError(err) 8794 } 8795 }() 8796 8797 result, err = p.pipelineInternal() 8798 return result, err 8799 } else { 8800 return p.pipelineInternal() 8801 } 8802 } 8803 8804 // pipelineInternal allows actions against redis to be handled in a batched fashion 8805 func (p *PIPELINE) pipelineInternal() (redis.Pipeliner, error) { 8806 // validate 8807 if p.core == nil { 8808 return nil, errors.New("Redis Pipeline Failed: " + "Base is Nil") 8809 } 8810 8811 if !p.core.cnAreReady { 8812 return nil, errors.New("Redis Pipeline Failed: " + "Endpoint Connections Not Ready") 8813 } 8814 8815 return p.core.cnWriter.Pipeline(), nil 8816 } 8817 8818 // Pipelined allows actions against redis to be handled in a batched fashion 8819 func (p *PIPELINE) Pipelined(fn func(redis.Pipeliner) error) (result []redis.Cmder, err error) { 8820 // get new xray segment for tracing 8821 seg := xray.NewSegmentNullable("Redis-Pipelined", p.core._parentSegment) 8822 8823 if seg != nil { 8824 defer seg.Close() 8825 defer func() { 8826 _ = seg.Seg.AddMetadata("Redis-Pipelined-Result", result) 8827 8828 if err != nil { 8829 _ = seg.Seg.AddError(err) 8830 } 8831 }() 8832 8833 result, err = p.pipelinedInternal(fn) 8834 return result, err 8835 } else { 8836 return p.pipelinedInternal(fn) 8837 } 8838 } 8839 8840 // pipelinedInternal allows actions against redis to be handled in a batched fashion 8841 func (p *PIPELINE) pipelinedInternal(fn func(redis.Pipeliner) error) ([]redis.Cmder, error) { 8842 // validate 8843 if p.core == nil { 8844 return nil, errors.New("Redis Pipelined Failed: " + "Base is Nil") 8845 } 8846 8847 if !p.core.cnAreReady { 8848 return nil, errors.New("Redis Pipelined Failed: " + "Endpoint Connections Not Ready") 8849 } 8850 8851 return p.core.cnWriter.Pipelined(p.core.cnWriter.Context(), fn) 8852 } 8853 8854 // TxPipeline allows actions against redis to be handled in a batched fashion 8855 func (p *PIPELINE) TxPipeline() (result redis.Pipeliner, err error) { 8856 // get new xray segment for tracing 8857 seg := xray.NewSegmentNullable("Redis-TxPipeline", p.core._parentSegment) 8858 8859 if seg != nil { 8860 defer seg.Close() 8861 defer func() { 8862 _ = seg.Seg.AddMetadata("Redis-TxPipeline-Result", result) 8863 8864 if err != nil { 8865 _ = seg.Seg.AddError(err) 8866 } 8867 }() 8868 8869 result, err = p.txPipelineInternal() 8870 return result, err 8871 } else { 8872 return p.txPipelineInternal() 8873 } 8874 } 8875 8876 // txPipelineInternal allows actions against redis to be handled in a batched fashion 8877 func (p *PIPELINE) txPipelineInternal() (redis.Pipeliner, error) { 8878 // validate 8879 if p.core == nil { 8880 return nil, errors.New("Redis TxPipeline Failed: " + "Base is Nil") 8881 } 8882 8883 if !p.core.cnAreReady { 8884 return nil, errors.New("Redis TxPipeline Failed: " + "Endpoint Connections Not Ready") 8885 } 8886 8887 return p.core.cnWriter.TxPipeline(), nil 8888 } 8889 8890 // TxPipelined allows actions against redis to be handled in a batched fashion 8891 func (p *PIPELINE) TxPipelined(fn func(redis.Pipeliner) error) (result []redis.Cmder, err error) { 8892 // get new xray segment for tracing 8893 seg := xray.NewSegmentNullable("Redis-TxPipelined", p.core._parentSegment) 8894 8895 if seg != nil { 8896 defer seg.Close() 8897 defer func() { 8898 _ = seg.Seg.AddMetadata("Redis-TxPipelined-Result", result) 8899 8900 if err != nil { 8901 _ = seg.Seg.AddError(err) 8902 } 8903 }() 8904 8905 result, err = p.txPipelinedInternal(fn) 8906 return result, err 8907 } else { 8908 return p.txPipelinedInternal(fn) 8909 } 8910 } 8911 8912 // txPipelinedInternal allows actions against redis to be handled in a batched fashion 8913 func (p *PIPELINE) txPipelinedInternal(fn func(redis.Pipeliner) error) ([]redis.Cmder, error) { 8914 // validate 8915 if p.core == nil { 8916 return nil, errors.New("Redis TxPipelined Failed: " + "Base is Nil") 8917 } 8918 8919 if !p.core.cnAreReady { 8920 return nil, errors.New("Redis TxPipelined Failed: " + "Endpoint Connections Not Ready") 8921 } 8922 8923 return p.core.cnWriter.TxPipelined(p.core.cnWriter.Context(), fn) 8924 } 8925 8926 // ---------------------------------------------------------------------------------------------------------------- 8927 // TTL functions 8928 // ---------------------------------------------------------------------------------------------------------------- 8929 8930 // TTL returns the remainder time to live in seconds or milliseconds, for key that has a TTL set, 8931 // returns -1 if no TTL applicable (forever living) 8932 func (t *TTL) TTL(key string, bGetMilliseconds bool) (valTTL int64, notFound bool, err error) { 8933 // get new xray segment for tracing 8934 seg := xray.NewSegmentNullable("Redis-TTL", t.core._parentSegment) 8935 8936 if seg != nil { 8937 defer seg.Close() 8938 defer func() { 8939 _ = seg.Seg.AddMetadata("Redis-TTL-Key", key) 8940 _ = seg.Seg.AddMetadata("Redis-TTL-Not-Found", notFound) 8941 8942 if bGetMilliseconds { 8943 _ = seg.Seg.AddMetadata("Redis-TTL-Remainder-Milliseconds", valTTL) 8944 } else { 8945 _ = seg.Seg.AddMetadata("Redis-TTL-Remainder-Seconds", valTTL) 8946 } 8947 8948 if err != nil { 8949 _ = seg.Seg.AddError(err) 8950 } 8951 }() 8952 8953 valTTL, notFound, err = t.TTL(key, bGetMilliseconds) 8954 return valTTL, notFound, err 8955 } else { 8956 return t.TTL(key, bGetMilliseconds) 8957 } 8958 } 8959 8960 // ttlInternal returns the remainder time to live in seconds or milliseconds, for key that has a TTL set, 8961 // returns -1 if no TTL applicable (forever living) 8962 func (t *TTL) ttlInternal(key string, bGetMilliseconds bool) (valTTL int64, notFound bool, err error) { 8963 // validate 8964 if t.core == nil { 8965 return 0, false, errors.New("Redis TTL Failed: " + "Base is Nil") 8966 } 8967 8968 if !t.core.cnAreReady { 8969 return 0, false, errors.New("Redis TTL Failed: " + "Endpoint Connections Not Ready") 8970 } 8971 8972 if len(key) <= 0 { 8973 return 0, false, errors.New("Redis TTL Failed: " + "Key is Required") 8974 } 8975 8976 var cmd *redis.DurationCmd 8977 8978 if bGetMilliseconds { 8979 cmd = t.core.cnReader.PTTL(t.core.cnReader.Context(), key) 8980 } else { 8981 cmd = t.core.cnReader.TTL(t.core.cnReader.Context(), key) 8982 } 8983 8984 var d time.Duration 8985 8986 d, notFound, err = t.core.handleDurationCmd(cmd, "Redis TTL Failed: ") 8987 8988 if err != nil { 8989 return 0, false, err 8990 } 8991 8992 if bGetMilliseconds { 8993 valTTL = d.Milliseconds() 8994 } else { 8995 valTTL = int64(d.Seconds()) 8996 } 8997 8998 if valTTL == -2 { 8999 // not found 9000 return 0, true, nil 9001 } else { 9002 // else 9003 return valTTL, notFound, err 9004 } 9005 } 9006 9007 // Expire sets a timeout on key (seconds or milliseconds based on input parameter) 9008 // 9009 // expireValue = in seconds or milliseconds 9010 func (t *TTL) Expire(key string, bSetMilliseconds bool, expireValue time.Duration) (err error) { 9011 // get new xray segment for tracing 9012 seg := xray.NewSegmentNullable("Redis-Expire", t.core._parentSegment) 9013 9014 if seg != nil { 9015 defer seg.Close() 9016 defer func() { 9017 _ = seg.Seg.AddMetadata("Redis-Expire-Key", key) 9018 9019 if bSetMilliseconds { 9020 _ = seg.Seg.AddMetadata("Redis-Expire-Milliseconds", expireValue.Milliseconds()) 9021 } else { 9022 _ = seg.Seg.AddMetadata("Redis-Expire-Seconds", expireValue.Seconds()) 9023 } 9024 9025 if err != nil { 9026 _ = seg.Seg.AddError(err) 9027 } 9028 }() 9029 9030 err = t.expireInternal(key, bSetMilliseconds, expireValue) 9031 return err 9032 } else { 9033 return t.expireInternal(key, bSetMilliseconds, expireValue) 9034 } 9035 } 9036 9037 // expireInternal sets a timeout on key (seconds or milliseconds based on input parameter) 9038 // 9039 // expireValue = in seconds or milliseconds 9040 func (t *TTL) expireInternal(key string, bSetMilliseconds bool, expireValue time.Duration) error { 9041 // validate 9042 if t.core == nil { 9043 return errors.New("Redis Expire Failed: " + "Base is Nil") 9044 } 9045 9046 if !t.core.cnAreReady { 9047 return errors.New("Redis Expire Failed: " + "Endpoint Connections Not Ready") 9048 } 9049 9050 if len(key) <= 0 { 9051 return errors.New("Redis Expire Failed: " + "Key is Required") 9052 } 9053 9054 if expireValue < 0 { 9055 return errors.New("Redis Expire Failed: " + "Expire Value Must Be 0 or Greater") 9056 } 9057 9058 var cmd *redis.BoolCmd 9059 9060 if bSetMilliseconds { 9061 cmd = t.core.cnWriter.PExpire(t.core.cnWriter.Context(), key, expireValue) 9062 } else { 9063 cmd = t.core.cnWriter.Expire(t.core.cnWriter.Context(), key, expireValue) 9064 } 9065 9066 if val, err := t.core.handleBoolCmd(cmd, "Redis Expire Failed: "); err != nil { 9067 return err 9068 } else { 9069 if val { 9070 // success 9071 return nil 9072 } else { 9073 // key not exist 9074 return errors.New("Redis Expire Failed: " + "Key Was Not Found") 9075 } 9076 } 9077 } 9078 9079 // ExpireAt sets the hard expiration date time based on unix timestamp for a given key 9080 // 9081 // Setting expireTime to the past immediately deletes the key 9082 func (t *TTL) ExpireAt(key string, expireTime time.Time) (err error) { 9083 // get new xray segment for tracing 9084 seg := xray.NewSegmentNullable("Redis-ExpireAt", t.core._parentSegment) 9085 9086 if seg != nil { 9087 defer seg.Close() 9088 defer func() { 9089 _ = seg.Seg.AddMetadata("Redis-ExpireAt-Key", key) 9090 _ = seg.Seg.AddMetadata("Redis-ExpireAt-Expire-Time", expireTime) 9091 9092 if err != nil { 9093 _ = seg.Seg.AddError(err) 9094 } 9095 }() 9096 9097 err = t.expireAtInternal(key, expireTime) 9098 return err 9099 } else { 9100 return t.expireAtInternal(key, expireTime) 9101 } 9102 } 9103 9104 // expireAtInternal sets the hard expiration date time based on unix timestamp for a given key 9105 // 9106 // Setting expireTime to the past immediately deletes the key 9107 func (t *TTL) expireAtInternal(key string, expireTime time.Time) error { 9108 // validate 9109 if t.core == nil { 9110 return errors.New("Redis ExpireAt Failed: " + "Base is Nil") 9111 } 9112 9113 if !t.core.cnAreReady { 9114 return errors.New("Redis ExpireAt Failed: " + "Endpoint Connections Not Ready") 9115 } 9116 9117 if len(key) <= 0 { 9118 return errors.New("Redis ExpireAt Failed: " + "Key is Required") 9119 } 9120 9121 if expireTime.IsZero() { 9122 return errors.New("Redis ExpireAt Failed: " + "Expire Time is Required") 9123 } 9124 9125 cmd := t.core.cnWriter.ExpireAt(t.core.cnWriter.Context(), key, expireTime) 9126 9127 if val, err := t.core.handleBoolCmd(cmd, "Redis ExpireAt Failed: "); err != nil { 9128 return err 9129 } else { 9130 if val { 9131 // success 9132 return nil 9133 } else { 9134 // fail 9135 return errors.New("Redis ExpireAt Failed: " + "Key Was Not Found") 9136 } 9137 } 9138 } 9139 9140 // Touch alters the last access time of a key or keys, 9141 // if key doesn't exist, it is ignored 9142 func (t *TTL) Touch(key ...string) (err error) { 9143 // get new xray segment for tracing 9144 seg := xray.NewSegmentNullable("Redis-Touch", t.core._parentSegment) 9145 9146 if seg != nil { 9147 defer seg.Close() 9148 defer func() { 9149 _ = seg.Seg.AddMetadata("Redis-Touch-Keys", key) 9150 9151 if err != nil { 9152 _ = seg.Seg.AddError(err) 9153 } 9154 }() 9155 9156 err = t.touchInternal(key...) 9157 return err 9158 } else { 9159 return t.touchInternal(key...) 9160 } 9161 } 9162 9163 // touchInternal alters the last access time of a key or keys, 9164 // if key doesn't exist, it is ignored 9165 func (t *TTL) touchInternal(key ...string) error { 9166 // validate 9167 if t.core == nil { 9168 return errors.New("Redis Touch Failed: " + "Base is Nil") 9169 } 9170 9171 if !t.core.cnAreReady { 9172 return errors.New("Redis Touch Failed: " + "Endpoint Connections Not Ready") 9173 } 9174 9175 if len(key) <= 0 { 9176 return errors.New("Redis Touch Failed: " + "At Least 1 Key is Required") 9177 } 9178 9179 cmd := t.core.cnWriter.Touch(t.core.cnWriter.Context(), key...) 9180 9181 if val, _, err := t.core.handleIntCmd(cmd, "Redis Touch Failed: "); err != nil { 9182 return err 9183 } else { 9184 if val > 0 { 9185 // success 9186 return nil 9187 } else { 9188 // fail 9189 return errors.New("Redis Touch Failed: " + "All Keys in Param Not Found") 9190 } 9191 } 9192 } 9193 9194 // Persist removes existing timeout TTL of a key so it lives forever 9195 func (t *TTL) Persist(key string) (err error) { 9196 // get new xray segment for tracing 9197 seg := xray.NewSegmentNullable("Redis-Persist", t.core._parentSegment) 9198 9199 if seg != nil { 9200 defer seg.Close() 9201 defer func() { 9202 _ = seg.Seg.AddMetadata("Redis-Persist-Key", key) 9203 9204 if err != nil { 9205 _ = seg.Seg.AddError(err) 9206 } 9207 }() 9208 9209 err = t.persistInternal(key) 9210 return err 9211 } else { 9212 return t.persistInternal(key) 9213 } 9214 } 9215 9216 // persistInternal removes existing timeout TTL of a key so it lives forever 9217 func (t *TTL) persistInternal(key string) error { 9218 // validate 9219 if t.core == nil { 9220 return errors.New("Redis Persist Failed: " + "Base is Nil") 9221 } 9222 9223 if !t.core.cnAreReady { 9224 return errors.New("Redis Persist Failed: " + "Endpoint Connections Not Ready") 9225 } 9226 9227 if len(key) <= 0 { 9228 return errors.New("Redis Persist Failed: " + "Key is Required") 9229 } 9230 9231 cmd := t.core.cnWriter.Persist(t.core.cnWriter.Context(), key) 9232 9233 if val, err := t.core.handleBoolCmd(cmd, "Redis Persist Failed: "); err != nil { 9234 return err 9235 } else { 9236 if val { 9237 // success 9238 return nil 9239 } else { 9240 // fail 9241 return errors.New("Redis Persist Failed: " + "Key Was Not Found") 9242 } 9243 } 9244 } 9245 9246 // ---------------------------------------------------------------------------------------------------------------- 9247 // UTILS functions 9248 // ---------------------------------------------------------------------------------------------------------------- 9249 9250 // Ping will ping the redis server to see if its up 9251 // 9252 // result nil = success; otherwise error info is returned via error object 9253 func (u *UTILS) Ping() (err error) { 9254 // get new xray segment for tracing 9255 seg := xray.NewSegmentNullable("Redis-Ping", u.core._parentSegment) 9256 9257 if seg != nil { 9258 defer seg.Close() 9259 defer func() { 9260 if err != nil { 9261 _ = seg.Seg.AddError(err) 9262 } 9263 }() 9264 9265 err = u.pingInternal() 9266 return err 9267 } else { 9268 return u.pingInternal() 9269 } 9270 } 9271 9272 // pingInternal will ping the redis server to see if its up 9273 // 9274 // result nil = success; otherwise error info is returned via error object 9275 func (u *UTILS) pingInternal() error { 9276 // validate 9277 if u.core == nil { 9278 return errors.New("Redis Ping Failed: " + "Base is Nil") 9279 } 9280 9281 if !u.core.cnAreReady { 9282 return errors.New("Redis Ping Failed: " + "Endpoint Connections Not Ready") 9283 } 9284 9285 cmd := u.core.cnReader.Ping(u.core.cnReader.Context()) 9286 return u.core.handleStatusCmd(cmd, "Redis Ping Failed: ") 9287 } 9288 9289 // DBSize returns number of keys in the redis database 9290 func (u *UTILS) DBSize() (val int64, err error) { 9291 // get new xray segment for tracing 9292 seg := xray.NewSegmentNullable("Redis-DBSize", u.core._parentSegment) 9293 9294 if seg != nil { 9295 defer seg.Close() 9296 defer func() { 9297 _ = seg.Seg.AddMetadata("Redis-DBSize-Result", val) 9298 9299 if err != nil { 9300 _ = seg.Seg.AddError(err) 9301 } 9302 }() 9303 9304 val, err = u.dbSizeInternal() 9305 return val, err 9306 } else { 9307 return u.dbSizeInternal() 9308 } 9309 } 9310 9311 // dbSizeInternal returns number of keys in the redis database 9312 func (u *UTILS) dbSizeInternal() (val int64, err error) { 9313 // validate 9314 if u.core == nil { 9315 return 0, errors.New("Redis DBSize Failed: " + "Base is Nil") 9316 } 9317 9318 if !u.core.cnAreReady { 9319 return 0, errors.New("Redis DBSize Failed: " + "Endpoint Connections Not Ready") 9320 } 9321 9322 cmd := u.core.cnReader.DBSize(u.core.cnReader.Context()) 9323 val, _, err = u.core.handleIntCmd(cmd, "Redis DBSize Failed: ") 9324 return val, err 9325 } 9326 9327 // Time returns the redis server time 9328 func (u *UTILS) Time() (val time.Time, err error) { 9329 // get new xray segment for tracing 9330 seg := xray.NewSegmentNullable("Redis-Time", u.core._parentSegment) 9331 9332 if seg != nil { 9333 defer seg.Close() 9334 defer func() { 9335 _ = seg.Seg.AddMetadata("Redis-Time-Result", val) 9336 9337 if err != nil { 9338 _ = seg.Seg.AddError(err) 9339 } 9340 }() 9341 9342 val, err = u.timeInternal() 9343 return val, err 9344 } else { 9345 return u.timeInternal() 9346 } 9347 } 9348 9349 // timeInternal returns the redis server time 9350 func (u *UTILS) timeInternal() (val time.Time, err error) { 9351 // validate 9352 if u.core == nil { 9353 return time.Time{}, errors.New("Redis Time Failed: " + "Base is Nil") 9354 } 9355 9356 if !u.core.cnAreReady { 9357 return time.Time{}, errors.New("Redis Time Failed: " + "Endpoint Connections Not Ready") 9358 } 9359 9360 cmd := u.core.cnReader.Time(u.core.cnReader.Context()) 9361 val, _, err = u.core.handleTimeCmd(cmd, "Redis Time Failed: ") 9362 return val, err 9363 } 9364 9365 // LastSave checks if last db save action was successful 9366 func (u *UTILS) LastSave() (val time.Time, err error) { 9367 // get new xray segment for tracing 9368 seg := xray.NewSegmentNullable("Redis-LastSave", u.core._parentSegment) 9369 9370 if seg != nil { 9371 defer seg.Close() 9372 defer func() { 9373 _ = seg.Seg.AddMetadata("Redis-LastSave-Result", val) 9374 9375 if err != nil { 9376 _ = seg.Seg.AddError(err) 9377 } 9378 }() 9379 9380 val, err = u.lastSaveInternal() 9381 return val, err 9382 } else { 9383 return u.lastSaveInternal() 9384 } 9385 } 9386 9387 // lastSaveInternal checks if last db save action was successful 9388 func (u *UTILS) lastSaveInternal() (val time.Time, err error) { 9389 // validate 9390 if u.core == nil { 9391 return time.Time{}, errors.New("Redis LastSave Failed: " + "Base is Nil") 9392 } 9393 9394 if !u.core.cnAreReady { 9395 return time.Time{}, errors.New("Redis LastSave Failed: " + "Endpoint Connections Not Ready") 9396 } 9397 9398 cmd := u.core.cnReader.LastSave(u.core.cnReader.Context()) 9399 v, _, e := u.core.handleIntCmd(cmd, "Redis LastSave Failed: ") 9400 9401 if e != nil { 9402 return time.Time{}, e 9403 } else { 9404 return time.Unix(v, 0), nil 9405 } 9406 } 9407 9408 // Type returns the redis key's value type stored 9409 // expected result in string = list, set, zset, hash, and stream 9410 func (u *UTILS) Type(key string) (val rediskeytype.RedisKeyType, err error) { 9411 // get new xray segment for tracing 9412 seg := xray.NewSegmentNullable("Redis-Type", u.core._parentSegment) 9413 9414 if seg != nil { 9415 defer seg.Close() 9416 defer func() { 9417 _ = seg.Seg.AddMetadata("Redis-Type-Key", key) 9418 _ = seg.Seg.AddMetadata("Redis-Type-Result", val) 9419 9420 if err != nil { 9421 _ = seg.Seg.AddError(err) 9422 } 9423 }() 9424 9425 val, err = u.typeInternal(key) 9426 return val, err 9427 } else { 9428 return u.typeInternal(key) 9429 } 9430 } 9431 9432 // typeInternal returns the redis key's value type stored 9433 // expected result in string = list, set, zset, hash, and stream 9434 func (u *UTILS) typeInternal(key string) (val rediskeytype.RedisKeyType, err error) { 9435 // validate 9436 if u.core == nil { 9437 return rediskeytype.UNKNOWN, errors.New("Redis Type Failed: " + "Base is Nil") 9438 } 9439 9440 if !u.core.cnAreReady { 9441 return rediskeytype.UNKNOWN, errors.New("Redis Type Failed: " + "Endpoint Connections Not Ready") 9442 } 9443 9444 if len(key) <= 0 { 9445 return rediskeytype.UNKNOWN, errors.New("Redis Type Failed: " + "Key is Required") 9446 } 9447 9448 cmd := u.core.cnReader.Type(u.core.cnReader.Context(), key) 9449 9450 if v, _, e := u.core.handleStringStatusCmd(cmd, "Redis Type Failed: "); e != nil { 9451 return rediskeytype.UNKNOWN, e 9452 } else { 9453 switch strings.ToUpper(v) { 9454 case "STRING": 9455 return rediskeytype.String, nil 9456 case "LIST": 9457 return rediskeytype.List, nil 9458 case "SET": 9459 return rediskeytype.Set, nil 9460 case "ZSET": 9461 return rediskeytype.ZSet, nil 9462 case "HASH": 9463 return rediskeytype.Hash, nil 9464 case "STREAM": 9465 return rediskeytype.Stream, nil 9466 default: 9467 return rediskeytype.UNKNOWN, errors.New("Redis Type Failed: " + "Type '" + v + "' Not Expected Value") 9468 } 9469 } 9470 } 9471 9472 // ObjectEncoding returns the internal representation used in order to store the value associated with a key 9473 func (u *UTILS) ObjectEncoding(key string) (val string, notFound bool, err error) { 9474 // get new xray segment for tracing 9475 seg := xray.NewSegmentNullable("Redis-ObjectEncoding", u.core._parentSegment) 9476 9477 if seg != nil { 9478 defer seg.Close() 9479 defer func() { 9480 _ = seg.Seg.AddMetadata("Redis-ObjectEncoding-Key", key) 9481 _ = seg.Seg.AddMetadata("Redis-ObjectEncoding-Not-Found", notFound) 9482 _ = seg.Seg.AddMetadata("Redis-ObjectEncoding-Result", val) 9483 9484 if err != nil { 9485 _ = seg.Seg.AddError(err) 9486 } 9487 }() 9488 9489 val, notFound, err = u.objectEncodingInternal(key) 9490 return val, notFound, err 9491 } else { 9492 return u.objectEncodingInternal(key) 9493 } 9494 } 9495 9496 // objectEncodingInternal returns the internal representation used in order to store the value associated with a key 9497 func (u *UTILS) objectEncodingInternal(key string) (val string, notFound bool, err error) { 9498 // validate 9499 if u.core == nil { 9500 return "", false, errors.New("Redis ObjectEncoding Failed: " + "Base is Nil") 9501 } 9502 9503 if !u.core.cnAreReady { 9504 return "", false, errors.New("Redis ObjectEncoding Failed: " + "Endpoint Connections Not Ready") 9505 } 9506 9507 if len(key) <= 0 { 9508 return "", false, errors.New("Redis ObjectEncoding Failed: " + "Key is Required") 9509 } 9510 9511 cmd := u.core.cnReader.ObjectEncoding(u.core.cnReader.Context(), key) 9512 return u.core.handleStringCmd2(cmd, "Redis ObjectEncoding Failed: ") 9513 } 9514 9515 // ObjectIdleTime returns the number of seconds since the object stored at the specified key is idle (not requested by read or write operations) 9516 func (u *UTILS) ObjectIdleTime(key string) (val time.Duration, notFound bool, err error) { 9517 // get new xray segment for tracing 9518 seg := xray.NewSegmentNullable("Redis-ObjectIdleTime", u.core._parentSegment) 9519 9520 if seg != nil { 9521 defer seg.Close() 9522 defer func() { 9523 _ = seg.Seg.AddMetadata("Redis-ObjectIdleTime-Key", key) 9524 _ = seg.Seg.AddMetadata("Redis-ObjectIdleTime-Not-Found", notFound) 9525 _ = seg.Seg.AddMetadata("Redis-ObjectIdleTime-Result-Seconds", val.Seconds()) 9526 9527 if err != nil { 9528 _ = seg.Seg.AddError(err) 9529 } 9530 }() 9531 9532 val, notFound, err = u.objectIdleTimeInternal(key) 9533 return val, notFound, err 9534 } else { 9535 return u.objectIdleTimeInternal(key) 9536 } 9537 } 9538 9539 // objectIdleTimeInternal returns the number of seconds since the object stored at the specified key is idle (not requested by read or write operations) 9540 func (u *UTILS) objectIdleTimeInternal(key string) (val time.Duration, notFound bool, err error) { 9541 // validate 9542 if u.core == nil { 9543 return 0, false, errors.New("Redis ObjectIdleTime Failed: " + "Base is Nil") 9544 } 9545 9546 if !u.core.cnAreReady { 9547 return 0, false, errors.New("Redis ObjectIdleTime Failed: " + "Endpoint Connections Not Ready") 9548 } 9549 9550 if len(key) <= 0 { 9551 return 0, false, errors.New("Redis ObjectIdleTime Failed: " + "Key is Required") 9552 } 9553 9554 cmd := u.core.cnReader.ObjectIdleTime(u.core.cnReader.Context(), key) 9555 return u.core.handleDurationCmd(cmd, "Redis ObjectIdleTime Failed: ") 9556 } 9557 9558 // ObjectRefCount returns the number of references of the value associated with the specified key 9559 func (u *UTILS) ObjectRefCount(key string) (val int64, notFound bool, err error) { 9560 // get new xray segment for tracing 9561 seg := xray.NewSegmentNullable("Redis-ObjectRefCount", u.core._parentSegment) 9562 9563 if seg != nil { 9564 defer seg.Close() 9565 defer func() { 9566 _ = seg.Seg.AddMetadata("Redis-ObjectRefCount-Key", key) 9567 _ = seg.Seg.AddMetadata("Redis-ObjectRefCount-Not-Found", notFound) 9568 _ = seg.Seg.AddMetadata("Redis-ObjectRefCount-Result", val) 9569 9570 if err != nil { 9571 _ = seg.Seg.AddError(err) 9572 } 9573 }() 9574 9575 val, notFound, err = u.objectRefCountInternal(key) 9576 return val, notFound, err 9577 } else { 9578 return u.objectRefCountInternal(key) 9579 } 9580 } 9581 9582 // objectRefCountInternal returns the number of references of the value associated with the specified key 9583 func (u *UTILS) objectRefCountInternal(key string) (val int64, notFound bool, err error) { 9584 // validate 9585 if u.core == nil { 9586 return 0, false, errors.New("Redis ObjectRefCount Failed: " + "Base is Nil") 9587 } 9588 9589 if !u.core.cnAreReady { 9590 return 0, false, errors.New("Redis ObjectRefCount Failed: " + "Endpoint Connections Not Ready") 9591 } 9592 9593 if len(key) <= 0 { 9594 return 0, false, errors.New("Redis ObjectRefCount Failed: " + "Key is Required") 9595 } 9596 9597 cmd := u.core.cnReader.ObjectRefCount(u.core.cnReader.Context(), key) 9598 return u.core.handleIntCmd(cmd, "Redis ObjectRefCount: ") 9599 } 9600 9601 // Scan is used to incrementally iterate over a set of keys, 9602 // Scan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 9603 // 9604 // start iteration = cursor set to 0 9605 // stop iteration = when redis returns cursor value of 0 9606 // 9607 // match = filters elements based on match filter, for elements retrieved from redis before return to client 9608 // 9609 // glob-style patterns: 9610 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 9611 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 9612 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 9613 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 9614 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 9615 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 9616 // 7) Use \ to escape special characters if needing to match verbatim 9617 // 9618 // count = hint to redis count of elements to retrieve in the call 9619 func (u *UTILS) Scan(cursor uint64, match string, count int64) (keys []string, resultCursor uint64, err error) { 9620 // get new xray segment for tracing 9621 seg := xray.NewSegmentNullable("Redis-Scan", u.core._parentSegment) 9622 9623 if seg != nil { 9624 defer seg.Close() 9625 defer func() { 9626 _ = seg.Seg.AddMetadata("Redis-Scan-Match", match) 9627 _ = seg.Seg.AddMetadata("Redis-Scan-Scan-Cursor", cursor) 9628 _ = seg.Seg.AddMetadata("Redis-Scan-Scan-Count", count) 9629 _ = seg.Seg.AddMetadata("Redis-Scan-Result-Cursor", resultCursor) 9630 _ = seg.Seg.AddMetadata("Redis-Scan-Keys-Found", keys) 9631 9632 if err != nil { 9633 _ = seg.Seg.AddError(err) 9634 } 9635 }() 9636 9637 keys, resultCursor, err = u.scanInternal(cursor, match, count) 9638 return keys, resultCursor, err 9639 } else { 9640 return u.scanInternal(cursor, match, count) 9641 } 9642 } 9643 9644 // scanInternal is used to incrementally iterate over a set of keys, 9645 // Scan is a cursor based iterator, at every call of the command, redis returns an updated cursor that client must use for next call to sort, 9646 // 9647 // start iteration = cursor set to 0 9648 // stop iteration = when redis returns cursor value of 0 9649 // 9650 // match = filters elements based on match filter, for elements retrieved from redis before return to client 9651 // 9652 // glob-style patterns: 9653 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 9654 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 9655 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 9656 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 9657 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 9658 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 9659 // 7) Use \ to escape special characters if needing to match verbatim 9660 // 9661 // count = hint to redis count of elements to retrieve in the call 9662 func (u *UTILS) scanInternal(cursor uint64, match string, count int64) (keys []string, resultCursor uint64, err error) { 9663 // validate 9664 if u.core == nil { 9665 return nil, 0, errors.New("Redis Scan Failed: " + "Base is Nil") 9666 } 9667 9668 if !u.core.cnAreReady { 9669 return nil, 0, errors.New("Redis Scan Failed: " + "Endpoint Connections Not Ready") 9670 } 9671 9672 cmd := u.core.cnReader.Scan(u.core.cnReader.Context(), cursor, match, count) 9673 return u.core.handleScanCmd(cmd, "Redis Scan Failed: ") 9674 } 9675 9676 // Keys returns all keys matching given pattern (use with extreme care, use for debugging only, may slow production system down significantly) 9677 // 9678 // start iteration = cursor set to 0 9679 // stop iteration = when redis returns cursor value of 0 9680 // 9681 // match = filters elements based on match filter, for elements retrieved from redis before return to client 9682 // 9683 // glob-style patterns: 9684 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 9685 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 9686 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 9687 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 9688 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 9689 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 9690 // 7) Use \ to escape special characters if needing to match verbatim 9691 func (u *UTILS) Keys(match string) (valKeys []string, notFound bool, err error) { 9692 // get new xray segment for tracing 9693 seg := xray.NewSegmentNullable("Redis-Keys", u.core._parentSegment) 9694 9695 if seg != nil { 9696 defer seg.Close() 9697 defer func() { 9698 _ = seg.Seg.AddMetadata("Redis-Keys-Match", match) 9699 _ = seg.Seg.AddMetadata("Redis-Keys-Not-Found", notFound) 9700 _ = seg.Seg.AddMetadata("Redis-Keys-Keys-Found", valKeys) 9701 9702 if err != nil { 9703 _ = seg.Seg.AddError(err) 9704 } 9705 }() 9706 9707 valKeys, notFound, err = u.keysInternal(match) 9708 return valKeys, notFound, err 9709 } else { 9710 return u.keysInternal(match) 9711 } 9712 } 9713 9714 // keysInternal returns all keys matching given pattern (use with extreme care, use for debugging only, may slow production system down significantly) 9715 // 9716 // start iteration = cursor set to 0 9717 // stop iteration = when redis returns cursor value of 0 9718 // 9719 // match = filters elements based on match filter, for elements retrieved from redis before return to client 9720 // 9721 // glob-style patterns: 9722 // 1) h?llo = ? represents any single char match (hello, hallo, hxllo match, but heello not match) 9723 // 2) h??llo = ?? represents any two char match (heello, haello, hxyllo match, but heeello not match) 9724 // 3) h*llo = * represents any single or more char match (hllo, heeeelo match) 9725 // 4) h[ae]llo = [ae] represents char inside [ ] that are to match (hello, hallo match, but hillo not match) 9726 // 5) h[^e]llo = [^e] represents any char other than e to match (hallo, hbllo match, but hello not match) 9727 // 6) h[a-b]llo = [a-b] represents any char match between the a-b range (hallo, hbllo match, but hcllo not match) 9728 // 7) Use \ to escape special characters if needing to match verbatim 9729 func (u *UTILS) keysInternal(match string) (valKeys []string, notFound bool, err error) { 9730 // validate 9731 if u.core == nil { 9732 return nil, false, errors.New("Redis Keys Failed: " + "Base is Nil") 9733 } 9734 9735 if !u.core.cnAreReady { 9736 return nil, false, errors.New("Redis Keys Failed: " + "Endpoint Connections Not Ready") 9737 } 9738 9739 if len(match) <= 0 { 9740 return nil, false, errors.New("Redis Keys Failed: " + "Match is Required") 9741 } 9742 9743 cmd := u.core.cnReader.Keys(u.core.cnReader.Context(), match) 9744 return u.core.handleStringSliceCmd(cmd, "Redis Keys Failed: ") 9745 } 9746 9747 // RandomKey returns a random key from redis 9748 func (u *UTILS) RandomKey() (val string, err error) { 9749 // get new xray segment for tracing 9750 seg := xray.NewSegmentNullable("Redis-RandomKey", u.core._parentSegment) 9751 9752 if seg != nil { 9753 defer seg.Close() 9754 defer func() { 9755 _ = seg.Seg.AddMetadata("Redis-RandomKey-Result", val) 9756 9757 if err != nil { 9758 _ = seg.Seg.AddError(err) 9759 } 9760 }() 9761 9762 val, err = u.randomKeyInternal() 9763 return val, err 9764 } else { 9765 return u.randomKeyInternal() 9766 } 9767 } 9768 9769 // randomKeyInternal returns a random key from redis 9770 func (u *UTILS) randomKeyInternal() (val string, err error) { 9771 // validate 9772 if u.core == nil { 9773 return "", errors.New("Redis RandomKey Failed: " + "Base is Nil") 9774 } 9775 9776 if !u.core.cnAreReady { 9777 return "", errors.New("Redis RandomKey Failed: " + "Endpoint Connections Not Ready") 9778 } 9779 9780 cmd := u.core.cnReader.RandomKey(u.core.cnReader.Context()) 9781 val, _, err = u.core.handleStringCmd2(cmd, "Redis RandomKey Failed: ") 9782 return val, err 9783 } 9784 9785 // Rename will rename the keyOriginal to be keyNew in redis, 9786 // if keyNew already exist in redis, then Rename will override existing keyNew with keyOriginal 9787 // if keyOriginal is not in redis, error is returned 9788 func (u *UTILS) Rename(keyOriginal string, keyNew string) (err error) { 9789 // get new xray segment for tracing 9790 seg := xray.NewSegmentNullable("Redis-Rename", u.core._parentSegment) 9791 9792 if seg != nil { 9793 defer seg.Close() 9794 defer func() { 9795 _ = seg.Seg.AddMetadata("Redis-Rename-OriginalKey", keyOriginal) 9796 _ = seg.Seg.AddMetadata("Redis-Rename-NewKey", keyNew) 9797 9798 if err != nil { 9799 _ = seg.Seg.AddError(err) 9800 } 9801 }() 9802 9803 err = u.renameInternal(keyOriginal, keyNew) 9804 return err 9805 } else { 9806 return u.renameInternal(keyOriginal, keyNew) 9807 } 9808 } 9809 9810 // renameInternal will rename the keyOriginal to be keyNew in redis, 9811 // if keyNew already exist in redis, then Rename will override existing keyNew with keyOriginal 9812 // if keyOriginal is not in redis, error is returned 9813 func (u *UTILS) renameInternal(keyOriginal string, keyNew string) error { 9814 // validate 9815 if u.core == nil { 9816 return errors.New("Redis Rename Failed: " + "Base is Nil") 9817 } 9818 9819 if !u.core.cnAreReady { 9820 return errors.New("Redis Rename Failed: " + "Endpoint Connections Not Ready") 9821 } 9822 9823 if len(keyOriginal) <= 0 { 9824 return errors.New("Redis Rename Failed: " + "Key Original is Required") 9825 } 9826 9827 if len(keyNew) <= 0 { 9828 return errors.New("Redis Rename Failed: " + "Key New is Required") 9829 } 9830 9831 cmd := u.core.cnWriter.Rename(u.core.cnWriter.Context(), keyOriginal, keyNew) 9832 return u.core.handleStatusCmd(cmd, "Redis Rename Failed: ") 9833 } 9834 9835 // RenameNX will rename the keyOriginal to be keyNew IF keyNew does not yet exist in redis 9836 // if RenameNX fails due to keyNew already exist, or other errors, the error is returned 9837 func (u *UTILS) RenameNX(keyOriginal string, keyNew string) (err error) { 9838 // get new xray segment for tracing 9839 seg := xray.NewSegmentNullable("Redis-RenameNX", u.core._parentSegment) 9840 9841 if seg != nil { 9842 defer seg.Close() 9843 defer func() { 9844 _ = seg.Seg.AddMetadata("Redis-RenameNX-OriginalKey", keyOriginal) 9845 _ = seg.Seg.AddMetadata("Redis-RenameNX-NewKey", keyNew) 9846 9847 if err != nil { 9848 _ = seg.Seg.AddError(err) 9849 } 9850 }() 9851 9852 err = u.renameInternal(keyOriginal, keyNew) 9853 return err 9854 } else { 9855 return u.renameInternal(keyOriginal, keyNew) 9856 } 9857 } 9858 9859 // renameNXInternal will rename the keyOriginal to be keyNew IF keyNew does not yet exist in redis 9860 // if RenameNX fails due to keyNew already exist, or other errors, the error is returned 9861 func (u *UTILS) renameNXInternal(keyOriginal string, keyNew string) error { 9862 // validate 9863 if u.core == nil { 9864 return errors.New("Redis RenameNX Failed: " + "Base is Nil") 9865 } 9866 9867 if !u.core.cnAreReady { 9868 return errors.New("Redis RenameNX Failed: " + "Endpoint Connections Not Ready") 9869 } 9870 9871 if len(keyOriginal) <= 0 { 9872 return errors.New("Redis RenameNX Failed: " + "Key Original is Required") 9873 } 9874 9875 if len(keyNew) <= 0 { 9876 return errors.New("Redis RenameNX Failed: " + "Key New is Required") 9877 } 9878 9879 cmd := u.core.cnWriter.RenameNX(u.core.cnWriter.Context(), keyOriginal, keyNew) 9880 if val, err := u.core.handleBoolCmd(cmd, "Redis RenameNX Failed: "); err != nil { 9881 return err 9882 } else { 9883 if val { 9884 // success 9885 return nil 9886 } else { 9887 // not success 9888 return errors.New("Redis RenameNX Failed: " + "Key Was Not Renamed") 9889 } 9890 } 9891 } 9892 9893 // Sort will sort values as defined by keyToSort, along with sortPattern, and then return the sorted data via string slice 9894 // sort is applicable to list, set, or sorted set as defined by key 9895 // 9896 // sortPattern = defines the sort conditions (see redis sort documentation for details) 9897 func (u *UTILS) Sort(key string, sortPattern *redis.Sort) (val []string, notFound bool, err error) { 9898 // get new xray segment for tracing 9899 seg := xray.NewSegmentNullable("Redis-Sort", u.core._parentSegment) 9900 9901 if seg != nil { 9902 defer seg.Close() 9903 defer func() { 9904 _ = seg.Seg.AddMetadata("Redis-Sort-Key", key) 9905 _ = seg.Seg.AddMetadata("Redis-Sort-SortPattern", sortPattern) 9906 _ = seg.Seg.AddMetadata("Redis-Sort-Not-Found", notFound) 9907 _ = seg.Seg.AddMetadata("Redis-Sort-Result", val) 9908 9909 if err != nil { 9910 _ = seg.Seg.AddError(err) 9911 } 9912 }() 9913 9914 val, notFound, err = u.sortInternal(key, sortPattern) 9915 return val, notFound, err 9916 } else { 9917 return u.sortInternal(key, sortPattern) 9918 } 9919 } 9920 9921 // sortInternal will sort values as defined by keyToSort, along with sortPattern, and then return the sorted data via string slice 9922 // sort is applicable to list, set, or sorted set as defined by key 9923 // 9924 // sortPattern = defines the sort conditions (see redis sort documentation for details) 9925 func (u *UTILS) sortInternal(key string, sortPattern *redis.Sort) (val []string, notFound bool, err error) { 9926 // validate 9927 if u.core == nil { 9928 return nil, false, errors.New("Redis Sort Failed: " + "Base is Nil") 9929 } 9930 9931 if !u.core.cnAreReady { 9932 return nil, false, errors.New("Redis Sort Failed: " + "Endpoint Connections Not Ready") 9933 } 9934 9935 if len(key) <= 0 { 9936 return nil, false, errors.New("Redis Sort Failed: " + "Key is Required") 9937 } 9938 9939 cmd := u.core.cnReader.Sort(u.core.cnReader.Context(), key, sortPattern) 9940 return u.core.handleStringSliceCmd(cmd, "Redis Sort Failed: ") 9941 } 9942 9943 // SortInterfaces will sort values as defined by keyToSort, along with sortPattern, and then return the sorted data via []interface{} 9944 // sort is applicable to list, set, or sorted set as defined by key 9945 // 9946 // sortPattern = defines the sort conditions (see redis sort documentation for details) 9947 func (u *UTILS) SortInterfaces(keyToSort string, sortPattern *redis.Sort) (val []interface{}, notFound bool, err error) { 9948 // get new xray segment for tracing 9949 seg := xray.NewSegmentNullable("Redis-SortInterfaces", u.core._parentSegment) 9950 9951 if seg != nil { 9952 defer seg.Close() 9953 defer func() { 9954 _ = seg.Seg.AddMetadata("Redis-SortInterfaces-SortKey", keyToSort) 9955 _ = seg.Seg.AddMetadata("Redis-SortInterfaces-SortPattern", sortPattern) 9956 _ = seg.Seg.AddMetadata("Redis-SortInterfaces-Not-Found", notFound) 9957 _ = seg.Seg.AddMetadata("Redis-SortInterfaces-Result", val) 9958 9959 if err != nil { 9960 _ = seg.Seg.AddError(err) 9961 } 9962 }() 9963 9964 val, notFound, err = u.sortInterfacesInternal(keyToSort, sortPattern) 9965 return val, notFound, err 9966 } else { 9967 return u.sortInterfacesInternal(keyToSort, sortPattern) 9968 } 9969 } 9970 9971 // sortInterfacesInternal will sort values as defined by keyToSort, along with sortPattern, and then return the sorted data via []interface{} 9972 // sort is applicable to list, set, or sorted set as defined by key 9973 // 9974 // sortPattern = defines the sort conditions (see redis sort documentation for details) 9975 func (u *UTILS) sortInterfacesInternal(keyToSort string, sortPattern *redis.Sort) (val []interface{}, notFound bool, err error) { 9976 // validate 9977 if u.core == nil { 9978 return nil, false, errors.New("Redis SortInterfaces Failed: " + "Base is Nil") 9979 } 9980 9981 if !u.core.cnAreReady { 9982 return nil, false, errors.New("Redis SortInterfaces Failed: " + "Endpoint Connections Not Ready") 9983 } 9984 9985 if len(keyToSort) <= 0 { 9986 return nil, false, errors.New("Redis SortInterfaces Failed: " + "KeyToSort is Required") 9987 } 9988 9989 cmd := u.core.cnReader.SortInterfaces(u.core.cnReader.Context(), keyToSort, sortPattern) 9990 return u.core.handleSliceCmd(cmd, "Redis SortInterfaces Failed: ") 9991 } 9992 9993 // SortStore will sort values defined by keyToSort, and sort according to sortPattern, and set sorted results into keyToStore in redis 9994 // sort is applicable to list, set, or sorted set as defined by key 9995 // 9996 // sortPattern = defines the sort conditions (see redis sort documentation for details) 9997 func (u *UTILS) SortStore(keyToSort string, keyToStore string, sortPattern *redis.Sort) (err error) { 9998 // get new xray segment for tracing 9999 seg := xray.NewSegmentNullable("Redis-SortStore", u.core._parentSegment) 10000 10001 if seg != nil { 10002 defer seg.Close() 10003 defer func() { 10004 _ = seg.Seg.AddMetadata("Redis-SortStore-SortKey", keyToSort) 10005 _ = seg.Seg.AddMetadata("Redis-SortStore-SortPattern", sortPattern) 10006 _ = seg.Seg.AddMetadata("Redis-SortStore-StoreKey", keyToStore) 10007 10008 if err != nil { 10009 _ = seg.Seg.AddError(err) 10010 } 10011 }() 10012 10013 err = u.sortStoreInternal(keyToSort, keyToStore, sortPattern) 10014 return err 10015 } else { 10016 return u.sortStoreInternal(keyToSort, keyToStore, sortPattern) 10017 } 10018 } 10019 10020 // sortStoreInternal will sort values defined by keyToSort, and sort according to sortPattern, and set sorted results into keyToStore in redis 10021 // sort is applicable to list, set, or sorted set as defined by key 10022 // 10023 // sortPattern = defines the sort conditions (see redis sort documentation for details) 10024 func (u *UTILS) sortStoreInternal(keyToSort string, keyToStore string, sortPattern *redis.Sort) error { 10025 // validate 10026 if u.core == nil { 10027 return errors.New("Redis SortStore Failed: " + "Base is Nil") 10028 } 10029 10030 if !u.core.cnAreReady { 10031 return errors.New("Redis SortStore Failed: " + "Endpoint Connections Not Ready") 10032 } 10033 10034 if len(keyToSort) <= 0 { 10035 return errors.New("Redis SortStore Failed: " + "KeyToSort is Required") 10036 } 10037 10038 if len(keyToStore) <= 0 { 10039 return errors.New("Redis SortStore Failed: " + "KeyToStore is Required") 10040 } 10041 10042 cmd := u.core.cnWriter.SortStore(u.core.cnWriter.Context(), keyToSort, keyToStore, sortPattern) 10043 _, _, err := u.core.handleIntCmd(cmd, "Redis SortStore Failed: ") 10044 return err 10045 }