Relationships
Bob のコード生成では、データベースのリレーションシップを自動的に検出し、対応するコードを生成します。
自動リレーションシップ検出
Bob は外部キー制約に基づいて自動的にリレーションシップを検出します。
基本的な外部キー
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
user_id INTEGER REFERENCES users(id),
title VARCHAR(200),
content TEXT
);
この場合、Bob は以下のリレーションシップを生成します:
// User モデル
type User struct {
ID int `db:"id"`
Name string `db:"name"`
}
// Post モデル
type Post struct {
ID int `db:"id"`
UserID int `db:"user_id"`
Title string `db:"title"`
Content string `db:"content"`
}
// リレーションシップメソッド
func (u *User) Posts() *PostQuery {
return Posts.Query().Where(PostColumns.UserID.EQ(psql.Arg(u.ID)))
}
func (p *Post) User() *UserQuery {
return Users.Query().Where(UserColumns.ID.EQ(psql.Arg(p.UserID)))
}
One-to-One リレーションシップ
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE user_profiles (
id SERIAL PRIMARY KEY,
user_id INTEGER UNIQUE REFERENCES users(id),
bio TEXT,
avatar_url VARCHAR(255)
);
生成されるコード:
// User から UserProfile へのリレーション
func (u *User) Profile() *UserProfileQuery {
return UserProfiles.Query().Where(UserProfileColumns.UserID.EQ(psql.Arg(u.ID)))
}
// UserProfile から User へのリレーション
func (p *UserProfile) User() *UserQuery {
return Users.Query().Where(UserColumns.ID.EQ(psql.Arg(p.UserID)))
}
One-to-Many リレーションシップ
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE products (
id SERIAL PRIMARY KEY,
category_id INTEGER REFERENCES categories(id),
name VARCHAR(100),
price DECIMAL(10,2)
);
生成されるコード:
// Category から Products へのリレーション
func (c *Category) Products() *ProductQuery {
return Products.Query().Where(ProductColumns.CategoryID.EQ(psql.Arg(c.ID)))
}
// Product から Category へのリレーション
func (p *Product) Category() *CategoryQuery {
return Categories.Query().Where(CategoryColumns.ID.EQ(psql.Arg(p.CategoryID)))
}
Many-to-Many リレーションシップ
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE roles (
id SERIAL PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE user_roles (
user_id INTEGER REFERENCES users(id),
role_id INTEGER REFERENCES roles(id),
PRIMARY KEY (user_id, role_id)
);
生成されるコード:
// User から Roles へのリレーション(中間テーブル経由)
func (u *User) Roles() *RoleQuery {
return Roles.Query().
Join("user_roles", RoleColumns.ID.EQ(psql.Quote("user_roles", "role_id"))).
Where(psql.Quote("user_roles", "user_id").EQ(psql.Arg(u.ID)))
}
// Role から Users へのリレーション(中間テーブル経由)
func (r *Role) Users() *UserQuery {
return Users.Query().
Join("user_roles", UserColumns.ID.EQ(psql.Quote("user_roles", "user_id"))).
Where(psql.Quote("user_roles", "role_id").EQ(psql.Arg(r.ID)))
}
カスタムリレーションシップ
設定ファイルでカスタムリレーションシップを定義できます:
relationships:
- name: "recent_posts"
local_table: "users"
foreign_table: "posts"
local_columns: ["id"]
foreign_columns: ["user_id"]
type: "has_many"
where: "created_at > NOW() - INTERVAL '30 days'"
- name: "active_users"
local_table: "posts"
foreign_table: "users"
local_columns: ["user_id"]
foreign_columns: ["id"]
type: "belongs_to"
where: "active = true"
生成されるコード:
// カスタムリレーション
func (u *User) RecentPosts() *PostQuery {
return Posts.Query().
Where(PostColumns.UserID.EQ(psql.Arg(u.ID))).
Where(psql.Raw("created_at > NOW() - INTERVAL '30 days'"))
}
func (p *Post) ActiveUser() *UserQuery {
return Users.Query().
Where(UserColumns.ID.EQ(psql.Arg(p.UserID))).
Where(psql.Raw("active = true"))
}
Eager Loading
生成されたリレーションシップは Eager Loading をサポートします:
// ユーザーと関連する投稿を一度に取得
users, err := Users.Query().
Preload("Posts").
All(ctx, db)
// 投稿と関連するユーザーを取得
posts, err := Posts.Query().
Preload("User").
All(ctx, db)
// 複数のリレーションを同時に読み込み
users, err := Users.Query().
Preload("Posts", "Profile").
All(ctx, db)
複合外部キー
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER,
branch_id INTEGER
);
CREATE TABLE order_items (
id SERIAL PRIMARY KEY,
order_id INTEGER,
customer_id INTEGER,
branch_id INTEGER,
product_id INTEGER,
FOREIGN KEY (order_id, customer_id, branch_id)
REFERENCES orders(id, customer_id, branch_id)
);
生成されるコード:
func (o *Order) Items() *OrderItemQuery {
return OrderItems.Query().
Where(
OrderItemColumns.OrderID.EQ(psql.Arg(o.ID)),
OrderItemColumns.CustomerID.EQ(psql.Arg(o.CustomerID)),
OrderItemColumns.BranchID.EQ(psql.Arg(o.BranchID)),
)
}
設定オプション
relationships:
enabled: true
auto_detect: true
eager_loading: true
naming:
singular: true
plural: true
include:
- "users"
- "posts"
exclude:
- "migrations"
- "sessions"
これらの機能により、Bob は複雑なデータベースリレーションシップを自動的に検出し、使いやすい Go コードを生成します。