extid

package
v0.298.2 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 2025 License: Apache-2.0 Imports: 7 Imported by: 3

README

extid – Eternal Identifier

A flexible utility package for working with external identifiers in Go.
It provides mechanisms to get, set, and lookup identifier values using a variety of conventions. The main goal of extid to enable the development of generic Repository implementations, where we don't work with concrete types. Through this

Features

Convention over configuration, locates automatically ID fields using heuristics.

  • Locate external IDs through:
    • Struct field named ID
    • Struct field tagged with ext:"id"
    • Field with a registered identifier type

Usage

Package-Level Helpers

Simple and direct:

  • extid.Get[ID](ent): Retrieve an external identifier from a entity struct.
  • extid.Set[ID](ent): Assign an external identifier to the ID external id entity struct field.
  • extid.Lookup[ID](ent): Inspect a struct to locate the appropriate identifier field.

These functions work without additional setup and are suitable for most generic use cases.

Accessor Helper

The Accessor is a generic, dependency-injectable utility for working with external IDs in a consistent and type-safe way. You can list it as a field in your generic implementation, and enable configurability of your implementation on what field it should use as its external id. If left unset (zero value), it automatically falls back to package-level helpers—thanks to a built-in null object pattern. It provides the same Get, Set, and Lookup methods as the Package-Level helpers.

type MyRepoImplementation[ENT, ID any] struct {
    IDA extid.Accessor[ENT, ID]
}

Use Cases

The extid package follows a few common conventions to locate external identifiers automatically. These conventions work out of the box, with no configuration needed.

Struct Field Named ID

The simplest convention: if a struct has a field named ID, then it could be used as the external identifier.

type Entity struct {
    ID string
}
Field Tagged with ext:"id"

You can explicitly mark a field as the external ID using the ext tag with the value of "id".

type Entity struct {
    RepoID string `ext:"id"`
}
Field with a Custom Identifier Type

If your design uses dedicated identifier types, extid will recognise fields by their registered types.

type NoteID string
type UserID string

type Note struct {
    ID     NoteID
    UserID UserID
}

Performance

measured on Apple M3 Max

extid is designed to be efficient. Package-Level common operations like Get, Set, and Lookup complete in under 100ns. Using a preconfigured Accessor is even faster, reducing overhead to as little as ~12ns per call.

Documentation

Index

Examples

Constants

View Source
const ErrIDFieldNotFound errorkit.Error = "ErrIDFieldNotFound"

Variables

This section is empty.

Functions

func ExtractIdentifierField added in v0.261.0

func ExtractIdentifierField(ent any) (reflect.StructField, reflect.Value, bool)

func Get added in v0.298.0

func Get[ID, ENT any](ent ENT) ID

func Lookup

func Lookup[ID, ENT any](ent ENT) (id ID, ok bool)

Lookup checks if the given ENT struct type contains a field of type ID.

It returns two values: - The ID field, if found. - A boolean OK indicating whether an ID field exists in the given ENT struct.

The function prioritises the following when selecting an ID field: - Any field of type ID. - If multiple fields of type ID exist, the one tagged as 'ext:"id"' is preferred.

This function helps identify the primary ID field in ENT structs consistently.

Example
package main

import (
	"fmt"

	"go.llib.dev/frameless/port/crud/extid"
)

type Entity struct {
	ID string `ext:"id"`
}

func main() {
	ent := Entity{}

	_, ok := extid.Lookup[string](ent)
	fmt.Println(`found:`, ok) // false

	ent.ID = `42`
	id, ok := extid.Lookup[string](ent)
	fmt.Println(`found:`, ok)    // true
	fmt.Println(`id value:`, id) // "42"
}

func RegisterType

func RegisterType[ENT, ID any](
	Get func(ENT) ID,
	Set func(*ENT, ID),
) func()

func Set

func Set[ID any](ptr any, id ID) error
Example
package main

import (
	"fmt"

	"go.llib.dev/frameless/port/crud/extid"
)

type Entity struct {
	ID string `ext:"id"`
}

func main() {
	ent := Entity{}
	id := "id-value"

	if err := extid.Set(&ent, id); err != nil {
		panic(err)
	}

	fmt.Println(`ent.ID == id:`, ent.ID == id) // true
}

Types

type Accessor added in v0.239.0

type Accessor[ENT, ID any] func(*ENT) *ID

Accessor is a function that allows describing how to access an ID field in an ENT type. The returned id pointer will be used to Lookup its value, or to set new value to this ID pointer. Its functions will panic if func is provided, but it returns a nil pointer, as it is considered as implementation error.

Example implementation:

extid.Accessor[Foo, FooID](func(v Foo) *FooID { return &v.ID })

default: extid.Lookup, extid.Set, which will use either the `ext:"id"` tag, or the `ENT.ID()` & `ENT.SetID()` methods.

func (Accessor[ENT, ID]) Get added in v0.296.0

func (fn Accessor[ENT, ID]) Get(ent ENT) ID

func (Accessor[ENT, ID]) Lookup added in v0.239.0

func (fn Accessor[ENT, ID]) Lookup(ent ENT) (ID, bool)

func (Accessor[ENT, ID]) ReflectLookup added in v0.261.0

func (fn Accessor[ENT, ID]) ReflectLookup(rENT reflect.Value) (rID reflect.Value, ok bool)

func (Accessor[ENT, ID]) ReflectSet added in v0.261.0

func (fn Accessor[ENT, ID]) ReflectSet(ptrENT reflect.Value, id reflect.Value) error

func (Accessor[ENT, ID]) Set added in v0.239.0

func (fn Accessor[ENT, ID]) Set(ent *ENT, id ID) error

type LookupIDFunc added in v0.242.0

type LookupIDFunc[ENT, ID any] func(ENT) (ID, bool)

type ReflectAccessor added in v0.261.0

type ReflectAccessor func(ptrENT reflect.Value) (ptrID reflect.Value)

func (ReflectAccessor) ReflectLookup added in v0.261.0

func (fn ReflectAccessor) ReflectLookup(rENT reflect.Value) (rID reflect.Value, ok bool)

func (ReflectAccessor) ReflectSet added in v0.261.0

func (fn ReflectAccessor) ReflectSet(ptrENT reflect.Value, id reflect.Value) (rErr error)

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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