Schema Definition¶
The schema DSL is a code-first way to describe SurrealDB tables, edges, fields, indexes, events, and access rules. Definitions render to DEFINE statements and feed the migration generator + validator + visualizer.
Tables¶
user, _ := schema.NewTableDefinition(
"user",
schema.WithMode(schema.TableModeSchemafull),
schema.WithFields(
schema.StringField("email").WithAssertion("string::is::email($value)"),
schema.IntField("age"),
),
schema.WithIndexes(schema.UniqueIndex("email_idx", []string{"email"})),
)
TableMode has three variants: TableModeSchemafull, TableModeSchemaless, TableModeDrop.
Field helpers¶
| Helper | SurrealDB type |
|---|---|
StringField | string |
IntField | int |
FloatField | float |
BoolField | bool |
DatetimeField | datetime |
DurationField | duration |
DecimalField | decimal |
ObjectField | object (defaults Flexible=true) |
ArrayField | array |
RecordField(t) | record<t> |
ComputedField | VALUE <expr> |
Chainable setters: WithAssertion, WithDefault, WithValue, WithReadonly, WithFlexible, WithPermissions.
Indexes¶
Index(name, cols)UniqueIndex(name, cols)SearchIndex(name, cols)-- full-text index; renders the SurrealDB 3.xFULLTEXTkeyword (see v3 Patterns)BM25Index(name, cols, analyzer)-- BM25-scored full-text indexMTreeIndex(name, col, dimension, opts)withMTreeIndexOptions{Distance, VectorType}HnswIndex(name, col, dimension, opts)withHnswIndexOptions{Distance, VectorType, EFC, M}
Full-text indexes are chainable: SearchIndex("s", []string{"content"}).WithAnalyzer("text_en").WithBM25().WithHighlights(). WithBM25 is required for search::score to return a value; WithHighlights stores positional data for search::highlight / search::offsets. With no analyzer set, the index renders the historical ascii default.
Analyzers¶
A full-text index references an analyzer that turns stored and query text into comparable tokens (a tokenizer chain + a filter chain). Define it in code rather than hand-authoring SurrealQL:
import "github.com/Oneiriq/surql-go/pkg/surql/schema"
// class tokenizer + lowercase + ascii, plus English stemming.
a := schema.StandardAnalyzer("text_en", schema.WithFilter(schema.Snowball("english")))
// DEFINE ANALYZER text_en TOKENIZERS class FILTERS lowercase,ascii,snowball(english);
ddl := a.ToSurql()
- Tokenizers:
TokenizerBlank/TokenizerCamel/TokenizerClass/TokenizerPunct. - Filters:
ASCII()/Lowercase()/Uppercase()/EdgeNgram(min,max)/Ngram(min,max)/Snowball(lang). Analyzer(name, opts...)builds an empty analyzer;StandardAnalyzer(name, opts...)isclass+lowercase+ascii— a sensible default for BM25 lexical recall.GenerateAnalyzerSQL(a)/GenerateAnalyzerSQLIfNotExists(a)render theDEFINE ANALYZERstatement, which must be applied before the index that references it.GenerateSchemaSQLFromSlicesWithAnalyzers(analyzers, tables, edges, ifNotExists)emits analyzer DDL first, then tables, then edges.
Events¶
ev := schema.Event("new_user").
WithWhen("$event = 'CREATE'").
WithThen("CREATE log SET table = 'user', id = $value.id")
Edges¶
likes, _ := schema.NewEdgeDefinition(
"likes",
schema.WithEdgeMode(schema.EdgeModeRelation),
schema.WithEdgeFrom("user"),
schema.WithEdgeTo("post"),
)
Access (record + JWT)¶
api, _ := schema.NewAccessDefinition(
"api",
schema.WithAccessType(schema.AccessTypeJwt),
schema.WithJwt(schema.JwtConfig{Algorithm: "HS512", Key: "secret"}),
schema.WithDurationToken("1h"),
)
Registry + SQL generation¶
reg := schema.NewSchemaRegistry()
reg.RegisterTable(user)
reg.RegisterEdge(likes)
stmts, _ := schema.GenerateSchemaSQL(reg, false)
What's next¶
- Migrations -- turning schema changes into migration files.
- Visualization -- Mermaid / GraphViz / ASCII diagrams from the registry.