Skip to content

Model References

datagen allows you to create relationships between different models, enabling you to generate realistic, interconnected data. The self.datagen object is used to reference fields from other models, while self references fields from the same model.

self.field_name(iter)
self.datagen.ModelName().field_name(iter)

If you request an index beyond already-generated rows, datagen automatically generates rows up to that index, then returns the requested value.

Example:

Project.dg
// User model has metadata count: 5 (generates only 5 rows initially)
// But in Project model, we access User.id(10)
func owner_id() {
return self.datagen.User().id(10)
// Datagen will generate User rows for iter 5-10 first, then return id(10)
}

datagen separates three distinct responsibilities:

  1. Generation logic - Defined in gens functions (how to create values)
  2. Parameter values - Provided in calls section (configuration for parameterized fields)
  3. Field access - Done via self or self.datagen (retrieving generated values)

Example:

Product.dg
model Product {
fields {
id() int
price(min float64, max float64) float64 // Parameterized field
discounted_price() float64
}
gens {
func id() {
return iter + 1
}
// Generation logic: how to create a price
func price(min float64, max float64) {
return FloatBetween(min, max)
}
func discounted_price() {
// Access: retrieve the generated price value
return self.price(iter) * 0.9
}
}
// Parameter values: configure the price range
calls {
price(10.0, 100.0)
}
}

In this example:

  • Generation logic (FloatBetween) is in the price function
  • Parameter values (10.0, 100.0) are in the calls section
  • Field access (self.price(iter)) retrieves the generated value

Reference other fields within the same model to create calculated or dependent fields.

Order.dg
model Order {
fields {
id() int
base_amount() float64
tax_amount() float64
total_amount() float64
}
gens {
func id() {
return iter + 1
}
func base_amount() {
return FloatBetween(50.0, 500.0)
}
func tax_amount() {
return self.base_amount(iter) * 0.08
}
func total_amount() {
return self.base_amount(iter) + self.tax_amount(iter)
}
}
}

Running the example:

Terminal window
datagenc gen Order.dg -n 5

Output:

Terminal window
Order{id:1 base_amount:152.76 tax_amount:12.220799999999999 total_amount:164.9808}
Order{id:2 base_amount:477.97 tax_amount:38.2376 total_amount:516.2076000000001}
Order{id:3 base_amount:350.43 tax_amount:28.0344 total_amount:378.4644}
Order{id:4 base_amount:80.09 tax_amount:6.4072000000000005 total_amount:86.4972}
Order{id:5 base_amount:170.45 tax_amount:13.636 total_amount:184.08599999999998}

Create relationships between different models to generate interconnected, realistic data.

Create two models in a directory library:

Author.dg
model Author {
fields {
id() int
name() string
country() string
}
gens {
func id() {
return iter + 1
}
func name() {
return Name()
}
func country() {
countries := []string{"USA", "UK", "Canada", "Australia", "India"}
return countries[IntBetween(0, len(countries)-1)]
}
}
}
Book.dg
model Book {
fields {
id() int
title() string
author_id() int
author_name() string
}
gens {
func id() {
return iter + 1
}
func title() {
return fmt.Sprintf("Book Title %d", iter+1)
}
func author_id() {
// Reference Author model's id field
return self.datagen.Author().id(IntBetween(0, 4))
}
func author_name() {
// Reference Author model's name field
authorIdx := self.author_id(iter) - 1
return self.datagen.Author().name(authorIdx)
}
}
}

Running the example:

Terminal window
datagenc gen ./library -n 5

Output:

Terminal window
Author{id:1 name:Lillian Haley country:USA}
Author{id:2 name:Emilie Torphy country:Canada}
Author{id:3 name:Verner Nicolas country:India}
Author{id:4 name:Macie Schowalter country:UK}
Author{id:5 name:Americo Konopelski country:Australia}
Book{id:1 title:Book Title 1 author_id:2 author_name:Emilie Torphy}
Book{id:2 title:Book Title 2 author_id:4 author_name:Macie Schowalter}
Book{id:3 title:Book Title 3 author_id:1 author_name:Lillian Haley}
Book{id:4 title:Book Title 4 author_id:3 author_name:Verner Nicolas}
Book{id:5 title:Book Title 5 author_id:2 author_name:Emilie Torphy}

Create complex relationships with conditional logic:

Customer.dg
model Customer {
metadata {
count: 1000
}
fields {
id() int
tier() string
}
gens {
func id() {
return iter + 1
}
func tier() {
rand := IntBetween(1, 100)
if rand <= 10 {
return "premium"
} else if rand <= 40 {
return "gold"
}
return "standard"
}
}
}
Order.dg
model Order {
fields {
id() int
customer_id() int
discount() float32
total() float32
}
gens {
func id() {
return iter + 1
}
func customer_id() {
return self.datagen.Customer().id(IntBetween(0, 999))
}
func discount() {
// Get customer tier and apply discount
tier := self.datagen.Customer().tier(iter)
if tier == "premium" {
return 20.0
} else if tier == "gold" {
return 10.0
}
return 2.0
}
func total() {
base := Float32Between(100.0, 500.0)
discount := self.discount(iter)
return base * (1.0 - discount/100.0)
}
}
}

Running the example:

Terminal window
datagenc gen ./orders -n 5

Output:

Terminal window
Customer{id:1 tier:standard}
Customer{id:2 tier:standard}
Customer{id:3 tier:standard}
Customer{id:4 tier:standard}
Customer{id:5 tier:premium}
Order{id:1 customer_id:444 discount:2 total:288.7864}
Order{id:2 customer_id:519 discount:2 total:397.6546}
Order{id:3 customer_id:519 discount:2 total:378.1134}
Order{id:4 customer_id:563 discount:2 total:337.071}
Order{id:5 customer_id:693 discount:20 total:265.168}
// In Order model
func user_id() {
maxUsers := 1000
return self.datagen.User().id(IntBetween(0, maxUsers-1))
}
// In Payment model
func order_id() {
return self.datagen.Order().id(iter)
}
func customer_id() {
// Get customer_id from the referenced Order
return self.datagen.Order().customer_id(iter)
}
func assigned_user() {
totalUsers := 50
return self.datagen.User().id(iter % totalUsers)
}
func manager_id() {
if iter < 10 {
return 1 // First 10 records report to manager 1
}
return self.datagen.User().id(IntBetween(0, 9))
}
  1. Data Consistency - Ensures referenced IDs actually exist
  2. Realistic Relationships - Creates proper foreign key relationships
  3. Dynamic References - Can reference any field from any model
  4. Flexible Logic - Combine multiple model references in complex ways