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 }