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.
Basic Usage
Section titled “Basic Usage”The iter variable is available in all gens functions without any declaration:
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:
datagenc gen User.dg -n 3Output:
User{id:1 name:User-0}User{id:2 name:User-1}User{id:3 name:User-2}Common Patterns
Section titled “Common Patterns”Sequential IDs
Section titled “Sequential IDs”Generate 1-based or custom-offset IDs:
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:
datagenc gen Records.dg -n 5Output:
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}Batch Grouping
Section titled “Batch Grouping”Group records into batches:
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:
datagenc gen Batch.dg -n 201Output (showing records 0, 50, 100, 150, 200):
Batch{batch_id:0 batch_name:Batch-0} # iter=0Batch{batch_id:0 batch_name:Batch-1} # iter=50Batch{batch_id:1 batch_name:Batch-2} # iter=100Batch{batch_id:1 batch_name:Batch-3} # iter=150Batch{batch_id:2 batch_name:Batch-4} # iter=200Alternating Patterns
Section titled “Alternating Patterns”Create alternating or repeating patterns:
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:
datagenc gen Records.dg -n 12Output:
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}Conditional Logic
Section titled “Conditional Logic”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:
datagenc gen Records.dg -n 60Output (showing key records):
Records{tier:premium discount:20} # iter=0Records{tier:premium discount:0} # iter=5Records{tier:premium discount:20} # iter=10Records{tier:standard discount:0} # iter=12Records{tier:standard discount:20} # iter=45Records{tier:basic discount:0} # iter=51Records{tier:basic discount:20} # iter=55Advanced Techniques
Section titled “Advanced Techniques”Time-Based Sequences
Section titled “Time-Based Sequences”Generate timestamps with precise intervals based on the iteration index:
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:
datagenc gen Event.dg -n 5Output:
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>}}Distribution Control
Section titled “Distribution Control”Control the distribution of values across your dataset using modulo operations:
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:
datagenc gen Account.dg -n 10Output:
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}Compound Keys
Section titled “Compound Keys”Generate compound keys for partitioned systems like databases or distributed storage:
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:
datagenc gen DataRecord.dg -n 2501Output (showing partition boundaries):
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}Best Practices
Section titled “Best Practices”- Use iter for deterministic patterns: When you need predictable, repeatable data
- Combine with randomness: Mix
iterwith random functions for realistic variation - Start with simple patterns: Test with small record counts first
- Document your logic: Complex iter-based patterns can be hard to understand later
Common Pitfalls
Section titled “Common Pitfalls”Off-by-One Errors
Section titled “Off-by-One Errors”// Incorrect: 0-based IDsfunc id() { return iter}
// Correct: 1-based IDsfunc id() { return iter + 1}Division by Zero
Section titled “Division by Zero”// Risky: iter=0 causes division by zerofunc value() { return 100 / iter}
// Safe: Handle zero casefunc value() { if iter == 0 { return 100 } return 100 / iter}See Also
Section titled “See Also”- Data Model - Core model concepts
- Examples - iter - Practical iter examples
- Model References - Using iter with references