1. ent 도구 설치

ent 코드 생성 도구를 설치하려면 다음 단계를 따르세요:

먼저 시스템에 Go 언어 환경이 설치되어 있는지 확인하세요. 그런 다음 다음 명령을 실행하여 ent 도구를 얻을 수 있습니다:

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

이 명령은 ent 도구의 코드를 다운로드하지만 즉시 컴파일하고 설치하지는 않습니다. $GOPATH/bin 디렉토리에 ent를 설치하여 어디에서나 사용할 수 있도록 하려면 다음 명령도 실행해야 합니다:

go install entgo.io/ent/cmd/ent

설치가 완료되면 ent 도구가 올바르게 설치되었는지 확인하고 ent -h를 실행하여 사용 가능한 명령 및 지침을 볼 수 있습니다.

2. 스키마 초기화

2.1 ent init을 사용한 템플릿 초기화

코드 생성을 위해 ent를 사용하기 시작하려면 새로운 스키마 파일을 만드는 것이 첫 단계입니다. 다음 명령을 실행하여 스키마 템플릿을 초기화할 수 있습니다.

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

이 명령은 user.gopet.go 두 개의 새로운 스키마 파일을 만들고 ent/schema 디렉토리에 배치합니다. ent 디렉토리가 없는 경우 이 명령은 자동으로 생성합니다.

프로젝트의 루트 디렉토리에서 ent init 명령을 실행하는 것이 프로젝트 디렉토리 구조와 명확성을 유지하는 데 도움이 되는 좋은 관행입니다.

2.2 스키마 파일 구조

ent/schema 디렉토리에는 각 스키마가 Go 언어 소스 파일에 해당합니다. 스키마 파일은 데이터베이스 모델을 정의하는 곳으로, 필드 및 엣지(관계)를 포함합니다.

예를 들어, user.go 파일에서는 사용자 모델을 정의하고, 사용자 이름 및 나이와 같은 필드를 정의하고 사용자와 애왁이의 관계를 정의할 수 있습니다. 마찬가지로 pet.go 파일에서는 애왁이 모델 및 애왁이 이름, 유형 등의 관련 필드를 정의하고 애왁이와 사용자 간의 관계를 정의할 수 있습니다.

이러한 파일은 최종적으로 ent 도구에 의해 대응하는 Go 코드를 생성하는 데 사용되며, 이는 데이터베이스 작업 및 CRUD(Create, Read, Update, Delete) 작업을 위한 클라이언트 코드를 포함합니다.

// 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 프레임워크에서 제공하는 API를 사용하여 이러한 구조를 정의합니다. 이 접근 방식은 ent를 매우 직관적이고 확장하기 쉽게 만들어주며, 동시에 Go 언어의 강력한 유형 지정을 활용합니다.

3.1 코드 생성 실행

ent 프레임워크에서 코드 생성을 실행하는 것은 매우 중요한 단계입니다. 이 명령을 사용하면 정의된 스키마에 기반하여 해당하는 Go 코드 파일이 생성되어 후속 개발 작업을 용이하게 합니다. 코드 생성을 실행하는 명령은 간단합니다.

go generate ./ent

위의 명령은 프로젝트의 루트 디렉토리에서 실행해야 합니다. go generate가 호출될 때 특정 어노테이션을 포함하는 모든 Go 파일을 검색하고 어노테이션에서 지정된 명령을 실행합니다. 예제에서는 ent의 코드 생성기를 지정한 것입니다.

실행 전에 스키마 초기화와 필요한 필드 추가가 완료되었는지 확인하세요. 그렇지 않으면 생성된 코드에 모든 필요한 부분이 포함되지 않을 수 있습니다.

3.2 생성된 코드 자산 이해하기

생성된 코드 자산에는 각각 다른 기능을 가진 여러 구성 요소가 포함되어 있습니다:

  • 클라이언트 및 Tx 객체: 데이터 그래프와 상호 작용하는 데 사용됩니다. 클라이언트는 트랜잭션(Tx)을 생성하거나 데이터베이스 작업을 직접 실행하는 메서드를 제공합니다.

  • CRUD 빌더: 각 스키마 유형에 대해 해당 엔티티의 작업 논리를 간단화하는 생성, 읽기, 업데이트 및 삭제 빌더를 생성합니다.

  • 엔티티 객체 (Go 구조체): 스키마의 각 유형에 대한 해당 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 방언을 지원하는 것 외에도 SQL 및 Gremlin 방언에 대한 코드 자산 생성을 지원합니다. 프로젝트가 Gremlin 데이터베이스에 연결해야 하는 경우 해당 데이터베이스 방언을 구성해야 합니다. 다음은 저장 옵션을 지정하는 방법을 보여줍니다:

ent generate --storage gremlin ./ent/schema

위 명령은 코드 생성 시 Gremlin 방언을 사용하도록 ent에 지시합니다. 이를 통해 생성된 자산이 특정 그래프 데이터베이스와의 호환성을 보장하고 해당 데이터베이스 요구 사항에 맞게 맞추어지도록합니다.

6. 고급 사용: entc 패키지

6.1 프로젝트에서 entc 패키지로의 사용

entcent 프레임워크의 코드 생성에 사용되는 핵심 패키지입니다. 명령줄 도구 외에도 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)
    }
}

이 방법을 사용할 때, main 함수 내에서 gen.Config 구조체를 수정하여 다양한 구성 옵션을 적용할 수 있습니다. 필요에 따라 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("ent 코드 생성 중 오류 발생: %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("ent 코드 생성 중 오류 발생: %v", err)
    }
}

이 예시에서는 http.Clientio.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 훅 사용 예시

아래 예시는 모든 필드에 특정 구조 태그(e.g., json)를 포함해야 함을 보장하기 위해 훅을 사용하는 예시입니다:

func main() {
    err := entc.Generate("./schema", &gen.Config{
        Hooks: []gen.Hook{
            EnsureStructTag("json"),
        },
    })
    if err != nil {
        log.Fatalf("ent 코드 생성 중 오류 발생: %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("%s.%s 필드에 구조 태그 %q가 누락되었습니다", node.Name, field.Name, name)
                    }
                }
            }
            return next.Generate(g)
        })
    }
}

이 예시에서는 코드를 생성하기 전에 EnsureStructTag 함수가 각 필드를 json 태그로 확인합니다. 만약 필드에 이 태그가 누락된 경우, 코드 생성이 중단되고 오류가 반환됩니다. 이는 코드 깨끗함과 일관성을 유지하는 효과적인 방법입니다.