# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview RelSpec is a database relations specification tool that provides bidirectional conversion between various database schema formats. It reads database schemas from multiple sources (live databases, DBML, DCTX, DrawDB, etc.) and writes them to various formats (GORM, Bun, JSON, YAML, SQL, etc.). ## Build Commands ```bash # Build the binary make build # Outputs to build/relspec go build -o build/relspec ./cmd/relspec # Run tests make test # Run all tests with race detection and coverage go test ./... # Run tests without coverage # Run a single test go test -run TestName ./pkg/readers/dbml # Linting make lint # Requires golangci-lint installed # Coverage report make coverage # Generates coverage.html # Clean build artifacts make clean # Install binary make install # Installs to $GOPATH/bin ``` ## Architecture ### Core Data Model (pkg/models/) The central data structure is the `Database` model, which represents a complete database schema with this hierarchy: ``` Database └── Schemas ([]Schema) └── Tables ([]Table) ├── Columns (map[string]Column) ├── Constraints (map[string]Constraint) ├── Indexes (map[string]Index) └── Relationships (map[string]Relationship) ``` **Key architectural decisions:** - Tables use **maps** for Columns, Constraints, Indexes, and Relationships (keyed by name for O(1) lookup) - Schemas use **slices** for Tables (order matters for generation) - All model types implement `SQLNamer` interface (returns lowercase SQL-safe names) - Use `Init*` functions (e.g., `InitTable()`, `InitSchema()`) to create properly initialized models with empty maps/slices **Model Views:** - `flatview.go`: Provides denormalized views with fully qualified names (e.g., `database.schema.table.column`) - `summaryview.go`: Lightweight summary views with counts and essential metadata - Use `.ToFlatColumns()`, `.ToSummary()` methods to convert between views ### Reader/Writer Pattern (pkg/readers/, pkg/writers/) All readers and writers implement consistent interfaces with three granularity levels: ```go // Reader interface type Reader interface { ReadDatabase() (*models.Database, error) ReadSchema() (*models.Schema, error) ReadTable() (*models.Table, error) } // Writer interface type Writer interface { WriteDatabase(db *models.Database) error WriteSchema(schema *models.Schema) error WriteTable(table *models.Table) error } ``` **Important patterns:** - Each format (dbml, dctx, drawdb, etc.) has its own `pkg/readers//` and `pkg/writers//` subdirectories - Use `ReaderOptions` and `WriterOptions` structs for configuration (file paths, connection strings, metadata) - Schema reading typically returns the first schema when reading from Database - Table reading typically returns the first table when reading from Schema ### Transformation Layer (pkg/transform/) The `Transformer` provides validation and normalization utilities. Note: validation methods are currently stubs (return nil) and need implementation when used. ### Database-Specific Utilities (pkg/pgsql/) Contains PostgreSQL-specific helpers: - `keywords.go`: SQL reserved keywords validation - `datatypes.go`: PostgreSQL data type mappings and conversions ## Development Patterns ### Adding a New Reader 1. Create `pkg/readers//` directory 2. Implement the `Reader` interface with all three methods 3. Create a `NewReader(options *readers.ReaderOptions)` constructor 4. Parse format-specific data into the canonical `models.Database` structure 5. Use `models.Init*()` functions to create properly initialized structs ### Adding a New Writer 1. Create `pkg/writers//` directory 2. Implement the `Writer` interface with all three methods 3. Create a `NewWriter(options *writers.WriterOptions)` constructor 4. Transform canonical models into format-specific output 5. Handle file writing or other I/O in the writer implementation ### Working with Models ```go // Creating models - ALWAYS use Init functions db := models.InitDatabase("mydb") schema := models.InitSchema("public") table := models.InitTable("users", "public") column := models.InitColumn("id", "users", "public") // Adding to parent structures schema.Tables = append(schema.Tables, table) table.Columns["id"] = column // Use map key access for columns db.Schemas = append(db.Schemas, schema) // Accessing primary keys and foreign keys pk := table.GetPrimaryKey() // Returns *Column or nil fks := table.GetForeignKeys() // Returns []*Constraint ``` ## CLI Implementation Status The CLI in `cmd/relspec/main.go` is currently a placeholder showing usage examples. It will be implemented using the Cobra framework (already in dependencies). ## Testing - Test files should be in the same package as the code they test - Use table-driven tests for multiple test cases - All tests run with race detection via `make test` - Coverage reports available via `make coverage` ## Module Information - Module path: `git.warky.dev/wdevs/relspecgo` - Go version: 1.25.5 - Uses Cobra for CLI, Viper for configuration