1. ent aracısının kurulması

ent kod oluşturma aracını kurmak için aşağıdaki adımları takip etmeniz gerekmektedir:

Öncelikle sisteminizde Go dil ortamının kurulu olduğundan emin olun. Ardından, aşağıdaki komutu çalıştırarak ent aracını elde edin:

go get -d entgo.io/ent/cmd/ent

Bu komut ent aracı için kodu indirecek ancak derlemeye ve hemen kurmaya değil. ent aracını her yerde kullanabilmeniz için $GOPATH/bin dizinine kurmak istiyorsanız aşağıdaki komutu da çalıştırmanız gerekmektedir:

go install entgo.io/ent/cmd/ent

Kurulum tamamlandığında ent aracının uygun şekilde kurulup kurulmadığını kontrol etmek ve kullanılabilir komutları ve talimatları görmek için ent -h komutunu çalıştırabilirsiniz.

2. Şema Başlatma

2.1 ent init Kullanarak Şema Başlatma

Kod oluşturma için ent'yi kullanmaya başlamanın ilk adımı yeni bir şema dosyası oluşturmaktır. Aşağıdaki komutu çalıştırarak şema şablonunu başlatabilirsiniz:

go run -mod=mod entgo.io/ent/cmd/ent new User Pet

Bu komut iki yeni şema dosyası olan user.go ve pet.go dosyaları oluşturacak ve bunları ent/schema dizinine yerleştirecektir. Eğer ent dizini mevcut değilse, bu komut otomatik olarak oluşturacaktır.

Proje kök dizininde ent init komutunu çalıştırmak, proje dizininin yapısını ve netliğini korumaya yardımcı olan iyi bir uygulamadır.

2.2 Şema Dosyası Yapısı

ent/schema dizininde her şema bir Go dilindeki bir kaynak dosyasına denk gelir. Şema dosyaları veritabanı modelini, alanları ve kenarları (ilişkileri) tanımladığınız yerlerdir.

Örneğin, user.go dosyasında kullanıcı modelini, kullanıcı adı ve yaş gibi alanları tanımlayabilir ve kullanıcılar ve evcil hayvanlar arasındaki ilişkiyi tanımlayabilirsiniz. Benzer şekilde, pet.go dosyasında, evcil hayvan modelini ve adı, türü gibi ilgili alanları ve evcil hayvanlar ile kullanıcılar arasındaki ilişkiyi tanımlayabilirsiniz.

Bu dosyalar sonunda ent aracı tarafından veritabanı işlemleri ve CRUD (Oluşturma, Okuma, Güncelleme, Silme) işlemleri için istemci kodunu oluşturmak için kullanılacaktır.

// ent/schema/user.go
package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/schema/field"
)

// User, Kullanıcı varlığı için şemayı tanımlar.
type User struct {
    ent.Schema
}

// Fields yöntemi varlığın alanlarını tanımlamak için kullanılır.
func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("name").Unique(),
        field.Int("age").Positive(),
    }
}

// Edges yöntemi varlığın ilişkilerini tanımlamak için kullanılır.
func (User) Edges() []ent.Edge {
    // İlişkiler bir sonraki bölümde daha detaylı açıklanacaktır.
}

ent'in şema dosyaları, veritabanı modelinin yapısını, alanları ve modeller arasındaki ilişkileri belirtmek için Go dilindeki türleri ve fonksiyonları kullanır ve bu yapıları tanımlamak için ent çerçevesinin sağladığı API'yi kullanır. Bu yaklaşım, ent'i çok sezgisel ve genişletmesi kolay hale getirirken aynı zamanda Go dilinin güçlü tip sisteminden de faydalanır.

3.1 Kod Oluşturma İşleminin Çalıştırılması

Kod oluşturma işlemini başlatmak ent çerçevesinde kritik bir adımdır. Bu komut ile tanımlanan şemalara dayalı olarak karşılık gelen Go kod dosyalarını oluşturarak sonraki geliştirme işini kolaylaştıracaktır. Kod oluşturma işlemini yürütmek için kullanılacak komut oldukça basittir:

go generate ./ent

Yukarıdaki komut proje kök dizininde çalıştırılmalıdır. go generate çağrıldığında, belirli açıklamalar içeren tüm Go dosyaları aranacak ve açıklamalarda belirtilen komutlar çalıştırılacaktır. Örneğimizde bu komut, ent için kod oluşturucuyu belirtmektedir.

Yürütmeden önce şema başlatma ve gerekli alan eklemelerinin tamamlandığından emin olun. Ancak o zaman oluşturulan kod tüm gerekli parçaları içerecektir.

3.2 Oluşturulan Kod Varlıklarını Anlama

Oluşturulan kod varlıkları farklı işlevlere sahip birçok bileşeni içerir:

  • Client ve Tx nesneleri: Veri grafiğiyle etkileşim kurmak için kullanılır. Client, işlemler oluşturmak için (Tx) veya doğrudan veritabanı işlemlerini gerçekleştirmek için yöntemler sağlar.

  • CRUD oluşturucuları: Her şema türü için, karşılık gelen varlık işlemlerinin (oluşturma, okuma, güncelleme ve silme) oluşturucularını oluşturur ve ilgili varlığın işlem mantığını basitleştirir.

  • Varlık nesnesi (Go struct): Şemadaki her tür için karşılık gelen Go yapılarını oluşturur ve bu yapıları veritabanındaki tablolara eşler.

  • Sabitler ve predicate paketi: Oluşturucularla etkileşim için sabitler ve predicate'leri içerir.

  • Migrate paketi: SQL lehçeleri için uygun olan veritabanı göçü için bir paket sağlar.

  • Hook paketi: Değişiklik middleware'ı eklemek için işlevsellik sağlar ve varlıklar oluşturulmadan önce veya sonra özel mantığın yürütülmesine izin verir.

Oluşturulan kodları inceleyerek, ent çerçevesinin şemalarınız için veri erişim kodlarını otomatikleştirme sürecini daha derinlemesine anlayabilirsiniz.

4. Kod Oluşturma Seçenekleri

ent generate komutu, kod oluşturma sürecini özelleştirmek için çeşitli seçenekleri destekler. Tüm desteklenen oluşturma seçeneklerini aşağıdaki komut aracılığıyla sorgulayabilirsiniz:

ent generate -h

İşte bazı yaygın kullanılan komut satırı seçenekleri:

  • --feature strings: Ek fonksiyonelliği ekleyerek kod oluşturmayı genişletir.
  • --header string: Kod oluşturma başlık dosyasını geçersiz kılar.
  • --storage string: Kod oluşturmada desteklenen depolama sürücüsünü belirtir, varsayılan olarak "sql" olarak ayarlanır.
  • --target string: Kod oluşturma hedef dizinini belirtir.
  • --template strings: Ek Go şablonlarını yürütür. Dosya, dizin ve joker yolunu destekler, örneğin: --template file="path/to/file.tmpl".

Bu seçenekler, geliştiricilere farklı ihtiyaçlara ve tercihlere göre kod oluşturma sürecini özelleştirmelerine olanak tanır.

5. Depolama Seçeneği Yapılandırma

ent, varsayılan olarak SQL lehçesini desteklerken, SQL ve Gremlin lehçeleri için kod varlıklarının oluşturulmasını destekler. Projenin Gremlin veritabanına bağlanması gerekiyorsa, ilgili veritabanı lehçesinin yapılandırılması gerekmektedir. Aşağıdaki, depolama seçeneklerinin nasıl belirtileceğini gösterir:

ent generate --storage gremlin ./ent/schema

Yukarıdaki komut, kod oluşturulurken Gremlin lehçesinin kullanılmasını ent'e talimat verir. Bu, oluşturulan varlıkların belirli bir graf veritabanıyla uyumlu olmasını sağlayarak Gremlin veritabanı gereksinimlerine uygun hale getirilmesini sağlar.

6. Gelişmiş Kullanım: entc Paketi

6.1 entc'nin Projedeki Paket Olarak Kullanımı

entc, ent çerçevesinde kod oluşturma için kullanılan temel bir pakettir. Komut satırı aracının yanı sıra, entc ayrıca projeye paket olarak entegre edilebilir, bu sayede geliştiriciler kod oluşturma sürecini kendileri kod içinde kontrol edip özelleştirebilirler.

entc'yi projedeki bir paket olarak kullanmak için, entc.go adında bir dosya oluşturmanız ve dosyaya aşağıdaki içeriği eklemeniz gerekmektedir:

// +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("ent codegen çalıştırılırken hata oluştu:", err)
    }
}

Bu yaklaşımı kullanırken, main fonksiyonu içerisinde gen.Config yapısını değiştirerek farklı yapılandırma seçeneklerini uygulayabilirsiniz. İhtiyaç duyulduğunda entc.Generate fonksiyonunu çağırarak kod oluşturma sürecini esnek bir şekilde kontrol edebilirsiniz.

6.2 entc'nin Detaylı Yapılandırması

entc, geliştiricilere üretilen kodu özelleştirmelerine olanak tanıyan kapsamlı yapılandırma seçenekleri sunar. Örneğin, özel kancalar, üretilen kodu denetlemek veya değiştirmek için yapılandırılabilir ve dış bağımlılıklar bağımlılık enjeksiyonu kullanılarak eklenir.

Aşağıdaki örnek, entc.Generate işlevi için özel kancaların nasıl sağlanacağını göstermektedir:

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Hooks: []gen.Hook{
            HookFonksiyonu,
        },
    })
    if err != nil {
        log.Fatalf("ent kod üretimi çalıştırılırken hata oluştu: %v", err)
    }
}

// HookFonksiyonu özel kancadır
func HookFonksiyonu(sonraki gen.Generator) gen.Generator {
    return gen.GenerateFunc(func(g *gen.Graph) error {
        // Burada g tarafından temsil edilen graf modunu işleyebilir
        // Örneğin, alanların varlığını doğrulayabilir veya yapıyı değiştirebilir
        return sonraki.Generate(g)
    })
}

Ayrıca, entc.Dependency kullanılarak dış bağımlılıklar eklenir:

func main() {
    seçenekler := []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{}, seçenekler...); err != nil {
        log.Fatalf("ent kod üretimi çalıştırılırken hata oluştu: %v", err)
    }
}

Bu örnekte, http.Client ve io.Writerın üretilmiş istemci nesnelerine bağımlılık olarak enjekte edildiği görülmektedir.

7. Şema Açıklamasının Çıktısı

ent çerçevesinde, ent describe komutu, şema açıklamasını grafiksel bir formatta çıktılamak için kullanılabilir. Bu, mevcut varlıkları ve ilişkileri hızlı bir şekilde anlamak için geliştiricilere yardımcı olabilir.

Aşağıdaki komutu yürüterek şema açıklamasını elde edebilirsiniz:

go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema

Yukarıdaki komut, her bir varlık için alanlar, türler, ilişkiler vb. gibi bilgileri görüntüleyen aşağıdaki gibi bir tablo çıktılar:

Kullanıcı:
    +-------+---------+--------+-----------+ ...
    | Alan  |  Tür    | Benzersiz | İsteğe Bağlı  | ...
    +-------+---------+--------+-----------+ ...
    | id    | int     | false  | false     | ...
    | ad    | string  | true   | false     | ...
    +-------+---------+--------+-----------+ ...
    +-------+--------+---------+-----------+ ...
    | Kenar  |  Tür  | Ters   | İlişki  | ...
    +-------+--------+---------+-----------+ ...
    | pets  | Pet    | false   | O2M       | ...
    +-------+--------+---------+-----------+ ...

8. Kod Üretimi Kancaları

8.1 Kancaların Kavramı

Kancalar, ent kod üretim sürecine yerleştirilebilen orta yazılım işlevleridir ve kod üretiminden önce ve sonra özel mantık eklemeyi sağlar. Kancalar, üretilen kodun soyut sözdizim ağacını (AST) manipüle etmek, doğrulama yapmak veya ek kod parçaları eklemek için kullanılabilir.

8.2 Kancaların Kullanımına İlişkin Örnek

İşte, tüm alanların belirli bir yapı etiketi (örneğin, json) içerdiğinden emin olmak için bir kancanın nasıl kullanılacağına dair bir örnek:

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Hooks: []gen.Hook{
            BelirliStructEtiketiSağla("json"),
        },
    })
    if err != nil {
        log.Fatalf("ent kod üretimi çalıştırılırken hata oluştu: %v", err)
    }
}

// BelirliStructEtiketiSağla, grafikteki tüm alanların belirli bir yapı etiketine sahip olduğundan emin olur
func BelirliStructEtiketiSağla(isim string) gen.Hook {
    return func(sonraki 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(isim); !ok {
                        return fmt.Errorf("%s.%s alanı için %q yapı etiketi eksik", node.Name, field.Name, name)
                    }
                }
            }
            return sonraki.Generate(g)
        })
    }
}

Bu örnekte, kod üretiminden önce BelirliStructEtiketiSağla işlevi her bir alanı json etiketi için kontrol eder. Bir alan bu etiketi eksikse, kod üretimi durdurulur ve bir hata döndürülür. Bu, kod temizliğini ve tutarlılığını korumanın etkili bir yoludur.