Skip to content

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.

Terminal window
# Generate code for all .scaf files in current directory
scaf generate
# Generate code for specific file
scaf generate queries/users.scaf
# Generate code for a directory
scaf generate ./queries

Target language for code generation (default: go):

Terminal window
scaf generate --lang=go
LanguageStatus
go✅ Available

Database adapter to use for the generated code:

Terminal window
scaf generate --adapter=neogo
AdapterDatabaseStatus
neogoNeo4j✅ Available
pgxPostgreSQL🚧 Planned
mysqlMySQL🚧 Planned
sqliteSQLite🚧 Planned

If not specified, the adapter is inferred from your .scaf.yaml configuration.

See Adapters for detailed adapter documentation.

Query dialect for parsing (default: inferred from config):

Terminal window
scaf generate --dialect=cypher

Output directory for generated files:

Terminal window
scaf generate --out=./generated

If not specified, files are generated in the same directory as the input file.

Go package name for generated code:

Terminal window
scaf generate --package=queries

If not specified, uses the output directory name.

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: queries

Given this scaf file:

users.scaf
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:

users_gen.go
// 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 age
func 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 id
func 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 count
func 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
}
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)
}

scaf analyzes your queries to infer types:

Parameter types are inferred from usage context in the query:

Cypher PatternInferred Go Type
{id: $id}string
LIMIT $limitint64
WHERE n.active = $activebool
Unknownany

Return types are inferred from expressions:

Cypher ExpressionInferred Go Type
n.namestring
n.ageint64
n.activebool
count(n)int64
collect(n)[]any
Complex/Unknownany

Add a generate directive to your Go code:

//go:generate scaf generate ./queries

Then run:

Terminal window
go generate ./...
.PHONY: generate
generate:
scaf generate ./queries
#!/bin/sh
scaf generate ./queries
git add ./queries/*_gen.go
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"

If types aren’t inferred correctly:

  1. Use explicit AS aliases in your queries
  2. Check that your query syntax is valid Cypher/SQL
  3. Fall back to any type and cast in your code
  1. Check that you’re running generate after changing the .scaf file
  2. Verify the output path is correct
  3. Check for parse errors in your scaf file with scaf fmt --check