1. نصب ابزار ent
برای نصب ابزار تولید کد ent
، باید این مراحل را دنبال کنید:
ابتدا مطمئن شوید که محیط Go برنامه نویسی بر روی سیستم شما نصب شده است. سپس دستور زیر را اجرا کنید تا ابزار ent
را دریافت کنید:
go get -d entgo.io/ent/cmd/ent
این دستور کد ent
را دانلود میکند، اما آن را ترجمه و نصب نمیکند. اگر میخواهید ent
را در دایرکتوری $GOPATH/bin
نصب کنید تا بتوانید آن را در هر کجا استفاده کنید، باید دستور زیر را نیز اجرا کنید:
go install entgo.io/ent/cmd/ent
بعد از اتمام نصب، میتوانید با اجرای ent -h
بررسی کنید که آیا ابزار ent
به درستی نصب شده است و دستورها و دستورالعملهای موجود را ببینید.
2. مقدماتیسازی طرح
2.1 مقدماتیسازی الگو با استفاده از ent init
ایجاد یک پرونده طرح جدید، اولین گام برای استفاده از ent
برای تولید کد است. میتوانید الگوی طرح را با اجرای دستور زیر مقدماتیسازی کنید:
go run -mod=mod entgo.io/ent/cmd/ent new User Pet
این دستور دو پرونده طرح جدید به نامهای user.go
و pet.go
ایجاد میکند و آنها را در دایرکتوری ent/schema
قرار میدهد. اگر دایرکتوری ent
وجود نداشته باشد، این دستور نیز آن را به طور خودکار ایجاد میکند.
اجرای دستور ent init
در ریشه پروژه یک شیوه خوب است، زیرا به حفظ ساختار و وضوح دایرکتوری پروژه کمک میکند.
2.2 ساختار پرونده طرح
در دایرکتوری ent/schema
، هر طرح با یک پرونده منبع زبان Go متناظر است. پروندههای طرح، جایی هستند که مدل پایگاه داده و شامل فیلدها و یالها (رابطهها) را تعریف میکنید.
به عنوان مثال، در پرونده user.go
ممکن است یک مدل کاربر را تعریف کنید که شامل فیلدهایی مانند نام کاربری و سن است و رابطه بین کاربران و حیوانات خانگی را تعریف میکنید. به طور مشابه، در پرونده pet.go
، میتوانید مدل حیوانات خانگی و فیلدهای مرتبط با آن مانند نام، نوع و رابطه بین حیوانات خانگی و کاربران را تعریف کنید.
این پروندهها در نهایت توسط ابزار ent
برای تولید کد Go متناظر استفاده میشوند، شامل کد مشتری برای عملیات پایگاه داده و عملیات CRUD (ایجاد، خواندن، بهروزرسانی، حذف).
// ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// User تعریف طرح برای موجودیت کاربر.
type User struct {
ent.Schema
}
// Fields برای تعریف فیلدهای موجودیت استفاده میشود.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").Unique(),
field.Int("age").Positive(),
}
}
// Edges برای تعریف انجمنهای موجودیت استفاده میشود.
func (User) Edges() []ent.Edge {
// جزئیات انجمنها در بخش بعدی توضیح داده خواهد شد.
}
پروندههای طرح ent
از انواع و توابع زبان Go برای اعلام ساختار مدل پایگاه داده، شامل فیلدها و روابط بین مدلها استفاده میکنند و از رابط برنامه نویسی برای تعریف این ساختارها استفاده میکنند. این رویکرد باعث میشود ent
بسیار شفاف و آسان برای گسترش باشد و همچنین از نوعیت قوی زبان Go بهره ببرد.
3.1 اجرای تولید کد
اجرای ent generate
برای تولید کد، یک مرحله حیاتی در چارچوب ent
است. با این دستور، ent
فایلهای کد متناظری بر اساس طرحهای تعریف شده، تولید خواهد کرد که کار توسعهی بعدی را آسان میکند. دستور اجرای تولید کد به شکل ساده زیر است:
go generate ./ent
این دستور باید در ریشه پروژه اجرا شود. هنگامی که go generate
فراخوانی میشود، به دنبال تمام فایلهای Go میگردد که شامل شرحهای خاصی هستند و دستورات مشخص شده در شرحها را اجرا میکند. در مثال ما، این دستور مولد کد برای ent
را مشخص میکند.
حتماً اطمینان حاصل کنید که مقدماتیسازی طرح و افزودن فیلدهای ضروری انجام شده باشد قبل از اجرا. فقط در این صورت، کد تولیدشده شامل تمام بخشهای ضروری خواهد بود.
3.2 Understanding the Generated Code Assets
موارد کد تولیدی شامل چندین مولفه هستند، هر کدام با توابع مختلفی:
-
شیهای Client و Tx: برای تعامل با گراف داده استفاده میشوند. Client امکان ارائه متدها برای ایجاد تراکنشها (Tx) یا انجام مستقیم عملیات پایگاه داده را فراهم میکند.
-
سازندگان CRUD: برای هر نوع طرح، سازندگانی برای ایجاد، خواندن، به روزرسانی و حذف را ایجاد میکند که منطق عملیات مرتبط با موجودیت مورد نظر را ساده میکند.
-
شی موجودیت (Go struct): برای هر نوع در طرح، ساختارهای Go متناظری ایجاد میکند که این ساختارها را به جداول در پایگاه داده نگاشت میکند.
-
بستهی ثابتها و پردیکیتها: شامل ثابتها و پردیکیتها برای تعامل با سازندگان است.
-
بستهی مهاجرت: یک بسته برای مهاجرت پایگاه داده، مناسب برای لهجههای SQL.
-
بستهی گیریز: امکان اضافه کردن میانافزار تغییر را فراهم میکند که منطق سفارشی را قبل یا بعد از ایجاد، بهروزرسانی یا حذف موجودیتها اجرا میکند.
با بررسی کد تولیدی، میتوانید درک عمیقتری از نحوهی خودکار کردن کد دسترسی به داده برای طرحهای شمای ent
پیدا کنید.
4. گزینههای تولید کد
دستور ent generate
از گزینههای مختلفی برای سفارشیسازی فرآیند تولید کد پشتیبانی میکند. میتوانید تمام گزینههای تولید پشتیبانی شده را از طریق دستور زیر پرسوجو کنید:
ent generate -h
در زیر تعدادی از گزینههای معمول استفاده شده از خط فرمان آمده است:
-
--feature strings
: گسترش تولید کد با اضافه کردن قابلیتهای اضافی. -
--header string
: جایگزینی فایل سرآیند تولید کد. -
--storage string
: مشخص کردن درایور ذخیرهسازی پشتیبانی شده در تولید کد که بهطور پیشفرض "sql" است. -
--target string
: مشخص کردن دایرکتوری مقصد برای تولید کد. -
--template strings
: اجرای قالبهای Go اضافی. از فایل، دایرکتوری و مسیر جوکری پشتیبانی میکند، برای مثال:--template file="path/to/file.tmpl"
.
این گزینهها به توسعهدهندگان امکان میدهند فرآیند تولید کد خود را براساس نیازها و ترجیحات مختلف سفارشیسازی کنند.
5. پیکربندی گزینه ذخیرهسازی
ent
از تولید کد برای هر دو لهجهی SQL و Gremlin پشتیبانی میکند، بهطور پیشفرض لهجهی SQL است. اگر پروژه نیاز به اتصال به پایگاه داده Gremlin دارد، لهجهی پایگاه داده مورد نظر باید پیکربندی شود. در زیر نحوهی مشخص کردن گزینههای ذخیرهسازی نشان داده شده است:
ent generate --storage gremlin ./ent/schema
دستور فوق به ent
دستور میدهد که هنگام تولید کد از لهجهی Gremlin استفاده کند. این اطمینان مییابد که داراییهای تولید شده به نیازهای پایگاه داده Gremlin تنظیم شده باشند و سازگاری با یک پایگاه داده گراف مشخص را اطمینان میدهد.
6. استفاده پیشرفته: بسته entc
6.1 استفاده از entc
به عنوان یک بسته در پروژه
entc
بسته اصلی برای تولید کد در چارچوب ent
است. علاوه بر ابزار خط فرمان، entc
همچنین میتواند به عنوان یک بسته به پروژه اضافه شود و امکان کنترل و سفارشیسازی فرآیند تولید کد در داخل خود کد را فراهم میکند.
برای استفاده از entc
به عنوان یک بسته در پروژه، باید یک فایل با نام entc.go
ایجاد کرده و محتوای زیر را به فایل اضافه کنید:
// +build ignore
package main
import (
"log"
"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)
func main() {
if err := entc.Generate("./schema", &gen.Config{}); err != nil {
log.Fatal("running ent codegen:", err)
}
}
در این روش، میتوانید ساختار gen.Config
را درون تابع main
تغییر دهید تا گزینههای پیکربندی مختلف را اعمال کنید. با فراخوانی تابع entc.Generate
بهصورت نیازمند، میتوانید بهصورت انعطافپذیر فرآیند تولید کد را کنترل کنید.
6.2 پیکربندی دقیق entc
entc
گزینههای پیکربندی فراوانی ارائه میدهد که به توسعهدهندگان امکان سفارشیسازی کدهای تولیدشده را میدهد. به عنوان مثال، قابلیت پیکربندی هواکهای سفارشی برای بازرسی یا اصلاح کدهای تولیدشده و درج وابستگیهای خارجی با استفاده از تزریق وابستگی وجود دارد.
مثال زیر نشان میدهد چگونه میتوان هواکهای سفارشی برای تابع entc.Generate
ارائه داد:
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
HookFunction,
},
})
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
// HookFunction یک تابع هواک سفارشی است
func HookFunction(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
// ممکن است مود گراف را که توسط g نماینده شده است، در اینجا پردازش نماید
// به عنوان مثال، اعتبار سنجی وجود فیلدها یا اصلاح ساختار
return next.Generate(g)
})
}
به علاوه، میتوان از entc.Dependency
برای افزودن وابستگیهای خارجی استفاده کرد:
func main() {
opts := []entc.Option{
entc.Dependency(
entc.DependencyType(&http.Client{}),
),
entc.Dependency(
entc.DependencyName("Writer"),
entc.DependencyTypeInfo(&field.TypeInfo{
Ident: "io.Writer",
PkgPath: "io",
}),
),
}
if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
در این مثال، ما http.Client
و io.Writer
را به عنوان وابستگیها به اشیاء ساختهشده تزریق میکنیم.
7. خروجی توضیحات طراحی
در چارچوب ent
، دستور ent describe
برای خروجی دادن توضیحات طرح در یک قالب گرافیکی قابل استفاده است. این کار به توسعهدهندگان کمک میکند تا به سرعت موجودیتها و روابط موجود را درک کنند.
به منظور دریافت توضیحات طرح از دستور زیر استفاده نمایید:
go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema
دستور فوق، یک جدول شبیه به زیر را خروجی میدهد و اطلاعاتی همچون فیلدها، انواع داده، روابط و غیره برای هر موجودیت نمایش میدهد:
User:
+-------+---------+--------+-----------+ ...
| Field | Type | Unique | Optional | ...
+-------+---------+--------+-----------+ ...
| id | int | false | false | ...
| name | string | true | false | ...
+-------+---------+--------+-----------+ ...
+-------+--------+---------+-----------+ ...
| Edge | Type | Inverse | Relation | ...
+-------+--------+---------+-----------+ ...
| pets | Pet | false | O2M | ...
+-------+--------+---------+-----------+ ...
8. هواکهای تولید کد
8.1 مفهوم هواکها
هواکها توابع وسطافزاری هستند که میتوانند در فرآیند تولید کد ent
درج شود و اجازه میدهند تا منطق سفارشی قبل و بعد از تولید کدها درج شود. هواکها میتوانند برای دستکاری درخت نحو انتزاعی (AST) کدهای تولیدشده، انجام اعتبارسنجی یا اضافه کردن قطعهکدهای اضافی استفاده شوند.
8.2 مثالی از استفاده از هواکها
در زیر مثالی از استفاده از هوک برای اطمینان از وجود یک تگ ساختاری خاص (مثلاً json
) در تمام فیلدها وجود دارد:
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
EnsureStructTag("json"),
},
})
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}
// EnsureStructTag اطمینان دادن از وجود تگ ساختاری خاص در فیلدهای گراف
func EnsureStructTag(name string) gen.Hook {
return func(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
for _, node := range g.Nodes {
for _, field := range node.Fields {
tag := reflect.StructTag(field.StructTag)
if _, ok := tag.Lookup(name); !ok {
return fmt.Errorf("تگ ساختاری %q برای فیلد %s.%s وجود ندارد", name, node.Name, field.Name)
}
}
}
return next.Generate(g)
})
}
}
در این مثال، قبل از تولید کد، تابع EnsureStructTag
برای هر فیلد، تگ json
را بررسی میکند. اگر یک فیلد این تگ را نداشته باشد، مولفهدهی کد متوقف و یک خطای برگشتی میدهد. این یک راه کار موثر برای حفظ تمیزی و سازگاری کدها است.