1. Installation de l'outil ent
Pour installer l'outil de génération de code ent
, vous devez suivre ces étapes :
Tout d'abord, assurez-vous que votre système dispose de l'environnement du langage Go installé. Ensuite, exécutez la commande suivante pour obtenir l'outil ent
:
go get -d entgo.io/ent/cmd/ent
Cette commande téléchargera le code de l'outil ent
, mais ne le compilera et ne l'installera pas immédiatement. Si vous souhaitez installer ent
dans le répertoire $GOPATH/bin
pour pouvoir l'utiliser n'importe où, vous devrez également exécuter la commande suivante :
go install entgo.io/ent/cmd/ent
Une fois l'installation terminée, vous pouvez vérifier si l'outil ent
est correctement installé et afficher les commandes disponibles ainsi que les instructions en exécutant ent -h
.
2. Initialisation du schéma
2.1 Initialisation du modèle en utilisant ent init
Créer un nouveau fichier de schéma est la première étape pour commencer à utiliser ent
pour la génération de code. Vous pouvez initialiser le modèle de schéma en exécutant la commande suivante :
go run -mod=mod entgo.io/ent/cmd/ent new User Pet
Cette commande créera deux nouveaux fichiers de schéma : user.go
et pet.go
, et les placera dans le répertoire ent/schema
. Si le répertoire ent
n'existe pas, cette commande le créera automatiquement.
Il est recommandé d'exécuter la commande ent init
dans le répertoire racine du projet, car cela aide à maintenir la structure et la clarté du répertoire du projet.
2.2 Structure du fichier de schéma
Dans le répertoire ent/schema
, chaque schéma correspond à un fichier source du langage Go. Les fichiers de schéma sont l'endroit où vous définissez le modèle de la base de données, y compris les champs et les relations (liens).
Par exemple, dans le fichier user.go
, vous pourriez définir un modèle d'utilisateur, comprenant des champs tels que le nom d'utilisateur et l'âge, et définir la relation entre les utilisateurs et les animaux de compagnie. De même, dans le fichier pet.go
, vous définiriez le modèle de l'animal de compagnie et ses champs associés, tels que le nom de l'animal, le type, et la relation entre les animaux de compagnie et les utilisateurs.
Ces fichiers seront finalement utilisés par l'outil ent
pour générer du code Go correspondant, y compris du code client pour les opérations de base de données et les opérations CRUD (Créer, Lire, Mettre à jour, Supprimer).
// ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// User définit le schéma pour l'entité Utilisateur.
type User struct {
ent.Schema
}
// La méthode Fields est utilisée pour définir les champs de l'entité.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("name").Unique(),
field.Int("age").Positive(),
}
}
// La méthode Edges est utilisée pour définir les associations de l'entité.
func (User) Edges() []ent.Edge {
// Les associations seront expliquées plus en détail dans la section suivante.
}
Les fichiers de schéma de ent
utilisent des types et des fonctions du langage Go pour déclarer la structure du modèle de base de données, y compris les champs et les relations entre les modèles, et utilisent l'API fournie par le cadre ent
pour définir ces structures. Cette approche rend ent
très intuitive et facile à étendre, tout en tirant parti du typage fort du langage Go.
3.1 Exécution de la génération de code
Exécuter ent generate
pour générer du code est une étape cruciale dans le cadre ent
. Avec cette commande, ent
générera des fichiers de code Go correspondants en fonction des schémas définis, facilitant ainsi le travail de développement ultérieur. La commande pour exécuter la génération de code est simple :
go generate ./ent
La commande ci-dessus doit être exécutée dans le répertoire racine du projet. Lorsque go generate
est appelé, il recherchera tous les fichiers Go contenant des annotations spécifiques et exécutera les commandes spécifiées dans les annotations. Dans notre exemple, cette commande spécifie le générateur de code pour ent
.
Assurez-vous que l'initialisation du schéma et les ajouts de champs nécessaires ont été effectués avant l'exécution. Seulement alors, le code généré inclura toutes les parties nécessaires.
3.2 Compréhension des éléments de code générés
Les éléments de code générés contiennent plusieurs composants, chacun ayant des fonctions différentes :
-
Objets Client et Tx : Utilisés pour interagir avec le graphe de données. Le Client fournit des méthodes pour créer des transactions (Tx) ou exécuter directement des opérations de base de données.
-
Constructeurs CRUD : Pour chaque type de schéma, il génère des constructeurs pour créer, lire, mettre à jour et supprimer, simplifiant la logique des opérations de l'entité correspondante.
-
Objet Entité (struct Go) : Il génère les structs Go correspondants pour chaque type de schéma, en faisant correspondre ces structs aux tables de la base de données.
-
Package de constantes et prédicats : Contient des constantes et des prédicats pour interagir avec les constructeurs.
-
Package de migration : Un package pour la migration de base de données, adapté aux dialectes SQL.
-
Package de hook : Fournit la fonctionnalité d'ajouter un middleware de changement, permettant d'exécuter une logique personnalisée avant ou après la création, la mise à jour ou la suppression d'entités.
En examinant le code généré, vous pouvez avoir une compréhension plus approfondie de la manière dont le framework ent
automatise le code d'accès aux données pour vos schémas.
4. Options de génération de code
La commande ent generate
prend en charge diverses options pour personnaliser le processus de génération de code. Vous pouvez interroger toutes les options de génération prises en charge via la commande suivante :
ent generate -h
Voici quelques options de ligne de commande couramment utilisées :
-
--feature strings
: Étend la génération de code, ajoutant des fonctionnalités supplémentaires. -
--header string
: Remplace le fichier d'en-tête de génération de code. -
--storage string
: Spécifie le pilote de stockage pris en charge dans la génération de code, par défaut "sql". -
--target string
: Spécifie le répertoire cible pour la génération de code. -
--template strings
: Exécute des modèles Go supplémentaires. Prend en charge les chemins de fichier, de répertoire et de joker, par exemple :--template file="chemin/vers/fichier.tmpl"
.
Ces options permettent aux développeurs de personnaliser leur processus de génération de code selon les besoins et les préférences.
5. Configuration des options de stockage
ent
prend en charge la génération d'éléments de code pour les dialectes SQL et Gremlin, le dialecte par défaut étant SQL. Si le projet doit se connecter à une base de données Gremlin, le dialecte de base de données correspondant doit être configuré. Ce qui suit montre comment spécifier les options de stockage :
ent generate --storage gremlin ./ent/schema
La commande ci-dessus indique à ent
d'utiliser le dialecte Gremlin lors de la génération de code. Cela garantit que les éléments générés sont adaptés aux besoins de la base de données Gremlin, assurant la compatibilité avec une base de données graphique spécifique.
6. Utilisation avancée : Package entc
6.1 Utilisation de entc
comme package dans le projet
entc
est le package central utilisé pour la génération de code dans le framework ent
. En plus de l'outil en ligne de commande, entc
peut également être intégré dans le projet en tant que package, permettant aux développeurs de contrôler et de personnaliser le processus de génération de code dans le code lui-même.
Pour utiliser entc
comme package dans le projet, vous devez créer un fichier nommé entc.go
et ajouter le contenu suivant au fichier :
// +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)
}
}
En utilisant cette approche, vous pouvez modifier la structure gen.Config
à l'intérieur de la fonction main
pour appliquer différentes options de configuration. En appelant la fonction entc.Generate
selon les besoins, vous pouvez contrôler de manière flexible le processus de génération de code.
6.2 Configuration détaillée de entc
entc
offre de nombreuses options de configuration, permettant aux développeurs de personnaliser le code généré. Par exemple, des hooks personnalisés peuvent être configurés pour inspecter ou modifier le code généré, et des dépendances externes peuvent être injectées à l'aide de l'injection de dépendances.
L'exemple suivant montre comment fournir des hooks personnalisés pour la fonction entc.Generate
:
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
HookFunction,
},
})
if err != nil {
log.Fatalf("exécution de la génération de code ent : %v", err)
}
}
// HookFunction est une fonction de hook personnalisée
func HookFunction(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
// Peut manipuler le mode graphique représenté par g ici
// Par exemple, valider l'existence de champs ou modifier la structure
return next.Generate(g)
})
}
De plus, des dépendances externes peuvent être ajoutées en utilisant 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("exécution de la génération de code ent : %v", err)
}
}
Dans cet exemple, nous injectons http.Client
et io.Writer
en tant que dépendances dans les objets client générés.
7. Sortie de la description du schéma
Dans le framework ent
, la commande ent describe
peut être utilisée pour afficher la description du schéma sous une forme graphique. Cela peut aider les développeurs à comprendre rapidement les entités et les relations existantes.
Exécutez la commande suivante pour obtenir la description du schéma :
go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema
La commande ci-dessus affichera un tableau similaire à ce qui suit, affichant des informations telles que les champs, les types, les relations, etc. pour chaque entité :
Utilisateur :
+-------+---------+--------+-----------+ ...
| Champ | Type | Unique | Optionnel | ...
+-------+---------+--------+-----------+ ...
| id | int | false | false | ...
| nom | string | true | false | ...
+-------+---------+--------+-----------+ ...
+-------+--------+---------+-----------+ ...
| Edge | Type | Inverse | Relation | ...
+-------+--------+---------+-----------+ ...
| animaux | Animal | false | O2M | ...
+-------+--------+---------+-----------+ ...
8. Hooks de génération de code
8.1 Concept des Hooks
Les hooks sont des fonctions middleware qui peuvent être insérées dans le processus de génération de code ent
, permettant d'insérer une logique personnalisée avant et après la génération de code. Les hooks peuvent être utilisés pour manipuler l'arbre de syntaxe abstraite (AST) du code généré, effectuer des validations ou ajouter des extraits de code supplémentaires.
8.2 Exemple d'utilisation des hooks
Voici un exemple d'utilisation d'un hook pour s'assurer que tous les champs contiennent une balise de structure spécifique (par exemple, json
) :
func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
EnsureStructTag("json"),
},
})
if err != nil {
log.Fatalf("exécution de la génération de code ent : %v", err)
}
}
// EnsureStructTag s'assure que tous les champs dans le graphique contiennent une balise de structure spécifique
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("balise de structure %q manquante pour le champ %s.%s", name, node.Name, field.Name)
}
}
}
return next.Generate(g)
})
}
}
Dans cet exemple, avant de générer le code, la fonction EnsureStructTag
vérifie chaque champ pour la balise json
. Si un champ ne possède pas cette balise, la génération de code s'arrêtera et renverra une erreur. Il s'agit d'un moyen efficace de maintenir la propreté et la cohérence du code.