uuid

package module
v0.0.0-...-6013e7b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 28, 2017 License: MIT Imports: 8 Imported by: 0

README

UUID - Custom IDs

This package provides functionality to generate random UUIDs with unique identification of its type within. Any UUID is randomly generated (version 4 UUID) but has certain bits set to identify exactly the 'type' is is refering to. This package does NOT generate UUIDs following RFC 4122. However, it nevertheless allows for exactly the same number of possible combinations (ignoring the type bits) which is 2^122 UUIDs for each type. UUID also has no 3rd party dependencies meaning that out-of-the-box just golang is needed.

Open Issues

none

Types and UUID Structure

Generally referred to as 'types' is the combination of the first 6 (most-significant) bits that basically set a group of UUIDs each belongs to. If you for example want to generate UUIDs for users, then the type could be 0x00 or 000000 in binary. Each user UUID will therefore always start with 00 in the hex-string identifying it easily as a user UUID.

But Why?

Using specific identifying bits allows one to continue using UUIDs (which are generally used across many systems and are widely used) while keeping track of what ID is supposed to identify. Imagine a database with users, posts and comments: One would rely on a UUID being passed in any way to be of the correct type. Detecting that an ID is incorrect would at least require one DB query while having set types, an ID will tell itself that it represents a very specific type. 64 different types can be used with 2^122 UUIDs for each type. This is the same space RFC compliant UUIDs have too.

Usage

There are a couple of very important points to get started. Once you're through that the rest is a piece of cake.

  1. Import the package (obviously)
import (
    "github.com/4xoc/uuid"
)
  1. You must initialize a string array with size 64 that defines the scopes of UUIDs within your project. This is necessary to ensure that the scopes and its binary representation never changes when re-running the program. Slice and map are not very safe. Only scopes defines in this array can be used when creating or reading UUIDs.
// declaring scopes; it can also be a constant
const MY_CONST_SCOPE string = "four"
myScopes := [64]string{
    "one", "two", "three", MY_CONST_SCOPE,
}

uuid.SetScopes(myScopes)
  1. Now we can create a new UUID
myUUID, err := uuid.New("one")

if err != nil {
    //basically only happens when the scope it unknown
    //use the packages constants which hold the error strings for detecting the reason of the failure.
    fmt.Printf("Failed to generate UUID with error: %s\n", err.Error())
}

//now we can access the information of the uuid
fmt.Printf("Generated UUID %s with scope %s and binary %08b\n", myUUID.Hex(), myUUID.Scope(), myUUID.Bin())

  1. And then we try reading one
myCopy, _ = uuid.Read(myUUID.Hex())

fmt.Printf("Copied UUID %s with scope %s and binary %08b\n", myCopy.Hex(), myCopy.Scope(), myCopy.Bin())

  1. Checking if a uuid matches any of the given scopes. This can be helpful to validate UUIDs before processing them further.
//one or more allowed scopes can be set, if any matches it'll be a true response
myScopes := []string{"one","two"}

if myCopy.ScopeMatches(myScope) {
    fmt.Println("Yay, this uuid is of the allowed scopes.")
}

Database

This package implements the database/sql/driver interfaces to give Golang's built-in sql package access to read and write data from and into the struct transparently for the developer. Simply use the UUID type in your structs and the interfaces do the magic themselves.

FAQ

Dude, why do I always need to call a function to just get a value?
All fields of the struct are not directly accessable to prevent problems with manual changes bin/scope/hex data that would either cause a panic or at least become unpredictable in its workings. Therefore only interfaces allow the access to actual values so that a change of any data always also updates the other (if necessary).

Is it safe to use concurrent actions like read/write Yes, but by design it is only possible to set the scope once.

Contribution

Anyone feel happy to get involved and respond to issues or simply create a PR.

Documentation

Overview

Package uuid provides functions to create and manage custom UUIDs.

It uses random data to generate the ID but uses the first 6 bits to set its type.

Index

Constants

View Source
const (
	// Errors
	ErrorMissingScope      string = "the provided scope is not known"
	ErrorBadScope          string = "the provided scope is not supported"
	ErrorBadString         string = "the provided string is not a UUID"
	ErrorOutOfScopes       string = "limit of scopes exeeded"
	ErrorMalformattedHex   string = "the Hex representation of the UUID is malformatted"
	ErrorUninitializedUUID string = "the provided pointer refers to an uninitialized struct"
	ErrorScopesAlreadySet  string = "scopes can only be set once"
)

Variables

This section is empty.

Functions

func Scopes

func Scopes() [64]string

Scopes provides a list of all currently set scopes in a [64]string. The order is not the same as set with SetScopes function.

func SetScopes

func SetScopes(newScopes [64]string) error

setScopes defines the scopes used within this package and its binary representation. This function can only set scopes when there aren't any configured yet. A dynamic update is not supported for the sake of preventing concurrency issues without compromising performance.

Types

type UUID

type UUID struct {
	// contains filtered or unexported fields
}

Type UUID holds the ID's information like the Scope as well as a hex string and binary representation.

func New

func New(scope string) (*UUID, error)

New generates a new UUID and sets its scope to the one provided as an argument. If the scope doesn't exist yet, it will return an error (see SetScopes function).

func Read

func Read(input string) (*UUID, error)

Read uses a given string and parses it into a UUID struct.

func (*UUID) Bin

func (uuid *UUID) Bin() [16]byte

Bin returns the binary representation of a given UUID.

func (*UUID) Hex

func (uuid *UUID) Hex() string

Hex returns the hex-string representation of a given UUID.

func (*UUID) Scan

func (uuid *UUID) Scan(src interface{}) error

Scan provides a database/sql/driver interface to read the data coming from a DB connection into a struct.

func (*UUID) Scope

func (uuid *UUID) Scope() string

Scope returns the scope of a UUID as a string.

This function is needed to have a private 'scope' variable in the struct. Errors where a scope has been manually changed should be prevented by this.

func (*UUID) ScopeMatches

func (uuid *UUID) ScopeMatches(scopes []string) bool

ScopeMatches checks a given slice of strings to check a for a matching scope. If any of the given scopes matches, the function returns true.

If the UUID is not initialized, false is returned.

func (UUID) Value

func (uuid UUID) Value() (driver.Value, error)

Value provides a database/sql/driver interface to read the struct's value and pass it to a DB connection.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL