Related values in one record
Real records have rules: updated_at comes after created_at, a sale price is not above the price, a confirmation matches the original. Ghost Bakery generates every field on its own unless the recipe links it to an earlier one.
version: "1"
output: { language: eng, format: csv, quantity: 3 }
fields:
- { name: id, type: autoint, start: 1001 }
- { name: reference, type: template, template: "ORD-{{id}}" }
- { name: email, type: email }
- { name: email_confirmation, type: email, eqfield: email }
- { name: email_sha256, type: hash, algorithm: sha256, sourceField: email }
- { name: created_at, type: datetime, min: "2024-01-01T00:00:00Z", max: "2024-06-30T23:59:59Z" }
- { name: updated_at, type: datetime, min: "2024-01-01T00:00:00Z", max: "2024-12-31T23:59:59Z", gtfield: created_at }
- { name: price, type: decimal, min: 10, max: 200, precision: 2 }
- { name: sale_price, type: decimal, min: 5, max: 200, precision: 2, ltefield: price }id,reference,email,email_confirmation,email_sha256,created_at,updated_at,price,sale_price
1001,ORD-1001,rebecca.edwards103@example.com,rebecca.edwards103@example.com,c48f5b37…,2024-06-07T07:52:49Z,2024-12-04T20:08:36Z,188.12,144.94
1002,ORD-1002,mark.butler574@example.com,mark.butler574@example.com,c0c18dac…,2024-06-24T16:55:37Z,2024-08-23T19:38:56Z,181.27,99.09Four tools
| Need | Use | How it works |
|---|---|---|
| Build a value from others | template |
Replaces each {{field}} with that field's value in the same record. |
| Fingerprint a value | hash |
Digests sourceField, or a template, with md5, sha256 and others. |
| Repeat a value | eqfield |
Copies the earlier field exactly. |
| Keep an order | gtfield, ltefield |
Draws again until the value is greater than, or at most, the earlier field. |
Two rules apply to all of them:
- Only earlier fields. A field can refer to fields declared above it in the same list — never below, and never outside its
jsonobject. Put the fields you refer to first. - Empty stays empty. If the field referred to is empty in a record (see
emptyRate),eqfieldgives an empty value andgtfield/ltefieldare skipped for that record.
Keep ranges overlapping
gtfield and ltefield do not narrow the range: they draw again, up to 256 times per record, and the job fails if no draw fits. In the example, updated_at may fall anywhere in 2024 but must follow a created_at from the first half, which almost always works at the first or second draw. A dependent range that barely overlaps its reference makes the job slow and likely to fail.
Compose, then transform
Textual options apply after the value is built, so a template can be cased and prefixed like any other text:
version: "1"
output: { language: eng, format: csv, quantity: 3 }
fields:
- { name: city, type: text, category: city }
- { name: id, type: autoint }
- { name: branch_key, type: template, template: "{{city}}-{{id}}", uppercase: true, prefix: "BR-" }This produces keys such as BR-BOSTON-1. Case changes and prefix/suffix always apply; length and character constraints are checks that fail the job when a value breaks them — see Textual constraints.