-
Notifications
You must be signed in to change notification settings - Fork 0
Schema Guide
GCORM schema files use the .gcorm extension. They are the source of truth for
generated Go models, query builders, and database DDL.
A schema can contain:
datasource Database provider and URL
generator Code generation settings
model Database table model
enum Enumeration type
GCORM supports multiple .gcorm files. Files are discovered from the configured
schema roots and merged in deterministic path order.
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
schema = "public"
}
Fields:
-
provider: required. One ofpostgresql,mysql, orsqlite. -
url: required for commands that connect to a database. Use a literal string orenv("NAME"). -
schema: optional PostgreSQL schema or namespace.
Examples:
url = env("DATABASE_URL")
url = "postgresql://localhost/app?sslmode=disable"
Avoid committing production credentials in schema files. Prefer env().
generator client {
provider = "gco-go"
output = "./gen"
package = "db"
}
Fields:
-
provider: usegco-go. -
output: output directory for generated Go code. -
package: generated package base name.
model Post {
id String @id @default(uuid())
title String
content String?
published Boolean @default(false)
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([authorId])
@@map("posts")
}
A model maps to a table. A scalar field maps to a column. Relation fields describe relationships and are not always stored as standalone columns.
| Schema type | Go type | Common SQL mapping |
|---|---|---|
String |
string |
TEXT |
Int |
int32 |
INTEGER |
SmallInt |
int16 |
SMALLINT / INTEGER
|
BigInt |
int64 |
BIGINT |
Float |
float64 |
DOUBLE / REAL
|
Decimal |
float64 |
DECIMAL |
Boolean |
bool |
BOOLEAN / TINYINT(1)
|
DateTime |
time.Time |
TIMESTAMP / DATETIME
|
Bytes |
[]byte |
BYTEA / BLOB
|
Json |
json.RawMessage |
JSONB / JSON / TEXT
|
UUID |
string |
UUID / VARCHAR(36) / TEXT
|
name String?
posts Post[]
-
?marks a nullable field. -
[]marks a list, usually used for relation fields.
id String @id @default(uuid())
email String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
name String @map("display_name")
author User @relation(fields: [authorId], references: [id])
Common attributes:
-
@id: primary key field. -
@unique: unique constraint. -
@default(value): database or application default. -
@updatedAt: update timestamp managed by generated code. -
@map("column_name"): map field to a database column name. -
@relation(...): relationship definition. -
@db.*: native type annotation, such as@db.VarChar(255)or@db.Text.
Supported default examples:
@default(uuid())
@default(cuid())
@default(now())
@default(autoincrement())
@default(0)
@default(0.0)
@default("")
@default(false)
@default(USER)
@@id([tenantId, id])
@@unique([email])
@@unique([tenantId, slug])
@@index([createdAt])
@@map("users")
@@schema("public")
Common model attributes:
-
@@id([...]): composite primary key. -
@@unique([...]): composite unique constraint. -
@@index([...]): index. -
@@map("table_name"): map model to a database table name. -
@@schema("name"): PostgreSQL schema name.
@@index supports partial indexes, PostgreSQL expressions, and per-column
index options. @@unique also supports PostgreSQL expressions:
model Announcement {
id Int
status Int
publishedAt DateTime?
@@index(
[status, publishedAt],
name: "idx_announcements_user",
where: "status = 1 AND published_at IS NOT NULL",
sort: [Desc, Asc],
nulls: [Last, Last],
opclass: ["int8_ops", "timestamptz_ops"],
collate: ["pg_catalog.default", "pg_catalog.default"]
)
}
model User {
id Int
email String
@@unique([email], name: "uq_users_email_ci", expression: "lower(email)")
}
Index arguments:
-
name: explicit database index name. -
where: raw SQL predicate for a partial or filtered index. -
sortororder:AscorDesc, either one value or one value per field. -
nulls:FirstorLast, either one value or one value per field. -
opclass,opclasses, orops: PostgreSQL operator class names. -
collateorcollation: collation names, such aspg_catalog.default. -
expressionorexpressions: raw PostgreSQL index expressions. An expression replaces the field at the same position in the generated index.
Indexes and unique keys that use expression or expressions must provide an
explicit, non-empty name. This keeps multiple expressions over the same field
unambiguous during schema diffing.
For a composite expression index, provide one expression entry per field. Use an empty string for positions that should remain ordinary columns:
@@unique(
[tenantId, email],
name: "uq_users_tenant_email_ci",
expressions: ["", "lower(email)"]
)
This generates a PostgreSQL unique index on tenantId, lower(email). PostgreSQL
implements expression uniqueness with CREATE UNIQUE INDEX, rather than a
table-level UNIQUE constraint.
Single-column example:
@@index([clickhouseRecordedAt], name: "idx_ihce_retry", where: "clickhouse_recorded_at IS NULL")
where and expression(s) are database SQL, not GCORM expressions. Use
database column names, including names declared with @map, in these values.
Partial indexes are supported by PostgreSQL and SQLite. Expression options are
PostgreSQL-only; schemas using them with MySQL or SQLite fail validation. MySQL
does not support partial indexes, so GCORM will not emit a valid MySQL partial
index for schemas that use where.
One-to-many:
model User {
id String @id @default(uuid())
posts Post[]
}
model Post {
id String @id @default(uuid())
authorId String
author User @relation(fields: [authorId], references: [id])
}
One-to-one:
model User {
id String @id @default(uuid())
profile Profile?
}
model Profile {
id String @id @default(uuid())
userId String @unique
user User @relation(fields: [userId], references: [id])
}
Many-to-many is represented by list relations on both sides:
model Post {
id String @id @default(uuid())
tags Tag[]
}
model Tag {
id String @id @default(uuid())
posts Post[]
}
For production systems, an explicit join model is often easier to migrate, index, and extend:
model PostTag {
postId String
tagId String
@@id([postId, tagId])
@@index([tagId])
}
enum Role {
USER
ADMIN
MODERATOR
}
Enums generate Go string types and constants. They can be used as field types:
model User {
id String @id @default(uuid())
role Role @default(USER)
}
Use clear model and field names for generated Go APIs. Use @map and @@map
when the database name differs from the Go-facing schema name.
model User {
id String @id @default(uuid())
createdAt DateTime @map("created_at")
@@map("users")
}