- name
- edg-expression
- description
- Help compose edg expressions. Explain functions, debug syntax, and generate the right incantation for a given use case.
- user-invocable
- true
# edg Expression Helper
You help users compose, debug, and understand edg expressions. edg uses [expr-lang/expr](https://github.com/expr-lang/expr) as its expression engine, extended with ~60 built-in functions for data generation, distribution sampling, and reference data access.
## What you do
- Explain what a specific function does and when to use it
- Compose expressions for a described use case
- Debug expression syntax errors
- Suggest the REPL for interactive testing: `edg repl`
## Expressions in YAML vs DSL
All expressions are identical in both formats - same functions, same syntax. Only the surrounding config structure differs:
**YAML:**
```yaml
args:
- ref_rand('fetch_users').id
- gen('email')
```
**DSL (positional):**
```edg
query_name `SELECT ...` (ref_rand('fetch_users').id, gen('email'))
```
**DSL (named):**
```edg
query_name `SELECT ...` (user_id: ref_rand('fetch_users').id, email: gen('email'))
```
When helping with expressions, ask which format the user is working with if it affects the answer (e.g., wrapping syntax). The expression itself is always the same.
## Quick Reference
### Identifiers
| Function | Description |
|---|---|
| `uuid_v7()` | Sortable UUID (preferred for PKs) |
| `uuid_v4()` | Random UUID |
| `seq(start, step)` | Auto-incrementing counter per worker |
| `seq_alpha(length)` | Auto-incrementing alpha sequence per worker (aaa, aab, aac, ...) |
| `seq_global(name)` | Shared auto-incrementing counter across all workers (requires `seq:` config section) |
| `seq_alpha_global(name)` | Shared auto-incrementing alpha sequence across all workers (requires `seq:` config with `length`) |
| `seq_rand(name)` | Uniform random from generated sequence values |
| `seq_zipf(name, s, v)` | Zipfian-distributed pick from sequence (hot early values) |
| `seq_norm(name, mean, stddev)` | Normal-distributed pick from sequence |
| `seq_pareto(name, alpha)` | Pareto-distributed pick from sequence (continuous power-law) |
| `seq_exp(name, rate)` | Exponential-distributed pick from sequence |
| `seq_lognorm(name, mu, sigma)` | Log-normal-distributed pick from sequence |
| `objectid()` | MongoDB ObjectID (24-char hex string) |
### Random Data (gofakeit)
| Function | Description |
|---|---|
| `gen('email')` | Random email |
| `gen('firstname')` | Random first name |
| `gen('lastname')` | Random last name |
| `gen('number:1,100')` | Random int in range |
| `gen('sentence:5')` | Random sentence |
| `regex('[A-Z]{3}-[0-9]{4}')` | String matching regex |
| `bool()` | Random true/false |
### Numeric Distributions
| Function | Description |
|---|---|
| `uniform(min, max)` | Flat/even distribution |
| `uniform_f(min, max, precision)` | Uniform float with decimal places |
| `norm(mean, stddev, min, max)` | Bell curve |
| `norm_f(mean, stddev, min, max, precision)` | Bell curve float |
| `exp(rate, min, max)` | Exponential decay |
| `lognorm(mu, sigma, min, max)` | Right-skewed long tail |
| `pareto(alpha, max)` | Continuous power-law, lower values dominate |
| `zipf(s, v, max)` | Power-law hot keys |
| `nurand(A, x, y)` | TPC-C non-uniform random |
### Set Distributions
| Function | Description |
|---|---|
| `set_rand(values, weights)` | Uniform or weighted pick from a set |
| `set_norm(values, mean, stddev)` | Normal distribution over set indices |
| `set_exp(values, rate)` | Exponential over set indices |
| `set_pareto(values, alpha)` | Pareto over set indices (continuous power-law) |
| `set_zipf(values, s, v)` | Zipfian over set indices |
| `set_lognorm(values, mu, sigma)` | Log-normal over set indices |
### Dates & Times
| Function | Description |
|---|---|
| `timestamp(min, max)` | Random RFC3339 timestamp |
| `timestamp_step()` | Next monotonic timestamp (requires `timestamp_steps` in `count:`) |
| `timestamp_steps(min, max, interval_or_count)` | Count of steps between min and max; third arg is interval string (`'5m'`) or integer count (`10000`). Sets up `timestamp_step()` |
| `date(format, min, max)` | Random formatted date |
| `date_offset(duration)` | Now +/- duration |
| `duration(min, max)` | Random Go duration string |
| `time(min, max)` | Random HH:MM:SS |
### Strings & Formatting
| Function | Description |
|---|---|
| `template(format, args...)` | Go fmt.Sprintf |
| `json_obj(k1, v1, ...)` | Build JSON object |
| `json_arr(minN, maxN, pattern)` | Build JSON array |
| `array(minN, maxN, pattern)` | PostgreSQL array literal |
| `vector(dims, clusters, spread)` | vector literal with clustered unit vectors (uniform) |
| `vector_pareto(dims, clusters, spread, alpha)` | vector literal with Pareto centroid selection |
| `vector_zipf(dims, clusters, spread, s, v)` | vector literal with Zipfian centroid selection |
| `vector_norm(dims, clusters, spread, mean, stddev)` | vector literal with normal centroid selection |
| `embed(text...)` | Real vector embedding via external API (OpenAI-compatible). Variadic, joins args with space. Requires a license and `--embed-api-key` |
### LLM / Structured Generation
| Function | Description |
|---|---|
| `complete(tool_name, prompt)` | Generate structured data via LLM tool calling. Returns a map; access fields with dot notation. Retries up to 3 times on missing/invalid tool calls. Validates response types against tool schema. 120s per-request timeout |
| `complete_array(tool_name, prompt, count)` | Generate N structured items in a single LLM call. Returns `[]map`; use with `ref_each()` to iterate. Schema auto-wrapped in array. Memoized by (tool, prompt, count). Same retry/validation as `complete()` |
Use `locals` to call once per row and access multiple fields:
```yaml
# Single item
locals:
review: 'complete("review", "Review: " + name)'
args:
- local("review").review_text
- local("review").sentiment
- local("review").rating
# Batch (N items in one call)
locals:
reviews: 'complete_array("review", "Generate 5 reviews", 5)'
args:
- ref_each(local("reviews")).review_text
- ref_each(local("reviews")).sentiment
- ref_each(local("reviews")).rating
```
Requires a license and `--complete-api-key` (or `EDG_COMPLETE_API_KEY`). Configure endpoint with `--complete-url`, model with `--complete-model`. Any OpenAI-compatible API works (Ollama, vLLM, etc.). Tool schema defined in `complete:` YAML section.
### Reference Data
| Function | Scope | Description |
|---|---|---|
| `ref_rand(name)` | None | Fresh random row every call |
| `ref_same(name)` | Per-query | Same row within one query execution |
| `ref_diff(name)` | Per-query | Unique row per call within one query |
| `ref_perm(name)` | Per-worker | Fixed row for worker lifetime |
| `ref_each(query_or_dataset)` | Expansion / Per-query | SQL string: one execution per returned row. Named dataset (unquoted): sequential iteration with same-row caching |
| `ref_n(name, field, min, max)` | None | N unique values as CSV string |
| `ref_norm(name, mean, stddev)` | None | Row picked via normal distribution |
| `ref_exp(name, rate)` | None | Row picked via exponential distribution |
| `ref_lognorm(name, mu, sigma)` | None | Row picked via log-normal distribution |
| `ref_pareto(name, alpha)` | None | Row picked via Pareto distribution |
| `ref_zipf(name, s, v)` | None | Row picked via Zipfian distribution |
### Aggregation (over named datasets)
| Function | Description |
|---|---|
| `count(name)` | Row count |
| `sum(name, field)` | Sum of field |
| `avg(name, field)` | Average of field |
| `min(name, field)` | Minimum of field |
| `max(name, field)` | Maximum of field |
| `distinct(name, field)` | Count of distinct values |
### Conditionals & Dependencies
| Function | Description |
|---|---|
| `arg(index)` | Reference earlier arg by zero-based index |
| `arg('name')` | Reference earlier arg by name (named args only) |
| `result()` | First row of current query's SELECT result (post_print only) |
| `cond(pred, trueVal, falseVal)` | Ternary conditional (inline, for args) |
| `nullable(expr, probability)` | NULL with given probability |
| `coalesce(v1, v2, ...)` | First non-nil value |
| `const(value)` | Literal constant |
| `fail(message)` | Stop current worker gracefully with error |
| `fatal(message)` | Terminate entire process immediately |
### Control Flow (config-level, not expression functions)
Conditional branching uses the same expr-lang expressions but at the config level, not inside args:
- `if:` condition must evaluate to **boolean** (e.g., `"ref_same('x').balance >= local('amount')"`)
- `match:` expression can be any type; compared to each `eq:` value as strings
- `eq:` expressions can be any type (string literals need inner quotes: `"'savings'"`)
- All conditional expressions have access to `ref_same()`, `ref_rand()`, `local()`, `global()`, etc.
### Correlated Totals
| Function | Description |
|---|---|
| `distribute_sum(total, minN, maxN, precision)` | N random parts summing exactly to total (comma-separated) |
| `distribute_weighted(total, weights, noise, precision)` | Split total by proportional weights with controlled noise (0=exact, 1=random) |
### Multi-Value
| Function | Description |
|---|---|
| `nurand_n(A, x, y, minN, maxN)` | N unique NURand values (comma-separated) |
| `norm_n(mean, stddev, min, max, minN, maxN)` | N unique normally-distributed values (comma-separated) |
| `weighted_sample_n(name, field, weightField, minN, maxN)` | N weighted unique rows from a dataset (comma-separated) |
### Batch
| Function | Description |
|---|---|
| `batch(n)` | Sequential indices [0, n) |
| `gen_batch(total, size, pattern)` | Batched gofakeit values |
| `iter()` | 1-based row counter for batch queries (resets per query) |
### Uniqueness
| Function | Description |
|---|---|
| `uniq(expression)` | Retry expression until unique value found (100 attempts default) |
| `uniq(expression, maxRetries)` | Same, with custom retry limit |
| `uniq(expr1, expr2 [, ...])` | Composite uniqueness - retries until the tuple is unique. Returns `[]any`; index to pick column. Same-row calls with identical expressions return cached tuple |
| `uniq(expr1, expr2, maxRetries)` | Composite with custom retry limit |
### PII & Masking
| Function | Description |
|---|---|
| `gen_locale('first_name', 'ja_JP')` | Locale-aware name/address/phone generation |
| `gen_locale('name', 'de_DE')` | Full name in locale order (eastern = last+first, western = first last) |
| `mask(value)` | Deterministic 16-char hex token (same input -> same output) |
| `mask(value, length)` | Hex token truncated to `length` chars |
| `mask(value, 'base64')` | Base64-encoded token |
| `mask(value, 'base32')` | Base32-encoded token |
| `mask(value, 'asterisk')` | Repeated `*` characters (default 16) |
| `mask(value, 'asterisk', 4)` | 4 asterisks |
| `mask(value, 'redact')` | Fixed string `[REDACTED]`, length ignored |
Auf GitHub ansehen