unixid

package module
v0.0.102 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2025 License: MIT Imports: 4 Imported by: 7

README

UnixID

Project Badges

A Go library for generating unique, time-based IDs using Unix timestamps at nanosecond precision.

Overview

UnixID provides functionality for generating and managing unique identifiers with the following features:

  • High-performance ID generation based on Unix nanosecond timestamps
  • Thread-safe concurrent ID generation
  • Built-in collision avoidance through sequential numbering
  • Support for both server-side and client-side (WebAssembly) environments
  • Date conversion utilities for timestamp-to-date formatting
  • Smart environment detection for automatic configuration
  • Versatile ID assignment for strings, struct fields and byte slices

Installation

go get github.com/cdvelop/unixid

Quick Start

Server-side Usage
package main

import (
	"github.com/cdvelop/unixid"
)

func main() {
	// Create a new UnixID handler (server-side)
	idHandler, err := unixid.NewUnixID()
	if err != nil {
		panic(err)
	}

	// Generate a new unique ID
	id := idHandler.GetNewID()

	fmt.Printf("Generated ID: %s\n", id)
	// Output: Generated ID: 1624397134562544800

	// Convert an ID to a human-readable date
	dateStr, err := idHandler.UnixNanoToStringDate(id)
	if err != nil {
		panic(err)
	}

	println("ID timestamp represents: ", dateStr)
	// Output: ID timestamp represents: 2021-06-23 15:38:54
}
Client-side (WebAssembly) Usage

For WebAssembly environments, you need to provide a session number handler:

// Example session handler implementation
type sessionHandler struct{}

func (sessionHandler) userSessionNumber() string {
	// In a real application, this would return the user's session number
	return "42"
}

// Create a new UnixID handler with session handler
idHandler, err := unixid.NewUnixID(&sessionHandler{})

ID Format

The generated IDs follow this format:

  • Server-side: [unix_timestamp_in_nanoseconds] (e.g., 1624397134562544800)
  • Client-side: [unix_timestamp_in_nanoseconds].[user_session_number] (e.g., 1624397134562544800.42)

Thread Safety & Avoiding Deadlocks

The library handles concurrent ID generation safely through mutex locking in server-side environments.

IMPORTANT: When integrating this library with other libraries that also use sync.Mutex, infinite deadlocks can occur. To avoid this issue, you can pass an existing mutex when initializing UnixID:

package main

import (
	"fmt"
	"sync"
	"github.com/cdvelop/unixid"
	"github.com/someother/library"
)

func main() {
	// Create a shared mutex
	var mu sync.Mutex
	
	// Pass the shared mutex to UnixID
	idHandler, err := unixid.NewUnixID(&mu)
	if (err != nil) {
		panic(err)
	}
	
	// Pass the same mutex to other libraries if they support it
	otherLib := library.New(&mu)
	
	// Now both libraries will use the same mutex,
	// preventing deadlocks when they need to lock resources
}
Deadlock Prevention with External Mutex

When an external mutex is provided to NewUnixID(), the library automatically detects this and changes its behavior:

  1. Instead of using the provided mutex internally, it switches to a no-op mutex that doesn't perform any actual locking.
  2. This allows GetNewID() to be safely called from within a context that has already acquired the same mutex.

Example of using GetNewID() inside a locked context:

var mu sync.Mutex
idHandler, err := unixid.NewUnixID(&mu)
if err != nil {
    panic(err)
}

// Later in your code...
mu.Lock()
defer mu.Unlock()

// This won't deadlock because internally the library uses a no-op mutex
// when an external mutex is provided
id := idHandler.GetNewID()
// Do something with id...

This behavior assumes that external synchronization is being properly handled by the caller, eliminating the risk of deadlocks when the same mutex is used in nested contexts.

API Reference

Core Functions
  • NewUnixID(...): Creates a new UnixID handler for ID generation with automatic environment detection

    • In server environments, no parameters are required
    • In WebAssembly environments, requires a userSessionNumber implementation
    • Uses build tags (wasm or !wasm) to determine the appropriate implementation
    • Thread-safe in server environments with mutex locking
    • No mutex in WebAssembly as JavaScript is single-threaded
    • Can accept an existing sync.Mutex or *sync.Mutex to prevent deadlocks when integrating with other libraries
  • GetNewID(): Generates a new unique ID

    • Returns a string representation of the ID
    • In WebAssembly builds, appends a user session number to the timestamp
  • SetNewID(target any): Sets a new unique ID to various target types

    • Accepts pointers to string, tinyreflect.Value, or byte slices
    • Thread-safe in server environments
    • Example usages:
      // Set ID to a string variable
      var id string
      idHandler.SetNewID(&id)
      
      // Set ID to a struct field
      type User struct { ID string }
      user := User{}
      idHandler.SetNewID(&user.ID)
      
      // Append ID to a byte slice
      buf := make([]byte, 0, 64)
      idHandler.SetNewID(buf)
      
      // Set ID to a tinyreflect.Value
      v := tinyreflect.ValueOf(&user)
      // The ValueOf(&data) returns a Ptr. We need to get the element it points to
      // before we can access its fields. This is what Elem() does.
      structVal, err := v.Elem()
      if err != nil {
      	// Failed to get element from pointer value:...
      }
      
      IDField, err := structVal.Field(0)
      if err != nil {
      	// Failed to get field 'ID':...
      }
      idHandler.SetNewID(&IDField)
      
      
  • UnixNanoToStringDate(unixNanoStr): Converts a Unix nanosecond timestamp ID to a human-readable date

Additional Utility Functions
  • UnixSecondsToTime(unixSeconds any) string: Converts a Unix timestamp in seconds to a formatted time string (HH:mm:ss). e.g., 1624397134 -> 15:38:54 supports int64, string, and float64 types

Validate ID

The ValidateID function validates and parses a given ID string. It returns the parsed ID as an int64 and an error if the ID is invalid.

Example
package main

import (
	"fmt"
	"github.com/cdvelop/unixid"
)

func main() {
	id := "1624397134562544800"
	parsedID, err := unixid.ValidateID(id)
	if err != nil {
		panic(err)
	}

	fmt.Printf("Parsed ID: %d\n", parsedID)
	// Output: Parsed ID: 1624397134562544800
}

Environment-Based Configuration

UnixID automatically detects the compilation environment and configures itself appropriately:

  • Server-side (!wasm build tag):

    • Uses Go's standard time package
    • Implements mutex-based thread safety
    • Generates simple timestamp-based IDs
  • WebAssembly (wasm build tag):

    • Uses JavaScript's Date API through syscall/js
    • Requires a session handler to manage user identifiers
    • Appends a user session number to IDs for cross-client uniqueness

This automatic configuration allows you to use the same API in both environments while the library handles the implementation details internally.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ValidateID added in v0.0.57

func ValidateID(new_id_in string) (id int64, err error)

ValidateID validates and parses a Unix timestamp ID string. It handles IDs in both server format (just timestamp) and client format (timestamp.userNumber). This function extracts the timestamp portion from the ID and returns it as an int64.

Parameters:

  • new_id_in: The ID string to validate (e.g., "1624397134562544800" or "1624397134562544800.42")

Returns:

  • id: The timestamp portion of the ID as an int64 value
  • err: An error if the ID format is invalid

Validation rules:

  • The ID must contain only digits and at most one decimal point
  • The timestamp portion (before the decimal point) must be a valid int64

Types

type Config added in v0.0.54

type Config struct {
	// Session provides user session numbers in WebAssembly environments
	Session userSessionNumber // e.g., userSessionNumber() string = "1","4","4000" etc.

	// TimeProvider provides time utilities including nanosecond timestamps and date formatting
	TimeProvider tinytime.TimeProvider // Provides UnixNano(), UnixSecondsToDate(), and UnixNanoToTime()
	// contains filtered or unexported fields
}

Config holds the configuration and dependencies for a UnixID instance

type UnixID

type UnixID struct {

	// Config holds the external dependencies for the UnixID
	*Config
	// contains filtered or unexported fields
}

UnixID is the main struct for ID generation and handling It contains all configuration and state needed for ID generation

func NewUnixID added in v0.0.59

func NewUnixID(handlerUserSessionNumber ...any) (*UnixID, error)

NewUnixID creates a new UnixID handler with appropriate configuration based on the runtime environment.

For WebAssembly environments (client-side): - Requires a userSessionNumber handler to be passed as a parameter - Creates IDs with format: "[timestamp].[user_number]" (e.g., "1624397134562544800.42") - No mutex is used as JavaScript is single-threaded

For non-WebAssembly environments (server-side): - Does not require any parameters - Creates IDs with format: "[timestamp]" (e.g., "1624397134562544800") - Uses a sync.Mutex for thread safety

IMPORTANT: When integrating with other libraries that also use sync.Mutex, you can pass an existing mutex as a parameter to avoid potential deadlocks. When an external mutex is provided, this library will use a no-op mutex internally to prevent deadlocks when GetNewID is called within a context that has already acquired the same mutex. This assumes that external synchronization is being handled by the caller.

Parameters:

  • handlerUserSessionNumber: Optional userSessionNumber implementation (required for WebAssembly)
  • sync.Mutex or *sync.Mutex: Optional mutex to use instead of creating a new one (server-side only)

Returns:

  • A configured *UnixID instance
  • An error if the configuration is invalid

Usage examples:

// Server-side usage:
idHandler, err := unixid.NewUnixID()

// WebAssembly usage:
type sessionHandler struct{}
func (sessionHandler) userSessionNumber() string { return "42" }
idHandler, err := unixid.NewUnixID(&sessionHandler{})

// Server-side usage with existing mutex to avoid deadlocks:
var mu sync.Mutex
idHandler, err := unixid.NewUnixID(&mu)

// With external mutex, when calling within a locked context:
var mu sync.Mutex
idHandler, err := unixid.NewUnixID(&mu)

mu.Lock()
defer mu.Unlock()
// This won't deadlock because NewUnixID uses a no-op mutex internally
// when an external mutex is provided
id := idHandler.GetNewID()

func (*UnixID) FieldType added in v0.0.55

func (u *UnixID) FieldType(tableName, fieldName string) (ID, PK bool)

FieldType determines if a field is an ID field and/or a primary key field. This function analyzes field names to identify ID fields and primary keys based on naming conventions.

Parameters:

  • tableName: The name of the table or entity that the field belongs to
  • fieldName: The name of the field to analyze

Returns:

  • ID: true if the field is an ID field (starts with "id")
  • PK: true if the field is a primary key (is named "id" or matches the pattern "id{tableName}" or "id_{tableName}")

Examples:

  • FieldType("user", "id") returns (true, true)
  • FieldType("user", "iduser") returns (true, true)
  • FieldType("user", "id_user") returns (true, true)
  • FieldType("user", "idaddress") returns (true, false)

func (*UnixID) GetNewID

func (id *UnixID) GetNewID() string

GetNewID generates a new unique ID based on Unix nanosecond timestamp. In WebAssembly environments, this appends a user session number to the timestamp. In server environments, this returns just the Unix nanosecond timestamp. Returns a string representation of the unique ID.

func (*UnixID) SetNewID added in v0.0.62

func (id *UnixID) SetNewID(target any)

SetNewID sets a new unique ID value to various types of targets. It generates a new unique ID based on Unix nanosecond timestamp and assigns it to the provided target. This function can work with multiple target types including tinyreflect.Value, string pointers, and byte slices.

In WebAssembly environments, IDs include a user session number as a suffix (e.g., "1624397134562544800.42"). In server environments, IDs are just the timestamp (e.g., "1624397134562544800").

Parameters:

  • target: The target to receive the new ID. Can be:
  • tinyreflect.Value or *tinyreflect.Value: For setting struct field values via tiny-reflection.
  • *string: For setting a string variable directly.
  • []byte: For appending the ID to a byte slice.

This function is thread-safe in server-side environments.

Examples:

// Setting a struct field using tiny-reflection
v := tinyreflect.ValueOf(&myStruct)
elem, _ := v.Elem()
field, _ := elem.Field(0) // Get field by index
idHandler.SetNewID(field)

// Setting a string variable
var id string
idHandler.SetNewID(&id)

// Appending to a byte slice
buf := make([]byte, 0, 64)
idHandler.SetNewID(buf)

func (*UnixID) UnixNanoToStringDate added in v0.0.54

func (u *UnixID) UnixNanoToStringDate(unixNanoStr string) (string, error)

UnixNanoToStringDate converts a Unix nanosecond timestamp ID to a human-readable date string. This function accepts a string representation of a Unix nanosecond timestamp (with or without a user number suffix) and returns a formatted date string in the format "2006-01-02 15:04" (year-month-day hour:minute).

Parameters:

  • unixNanoStr: String representation of a Unix timestamp in nanoseconds (e.g. "1624397134562544800" or "1624397134562544800.42")

Returns:

  • A formatted date string (e.g. "2021-06-22 15:32")
  • An error if the input is invalid or the conversion fails

Example:

dateStr, err := handler.UnixNanoToStringDate("1624397134562544800")
if err != nil {
  // handle error
}
fmt.Println(dateStr) // e.g. "2021-06-22 15:32"

func (*UnixID) UnixNanoToTime added in v0.0.68

func (id *UnixID) UnixNanoToTime(input any) string

UnixNanoToTime converts a Unix timestamp in nanoseconds to a formatted time string. Format: "15:04:05" (hour:minute:second) It accepts a parameter of type any and attempts to convert it to an int64 Unix timestamp in nanoseconds. eg: 1624397134562544800 -> "15:32:14" supported types: int64, int, float64, string

func (*UnixID) UnixSecondsToDate added in v0.0.93

func (id *UnixID) UnixSecondsToDate(unixSeconds int64) string

UnixSecondsToDate converts Unix seconds to a formatted date string. Format: "2006-01-02 15:04" (YYYY-MM-DD HH:MM) eg: 1624397134 -> "2021-06-22 15:32"

Jump to

Keyboard shortcuts

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