Skip to main content

ent

Work with Ent ORM schemas and generated code. Use when modifying ent schemas, debugging ent query issues, or dealing with Postgres type mappings.

설치로 이동

소스 정보

저장소
openmeterio/openmeter
최근 소스 활동
2026년 7월 28일 15:14
감지된 SKILL.md 언어
영어
스타
2,327
포크
220

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
ent
description
Work with Ent ORM schemas and generated code. Use when modifying ent schemas, debugging ent query issues, or dealing with Postgres type mappings.
allowed-tools
Read, Edit, Write, Bash, Grep, Glob, Agent
# Ent ORM Guidance for working with Ent in the OpenMeter codebase. ## Schema Location - **Schema definitions:** `openmeter/ent/schema/*.go` (source of truth) - **Generated code:** `openmeter/ent/db/` (DO NOT edit manually) After any schema change, regenerate with `make generate` before running tests. ## Postgres Array Columns (`text[]`) - **Do NOT** use `field.Strings(...)` for Postgres array columns. Without an explicit schema type it creates `jsonb`, and with `SchemaType(map[string]string{dialect.Postgres: "text[]"})` it changes DDL without changing the runtime encode/decode path for `field.Strings`. - **Prefer** `field.Other(..., pq.StringArray{}).SchemaType(map[string]string{dialect.Postgres: "text[]"})` for native Postgres `text[]` encode/decode with Ent methods (create/query/update). Import `github.com/lib/pq` in the schema file. ## Custom Selects & Joins - For custom Ent selects/joins, prefer the generated selected-value parsing helpers from the `entselectedparse` extension (`openmeter/ent/db/selectedparse.go`) instead of hand-written scanners. - Use `db.Parse<Entity>FromSelectedValues(prefix, row.Value)` for aliased joined columns. - Example: `db.ParseLedgerDimensionFromSelectedValues("dimension_", row.Value)` ## Common Patterns - **Soft-delete unique indexes** include `deleted_at` in the unique constraint (e.g., `index.Fields("namespace", "key", "deleted_at").Unique()`) — always filter with `Where(<entity>db.DeletedAtIsNil())` in queries. - **Foreign keys** use `char(26)` schema type to match ULID IDs. - **Cascade deletes** use `entsql.OnDelete(entsql.Cascade)` on the parent edge. - **PostgreSQL identifier length** is 63 bytes by default (PostgreSQL docs, “Lexical Structure” / `NAMEDATALEN`). Long Ent-generated table, index, and FK names can truncate and collide even when their full names differ. When a schema/entity/edge name is verbose, proactively shorten generated FK symbols with `StorageKey(edge.Symbol("..."))` and shorten index names with `StorageKey("...")` before generating migrations. - **JSONB fields** use `entutils.JSONStringValueScanner` — see `openmeter/ent/schema/llmcostprice.go`. - **Non-empty strings at the DB layer**: `field.String(...).NotEmpty()` enforces Ent-side validation, but Atlas may still diff only `SET NOT NULL` for existing tables. If the database must reject empty strings too, add an explicit `entsql.Checks(...)` annotation in the schema or mixin alongside `NotEmpty()`. - **Upserts with nullable/optional fields**: `UpdateNewValues()` only updates fields that were set on the create mutation. If an upsert must clear a previously set nullable/optional column, explicitly chain the generated `Update<Field>()` method for that field after `UpdateNewValues()` (for example `UpdateDescription()` or `UpdateDeletedAt()`). This lets Ent use the excluded insert value, including `NULL`, instead of leaving the old value untouched. See billing adapter upserts such as `openmeter/billing/adapter/stdinvoicelines.go`. - **Generated `SetOrClear<Field>` helpers**: prefer these helpers for nullable/optional update fields when they have a straightforward signature. For awkward generated signatures such as double-pointer JSON fields, prefer the explicit pattern used for fields like normalized metadata: `if value != nil { update = update.Set<Field>(value) } else { update = update.Clear<Field>() }`. This avoids passing the address of a nil pointer, which can make Ent treat the field as set with a nil value and then panic or fail in generated validators. - **No `SetNillable<Field>` for pointer GoTypes**: when an optional field's `GoType` is already a pointer (e.g. `field.String(...).GoType(&productcatalog.UnitConfig{}).ValueScanner(...)`), Ent does not generate a `SetNillable<Field>` variant — `Set<Field>` itself takes the pointer. On create paths, guard with `if value != nil { create = create.Set<Field>(value) }` (see `unit_config` in `openmeter/billing/charges/usagebased/adapter/charge.go` and `applied_unit_config` in `openmeter/billing/adapter/stdinvoicelines.go`); leaving the field unset writes NULL on insert and leaves the existing value untouched on conflict-update. ## Regeneration Depending on the change, the generators need to be re-run. For schema changes, edit files under `openmeter/ent/schema/` and run the repo generation target: ```bash # Regenerate all generated Go code, including Ent make generate ``` During local iteration, you can use the narrower Ent-only command when you intentionally want to avoid a full generation run: ```bash # Regenerate Ent only after schema changes go generate ./openmeter/ent/... ```
GitHub에서 보기