Skip to content

feat(Decider): add deterministic UUID generation (UUID v5) to Decision monad #596

@NickSeagull

Description

@NickSeagull

Summary

The Decision monad currently supports random UUID generation via generateUuid (which uses UUID v4 internally). There are use cases where a deterministic UUID derived from a known input (e.g., a text identifier from an external system) is needed within the decide function.

Use Case

When a command needs to derive an entity ID from an external identifier (e.g., a string-based user ID from an OAuth provider), there's currently no way to produce a stable, deterministic UUID from that input within the Decision monad. The only option is generateUuid, which produces a random UUID each time.

Proposed API

Add a generateDeterministicUuid (or uuidFromText) function to the Decider module:

-- | Generate a deterministic UUID (v5) from a namespace and a name.
-- Same inputs always produce the same UUID.
generateDeterministicUuid :: Uuid -> Text -> Decision Uuid

Or a simpler variant with a default namespace:

-- | Generate a deterministic UUID from a text value.
-- Same input always produces the same UUID.
uuidFromText :: Text -> Decision Uuid

This could be implemented using UUID v5 (SHA-1 based, RFC 4122) from the uuid package, which already provides Data.UUID.V5.generateNamed.

Alternatives Considered

  • Hashing outside the Decision monad: Not possible since decide is pure and getEntityId only has access to command fields.
  • Requiring the caller to pre-compute the UUID: Pushes the problem to the caller, who may also lack UUID v5 support in the framework.
  • Adding the function to the Uuid module instead: A Uuid.fromNamespace :: Uuid -> Text -> Uuid pure function would also solve this, and wouldn't need to be in the Decision monad at all since UUID v5 is deterministic and pure.

Notes

The uuid package (already a dependency via Data.UUID and Data.UUID.V4) includes Data.UUID.V5 which provides the necessary generateNamed function, so no new dependencies would be needed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions