1. Installazione dello strumento ent
Per installare lo strumento di generazione di codice ent
, è necessario seguire questi passaggi:
Innanzitutto, assicurati che il tuo sistema abbia l'ambiente di linguaggio Go installato. Quindi, esegui il seguente comando per ottenere lo strumento ent
:
go get -d entgo.io/ent/cmd/ent
Questo comando scaricherà il codice per lo strumento ent
, ma non lo compilerà e installerà immediatamente. Se desideri installare ent
nella directory $GOPATH/bin
in modo da poterlo utilizzare ovunque, è anche necessario eseguire il seguente comando:
go install entgo.io/ent/cmd/ent
Una volta completata l'installazione, puoi verificare se lo strumento ent
è stato installato correttamente e visualizzare i comandi disponibili e le istruzioni eseguendo ent -h
.
2. Inizializzazione dello Schema
2.1 Inizializzazione del Modello Utilizzando ent init
Creare un nuovo file di schema è il primo passo per iniziare a utilizzare ent
per la generazione di codice. È possibile inizializzare il modello dello schema eseguendo il seguente comando:
go run -mod=mod entgo.io/ent/cmd/ent new User Pet
Questo comando creerà due nuovi file di schema: user.go
e pet.go
, e li posizionerà nella directory ent/schema
. Se la directory ent
non esiste, questo comando la creerà automaticamente.
Eseguire il comando ent init
nella directory radice del progetto è una pratica consigliata, poiché aiuta a mantenere la struttura e la chiarezza della directory del progetto.
2.2 Struttura del File di Schema
Nella directory ent/schema
, ogni schema corrisponde a un file di origine del linguaggio Go. I file di schema sono dove si definisce il modello del database, inclusi i campi e gli edges (relazioni).
Ad esempio, nel file user.go
, potresti definire un modello utente, inclusi campi come nome utente ed età, e definire la relazione tra utenti e animali domestici. Allo stesso modo, nel file pet.go
, definiresti il modello dell'animale domestico e i suoi campi correlati, come il nome dell'animale, il tipo e la relazione tra animali domestici e utenti.
Questi file saranno infine utilizzati dallo strumento ent
per generare il corrispondente codice Go, inclusa la parte client per le operazioni sul database e le operazioni CRUD (Create, Read, Update, Delete).
// ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// User definisce lo schema per l'entità Utente.
type User struct {
ent.Schema
}
// Il metodo Fields viene utilizzato per definire i campi dell'entità.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("nome").Unique(),
field.Int("età").Positive(),
}
}
// Il metodo Edges viene utilizzato per definire le associazioni dell'entità.
func (User) Edges() []ent.Edge {
// Le associazioni saranno spiegate in dettaglio nella sezione successiva.
}
I file di schema di ent
utilizzano tipi e funzioni del linguaggio Go per dichiarare la struttura del modello del database, inclusi i campi e le relazioni tra i modelli, e utilizzano l'API fornita dal framework ent
per definire queste strutture. Questo approccio rende ent
molto intuitivo e facile da estendere, sfruttando al contempo la strong typing del linguaggio Go.
3.1 Esecuzione della Generazione del Codice
Eseguire ent generate
per generare il codice è un passaggio cruciale nel framework ent
. Con questo comando, ent
genererà i file di codice Go corrispondenti in base agli schemi definiti, facilitando il lavoro di sviluppo successivo. Il comando per eseguire la generazione del codice è semplice:
go generate ./ent
Il comando sopra indicato deve essere eseguito nella directory radice del progetto. Quando viene chiamato go generate
, verranno cercati tutti i file Go che contengono specifiche annotazioni e verranno eseguiti i comandi specificati nelle annotazioni. Nel nostro esempio, questo comando specifica il generatore di codice per ent
.
Assicurati che l'inizializzazione dello schema e le aggiunte di campi necessarie siano state completate prima dell'esecuzione. Solo in questo modo il codice generato includerà tutte le parti necessarie.
3.2 Comprensione dei Asset di Codice Generati
Gli asset di codice generati contengono diversi componenti, ognuno con funzioni diverse:
-
Oggetti Client e Tx: Utilizzati per interagire con il grafo dei dati. Il Client fornisce metodi per creare transazioni (Tx) o eseguire direttamente operazioni sul database.
-
Generatore CRUD: Per ogni tipo di schema, genera generatori per creare, leggere, aggiornare ed eliminare, semplificando la logica di operazione dell'entità corrispondente.
-
Oggetto Entità (struct Go): Genera le struct Go corrispondenti per ciascun tipo nello schema, mappando queste struct alle tabelle nel database.
-
Costanti e pacchetto dei predicati: Contiene costanti e predicati per interagire con i generatori.
-
Pacchetto Migrate: Un pacchetto per la migrazione del database, adatto ai dialetti SQL.
-
Pacchetto Hook: Fornisce la funzionalità per aggiungere middleware di modifica, consentendo l'esecuzione di logica personalizzata prima o dopo la creazione, l'aggiornamento o l'eliminazione delle entità.
Esaminando il codice generato, è possibile acquisire una comprensione più approfondita di come il framework ent
automatizzi il codice di accesso ai dati per i tuoi schemi.
4. Opzioni di Generazione del Codice
Il comando ent generate
supporta varie opzioni per personalizzare il processo di generazione del codice. È possibile controllare tutte le opzioni di generazione supportate tramite il seguente comando:
ent generate -h
Ecco alcune opzioni della riga di comando comunemente utilizzate:
-
--feature strings
: Estende la generazione del codice, aggiungendo funzionalità aggiuntive. -
--header string
: Sostituisce il file dell'intestazione di generazione del codice. -
--storage string
: Specifica il driver di storage supportato nella generazione del codice, predefinito su "sql". -
--target string
: Specifica la directory di destinazione per la generazione del codice. -
--template strings
: Esegue modelli Go aggiuntivi. Supporta file, directory e percorsi con caratteri jolly, ad esempio:--template file="percorso/al/file.tmpl"
.
Queste opzioni consentono ai developer di personalizzare il processo di generazione del codice in base a diverse esigenze e preferenze.
5. Configurazione delle Opzioni di Storage
ent
supporta la generazione di asset di codice sia per i dialetti SQL che per i dialetti Gremlin, con il dialetto predefinito che è SQL. Se il progetto ha bisogno di connettersi a un database Gremlin, è necessario configurare il dialetto del database corrispondente. Di seguito viene mostrato come specificare le opzioni di storage:
ent generate --storage gremlin ./ent/schema
Il comando sopra indica a ent
di utilizzare il dialetto Gremlin durante la generazione del codice. Ciò assicura che gli asset generati siano personalizzati per i requisiti del database Gremlin, garantendo la compatibilità con un database grafico specifico.
6. Utilizzo Avanzato: Pacchetto entc
6.1 Utilizzo di entc
come Pacchetto nel Progetto
entc
è il pacchetto principale utilizzato per la generazione del codice nel framework ent
. Oltre allo strumento della riga di comando, entc
può essere integrato nel progetto come pacchetto, consentendo ai developer di controllare e personalizzare il processo di generazione del codice all'interno del codice stesso.
Per utilizzare entc
come pacchetto nel progetto, è necessario creare un file chiamato entc.go
e aggiungere il seguente contenuto al file:
// +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("esecuzione di ent codegen:", err)
}
}
Utilizzando questo approccio, è possibile modificare la struct gen.Config
all'interno della funzione main
per applicare diverse opzioni di configurazione. Chiamando la funzione entc.Generate
secondo necessità, è possibile controllare in modo flessibile il processo di generazione del codice.
6.2 Configurazione dettagliata di entc
entc
fornisce ampie opzioni di configurazione, consentendo agli sviluppatori di personalizzare il codice generato. Ad esempio, è possibile configurare hook personalizzati per ispezionare o modificare il codice generato, nonché iniettare dipendenze esterne utilizzando l'iniezione delle dipendenze.
Nell'esempio seguente viene mostrato come fornire hook personalizzati per la funzione entc.Generate
:
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
HookFunction,
},
})
if err != nil {
log.Fatalf("esecuzione del codegen di ent: %v", err)
}
}
// HookFunction è una funzione hook personalizzata
func HookFunction(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
// È possibile gestire qui la modalità di grafo rappresentata da g
// Ad esempio, convalidare l'esistenza dei campi o modificare la struttura
return next.Generate(g)
})
}
Inoltre, le dipendenze esterne possono essere aggiunte utilizzando 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("esecuzione del codegen di ent: %v", err)
}
}
In questo esempio, vengono iniettate http.Client
e io.Writer
come dipendenze negli oggetti client generati.
7. Descrizione dello schema in output
Nel framework ent
, il comando ent describe
può essere utilizzato per visualizzare la descrizione dello schema in un formato grafico. Ciò può aiutare gli sviluppatori a comprendere rapidamente le entità e le relazioni esistenti.
Eseguire il seguente comando per ottenere la descrizione dello schema:
go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema
Il comando sopra mostrerà una tabella simile alla seguente, visualizzando informazioni come campi, tipi, relazioni, etc. per ciascuna entità:
Utente:
+-------+---------+--------+-----------+ ...
| Campo | Tipo | Unico | Opzionale | ...
+-------+---------+--------+-----------+ ...
| id | int | falso | falso | ...
| nome | string | vero | falso | ...
+-------+---------+--------+-----------+ ...
+-------+--------+---------+-----------+ ...
| Tratto| Tipo | Inverso | Relazione | ...
+-------+--------+---------+-----------+ ...
| animali| Animale | falso | O2M | ...
+-------+--------+---------+-----------+ ...
8. Hook di generazione del codice
8.1 Concetto degli Hook
Gli hook sono funzioni middleware che possono essere inserite nel processo di generazione del codice ent
, consentendo l'inserimento di logica personalizzata prima e dopo la generazione del codice. Gli hook possono essere utilizzati per manipolare l'albero della sintassi astratta (AST) del codice generato, eseguire la convalida o aggiungere frammenti di codice aggiuntivi.
8.2 Esempio di utilizzo degli Hook
Ecco un esempio di utilizzo di un hook per garantire che tutti i campi contengano un determinato tag di struttura (ad esempio, json
):
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
EnsureStructTag("json"),
},
})
if err != nil {
log.Fatalf("esecuzione del codegen di ent: %v", err)
}
}
// EnsureStructTag garantisce che tutti i campi nel grafo contengano un tag di struttura specifico
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("manca il tag di struttura %q per il campo %s.%s", name, node.Name, field.Name)
}
}
}
return next.Generate(g)
})
}
}
In questo esempio, prima di generare il codice, la funzione EnsureStructTag
controlla ciascun campo per il tag json
. Se un campo manca di questo tag, la generazione del codice terminerà e restituirà un errore. Si tratta di un modo efficace per mantenere la pulizia e la coerenza del codice.