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.

orders.yaml
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 }
ghostbakery-output.csv
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.09

Four 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 json object. Put the fields you refer to first.
  • Empty stays empty. If the field referred to is empty in a record (see emptyRate), eqfield gives an empty value and gtfield/ltefield are 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:

keys.yaml
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.