<#3694 feat: Expose UUID generation and parsing in...
# meltano-repo-activity
g
#3694 feat: Expose UUID generation and parsing in stream map expressions Issue created by ReubenFrankel Feature scope Taps (catalog, state, tests, etc.) Description Problem Working with UUIDs in stream map expressions can be useful in specific cases — generating surrogate keys, producing synthetic IDs, or validating that an incoming field is a real UUID. There's no first-class support for this today: the
uuid
module isn't available in the stream map function namespace, and it can't simply be added, since
simpleeval
blocks module objects outright (
FeatureNotAvailable: Sorry, modules are not allowed
). Some of this can be done today, but only through awkward workarounds: • Validation is possible with pure string manipulation — checking length, hyphen positions, and stripping the hex/hyphen character set — but the resulting expressions are long, hard to read, and easy to get subtly wrong. A canonical-shape check ends up looking like: __filter__: >- len(value) == 36 and value[8] == '-' and value[13] == '-' and value[18] == '-' and value[23] == '-' and value.strip('0123456789abcdef-') == '' It works, but it can't express stricter notions like "is a real v4 UUID," and the intent isn't obvious to a reader. • Generation has no equivalent workaround — there's no way to produce a random UUID from within an expression. First-class UUID callables would replace the string manipulation with something readable, and make generation possible at all. Proposal Register a small set of UUID callables in the stream map function namespace. At minimum: •
uuid4()
— generate a random UUID (returned as a
str
), for surrogate/synthetic keys. •
UUID(value)
— parse/validate a UUID string (
uuid.UUID
), enabling validation and canonicalization. import uuid functions = { # ...existing entries... "uuid4": lambda: str(uuid.uuid4()), "UUID": uuid.UUID, } Returning
uuid4()
as a
str
avoids leaking a
UUID
object into the record (which downstream JSON serialization / target type handling may not expect). Example usage Generate a surrogate key: stream_maps: my_stream: surrogate_id: uuid4() Validate / filter to real UUIDs (pairs well with a
try_cast
-style helper so bad input doesn't raise): __filter__: try_cast(value, UUID) is not None Canonicalize an incoming UUID string (lowercased, hyphenated) via round-trip: id: str(UUID(id)) Design considerations • Validation is already possible, just awkwardly — the string-manipulation approach above works today, so for validation this is largely about ergonomics and correctness; generation, by contrast, has no workaround at all. • Module can't be exposed directly —
simpleeval
rejects module objects, so functionality must be registered as named callables (as above). • Return
str
, not
UUID
objects
— keeps records JSON-serializable and consistent with how targets expect string keys. •
UUID()
raises on bad input
— on its own it can't be used safely in an expression (no `try`/`except`). It's most useful alongside an exception-handling helper; see the related request for a
try_cast
helper. • Determinism —
uuid4()
is random, so it's non-reproducible across re-runs. If a stable/deterministic ID is desirable, a
uuid5(namespace, name)
-style callable could be considered as a follow-up. --- Follows this Slack discussion - would go hand-in-hand with #3693. 🤖 Generated with Claude meltano/sdk