ITADN

feat: Expose UUID generation and parsing in stream map expressions

#3694OpenReubenFrankel 创建于 2026-07-09
kind/Featuregood first issueAccepting Pull Requestsvaluestream/SDKStream Maps
R
ReubenFrankelcommented
### 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: ```yaml __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. ```python 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: ```yaml 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): ```yaml __filter__: try_cast(value, UUID) is not None ``` Canonicalize an incoming UUID string (lowercased, hyphenated) via round-trip: ```yaml 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](https://meltano.slack.com/archives/C069CQNHDNF/p1783571869802079) - would go hand-in-hand with #3693. 🤖 Generated with [Claude](https://claude.ai)
0 条评论