github.com/aldelo/common@v1.5.1/helper-uuid.go (about)

     1  package helper
     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  import (
    20  	"database/sql"
    21  	"github.com/google/uuid"
    22  	"github.com/oklog/ulid/v2"
    23  	"math/rand"
    24  	"time"
    25  )
    26  
    27  // ================================================================================================================
    28  // UUID HELPERS
    29  // ================================================================================================================
    30  
    31  // GenerateUUIDv4 will generate a UUID Version 4 (Random) to represent a globally unique identifier (extremely rare chance of collision)
    32  func GenerateUUIDv4() (string, error) {
    33  	id, err := uuid.NewRandom()
    34  
    35  	if err != nil {
    36  		// error
    37  		return "", err
    38  	} else {
    39  		// has id
    40  		return id.String(), nil
    41  	}
    42  }
    43  
    44  // NewUUID will generate a UUID Version 4 (Random) and ignore error if any
    45  func NewUUID() string {
    46  	id, _ := GenerateUUIDv4()
    47  	return id
    48  }
    49  
    50  // ================================================================================================================
    51  // ULID HELPERS
    52  // ================================================================================================================
    53  
    54  // GenerateULID will generate a ULID that is globally unique (very slim chance of collision)
    55  func GenerateULID() (string, error) {
    56  	t := time.Now()
    57  	entropy := ulid.Monotonic(rand.New(rand.NewSource(t.UnixNano())), 0)
    58  
    59  	id, err := ulid.New(ulid.Timestamp(t), entropy)
    60  
    61  	if err != nil {
    62  		// error
    63  		return "", err
    64  	} else {
    65  		// has id
    66  		return id.String(), nil
    67  	}
    68  }
    69  
    70  // NewULID will generate a new ULID and ignore error if any
    71  func NewULID() string {
    72  	id, _ := GenerateULID()
    73  	return id
    74  }
    75  
    76  // GetULIDTimestamp will return the timestamp of the ulid string
    77  func GetULIDTimestamp(ulidStr string) (time.Time, error) {
    78  	if id, err := ulid.Parse(ulidStr); err != nil {
    79  		return time.Time{}, err
    80  	} else {
    81  		return time.UnixMilli(int64(id.Time())), nil
    82  	}
    83  }
    84  
    85  // IsULIDValid will check if the ulid string is valid
    86  func IsULIDValid(ulidStr string) bool {
    87  	if _, err := ulid.Parse(ulidStr); err != nil {
    88  		return false
    89  	} else {
    90  		return true
    91  	}
    92  }
    93  
    94  // ================================================================================================================
    95  // Random Number Generator
    96  // ================================================================================================================
    97  
    98  // GenerateRandomNumber with unix nano as seed
    99  func GenerateRandomNumber(maxNumber int) int {
   100  	seed := rand.NewSource(time.Now().UnixNano())
   101  	r := rand.New(seed)
   102  
   103  	return r.Intn(maxNumber)
   104  }
   105  
   106  // GenerateRandomChar will create a random character, using unix nano as seed
   107  func GenerateRandomChar() string {
   108  	r := GenerateRandomNumber(3)
   109  
   110  	// valid range of ascii
   111  	// 		33 - 126
   112  
   113  	// half the r until within range
   114  	// if not within min, double it until within range
   115  	if r <= 0 {
   116  		attempts := 0
   117  
   118  		for {
   119  			if r = GenerateRandomNumber(3); r > 0 {
   120  				break
   121  			} else {
   122  				if attempts > 25 {
   123  					return "~"
   124  				}
   125  			}
   126  
   127  			attempts++
   128  		}
   129  	}
   130  
   131  	if r < 33 {
   132  		for {
   133  			if r < 33 {
   134  				r *= 2
   135  			} else {
   136  				break
   137  			}
   138  		}
   139  	}
   140  
   141  	if r > 126 {
   142  		for {
   143  			if r > 126 {
   144  				r /= 2
   145  			} else {
   146  				break
   147  			}
   148  		}
   149  	}
   150  
   151  	// convert decimal ascii to char
   152  	return string(r)
   153  }
   154  
   155  // GenerateNewUniqueInt32 will take in old value and return new unique value with randomized seed and negated
   156  func GenerateNewUniqueInt32(oldIntVal int) int {
   157  	seed1 := GenerateRandomNumber(999)
   158  	seed2 := GenerateRandomNumber(99)
   159  
   160  	buf := Right(Itoa(oldIntVal), 5) + Padding(Itoa(seed2), 2, false, "0") + Padding(Itoa(seed1), 3, false, "0")
   161  
   162  	val, ok := ParseInt32(buf)
   163  
   164  	if !ok {
   165  		return oldIntVal * -1
   166  	} else {
   167  		return val * -1
   168  	}
   169  }
   170  
   171  // GenerateNewUniqueNullInt32 will take in old value and return new unique value with randomized seed and negated
   172  func GenerateNewUniqueNullInt32(oldIntVal sql.NullInt32) sql.NullInt32 {
   173  	if !oldIntVal.Valid {
   174  		return oldIntVal
   175  	}
   176  
   177  	seed1 := GenerateRandomNumber(999)
   178  	seed2 := GenerateRandomNumber(99)
   179  
   180  	buf := Right(Itoa(FromNullInt(oldIntVal)), 5) + Padding(Itoa(seed2), 2, false, "0") + Padding(Itoa(seed1), 3, false, "0")
   181  
   182  	val, ok := ParseInt32(buf)
   183  
   184  	if !ok {
   185  		return ToNullInt(int(oldIntVal.Int32)*-1, true)
   186  	} else {
   187  		return ToNullInt(val*-1, true)
   188  	}
   189  }
   190  
   191  // GenerateNewUniqueInt64 will take in old value and return new unique value with randomized seed and negated
   192  func GenerateNewUniqueInt64(oldIntVal int64) int64 {
   193  	seed1 := GenerateRandomNumber(999)
   194  	seed2 := GenerateRandomNumber(999)
   195  
   196  	buf := Right(Int64ToString(oldIntVal), 13) + Padding(Itoa(seed2), 3, false, "0") + Padding(Itoa(seed1), 3, false, "0")
   197  
   198  	val, ok := ParseInt64(buf)
   199  
   200  	if !ok {
   201  		return oldIntVal * -1
   202  	} else {
   203  		return val * -1
   204  	}
   205  }
   206  
   207  // GenerateNewUniqueNullInt64 will take in old value and return new unique value with randomized seed and negated
   208  func GenerateNewUniqueNullInt64(oldIntVal sql.NullInt64) sql.NullInt64 {
   209  	if !oldIntVal.Valid {
   210  		return oldIntVal
   211  	}
   212  
   213  	seed1 := GenerateRandomNumber(999)
   214  	seed2 := GenerateRandomNumber(999)
   215  
   216  	buf := Right(Int64ToString(FromNullInt64(oldIntVal)), 13) + Padding(Itoa(seed2), 3, false, "0") + Padding(Itoa(seed1), 3, false, "0")
   217  
   218  	val, ok := ParseInt64(buf)
   219  
   220  	if !ok {
   221  		return ToNullInt64(oldIntVal.Int64*-1, true)
   222  	} else {
   223  		return ToNullInt64(val*-1, true)
   224  	}
   225  }
   226  
   227  // ================================================================================================================
   228  // String Randomizer
   229  // ================================================================================================================
   230  
   231  // GenerateNewUniqueString will take in old value and return new unique value with randomized seed
   232  //
   233  //	stringLimit = 0 no limit, > 0 has limit
   234  func GenerateNewUniqueString(oldStrVal string, stringLimit int) string {
   235  	seed1 := Padding(Itoa(GenerateRandomNumber(999)), 3, false, "0")
   236  	seed2 := GenerateRandomChar()
   237  	seed3 := GenerateRandomChar()
   238  	seed4 := GenerateRandomChar()
   239  
   240  	buf := oldStrVal + seed2 + seed3 + seed4 + seed1
   241  
   242  	if stringLimit > 0 {
   243  		if stringLimit >= 6 {
   244  			buf = Right(buf, stringLimit)
   245  		} else {
   246  			if stringLimit >= 3 {
   247  				buf = Left(seed2+seed3+seed4+seed1, stringLimit)
   248  			} else {
   249  				buf = Left(seed2+seed3, stringLimit)
   250  			}
   251  		}
   252  	}
   253  
   254  	return buf
   255  }
   256  
   257  // GenerateNewUniqueNullString will take in old value and return new unique value with randomized seed
   258  //
   259  //	stringLimit = 0 no limit, > 0 has limit
   260  func GenerateNewUniqueNullString(oldStrVal sql.NullString, stringLimit int) sql.NullString {
   261  	if !oldStrVal.Valid {
   262  		return oldStrVal
   263  	}
   264  
   265  	seed1 := Padding(Itoa(GenerateRandomNumber(999)), 3, false, "0")
   266  	seed2 := GenerateRandomChar()
   267  	seed3 := GenerateRandomChar()
   268  	seed4 := GenerateRandomChar()
   269  
   270  	buf := FromNullString(oldStrVal) + seed2 + seed3 + seed4 + seed1
   271  
   272  	if stringLimit > 0 {
   273  		if stringLimit >= 6 {
   274  			buf = Right(buf, stringLimit)
   275  		} else {
   276  			if stringLimit >= 3 {
   277  				buf = Left(seed2+seed3+seed4+seed1, stringLimit)
   278  			} else {
   279  				buf = Left(seed2+seed3, stringLimit)
   280  			}
   281  		}
   282  	}
   283  
   284  	return ToNullString(buf, true)
   285  }