Using Context
View SourceSometimes you need to compute data once and share it across multiple tables. Blink provides the context feature for this purpose. Context data is not inserted into the database, but is available when building your table data.
What is context?
Context is arbitrary data stored in store.context that you can access from any table/2 or context/2 callback. It's useful for:
- Sharing computed values across tables (e.g., timestamps, IDs)
- Pre-generating data that multiple tables need
- Storing lookup tables or reference data
- Avoiding redundant computations
Basic example
Let's say we want to generate consistent timestamps and use them across multiple tables:
defmodule Blog.Seeders.BlogSeeder do
use Blink
def call do
new()
|> add_context("timestamps") # Register context first
|> add_table("users")
|> add_table("posts")
|> insert(Blog.Repo)
end
def context(_store, "timestamps") do
# Generate 30 days of timestamps
base = ~U[2024-01-01 00:00:00Z]
for day <- 0..29, do: DateTime.add(base, day, :day)
end
def table(store, "users") do
timestamps = store.context["timestamps"]
for i <- 1..100 do
%{
id: i,
name: "User #{i}",
email: "user#{i}@example.com",
inserted_at: Enum.random(timestamps),
updated_at: Enum.random(timestamps)
}
end
end
def table(store, "posts") do
users = store.tables["users"]
timestamps = store.context["timestamps"]
Enum.flat_map(users, fn user ->
for i <- 1..5 do
%{
id: (user.id - 1) * 5 + i,
title: "Post #{i}",
body: "Content here",
user_id: user.id,
inserted_at: Enum.random(timestamps),
updated_at: Enum.random(timestamps)
}
end
end)
end
endIn this example, we generate timestamps once and reuse them across both the users and posts tables.
Context with relationships
Context can help maintain referential integrity by providing consistent reference data:
def call do
new()
|> add_context("user_ids")
|> add_table("users")
|> add_table("posts")
|> add_table("comments")
|> insert(Blog.Repo)
end
def context(_store, "user_ids") do
# Generate a pool of user IDs
Enum.to_list(1..1000)
end
def table(store, "users") do
user_ids = store.context["user_ids"]
for id <- user_ids do
%{
id: id,
name: "User #{id}",
email: "user#{id}@example.com",
inserted_at: ~U[2024-01-01 00:00:00Z],
updated_at: ~U[2024-01-01 00:00:00Z]
}
end
end
def table(store, "posts") do
user_ids = store.context["user_ids"]
for i <- 1..5000 do
%{
id: i,
title: "Post #{i}",
body: "Content",
user_id: Enum.random(user_ids),
inserted_at: ~U[2024-01-01 00:00:00Z],
updated_at: ~U[2024-01-01 00:00:00Z]
}
end
end
def table(store, "comments") do
user_ids = store.context["user_ids"]
posts = store.tables["posts"]
Enum.flat_map(posts, fn post ->
for i <- 1..3 do
%{
id: (post.id - 1) * 3 + i,
body: "Comment #{i}",
post_id: post.id,
user_id: Enum.random(user_ids),
inserted_at: ~U[2024-01-01 00:00:00Z],
updated_at: ~U[2024-01-01 00:00:00Z]
}
end
end)
endContext for realistic data
Use context to generate realistic, consistent data:
def call do
new()
|> add_context("timestamps")
|> add_table("users")
|> add_table("posts")
|> insert(Blog.Repo)
end
def context(_store, "timestamps") do
base = ~U[2024-01-01 00:00:00Z]
for day <- 0..29, do: DateTime.add(base, day, :day)
end
def table(store, "users") do
timestamps = store.context["timestamps"]
for i <- 1..100 do
%{
id: i,
name: "User #{i}",
email: "user#{i}@example.com",
inserted_at: Enum.random(timestamps),
updated_at: Enum.random(timestamps)
}
end
end
def table(store, "posts") do
users = store.tables["users"]
timestamps = store.context["timestamps"]
Enum.flat_map(users, fn user ->
# Only use timestamps after the user was created
valid_timestamps =
Enum.filter(timestamps, fn ts ->
DateTime.compare(ts, user.inserted_at) == :gt
end)
for i <- 1..5 do
%{
id: (user.id - 1) * 5 + i,
title: "Post #{i}",
body: "Content here",
user_id: user.id,
inserted_at: Enum.random(valid_timestamps),
updated_at: Enum.random(valid_timestamps)
}
end
end)
endIn this example, we ensure posts are created after their associated user by filtering the available timestamps.
Summary
In this guide, we learned how to:
- Add context data with
add_context/2 - Define context callbacks with
context/2 - Access context from table callbacks via
store.context
For more information, see the Blink API documentation.