scaf generate
scaf generate
Section titled “scaf generate”The generate command creates type-safe code from your scaf query definitions. It analyzes your queries and generates functions with proper parameter and return types.
Basic Usage
Section titled “Basic Usage”# Generate code for all .scaf files in current directoryscaf generate
# Generate code for specific filescaf generate queries/users.scaf
# Generate code for a directoryscaf generate ./queriesOptions
Section titled “Options”--lang, -l
Section titled “--lang, -l”Target language for code generation (default: go):
scaf generate --lang=go| Language | Status |
|---|---|
go | ✅ Available |
--adapter, -a
Section titled “--adapter, -a”Database adapter to use for the generated code:
scaf generate --adapter=neogo| Adapter | Database | Status |
|---|---|---|
neogo | Neo4j | ✅ Available |
pgx | PostgreSQL | 🚧 Planned |
mysql | MySQL | 🚧 Planned |
sqlite | SQLite | 🚧 Planned |
If not specified, the adapter is inferred from your .scaf.yaml configuration.
See Adapters for detailed adapter documentation.
--dialect, -d
Section titled “--dialect, -d”Query dialect for parsing (default: inferred from config):
scaf generate --dialect=cypher--out, -o
Section titled “--out, -o”Output directory for generated files:
scaf generate --out=./generatedIf not specified, files are generated in the same directory as the input file.
--package, -p
Section titled “--package, -p”Go package name for generated code:
scaf generate --package=queriesIf not specified, uses the output directory name.
Configuration
Section titled “Configuration”Configure generation settings in .scaf.yaml:
neo4j: uri: bolt://localhost:7687 username: neo4j password: password
generate: lang: go adapter: neogo # inferred from neo4j if not set out: ./queries package: queriesExample
Section titled “Example”Given this scaf file:
fn GetUser `MATCH (u:User {id: $userId})RETURN u.name AS name, u.email AS email, u.age AS age`
fn CreateUser `CREATE (u:User {id: $id, name: $name, email: $email})RETURN u.id AS id`
fn CountUsers `MATCH (u:User)RETURN count(u) AS count`Running scaf generate users.scaf produces:
// Code generated by scaf. DO NOT EDIT.
package queries
import ( "context" "github.com/rlch/neogo")
// GetUser executes: MATCH (u:User {id: $userId}) RETURN u.name AS name, u.email AS email, u.age AS agefunc GetUser(ctx context.Context, db neogo.Driver, userId string) (name string, email string, age int64, err error) { err = db.Exec(). Cypher(`MATCH (u:User {id: $userId}) RETURN u.name AS name, u.email AS email, u.age AS age`). RunWithParams(ctx, map[string]any{"userId": userId}, "name", &name, "email", &email, "age", &age) if err != nil { return "", "", 0, err } return name, email, age, nil}
// CreateUser executes: CREATE (u:User {id: $id, name: $name, email: $email}) RETURN u.id AS idfunc CreateUser(ctx context.Context, db neogo.Driver, id string, name string, email string) (resultId string, err error) { err = db.Exec(). Cypher(`CREATE (u:User {id: $id, name: $name, email: $email}) RETURN u.id AS id`). RunWithParams(ctx, map[string]any{"id": id, "name": name, "email": email}, "id", &resultId) if err != nil { return "", err } return resultId, nil}
// CountUsers executes: MATCH (u:User) RETURN count(u) AS countfunc CountUsers(ctx context.Context, db neogo.Driver) (count int64, err error) { err = db.Exec(). Cypher(`MATCH (u:User) RETURN count(u) AS count`). Run(ctx, "count", &count) if err != nil { return 0, err } return count, nil}Using Generated Code
Section titled “Using Generated Code”package main
import ( "context" "log"
"github.com/rlch/neogo" "myproject/queries")
func main() { ctx := context.Background()
// Connect to Neo4j db, err := neogo.New(ctx, "bolt://localhost:7687", neogo.WithAuth("neo4j", "password")) if err != nil { log.Fatal(err) } defer db.Close(ctx)
// Use generated functions name, email, age, err := queries.GetUser(ctx, db, "user-123") if err != nil { log.Fatal(err) }
log.Printf("Found user: %s (%s), age %d", name, email, age)}Type Inference
Section titled “Type Inference”scaf analyzes your queries to infer types:
Parameters
Section titled “Parameters”Parameter types are inferred from usage context in the query:
| Cypher Pattern | Inferred Go Type |
|---|---|
{id: $id} | string |
LIMIT $limit | int64 |
WHERE n.active = $active | bool |
| Unknown | any |
Return Values
Section titled “Return Values”Return types are inferred from expressions:
| Cypher Expression | Inferred Go Type |
|---|---|
n.name | string |
n.age | int64 |
n.active | bool |
count(n) | int64 |
collect(n) | []any |
| Complex/Unknown | any |
Workflow Integration
Section titled “Workflow Integration”Go Generate
Section titled “Go Generate”Add a generate directive to your Go code:
//go:generate scaf generate ./queriesThen run:
go generate ./...Makefile
Section titled “Makefile”.PHONY: generategenerate: scaf generate ./queriesPre-commit Hook
Section titled “Pre-commit Hook”#!/bin/shscaf generate ./queriesgit add ./queries/*_gen.goTroubleshooting
Section titled “Troubleshooting””unknown adapter” Error
Section titled “”unknown adapter” Error”Error: unknown adapter "neogo" for language "go"Ensure you’re importing the adapter. The CLI does this automatically, but if you’re using scaf as a library:
import _ "github.com/rlch/scaf/adapters/neogo"Type Inference Issues
Section titled “Type Inference Issues”If types aren’t inferred correctly:
- Use explicit
ASaliases in your queries - Check that your query syntax is valid Cypher/SQL
- Fall back to
anytype and cast in your code
Generated File Not Updating
Section titled “Generated File Not Updating”- Check that you’re running generate after changing the
.scaffile - Verify the output path is correct
- Check for parse errors in your scaf file with
scaf fmt --check