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  }