Code Generator (tqlgen)

April 22, 2026 · View on GitHub

import "github.com/CaliLuke/go-typeql/tqlgen" -- pkg.go.dev

tqlgen generates Go struct definitions from TypeQL schema files. It produces structs with gotype.BaseEntity/BaseRelation embeds and typedb:"..." tags, ready for use with the ORM.

When parsing schema annotations, tqlgen decodes escaped string literals used in TypeQL string values, including unicode escapes such as \u0041 and \u{1F600} in @regex(...) and @values(...).

CLI Usage

go run github.com/CaliLuke/go-typeql/tqlgen/cmd/tqlgen \
    -schema schema.tql \
    -out models_gen.go \
    -pkg models

Flags

FlagDefaultDescription
-schema(required)Path to TypeQL .tql schema file
-outstdoutOutput file path
-pkgmodelsGo package name
-acronymstrueApply Go naming conventions for acronyms (ID, URL, API, etc.)
-skip-abstracttrueSkip abstract types in output
-inherittruePropagate parent owns to children
-enumstrueGenerate string constants from @values constraints
-registryfalseGenerate a schema registry instead of Go structs
-dtofalseGenerate DTO structs (Out/Create/Patch) for HTTP APIs
-id-fieldIDID field name in Out DTOs
-strict-outfalseMake required fields non-pointer in Out structs
-skip-relation-outfalseSkip generating relation Out structs
-schema-version(none)Embed a schema version string in the generated header
-version--Print tqlgen version and exit

What It Generates

Given a TypeQL schema, tqlgen produces:

  • Go structs embedding gotype.BaseEntity or gotype.BaseRelation
  • typedb:"..." tags with attribute names, key, unique, and card= options
  • Role player fields with role:name tags
  • Pointer types for optional fields (non-key attributes without explicit cardinality)
  • time.Time imports when datetime attributes are present
  • String constants from @values constraints (when -enums=true)
  • A // Code generated by tqlgen. DO NOT EDIT. header

Example

Input (schema.tql)

define
attribute name, value string;
attribute email, value string;
attribute age, value long;
attribute start_date, value datetime;

entity person,
    owns name @key,
    owns email @unique,
    owns age,
    plays employment:employee;

entity company,
    owns name @key,
    plays employment:employer;

relation employment,
    relates employee,
    relates employer,
    owns start_date;

Output

// Code generated by tqlgen. DO NOT EDIT.

package models

import (
    "github.com/CaliLuke/go-typeql/gotype"
    "time"
)

type Person struct {
    gotype.BaseEntity
    Name  string  `typedb:"name,key"`
    Email *string `typedb:"email,unique"`
    Age   *int64  `typedb:"age"`
}

type Company struct {
    gotype.BaseEntity
    Name string `typedb:"name,key"`
}

type Employment struct {
    gotype.BaseRelation
    Employee  *Person    `typedb:"role:employee"`
    Employer  *Company   `typedb:"role:employer"`
    StartDate *time.Time `typedb:"start_date"`
}

Enum Constants

When an attribute has @values constraints, tqlgen generates typed string constants (enabled by default, disable with -enums=false):

attribute status, value string @values("proposed", "accepted", "rejected");

Generates:

// Status values for the "status" attribute.
const (
 StatusProposed = "proposed"
 StatusAccepted = "accepted"
 StatusRejected = "rejected"
)

Registry Mode

The -registry flag generates a schema registry file instead of Go structs. This is useful for applications that need runtime access to schema metadata (type constants, parent maps, attribute lookups, relation schemas) without reflection.

tqlgen -schema schema.tql -registry -out registry_gen.go -pkg graph

The registry file contains:

  • Type constantsconst TypePerson = "person", const RelEmployment = "employment"
  • Entity parentsEntityParents map for inheritance lookups
  • Entity attributesEntityAttributes map of type → sorted owned attributes
  • Entity keysEntityKeys map of type → @key attribute names
  • Abstract trackingEntityAbstract and RelationAbstract maps
  • Attribute value typesAttributeValueTypes map of attribute → TypeDB value type
  • Attribute enum valuesAttributeEnumValues map for @values-constrained attributes
  • All attribute typesAllAttributeTypes sorted slice
  • Relation schemasRelationSchema map with N roles (not limited to binary) and player types
  • Relation attributesRelationAttributes map of relation → owned attributes
  • Relation parentsRelationParents map for relation inheritance
  • Sorted type listsAllEntityTypes and AllRelationTypes slices
  • Schema hashSchemaHash constant (SHA256 prefix) when schema text is provided
  • Convenience functionsGetEntityKeys(), IsAbstractEntity(), IsAbstractRelation(), GetRolePlayers(), GetEntityAttributes(), GetRelationAttributes()

Programmatic usage:

data := tqlgen.BuildRegistryData(schema, tqlgen.RegistryConfig{
    PackageName:  "graph",
    UseAcronyms:  true,
    SkipAbstract: true,
    Enums:        true,
    SchemaText:   schemaStr, // optional: enables SchemaHash in output
})
err := tqlgen.RenderRegistry(os.Stdout, data)

DTO Mode

The -dto flag generates Out/Create/Patch struct variants for HTTP API layers:

tqlgen -schema schema.tql -dto -out dto_gen.go -pkg dto

For each non-abstract entity Foo:

  • FooOut — response struct with ID, Type, and all attribute fields
  • FooCreate — create request with required fields non-pointer (@key, @unique, @card(1+)) and optional fields as *T
  • FooPatch — partial update with all fields as *T (nil = don't update)

For each non-abstract relation Bar:

  • BarOut — response with role player IIDs and owned attributes
  • BarCreate — request with role player IDs and owned attributes

Plus Go interfaces (EntityOut, EntityCreate, EntityPatch, RelationOut, RelationCreate) with TypeName() string methods.

DTO Configuration

dtoCfg := tqlgen.DTOConfig{
    PackageName:     "dto",
    UseAcronyms:     true,
    SkipAbstract:    true,
    StrictOut:       false,       // true = required fields non-pointer in Out
    IDFieldName:     "ID",
    ExcludeEntities: []string{"internal-counter"},
    SkipRelationOut: false,
    // Shared base structs for entity hierarchies
    BaseStructs: []tqlgen.BaseStructConfig{{
        SourceEntity:   "artifact",
        BaseName:       "BaseArtifact",
        InheritedAttrs: []string{"name", "status"},
    }},
    // Per-field overrides
    EntityFieldOverrides: []tqlgen.EntityFieldOverride{{
        Entity: "person", Field: "email", Variant: "create",
        Required: boolPtr(false),
    }},
}
data := tqlgen.BuildDTOData(schema, dtoCfg)
err := tqlgen.RenderDTO(os.Stdout, data)

Programmatic API

For use in tooling or migration workflows, you can parse schemas and render programmatically:

schema, err := tqlgen.ParseSchemaFile("schema.tql")
// or from a string:
schema, err := tqlgen.ParseSchema(schemaStr)

// Propagate parent owns to children
schema.AccumulateInheritance()

// Render to Go source
err = tqlgen.Render(os.Stdout, schema, tqlgen.DefaultConfig())

The ParsedSchema struct contains Attributes, Entities, Relations, Functions, and Structs slices. It is also used by the migration system (see Schema) for diffing against the live database schema.

Inheritance Propagation

AccumulateInheritance() merges parent owns/plays clauses into children, so each child struct has the complete set of fields. Child definitions override parent ones for the same attribute name. This is enabled by default in the CLI (-inherit=true).

Comment Annotations

ExtractAnnotations parses comment annotations above type definitions. Three syntaxes are supported:

  • # @key value — space-separated
  • # @key(value) — parenthesized
  • # @key — bare flag (empty string value)
annots := tqlgen.ExtractAnnotations(schemaText)
// annots["person"]["description"] = "A person entity"
// annots["project"]["prefix"] = "PROJ"
// annots["secret"]["internal"] = ""

Naming Conventions

tqlgen converts kebab-case and snake_case TypeDB names to PascalCase Go names. With -acronyms=true (the default), common Go acronyms are uppercased: user-id becomes UserID, api-url becomes APIURL.

The recognized acronyms are: ID, URL, UUID, API, HTTP, IID, NF.

Supported TypeQL Features

  • attribute definitions with value types (string, long, double, boolean, datetime)
  • entity and relation definitions with sub (inheritance)
  • @abstract, @key, @unique, @card(...) annotations
  • relates with optional as (role override) and @card(...)
  • plays clauses (used for role player type resolution)
  • @regex, @range annotations (parsed but not emitted as Go constraints)
  • @values annotations (parsed; emitted as string constants when -enums=true)
  • Escaped TypeQL string literals in annotations, including unicode escape forms \uXXXX and \u{...}
  • fun definitions (parsed for signature extraction, not emitted as Go code)
  • struct definitions (parsed for field extraction)
  • Comment annotations (# @key value, # @key(value), # @key above type definitions)

The parser uses participle/v2. TypeQL functions are stripped via pre-processing (truncate at first fun) rather than being parsed by the grammar.