Skip to content

The iter Variable

Every generation function has access to the built-in iter variable, which represents the current record index (0-based). This enables you to generate sequential IDs, create batches, implement patterns, and build index-dependent logic.

The iter variable is available in all gens functions without any declaration:

User.dg
model User {
fields {
id() int
name() string
}
gens {
func id() {
return iter + 1 // 1-based IDs
}
func name() {
return fmt.Sprintf("User-%d", iter)
}
}
}

Running the example:

Terminal window
datagenc gen User.dg -n 3

Output:

Terminal window
User{id:1 name:User-0}
User{id:2 name:User-1}
User{id:3 name:User-2}

Generate 1-based or custom-offset IDs:

Records.dg
model Records {
fields {
id() int
custom_id() int
}
gens {
func id() {
return iter + 1 // 1, 2, 3, ...
}
func custom_id() {
return iter + 1000 // 1000, 1001, 1002, ...
}
}
}

Running the example:

Terminal window
datagenc gen Records.dg -n 5

Output:

Terminal window
Records{id:1 custom_id:1000}
Records{id:2 custom_id:1001}
Records{id:3 custom_id:1002}
Records{id:4 custom_id:1003}
Records{id:5 custom_id:1004}

Group records into batches:

Batch.dg
model Batch {
fields {
batch_id() int
batch_name() string
}
gens {
func batch_id() {
return iter / 100 // Batch 0: 0-99, Batch 1: 100-199, etc.
}
func batch_name() {
batchNum := iter / 50
return fmt.Sprintf("Batch-%d", batchNum)
}
}
}

Running the example:

Terminal window
datagenc gen Batch.dg -n 201

Output (showing records 0, 50, 100, 150, 200):

Terminal window
Batch{batch_id:0 batch_name:Batch-0} # iter=0
Batch{batch_id:0 batch_name:Batch-1} # iter=50
Batch{batch_id:1 batch_name:Batch-2} # iter=100
Batch{batch_id:1 batch_name:Batch-3} # iter=150
Batch{batch_id:2 batch_name:Batch-4} # iter=200

Create alternating or repeating patterns:

Records.dg
model Records {
fields {
is_active() bool
priority() string
is_special() bool
}
gens {
func is_active() {
return iter%2 == 0 // alternates: true, false, true, false...
}
func priority() {
priorities := []string{"low", "medium", "high"}
return priorities[iter%3] // cycles through priorities
}
func is_special() {
return iter%10 == 0 // every 10th record is special
}
}
}

Running the example:

Terminal window
datagenc gen Records.dg -n 12

Output:

Terminal window
Records{is_active:true priority:low is_special:true}
Records{is_active:false priority:medium is_special:false}
Records{is_active:true priority:high is_special:false}
Records{is_active:false priority:low is_special:false}
Records{is_active:true priority:medium is_special:false}
Records{is_active:false priority:high is_special:false}
Records{is_active:true priority:low is_special:false}
Records{is_active:false priority:medium is_special:false}
Records{is_active:true priority:high is_special:false}
Records{is_active:false priority:low is_special:false}
Records{is_active:true priority:medium is_special:true}
Records{is_active:false priority:high is_special:false}
Records.dg
model Records {
fields {
tier() string
discount() float64
}
gens {
func tier() {
if iter < 10 {
return "premium" // first 10 records
} else if iter < 50 {
return "standard" // next 40 records
} else {
return "basic" // remaining records
}
}
func discount() {
if iter%5 == 0 {
return 20.0 // every 5th record gets 20% discount
}
return 0.0
}
}
}

Running the example:

Terminal window
datagenc gen Records.dg -n 60

Output (showing key records):

Terminal window
Records{tier:premium discount:20} # iter=0
Records{tier:premium discount:0} # iter=5
Records{tier:premium discount:20} # iter=10
Records{tier:standard discount:0} # iter=12
Records{tier:standard discount:20} # iter=45
Records{tier:basic discount:0} # iter=51
Records{tier:basic discount:20} # iter=55

Generate timestamps with precise intervals based on the iteration index:

Event.dg
model Event {
fields {
id() int
created_at() time.Time
}
gens {
func id() {
return iter + 1
}
func created_at() {
// Each record is created 1 hour after the previous
baseTime := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC)
return baseTime.Add(time.Duration(iter) * time.Hour)
}
}
}

Running the example:

Terminal window
datagenc gen Event.dg -n 5

Output:

Terminal window
Event{id:1 created_at:{wall:0 ext:63839664000 loc:<nil>}}
Event{id:2 created_at:{wall:0 ext:63839667600 loc:<nil>}}
Event{id:3 created_at:{wall:0 ext:63839671200 loc:<nil>}}
Event{id:4 created_at:{wall:0 ext:63839674800 loc:<nil>}}
Event{id:5 created_at:{wall:0 ext:63839678400 loc:<nil>}}

Control the distribution of values across your dataset using modulo operations:

Account.dg
model Account {
fields {
id() int
status() string
}
gens {
func id() {
return iter + 1
}
func status() {
// 70% active, 20% inactive, 10% pending
if iter%10 < 7 {
return "active"
} else if iter%10 < 9 {
return "inactive"
}
return "pending"
}
}
}

Running the example:

Terminal window
datagenc gen Account.dg -n 10

Output:

Terminal window
Account{id:1 status:active}
Account{id:2 status:active}
Account{id:3 status:active}
Account{id:4 status:active}
Account{id:5 status:active}
Account{id:6 status:active}
Account{id:7 status:active}
Account{id:8 status:inactive}
Account{id:9 status:inactive}
Account{id:10 status:pending}

Generate compound keys for partitioned systems like databases or distributed storage:

DataRecord.dg
model DataRecord {
fields {
partition_key() int
row_key() int
value() string
}
gens {
func partition_key() {
return iter / 1000 // Partition ID
}
func row_key() {
return iter % 1000 // Row within partition
}
func value() {
return fmt.Sprintf("data-%d", iter)
}
}
}

Running the example:

Terminal window
datagenc gen DataRecord.dg -n 2501

Output (showing partition boundaries):

Terminal window
DataRecord{partition_key:0 row_key:0 value:data-0}
DataRecord{partition_key:0 row_key:999 value:data-999}
DataRecord{partition_key:1 row_key:0 value:data-1000}
DataRecord{partition_key:1 row_key:999 value:data-1999}
DataRecord{partition_key:2 row_key:0 value:data-2000}
DataRecord{partition_key:2 row_key:500 value:data-2500}
  1. Use iter for deterministic patterns: When you need predictable, repeatable data
  2. Combine with randomness: Mix iter with random functions for realistic variation
  3. Start with simple patterns: Test with small record counts first
  4. Document your logic: Complex iter-based patterns can be hard to understand later
// Incorrect: 0-based IDs
func id() {
return iter
}
// Correct: 1-based IDs
func id() {
return iter + 1
}
// Risky: iter=0 causes division by zero
func value() {
return 100 / iter
}
// Safe: Handle zero case
func value() {
if iter == 0 {
return 100
}
return 100 / iter
}