diff --git a/README.md b/README.md index 9627a50..d707293 100644 --- a/README.md +++ b/README.md @@ -16,19 +16,47 @@ RelSpec provides bidirectional conversion and comparison between various databas ## Features -### Input Formats -- **XML** - Generic XML schema definitions -- **JSON** - JSON-based schema specifications -- **Clarion DCTX** - Clarion database dictionary format -- **Database Inspection** - Direct database introspection -- **GORM Models** - Read existing GORM Go structs -- **Bun Models** - Read existing Bun Go structs +### Readers (Input Formats) -### Output Formats -- **GORM Models** - Generate GORM-compatible Go structs -- **Bun Models** - Generate Bun-compatible Go structs -- **JSON** - Standard JSON schema output -- **YAML** - Human-readable YAML format +RelSpec can read database schemas from multiple sources: + +#### ORM Models +- [GORM](pkg/readers/gorm/README.md) - Go GORM model definitions +- [Bun](pkg/readers/bun/README.md) - Go Bun model definitions +- [Drizzle](pkg/readers/drizzle/README.md) - TypeScript Drizzle ORM schemas +- [Prisma](pkg/readers/prisma/README.md) - Prisma schema language +- [TypeORM](pkg/readers/typeorm/README.md) - TypeScript TypeORM entities + +#### Database Inspection +- [PostgreSQL](pkg/readers/pgsql/README.md) - Direct PostgreSQL database introspection + +#### Schema Formats +- [DBML](pkg/readers/dbml/README.md) - Database Markup Language (dbdiagram.io) +- [DCTX](pkg/readers/dctx/README.md) - Clarion database dictionary format +- [DrawDB](pkg/readers/drawdb/README.md) - DrawDB JSON format +- [JSON](pkg/readers/json/README.md) - RelSpec canonical JSON format +- [YAML](pkg/readers/yaml/README.md) - RelSpec canonical YAML format + +### Writers (Output Formats) + +RelSpec can write database schemas to multiple formats: + +#### ORM Models +- [GORM](pkg/writers/gorm/README.md) - Generate GORM-compatible Go structs +- [Bun](pkg/writers/bun/README.md) - Generate Bun-compatible Go structs +- [Drizzle](pkg/writers/drizzle/README.md) - Generate Drizzle ORM TypeScript schemas +- [Prisma](pkg/writers/prisma/README.md) - Generate Prisma schema files +- [TypeORM](pkg/writers/typeorm/README.md) - Generate TypeORM TypeScript entities + +#### Database DDL +- [PostgreSQL](pkg/writers/pgsql/README.md) - PostgreSQL DDL (CREATE TABLE, etc.) + +#### Schema Formats +- [DBML](pkg/writers/dbml/README.md) - Database Markup Language +- [DCTX](pkg/writers/dctx/README.md) - Clarion database dictionary format +- [DrawDB](pkg/writers/drawdb/README.md) - DrawDB JSON format +- [JSON](pkg/writers/json/README.md) - RelSpec canonical JSON format +- [YAML](pkg/writers/yaml/README.md) - RelSpec canonical YAML format ## Use of AI @@ -98,7 +126,7 @@ go test ./... Apache License 2.0 - See [LICENSE](LICENSE) for details. -Copyright 2025 wdevs +Copyright 2025 Warky Devs ## Contributing diff --git a/pkg/readers/bun/README.md b/pkg/readers/bun/README.md new file mode 100644 index 0000000..8386a67 --- /dev/null +++ b/pkg/readers/bun/README.md @@ -0,0 +1,106 @@ +# Bun Reader + +Reads Go source files containing Bun model definitions and extracts database schema information. + +## Overview + +The Bun Reader parses Go source code files that define Bun models (structs with `bun` struct tags) and converts them into RelSpec's internal database model representation. + +## Features + +- Parses Bun struct tags to extract column definitions +- Extracts table names from `bun:"table:tablename"` tags +- Identifies primary keys, foreign keys, and indexes +- Supports relationship detection +- Handles both single files and directories + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/bun" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/models.go", + } + + reader := bun.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read Bun models and convert to JSON +relspec --input bun --in-file models/ --output json --out-file schema.json + +# Convert Bun models to GORM +relspec --input bun --in-file models.go --output gorm --out-file gorm_models.go +``` + +## Supported Bun Tags + +The reader recognizes the following Bun struct tags: + +- `table` - Table name +- `column` - Column name +- `type` - SQL data type +- `pk` - Primary key +- `notnull` - NOT NULL constraint +- `autoincrement` - Auto-increment column +- `default` - Default value +- `unique` - Unique constraint +- `rel` - Relationship definition + +## Example Bun Model + +```go +package models + +import ( + "time" + "github.com/uptrace/bun" +) + +type User struct { + bun.BaseModel `bun:"table:users,alias:u"` + + ID int64 `bun:"id,pk,autoincrement"` + Username string `bun:"username,notnull,unique"` + Email string `bun:"email,notnull"` + CreatedAt time.Time `bun:"created_at,notnull,default:now()"` + + Posts []*Post `bun:"rel:has-many,join:id=user_id"` +} + +type Post struct { + bun.BaseModel `bun:"table:posts,alias:p"` + + ID int64 `bun:"id,pk"` + UserID int64 `bun:"user_id,notnull"` + Title string `bun:"title,notnull"` + Content string `bun:"content"` + + User *User `bun:"rel:belongs-to,join:user_id=id"` +} +``` + +## Notes + +- Test files (ending in `_test.go`) are automatically excluded +- The `bun.BaseModel` embedded struct is automatically recognized +- Schema defaults to `public` if not specified diff --git a/pkg/readers/dbml/README.md b/pkg/readers/dbml/README.md new file mode 100644 index 0000000..2ba2502 --- /dev/null +++ b/pkg/readers/dbml/README.md @@ -0,0 +1,101 @@ +# DBML Reader + +Reads Database Markup Language (DBML) files and extracts database schema information. + +## Overview + +The DBML Reader parses `.dbml` files that define database schemas using the DBML syntax (used by dbdiagram.io) and converts them into RelSpec's internal database model representation. + +## Features + +- Parses DBML syntax +- Extracts tables, columns, and relationships +- Supports DBML-specific features: + - Table groups and notes + - Enum definitions + - Indexes + - Foreign key relationships + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/dbml" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/schema.dbml", + } + + reader := dbml.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read DBML file and convert to JSON +relspec --input dbml --in-file schema.dbml --output json --out-file schema.json + +# Convert DBML to GORM models +relspec --input dbml --in-file database.dbml --output gorm --out-file models.go +``` + +## Example DBML File + +```dbml +Table users { + id bigserial [pk, increment] + username varchar(50) [not null, unique] + email varchar(100) [not null] + created_at timestamp [not null, default: `now()`] + + Note: 'Users table' +} + +Table posts { + id bigserial [pk] + user_id bigint [not null, ref: > users.id] + title varchar(200) [not null] + content text + + indexes { + user_id + (user_id, created_at) [name: 'idx_user_posts'] + } +} + +Ref: posts.user_id > users.id [delete: cascade] +``` + +## DBML Features Supported + +- Table definitions with columns +- Primary keys (`pk`) +- Not null constraints (`not null`) +- Unique constraints (`unique`) +- Default values (`default`) +- Inline references (`ref`) +- Standalone `Ref` blocks +- Indexes and composite indexes +- Table notes and column notes +- Enums + +## Notes + +- DBML is designed for database documentation and diagramming +- Schema name defaults to `public` +- Relationship cardinality is preserved diff --git a/pkg/readers/dctx/README.md b/pkg/readers/dctx/README.md new file mode 100644 index 0000000..736f1d6 --- /dev/null +++ b/pkg/readers/dctx/README.md @@ -0,0 +1,96 @@ +# DCTX Reader + +Reads Clarion database dictionary (DCTX) files and extracts database schema information. + +## Overview + +The DCTX Reader parses Clarion dictionary files (`.dctx`) that define database structures in the Clarion development system and converts them into RelSpec's internal database model representation. + +## Features + +- Parses Clarion DCTX XML format +- Extracts file (table) and field (column) definitions +- Supports Clarion data types +- Handles keys (indexes) and relationships + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/dctx" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/database.dctx", + } + + reader := dctx.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read DCTX file and convert to JSON +relspec --input dctx --in-file legacy.dctx --output json --out-file schema.json + +# Convert DCTX to GORM models for migration +relspec --input dctx --in-file app.dctx --output gorm --out-file models.go + +# Export DCTX to PostgreSQL DDL +relspec --input dctx --in-file database.dctx --output pgsql --out-file schema.sql +``` + +## Example DCTX Structure + +DCTX files are XML-based Clarion dictionary files that define: + +- Files (equivalent to tables) +- Fields (columns) with Clarion-specific types +- Keys (indexes) +- Relationships between files + +Common Clarion data types: +- `STRING` - Fixed-length string +- `CSTRING` - C-style null-terminated string +- `LONG` - 32-bit integer +- `SHORT` - 16-bit integer +- `DECIMAL` - Decimal number +- `REAL` - Floating point +- `DATE` - Date field +- `TIME` - Time field + +## Type Mapping + +The reader automatically maps Clarion data types to standard SQL types: + +| Clarion Type | SQL Type | +|--------------|----------| +| STRING | VARCHAR | +| CSTRING | VARCHAR | +| LONG | INTEGER | +| SHORT | SMALLINT | +| DECIMAL | NUMERIC | +| REAL | REAL | +| DATE | DATE | +| TIME | TIME | + +## Notes + +- DCTX is specific to Clarion development platform +- Useful for migrating legacy Clarion applications +- Schema name defaults to `public` +- Preserves field properties and constraints where possible diff --git a/pkg/readers/drawdb/README.md b/pkg/readers/drawdb/README.md new file mode 100644 index 0000000..975d3e6 --- /dev/null +++ b/pkg/readers/drawdb/README.md @@ -0,0 +1,96 @@ +# DrawDB Reader + +Reads DrawDB schema files and extracts database schema information. + +## Overview + +The DrawDB Reader parses JSON files exported from DrawDB (a free online database design tool) and converts them into RelSpec's internal database model representation. + +## Features + +- Parses DrawDB JSON format +- Extracts tables, fields, and relationships +- Supports DrawDB-specific metadata +- Preserves visual layout information + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/drawdb" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/diagram.json", + } + + reader := drawdb.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read DrawDB export and convert to JSON schema +relspec --input drawdb --in-file diagram.json --output json --out-file schema.json + +# Convert DrawDB design to GORM models +relspec --input drawdb --in-file design.json --output gorm --out-file models.go +``` + +## Example DrawDB Export + +DrawDB exports database designs as JSON files containing: + +```json +{ + "tables": [ + { + "id": "1", + "name": "users", + "fields": [ + { + "name": "id", + "type": "BIGINT", + "primary": true, + "autoIncrement": true + }, + { + "name": "username", + "type": "VARCHAR", + "size": 50, + "notNull": true, + "unique": true + } + ] + } + ], + "relationships": [ + { + "source": "posts", + "target": "users", + "type": "many-to-one" + } + ] +} +``` + +## Notes + +- DrawDB is a free online database designer at drawdb.vercel.app +- Export format preserves visual design metadata +- Useful for converting visual designs to code +- Schema defaults to `public` diff --git a/pkg/readers/drizzle/README.md b/pkg/readers/drizzle/README.md new file mode 100644 index 0000000..d0c65fb --- /dev/null +++ b/pkg/readers/drizzle/README.md @@ -0,0 +1,90 @@ +# Drizzle Reader + +Reads TypeScript/JavaScript files containing Drizzle ORM schema definitions and extracts database schema information. + +## Overview + +The Drizzle Reader parses Drizzle ORM schema files (TypeScript/JavaScript) that define database tables using Drizzle's schema builder and converts them into RelSpec's internal database model representation. + +## Features + +- Parses Drizzle schema definitions +- Extracts table, column, and relationship information +- Supports various Drizzle column types +- Handles constraints and indexes + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/drizzle" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/schema.ts", + } + + reader := drizzle.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read Drizzle schema and convert to JSON +relspec --input drizzle --in-file schema.ts --output json --out-file schema.json + +# Convert Drizzle to GORM models +relspec --input drizzle --in-file schema/ --output gorm --out-file models.go +``` + +## Example Drizzle Schema + +```typescript +import { pgTable, serial, varchar, text, timestamp, integer } from 'drizzle-orm/pg-core'; +import { relations } from 'drizzle-orm'; + +export const users = pgTable('users', { + id: serial('id').primaryKey(), + username: varchar('username', { length: 50 }).notNull().unique(), + email: varchar('email', { length: 100 }).notNull(), + createdAt: timestamp('created_at').notNull().defaultNow(), +}); + +export const posts = pgTable('posts', { + id: serial('id').primaryKey(), + userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), + title: varchar('title', { length: 200 }).notNull(), + content: text('content'), +}); + +export const usersRelations = relations(users, ({ many }) => ({ + posts: many(posts), +})); + +export const postsRelations = relations(posts, ({ one }) => ({ + user: one(users, { + fields: [posts.userId], + references: [users.id], + }), +})); +``` + +## Notes + +- Supports both PostgreSQL and MySQL Drizzle schemas +- Extracts relationship information from `relations` definitions +- Schema defaults to `public` for PostgreSQL diff --git a/pkg/readers/gorm/README.md b/pkg/readers/gorm/README.md new file mode 100644 index 0000000..b022317 --- /dev/null +++ b/pkg/readers/gorm/README.md @@ -0,0 +1,141 @@ +# GORM Reader + +Reads Go source files containing GORM model definitions and extracts database schema information. + +## Overview + +The GORM Reader parses Go source code files that define GORM models (structs with `gorm` struct tags) and converts them into RelSpec's internal database model representation. It supports reading from individual files or entire directories. + +## Features + +- Parses GORM struct tags to extract column definitions +- Extracts table names from `TableName()` methods +- Identifies primary keys, foreign keys, and indexes +- Supports relationship detection (has-many, belongs-to) +- Handles both single files and directories + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/gorm" +) + +func main() { + // Read from a single file + options := &readers.ReaderOptions{ + FilePath: "/path/to/models.go", + } + + reader := gorm.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### Reading from Directory + +```go +// Read all .go files from a directory +options := &readers.ReaderOptions{ + FilePath: "/path/to/models/", +} + +reader := gorm.NewReader(options) +db, err := reader.ReadDatabase() +if err != nil { + panic(err) +} +``` + +### CLI Example + +```bash +# Read GORM models and convert to JSON +relspec --input gorm --in-file models/ --output json --out-file schema.json + +# Convert GORM models to Bun +relspec --input gorm --in-file models.go --output bun --out-file bun_models.go +``` + +## Supported GORM Tags + +The reader recognizes the following GORM struct tags: + +- `column` - Column name +- `type` - SQL data type (e.g., `varchar(255)`, `bigint`) +- `primaryKey` or `primary_key` - Mark as primary key +- `not null` - NOT NULL constraint +- `autoIncrement` - Auto-increment column +- `default` - Default value +- `size` - Column size/length +- `index` - Create index +- `uniqueIndex` - Create unique index +- `unique` - Unique constraint +- `foreignKey` - Foreign key column +- `references` - Referenced column +- `constraint` - Constraint behavior (OnDelete, OnUpdate) + +## Example GORM Model + +```go +package models + +import ( + "time" + "gorm.io/gorm" +) + +type ModelUser struct { + gorm.Model + ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement"` + Username string `gorm:"column:username;type:varchar(50);not null;uniqueIndex"` + Email string `gorm:"column:email;type:varchar(100);not null"` + CreatedAt time.Time `gorm:"column:created_at;type:timestamp;not null;default:now()"` + + // Relationships + Posts []*ModelPost `gorm:"foreignKey:UserID;references:ID;constraint:OnDelete:CASCADE"` +} + +func (ModelUser) TableName() string { + return "public.users" +} + +type ModelPost struct { + ID int64 `gorm:"column:id;type:bigint;primaryKey"` + UserID int64 `gorm:"column:user_id;type:bigint;not null"` + Title string `gorm:"column:title;type:varchar(200);not null"` + Content string `gorm:"column:content;type:text"` + + // Belongs-to relationship + User *ModelUser `gorm:"foreignKey:UserID;references:ID"` +} + +func (ModelPost) TableName() string { + return "public.posts" +} +``` + +## Notes + +- Test files (ending in `_test.go`) are automatically excluded +- The `gorm.Model` embedded struct is automatically recognized and skipped +- Table names are derived from struct names if `TableName()` method is not present +- Schema defaults to `public` if not specified in `TableName()` +- Relationships are inferred from GORM relationship tags + +## Limitations + +- Complex relationship types (many-to-many with join tables) may need manual verification +- Custom GORM types may not be fully supported +- Some advanced GORM features may not be captured diff --git a/pkg/readers/json/README.md b/pkg/readers/json/README.md new file mode 100644 index 0000000..2d0bc57 --- /dev/null +++ b/pkg/readers/json/README.md @@ -0,0 +1,152 @@ +# JSON Reader + +Reads database schema definitions from JSON files. + +## Overview + +The JSON Reader parses JSON files that define database schemas in RelSpec's canonical JSON format and converts them into RelSpec's internal database model representation. + +## Features + +- Reads RelSpec's standard JSON schema format +- Supports complete schema representation including: + - Databases and schemas + - Tables, columns, and data types + - Constraints (PK, FK, unique, check) + - Indexes + - Relationships + - Views and sequences + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/json" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/schema.json", + } + + reader := json.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read JSON schema and convert to GORM models +relspec --input json --in-file schema.json --output gorm --out-file models.go + +# Convert JSON to PostgreSQL DDL +relspec --input json --in-file database.json --output pgsql --out-file schema.sql + +# Transform JSON to YAML +relspec --input json --in-file schema.json --output yaml --out-file schema.yaml +``` + +## Example JSON Schema + +```json +{ + "name": "myapp", + "database_type": "postgresql", + "schemas": [ + { + "name": "public", + "tables": [ + { + "name": "users", + "schema": "public", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "not_null": true, + "is_primary_key": true, + "auto_increment": true, + "sequence": 1 + }, + "username": { + "name": "username", + "type": "varchar", + "length": 50, + "not_null": true, + "sequence": 2 + }, + "email": { + "name": "email", + "type": "varchar", + "length": 100, + "not_null": true, + "sequence": 3 + } + }, + "constraints": { + "pk_users": { + "name": "pk_users", + "type": "PRIMARY KEY", + "columns": ["id"] + }, + "uq_users_username": { + "name": "uq_users_username", + "type": "UNIQUE", + "columns": ["username"] + } + }, + "indexes": { + "idx_users_email": { + "name": "idx_users_email", + "columns": ["email"], + "unique": false, + "type": "btree" + } + } + } + ] + } + ] +} +``` + +## Schema Structure + +The JSON format follows RelSpec's internal model structure: + +- `Database` - Top-level container + - `name` - Database name + - `database_type` - Database system (postgresql, mysql, etc.) + - `schemas[]` - Array of schemas + +- `Schema` - Schema/namespace + - `name` - Schema name + - `tables[]` - Array of tables + - `views[]` - Array of views + - `sequences[]` - Array of sequences + +- `Table` - Table definition + - `name` - Table name + - `columns{}` - Map of columns + - `constraints{}` - Map of constraints + - `indexes{}` - Map of indexes + - `relationships{}` - Map of relationships + +## Notes + +- This is RelSpec's native interchange format +- Preserves complete schema information +- Ideal for version control and schema documentation +- Can be used as an intermediate format for transformations diff --git a/pkg/readers/pgsql/README.md b/pkg/readers/pgsql/README.md new file mode 100644 index 0000000..258e284 --- /dev/null +++ b/pkg/readers/pgsql/README.md @@ -0,0 +1,138 @@ +# PostgreSQL Reader + +Reads schema information directly from a live PostgreSQL database. + +## Overview + +The PostgreSQL Reader connects to a PostgreSQL database and introspects its schema, extracting complete information about tables, columns, constraints, indexes, views, and sequences. + +## Features + +- Direct database introspection +- Extracts complete schema information including: + - Tables and columns + - Primary keys, foreign keys, unique constraints, check constraints + - Indexes + - Views + - Sequences +- Supports multiple schemas +- Captures constraint actions (ON DELETE, ON UPDATE) +- Derives relationships from foreign keys + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/pgsql" +) + +func main() { + options := &readers.ReaderOptions{ + ConnectionString: "postgres://user:password@localhost:5432/mydb?sslmode=disable", + } + + reader := pgsql.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Database: %s\n", db.Name) + fmt.Printf("Schemas: %d\n", len(db.Schemas)) + for _, schema := range db.Schemas { + fmt.Printf(" Schema: %s, Tables: %d\n", schema.Name, len(schema.Tables)) + } +} +``` + +### CLI Example + +```bash +# Inspect PostgreSQL database and export to JSON +relspec --input pgsql \ + --conn "postgres://user:password@localhost:5432/mydb" \ + --output json \ + --out-file schema.json + +# Generate GORM models from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://user:password@localhost:5432/mydb" \ + --output gorm \ + --out-file models.go + +# Export database structure to YAML +relspec --input pgsql \ + --conn "postgres://localhost/mydb?sslmode=disable" \ + --output yaml \ + --out-file schema.yaml +``` + +## Connection String Format + +The reader uses PostgreSQL connection strings in the format: + +``` +postgres://username:password@hostname:port/database?parameters +``` + +Examples: +``` +postgres://localhost/mydb +postgres://user:pass@localhost:5432/mydb +postgres://user@localhost/mydb?sslmode=disable +postgres://user:pass@db.example.com:5432/production?sslmode=require +``` + +## Extracted Information + +### Tables +- Table name and schema +- Comments/descriptions +- All columns with data types, nullable, defaults +- Sequences + +### Columns +- Column name, data type, length/precision +- NULL/NOT NULL constraints +- Default values +- Auto-increment information +- Primary key designation + +### Constraints +- Primary keys +- Foreign keys (with ON DELETE/UPDATE actions) +- Unique constraints +- Check constraints + +### Indexes +- Index name and type (btree, hash, gist, gin, etc.) +- Columns in index +- Unique/non-unique +- Partial indexes + +### Views +- View definitions +- Column information + +### Sequences +- Sequence properties +- Associated tables + +## Notes + +- Requires PostgreSQL connection permissions +- Reads all non-system schemas (excludes pg_catalog, information_schema, pg_toast) +- Captures PostgreSQL-specific data types +- Automatically maps PostgreSQL types to canonical types +- Preserves relationship metadata for downstream conversion + +## Requirements + +- Go library: `github.com/jackc/pgx/v5` +- Database user must have SELECT permissions on system catalogs diff --git a/pkg/readers/prisma/README.md b/pkg/readers/prisma/README.md new file mode 100644 index 0000000..589396d --- /dev/null +++ b/pkg/readers/prisma/README.md @@ -0,0 +1,103 @@ +# Prisma Reader + +Reads Prisma schema files and extracts database schema information. + +## Overview + +The Prisma Reader parses `.prisma` schema files that define database models using Prisma's schema language and converts them into RelSpec's internal database model representation. + +## Features + +- Parses Prisma schema syntax +- Extracts models, fields, and relationships +- Supports Prisma attributes and directives +- Handles enums and composite types + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/prisma" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/schema.prisma", + } + + reader := prisma.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read Prisma schema and convert to JSON +relspec --input prisma --in-file schema.prisma --output json --out-file schema.json + +# Convert Prisma to GORM models +relspec --input prisma --in-file schema.prisma --output gorm --out-file models.go +``` + +## Example Prisma Schema + +```prisma +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + username String @unique @db.VarChar(50) + email String @db.VarChar(100) + createdAt DateTime @default(now()) @map("created_at") + + posts Post[] + + @@map("users") +} + +model Post { + id Int @id @default(autoincrement()) + userId Int @map("user_id") + title String @db.VarChar(200) + content String @db.Text + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("posts") +} +``` + +## Supported Prisma Attributes + +- `@id` - Primary key +- `@unique` - Unique constraint +- `@default` - Default value +- `@map` - Column name mapping +- `@@map` - Table name mapping +- `@relation` - Relationship definition +- `@db.*` - Database-specific type annotations + +## Notes + +- Extracts datasource provider information +- Supports `@@map` for custom table names +- Handles Prisma-specific types and converts them to standard SQL types diff --git a/pkg/readers/typeorm/README.md b/pkg/readers/typeorm/README.md new file mode 100644 index 0000000..c2a4be5 --- /dev/null +++ b/pkg/readers/typeorm/README.md @@ -0,0 +1,122 @@ +# TypeORM Reader + +Reads TypeScript files containing TypeORM entity definitions and extracts database schema information. + +## Overview + +The TypeORM Reader parses TypeScript source files that define TypeORM entities (classes with TypeORM decorators) and converts them into RelSpec's internal database model representation. + +## Features + +- Parses TypeORM decorators and entity definitions +- Extracts table, column, and relationship information +- Supports various TypeORM column types and options +- Handles constraints, indexes, and relationships + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/typeorm" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/entities/", + } + + reader := typeorm.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read TypeORM entities and convert to JSON +relspec --input typeorm --in-file entities/ --output json --out-file schema.json + +# Convert TypeORM to GORM models +relspec --input typeorm --in-file User.ts --output gorm --out-file models.go +``` + +## Example TypeORM Entity + +```typescript +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + OneToMany, +} from 'typeorm'; +import { Post } from './Post'; + +@Entity('users') +export class User { + @PrimaryGeneratedColumn('increment') + id: number; + + @Column({ type: 'varchar', length: 50, unique: true }) + username: string; + + @Column({ type: 'varchar', length: 100 }) + email: string; + + @CreateDateColumn({ name: 'created_at' }) + createdAt: Date; + + @OneToMany(() => Post, (post) => post.user) + posts: Post[]; +} + +@Entity('posts') +export class Post { + @PrimaryGeneratedColumn('increment') + id: number; + + @Column({ name: 'user_id' }) + userId: number; + + @Column({ type: 'varchar', length: 200 }) + title: string; + + @Column({ type: 'text' }) + content: string; + + @ManyToOne(() => User, (user) => user.posts, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'user_id' }) + user: User; +} +``` + +## Supported TypeORM Decorators + +- `@Entity()` - Entity/table definition +- `@PrimaryGeneratedColumn()` - Auto-increment primary key +- `@PrimaryColumn()` - Primary key +- `@Column()` - Column definition +- `@CreateDateColumn()` - Auto-set creation timestamp +- `@UpdateDateColumn()` - Auto-update timestamp +- `@OneToMany()` - One-to-many relationship +- `@ManyToOne()` - Many-to-one relationship +- `@JoinColumn()` - Foreign key column +- `@Index()` - Index definition +- `@Unique()` - Unique constraint + +## Notes + +- Schema name can be specified in `@Entity()` decorator +- Supports both JavaScript and TypeScript entity files +- Relationship metadata is extracted from decorators diff --git a/pkg/readers/yaml/README.md b/pkg/readers/yaml/README.md new file mode 100644 index 0000000..b18f9fe --- /dev/null +++ b/pkg/readers/yaml/README.md @@ -0,0 +1,159 @@ +# YAML Reader + +Reads database schema definitions from YAML files. + +## Overview + +The YAML Reader parses YAML files that define database schemas in RelSpec's canonical YAML format and converts them into RelSpec's internal database model representation. + +## Features + +- Reads RelSpec's standard YAML schema format +- Human-readable alternative to JSON format +- Supports complete schema representation including: + - Databases and schemas + - Tables, columns, and data types + - Constraints (PK, FK, unique, check) + - Indexes + - Relationships + - Views and sequences + +## Usage + +### Basic Example + +```go +package main + +import ( + "fmt" + "git.warky.dev/wdevs/relspecgo/pkg/readers" + "git.warky.dev/wdevs/relspecgo/pkg/readers/yaml" +) + +func main() { + options := &readers.ReaderOptions{ + FilePath: "/path/to/schema.yaml", + } + + reader := yaml.NewReader(options) + db, err := reader.ReadDatabase() + if err != nil { + panic(err) + } + + fmt.Printf("Found %d schemas\n", len(db.Schemas)) +} +``` + +### CLI Example + +```bash +# Read YAML schema and convert to GORM models +relspec --input yaml --in-file schema.yaml --output gorm --out-file models.go + +# Convert YAML to PostgreSQL DDL +relspec --input yaml --in-file database.yaml --output pgsql --out-file schema.sql + +# Transform YAML to JSON +relspec --input yaml --in-file schema.yaml --output json --out-file schema.json +``` + +## Example YAML Schema + +```yaml +name: myapp +database_type: postgresql +schemas: + - name: public + tables: + - name: users + schema: public + columns: + id: + name: id + type: bigint + not_null: true + is_primary_key: true + auto_increment: true + sequence: 1 + username: + name: username + type: varchar + length: 50 + not_null: true + sequence: 2 + email: + name: email + type: varchar + length: 100 + not_null: true + sequence: 3 + constraints: + pk_users: + name: pk_users + type: PRIMARY KEY + columns: + - id + uq_users_username: + name: uq_users_username + type: UNIQUE + columns: + - username + indexes: + idx_users_email: + name: idx_users_email + columns: + - email + unique: false + type: btree + - name: posts + schema: public + columns: + id: + name: id + type: bigint + not_null: true + is_primary_key: true + sequence: 1 + user_id: + name: user_id + type: bigint + not_null: true + sequence: 2 + title: + name: title + type: varchar + length: 200 + not_null: true + sequence: 3 + constraints: + fk_posts_user_id: + name: fk_posts_user_id + type: FOREIGN KEY + columns: + - user_id + referenced_table: users + referenced_schema: public + referenced_columns: + - id + on_delete: CASCADE + on_update: NO ACTION +``` + +## Schema Structure + +The YAML format mirrors RelSpec's internal model structure with human-readable syntax: + +- Database level: `name`, `database_type`, `schemas` +- Schema level: `name`, `tables`, `views`, `sequences` +- Table level: `name`, `schema`, `columns`, `constraints`, `indexes`, `relationships` +- Column level: `name`, `type`, `length`, `not_null`, `default`, etc. + +## Notes + +- YAML format is more human-readable than JSON +- Ideal for manual editing and version control +- Comments are supported in YAML +- Preserves complete schema information +- Can be used for configuration and documentation diff --git a/pkg/writers/bun/README.md b/pkg/writers/bun/README.md new file mode 100644 index 0000000..a30f5cc --- /dev/null +++ b/pkg/writers/bun/README.md @@ -0,0 +1,129 @@ +# Bun Writer + +Generates Go source files with Bun model definitions from database schema information. + +## Overview + +The Bun Writer converts RelSpec's internal database model representation into Go source code with Bun struct definitions, complete with proper tags, relationships, and table configuration. + +## Features + +- Generates Bun-compatible Go structs +- Creates proper `bun` struct tags +- Adds relationship fields +- Supports both single-file and multi-file output +- Maps SQL types to Go types +- Handles nullable fields with sql.Null* types +- Generates table aliases + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/bun" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "models.go", + PackageName: "models", + } + + writer := bun.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate Bun models from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output bun \ + --out-file models.go \ + --package models + +# Convert GORM models to Bun +relspec --input gorm --in-file gorm_models.go --output bun --out-file bun_models.go + +# Multi-file output +relspec --input json --in-file schema.json --output bun --out-file models/ +``` + +## Generated Code Example + +```go +package models + +import ( + "time" + "database/sql" + "github.com/uptrace/bun" +) + +type User struct { + bun.BaseModel `bun:"table:users,alias:u"` + + ID int64 `bun:"id,pk,autoincrement" json:"id"` + Username string `bun:"username,notnull,unique" json:"username"` + Email string `bun:"email,notnull" json:"email"` + Bio sql.NullString `bun:"bio" json:"bio,omitempty"` + CreatedAt time.Time `bun:"created_at,notnull,default:now()" json:"created_at"` + + // Relationships + Posts []*Post `bun:"rel:has-many,join:id=user_id" json:"posts,omitempty"` +} + +type Post struct { + bun.BaseModel `bun:"table:posts,alias:p"` + + ID int64 `bun:"id,pk" json:"id"` + UserID int64 `bun:"user_id,notnull" json:"user_id"` + Title string `bun:"title,notnull" json:"title"` + Content sql.NullString `bun:"content" json:"content,omitempty"` + + // Belongs to + User *User `bun:"rel:belongs-to,join:user_id=id" json:"user,omitempty"` +} +``` + +## Supported Bun Tags + +- `table` - Table name and alias +- `column` - Column name (auto-derived if not specified) +- `pk` - Primary key +- `autoincrement` - Auto-increment +- `notnull` - NOT NULL constraint +- `unique` - Unique constraint +- `default` - Default value +- `rel` - Relationship definition +- `type` - Explicit SQL type + +## Type Mapping + +| SQL Type | Go Type | Nullable Type | +|----------|---------|---------------| +| bigint | int64 | sql.NullInt64 | +| integer | int | sql.NullInt32 | +| varchar, text | string | sql.NullString | +| boolean | bool | sql.NullBool | +| timestamp | time.Time | sql.NullTime | +| numeric | float64 | sql.NullFloat64 | + +## Notes + +- Model names are derived from table names (singularized, PascalCase) +- Table aliases are auto-generated from table names +- Multi-file mode: one file per table named `sql_{schema}_{table}.go` +- Generated code is auto-formatted +- JSON tags are automatically added diff --git a/pkg/writers/dbml/README.md b/pkg/writers/dbml/README.md new file mode 100644 index 0000000..bbad3f5 --- /dev/null +++ b/pkg/writers/dbml/README.md @@ -0,0 +1,161 @@ +# DBML Writer + +Generates Database Markup Language (DBML) files from database schema information. + +## Overview + +The DBML Writer converts RelSpec's internal database model representation into DBML syntax, suitable for use with dbdiagram.io and other DBML-compatible tools. + +## Features + +- Generates DBML syntax +- Creates table definitions with columns +- Defines relationships +- Includes indexes +- Adds notes and documentation +- Supports enums + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/dbml" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.dbml", + } + + writer := dbml.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate DBML from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output dbml \ + --out-file schema.dbml + +# Convert GORM models to DBML +relspec --input gorm --in-file models.go --output dbml --out-file database.dbml + +# Convert JSON to DBML for visualization +relspec --input json --in-file schema.json --output dbml --out-file diagram.dbml +``` + +## Generated DBML Example + +```dbml +Project MyDatabase { + database_type: 'PostgreSQL' +} + +Table users { + id bigserial [pk, increment] + username varchar(50) [not null, unique] + email varchar(100) [not null] + bio text [null] + created_at timestamp [not null, default: `now()`] + + Note: 'Users table' + + indexes { + email [name: 'idx_users_email'] + } +} + +Table posts { + id bigserial [pk, increment] + user_id bigint [not null] + title varchar(200) [not null] + content text [null] + created_at timestamp [default: `now()`] + + indexes { + user_id [name: 'idx_posts_user_id'] + (user_id, created_at) [name: 'idx_posts_user_created'] + } +} + +Ref: posts.user_id > users.id [delete: cascade, update: no action] +``` + +## DBML Features + +### Table Definitions +```dbml +Table table_name { + column_name type [attributes] +} +``` + +### Column Attributes +- `pk` - Primary key +- `increment` - Auto-increment +- `not null` - NOT NULL constraint +- `null` - Nullable (explicit) +- `unique` - Unique constraint +- `default: value` - Default value +- `note: 'text'` - Column note + +### Relationships +```dbml +Ref: table1.column > table2.column +Ref: table1.column < table2.column +Ref: table1.column - table2.column +``` + +Relationship types: +- `>` - Many-to-one +- `<` - One-to-many +- `-` - One-to-one + +Relationship actions: +```dbml +Ref: posts.user_id > users.id [delete: cascade, update: restrict] +``` + +### Indexes +```dbml +indexes { + column_name + (column1, column2) [name: 'idx_name', unique] +} +``` + +## Type Mapping + +| SQL Type | DBML Type | +|----------|-----------| +| bigint | bigint | +| integer | int | +| varchar(n) | varchar(n) | +| text | text | +| boolean | boolean | +| timestamp | timestamp | +| date | date | +| json | json | +| uuid | uuid | + +## Notes + +- DBML is designed for database visualization +- Can be imported into dbdiagram.io +- Human-readable format +- Schema names can be included in table names +- Comments and notes are preserved +- Ideal for documentation and sharing designs diff --git a/pkg/writers/dctx/README.md b/pkg/writers/dctx/README.md new file mode 100644 index 0000000..3a3f671 --- /dev/null +++ b/pkg/writers/dctx/README.md @@ -0,0 +1,111 @@ +# DCTX Writer + +Generates Clarion database dictionary (DCTX) files from database schema information. + +## Overview + +The DCTX Writer converts RelSpec's internal database model representation into Clarion dictionary XML format, used by the Clarion development platform. + +## Features + +- Generates DCTX XML format +- Creates file (table) definitions +- Defines fields (columns) with Clarion types +- Includes keys (indexes) +- Handles relationships + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/dctx" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "database.dctx", + } + + writer := dctx.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate DCTX from PostgreSQL database (for Clarion migration) +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output dctx \ + --out-file app.dctx + +# Convert GORM models to DCTX +relspec --input gorm --in-file models.go --output dctx --out-file legacy.dctx + +# Convert JSON schema to DCTX +relspec --input json --in-file schema.json --output dctx --out-file database.dctx +``` + +## Type Mapping + +Converts standard SQL types to Clarion types: + +| SQL Type | Clarion Type | Notes | +|----------|--------------|-------| +| VARCHAR(n) | STRING(n) | Fixed-length string | +| TEXT | STRING | Variable length | +| INTEGER | LONG | 32-bit integer | +| BIGINT | DECIMAL(20,0) | Large integer | +| SMALLINT | SHORT | 16-bit integer | +| NUMERIC(p,s) | DECIMAL(p,s) | Decimal number | +| REAL, FLOAT | REAL | Floating point | +| BOOLEAN | BYTE | 0/1 value | +| DATE | DATE | Date field | +| TIME | TIME | Time field | +| TIMESTAMP | LONG | Unix timestamp | + +## DCTX Structure + +DCTX files are XML-based with this structure: + +```xml + + + + + + + + + + + + + +``` + +## Features + +- File definitions (equivalent to tables) +- Field definitions with Clarion-specific types +- Key definitions (primary and foreign) +- Relationships between files +- Driver specifications (TOPSPEED, SQL, etc.) + +## Notes + +- DCTX is specific to Clarion development +- Useful for legacy system integration +- Field names are typically uppercase in Clarion +- Supports Clarion-specific attributes +- Can be imported into Clarion IDE diff --git a/pkg/writers/drawdb/README.md b/pkg/writers/drawdb/README.md new file mode 100644 index 0000000..fd2eac7 --- /dev/null +++ b/pkg/writers/drawdb/README.md @@ -0,0 +1,182 @@ +# DrawDB Writer + +Generates DrawDB-compatible JSON files from database schema information. + +## Overview + +The DrawDB Writer converts RelSpec's internal database model representation into JSON format compatible with DrawDB, a free online database design tool. + +## Features + +- Generates DrawDB JSON format +- Creates table and field definitions +- Defines relationships +- Includes visual layout information +- Preserves constraints and indexes + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/drawdb" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "diagram.json", + } + + writer := drawdb.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate DrawDB diagram from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output drawdb \ + --out-file diagram.json + +# Convert GORM models to DrawDB for visualization +relspec --input gorm --in-file models.go --output drawdb --out-file design.json + +# Convert JSON schema to DrawDB +relspec --input json --in-file schema.json --output drawdb --out-file diagram.json +``` + +## Generated JSON Example + +```json +{ + "version": "1.0", + "database": "PostgreSQL", + "tables": [ + { + "id": "1", + "name": "users", + "x": 100, + "y": 100, + "fields": [ + { + "id": "1", + "name": "id", + "type": "BIGINT", + "primary": true, + "autoIncrement": true, + "notNull": true + }, + { + "id": "2", + "name": "username", + "type": "VARCHAR", + "size": 50, + "notNull": true, + "unique": true + }, + { + "id": "3", + "name": "email", + "type": "VARCHAR", + "size": 100, + "notNull": true + } + ], + "indexes": [ + { + "name": "idx_users_email", + "fields": ["email"] + } + ] + }, + { + "id": "2", + "name": "posts", + "x": 400, + "y": 100, + "fields": [ + { + "id": "1", + "name": "id", + "type": "BIGINT", + "primary": true + }, + { + "id": "2", + "name": "user_id", + "type": "BIGINT", + "notNull": true + }, + { + "id": "3", + "name": "title", + "type": "VARCHAR", + "size": 200, + "notNull": true + } + ] + } + ], + "relationships": [ + { + "id": "1", + "source": "2", + "target": "1", + "sourceField": "user_id", + "targetField": "id", + "type": "many-to-one", + "onDelete": "CASCADE" + } + ] +} +``` + +## DrawDB Features + +### Table Properties +- `id` - Unique table identifier +- `name` - Table name +- `x`, `y` - Position in diagram +- `fields` - Array of field definitions +- `indexes` - Array of index definitions + +### Field Properties +- `id` - Unique field identifier +- `name` - Field name +- `type` - Data type (BIGINT, VARCHAR, etc.) +- `size` - Length for string types +- `primary` - Primary key flag +- `notNull` - NOT NULL constraint +- `unique` - Unique constraint +- `autoIncrement` - Auto-increment flag +- `default` - Default value + +### Relationship Properties +- `id` - Unique relationship identifier +- `source` - Source table ID +- `target` - Target table ID +- `sourceField` - Foreign key field +- `targetField` - Referenced field +- `type` - Relationship type (one-to-one, one-to-many, many-to-one) +- `onDelete` - Delete action +- `onUpdate` - Update action + +## Notes + +- DrawDB is available at drawdb.vercel.app +- Generated files can be imported for visual editing +- Visual positions (x, y) are auto-generated +- Ideal for creating ERD diagrams +- Supports modern database features +- Free and open-source tool diff --git a/pkg/writers/drizzle/README.md b/pkg/writers/drizzle/README.md new file mode 100644 index 0000000..a5141e7 --- /dev/null +++ b/pkg/writers/drizzle/README.md @@ -0,0 +1,120 @@ +# Drizzle Writer + +Generates TypeScript/JavaScript files with Drizzle ORM schema definitions from database schema information. + +## Overview + +The Drizzle Writer converts RelSpec's internal database model representation into TypeScript source code with Drizzle ORM schema definitions, including tables, columns, relationships, and constraints. + +## Features + +- Generates Drizzle-compatible TypeScript schema +- Supports PostgreSQL and MySQL schemas +- Creates table definitions with proper column types +- Generates relationship definitions +- Handles constraints and indexes +- Outputs formatted TypeScript code + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/drizzle" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.ts", + Metadata: map[string]interface{}{ + "database_type": "postgresql", // or "mysql" + }, + } + + writer := drizzle.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate Drizzle schema from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output drizzle \ + --out-file schema.ts + +# Convert GORM models to Drizzle +relspec --input gorm --in-file models.go --output drizzle --out-file schema.ts + +# Convert JSON schema to Drizzle +relspec --input json --in-file schema.json --output drizzle --out-file db/schema.ts +``` + +## Generated Code Example + +```typescript +import { pgTable, serial, varchar, text, timestamp, integer } from 'drizzle-orm/pg-core'; +import { relations } from 'drizzle-orm'; + +export const users = pgTable('users', { + id: serial('id').primaryKey(), + username: varchar('username', { length: 50 }).notNull().unique(), + email: varchar('email', { length: 100 }).notNull(), + bio: text('bio'), + createdAt: timestamp('created_at').notNull().defaultNow(), +}); + +export const posts = pgTable('posts', { + id: serial('id').primaryKey(), + userId: integer('user_id').notNull().references(() => users.id, { onDelete: 'cascade' }), + title: varchar('title', { length: 200 }).notNull(), + content: text('content'), +}); + +export const usersRelations = relations(users, ({ many }) => ({ + posts: many(posts), +})); + +export const postsRelations = relations(posts, ({ one }) => ({ + user: one(users, { + fields: [posts.userId], + references: [users.id], + }), +})); +``` + +## Supported Column Types + +### PostgreSQL +- `serial`, `bigserial` - Auto-increment integers +- `integer`, `bigint`, `smallint` - Integer types +- `varchar`, `text` - String types +- `boolean` - Boolean +- `timestamp`, `date`, `time` - Date/time types +- `json`, `jsonb` - JSON types +- `uuid` - UUID type + +### MySQL +- `int`, `bigint`, `smallint` - Integer types +- `varchar`, `text` - String types +- `boolean` - Boolean +- `datetime`, `timestamp` - Date/time types +- `json` - JSON type + +## Notes + +- Table names and column names are preserved as-is +- Relationships are generated as separate relation definitions +- Constraint actions (CASCADE, etc.) are included in references +- Schema names other than 'public' are supported +- Output is formatted TypeScript code diff --git a/pkg/writers/gorm/README.md b/pkg/writers/gorm/README.md new file mode 100644 index 0000000..d73ac86 --- /dev/null +++ b/pkg/writers/gorm/README.md @@ -0,0 +1,176 @@ +# GORM Writer + +Generates Go source files with GORM model definitions from database schema information. + +## Overview + +The GORM Writer converts RelSpec's internal database model representation into Go source code with GORM struct definitions, complete with proper tags, relationships, and methods. + +## Features + +- Generates GORM-compatible Go structs +- Creates proper `gorm` struct tags +- Generates `TableName()` methods +- Adds relationship fields (belongs-to, has-many) +- Supports both single-file and multi-file output +- Auto-generates helper methods (optional) +- Maps SQL types to Go types +- Handles nullable fields with custom sql_types + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/gorm" +) + +func main() { + // Assume db is a *models.Database from a reader + options := &writers.WriterOptions{ + OutputPath: "models.go", + PackageName: "models", + } + + writer := gorm.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate GORM models from PostgreSQL database (single file) +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output gorm \ + --out-file models.go \ + --package models + +# Generate GORM models with multi-file output (one file per table) +relspec --input json \ + --in-file schema.json \ + --output gorm \ + --out-file models/ \ + --package models + +# Convert DBML to GORM models +relspec --input dbml --in-file schema.dbml --output gorm --out-file models.go +``` + +## Output Modes + +### Single File Mode + +Generates all models in one file: + +```bash +relspec --input pgsql --conn "..." --output gorm --out-file models.go +``` + +### Multi-File Mode + +Generates one file per table (auto-detected when output is a directory): + +```bash +relspec --input pgsql --conn "..." --output gorm --out-file models/ +``` + +Files are named: `sql_{schema}_{table}.go` + +## Generated Code Example + +```go +package models + +import ( + "time" + sql_types "git.warky.dev/wdevs/sql_types" +) + +type ModelUser struct { + ID int64 `gorm:"column:id;type:bigint;primaryKey;autoIncrement" json:"id"` + Username string `gorm:"column:username;type:varchar(50);not null;uniqueIndex" json:"username"` + Email string `gorm:"column:email;type:varchar(100);not null" json:"email"` + CreatedAt time.Time `gorm:"column:created_at;type:timestamp;not null;default:now()" json:"created_at"` + + // Relationships + Pos []*ModelPost `gorm:"foreignKey:UserID;references:ID;constraint:OnDelete:CASCADE" json:"pos,omitempty"` +} + +func (ModelUser) TableName() string { + return "public.users" +} + +type ModelPost struct { + ID int64 `gorm:"column:id;type:bigint;primaryKey" json:"id"` + UserID int64 `gorm:"column:user_id;type:bigint;not null" json:"user_id"` + Title string `gorm:"column:title;type:varchar(200);not null" json:"title"` + Content sql_types.SqlString `gorm:"column:content;type:text" json:"content,omitempty"` + + // Belongs to + Use *ModelUser `gorm:"foreignKey:UserID;references:ID" json:"use,omitempty"` +} + +func (ModelPost) TableName() string { + return "public.posts" +} +``` + +## Writer Options + +### Metadata Options + +Configure the writer behavior using metadata in `WriterOptions`: + +```go +options := &writers.WriterOptions{ + OutputPath: "models.go", + PackageName: "models", + Metadata: map[string]interface{}{ + "multi_file": true, // Enable multi-file mode + "populate_refs": true, // Populate RefDatabase/RefSchema + "generate_get_id_str": true, // Generate GetIDStr() methods + }, +} +``` + +## Type Mapping + +| SQL Type | Go Type | Notes | +|----------|---------|-------| +| bigint, int8 | int64 | - | +| integer, int, int4 | int | - | +| smallint, int2 | int16 | - | +| varchar, text | string | Not nullable | +| varchar, text (nullable) | sql_types.SqlString | Nullable | +| boolean, bool | bool | - | +| timestamp, timestamptz | time.Time | - | +| numeric, decimal | float64 | - | +| uuid | string | - | +| json, jsonb | string | - | + +## Relationship Generation + +The writer automatically generates relationship fields: + +- **Belongs-to**: Generated for tables with foreign keys +- **Has-many**: Generated for tables referenced by foreign keys +- Relationship field names use 3-letter prefixes +- Includes proper `gorm` tags with `foreignKey` and `references` + +## Notes + +- Model names are prefixed with "Model" (e.g., `ModelUser`) +- Nullable columns use `sql_types.SqlString`, `sql_types.SqlInt64`, etc. +- Generated code is auto-formatted with `go fmt` +- JSON tags are automatically added +- Supports schema-qualified table names in `TableName()` method diff --git a/pkg/writers/json/README.md b/pkg/writers/json/README.md new file mode 100644 index 0000000..6b15e1f --- /dev/null +++ b/pkg/writers/json/README.md @@ -0,0 +1,277 @@ +# JSON Writer + +Generates database schema definitions in JSON format. + +## Overview + +The JSON Writer converts RelSpec's internal database model representation into JSON format, providing a complete, structured representation of the database schema. + +## Features + +- Generates RelSpec's canonical JSON schema format +- Complete schema representation including: + - Databases and schemas + - Tables, columns, and data types + - Constraints (PK, FK, unique, check) + - Indexes + - Relationships + - Views and sequences +- Pretty-printed, human-readable output +- Suitable for version control +- Ideal interchange format + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/json" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.json", + } + + writer := json.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Export PostgreSQL database to JSON +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output json \ + --out-file schema.json + +# Convert GORM models to JSON +relspec --input gorm --in-file models.go --output json --out-file schema.json + +# Convert DBML to JSON +relspec --input dbml --in-file diagram.dbml --output json --out-file schema.json +``` + +## Generated JSON Example + +```json +{ + "name": "myapp", + "description": "", + "database_type": "postgresql", + "database_version": "", + "source_format": "pgsql", + "schemas": [ + { + "name": "public", + "description": "", + "tables": [ + { + "name": "users", + "schema": "public", + "description": "", + "columns": { + "id": { + "name": "id", + "table": "users", + "schema": "public", + "type": "bigint", + "length": 0, + "precision": 0, + "scale": 0, + "not_null": true, + "is_primary_key": true, + "auto_increment": true, + "default": "", + "sequence": 1 + }, + "username": { + "name": "username", + "table": "users", + "schema": "public", + "type": "varchar", + "length": 50, + "not_null": true, + "is_primary_key": false, + "auto_increment": false, + "sequence": 2 + }, + "email": { + "name": "email", + "table": "users", + "schema": "public", + "type": "varchar", + "length": 100, + "not_null": true, + "sequence": 3 + } + }, + "constraints": { + "pk_users": { + "name": "pk_users", + "type": "PRIMARY KEY", + "table": "users", + "schema": "public", + "columns": ["id"] + }, + "uq_users_username": { + "name": "uq_users_username", + "type": "UNIQUE", + "table": "users", + "schema": "public", + "columns": ["username"] + } + }, + "indexes": { + "idx_users_email": { + "name": "idx_users_email", + "table": "users", + "schema": "public", + "columns": ["email"], + "unique": false, + "type": "btree" + } + }, + "relationships": {} + }, + { + "name": "posts", + "schema": "public", + "columns": { + "id": { + "name": "id", + "type": "bigint", + "not_null": true, + "is_primary_key": true, + "sequence": 1 + }, + "user_id": { + "name": "user_id", + "type": "bigint", + "not_null": true, + "sequence": 2 + }, + "title": { + "name": "title", + "type": "varchar", + "length": 200, + "not_null": true, + "sequence": 3 + }, + "content": { + "name": "content", + "type": "text", + "not_null": false, + "sequence": 4 + } + }, + "constraints": { + "fk_posts_user_id": { + "name": "fk_posts_user_id", + "type": "FOREIGN KEY", + "table": "posts", + "schema": "public", + "columns": ["user_id"], + "referenced_table": "users", + "referenced_schema": "public", + "referenced_columns": ["id"], + "on_delete": "CASCADE", + "on_update": "NO ACTION" + } + }, + "indexes": { + "idx_posts_user_id": { + "name": "idx_posts_user_id", + "columns": ["user_id"], + "unique": false, + "type": "btree" + } + } + } + ], + "views": [], + "sequences": [] + } + ] +} +``` + +## Schema Structure + +The JSON format includes: + +### Database Level +- `name` - Database name +- `description` - Database description +- `database_type` - Database system type +- `database_version` - Version information +- `source_format` - Original source format +- `schemas` - Array of schema objects + +### Schema Level +- `name` - Schema name +- `description` - Schema description +- `tables` - Array of table objects +- `views` - Array of view objects +- `sequences` - Array of sequence objects + +### Table Level +- `name` - Table name +- `schema` - Schema name +- `description` - Table description +- `columns` - Map of column objects +- `constraints` - Map of constraint objects +- `indexes` - Map of index objects +- `relationships` - Map of relationship objects + +### Column Level +- `name` - Column name +- `type` - Data type +- `length` - Type length +- `precision`, `scale` - Numeric precision +- `not_null` - NOT NULL flag +- `is_primary_key` - Primary key flag +- `auto_increment` - Auto-increment flag +- `default` - Default value +- `sequence` - Column order + +### Constraint Level +- `name` - Constraint name +- `type` - Constraint type (PRIMARY KEY, FOREIGN KEY, UNIQUE, CHECK) +- `columns` - Constrained columns +- `referenced_table`, `referenced_schema` - FK references +- `referenced_columns` - Referenced columns +- `on_delete`, `on_update` - FK actions + +### Index Level +- `name` - Index name +- `columns` - Indexed columns +- `unique` - Unique flag +- `type` - Index type + +## Use Cases + +- **Version Control** - Track schema changes in git +- **Documentation** - Human-readable schema documentation +- **Interchange** - Standard format for tool integration +- **Backup** - Schema backup without database access +- **Testing** - Test data for schema validation +- **API** - Schema information for APIs + +## Notes + +- Output is pretty-printed with 2-space indentation +- Preserves all schema metadata +- Can be round-tripped (read and write) without loss +- Schema-agnostic format +- Ideal for automation and tooling diff --git a/pkg/writers/pgsql/README.md b/pkg/writers/pgsql/README.md new file mode 100644 index 0000000..d4d1334 --- /dev/null +++ b/pkg/writers/pgsql/README.md @@ -0,0 +1,195 @@ +# PostgreSQL Writer + +Generates PostgreSQL DDL (Data Definition Language) SQL scripts from database schema information. + +## Overview + +The PostgreSQL Writer converts RelSpec's internal database model representation into PostgreSQL-compatible SQL DDL scripts, including CREATE TABLE statements, constraints, indexes, views, and sequences. + +## Features + +- Generates complete PostgreSQL DDL +- Creates schemas, tables, columns +- Defines constraints (PK, FK, unique, check) +- Creates indexes +- Generates views and sequences +- Supports migration scripts +- Includes audit triggers (optional) +- Handles PostgreSQL-specific data types + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/pgsql" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.sql", + } + + writer := pgsql.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate PostgreSQL DDL from JSON schema +relspec --input json \ + --in-file schema.json \ + --output pgsql \ + --out-file schema.sql + +# Convert GORM models to PostgreSQL DDL +relspec --input gorm \ + --in-file models.go \ + --output pgsql \ + --out-file create_tables.sql + +# Export live database schema to SQL +relspec --input pgsql \ + --conn "postgres://localhost/source_db" \ + --output pgsql \ + --out-file backup_schema.sql +``` + +## Generated SQL Example + +```sql +-- Schema: public + +CREATE SCHEMA IF NOT EXISTS public; + +-- Table: public.users + +CREATE TABLE IF NOT EXISTS public.users ( + id BIGSERIAL PRIMARY KEY, + username VARCHAR(50) NOT NULL, + email VARCHAR(100) NOT NULL, + bio TEXT, + created_at TIMESTAMP NOT NULL DEFAULT NOW() +); + +-- Constraints for public.users + +ALTER TABLE public.users + ADD CONSTRAINT uq_users_username UNIQUE (username); + +-- Indexes for public.users + +CREATE INDEX idx_users_email ON public.users (email); + +-- Table: public.posts + +CREATE TABLE IF NOT EXISTS public.posts ( + id BIGSERIAL PRIMARY KEY, + user_id BIGINT NOT NULL, + title VARCHAR(200) NOT NULL, + content TEXT, + created_at TIMESTAMP DEFAULT NOW() +); + +-- Foreign Keys for public.posts + +ALTER TABLE public.posts + ADD CONSTRAINT fk_posts_user_id + FOREIGN KEY (user_id) + REFERENCES public.users (id) + ON DELETE CASCADE + ON UPDATE NO ACTION; + +-- Indexes for public.posts + +CREATE INDEX idx_posts_user_id ON public.posts (user_id); +``` + +## Writer Options + +### Metadata Options + +```go +options := &writers.WriterOptions{ + OutputPath: "schema.sql", + Metadata: map[string]interface{}{ + "include_drop": true, // Include DROP statements + "include_audit": true, // Include audit triggers + "if_not_exists": true, // Use IF NOT EXISTS + "migration_mode": false, // Generate migration script + }, +} +``` + +## Features + +### Full DDL Generation + +Generates complete database structure: +- CREATE SCHEMA statements +- CREATE TABLE with all columns and types +- PRIMARY KEY constraints +- FOREIGN KEY constraints with actions +- UNIQUE constraints +- CHECK constraints +- CREATE INDEX statements +- CREATE VIEW statements +- CREATE SEQUENCE statements + +### Migration Mode + +When `migration_mode` is enabled, generates migration scripts with: +- Version tracking +- Up/down migrations +- Transactional DDL +- Rollback support + +### Audit Triggers + +When `include_audit` is enabled, adds: +- Created/updated timestamp triggers +- Audit logging functionality +- Change tracking + +## PostgreSQL-Specific Features + +- Serial types (SERIAL, BIGSERIAL) +- Advanced types (UUID, JSONB, ARRAY) +- Schema-qualified names +- Constraint actions (CASCADE, RESTRICT, SET NULL) +- Partial indexes +- Function-based indexes +- Check constraints with expressions + +## Data Types + +Supports all PostgreSQL data types: +- Integer types: SMALLINT, INTEGER, BIGINT, SERIAL, BIGSERIAL +- Numeric types: NUMERIC, DECIMAL, REAL, DOUBLE PRECISION +- String types: VARCHAR, CHAR, TEXT +- Date/Time: DATE, TIME, TIMESTAMP, TIMESTAMPTZ, INTERVAL +- Boolean: BOOLEAN +- Binary: BYTEA +- JSON: JSON, JSONB +- UUID: UUID +- Network: INET, CIDR, MACADDR +- Special: ARRAY, HSTORE + +## Notes + +- Generated SQL is formatted and readable +- Comments are preserved from source schema +- Schema names are fully qualified +- Default values are properly quoted +- Constraint names follow PostgreSQL conventions +- Compatible with PostgreSQL 12+ diff --git a/pkg/writers/prisma/README.md b/pkg/writers/prisma/README.md new file mode 100644 index 0000000..9b244ec --- /dev/null +++ b/pkg/writers/prisma/README.md @@ -0,0 +1,135 @@ +# Prisma Writer + +Generates Prisma schema files from database schema information. + +## Overview + +The Prisma Writer converts RelSpec's internal database model representation into Prisma schema language (`.prisma` files), complete with models, fields, relationships, and attributes. + +## Features + +- Generates Prisma schema syntax +- Creates model definitions with proper field types +- Adds Prisma attributes (@id, @unique, @default, etc.) +- Generates relationship fields +- Includes datasource and generator configurations +- Maps table/column names with @map and @@map + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/prisma" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.prisma", + Metadata: map[string]interface{}{ + "datasource_provider": "postgresql", + }, + } + + writer := prisma.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate Prisma schema from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output prisma \ + --out-file schema.prisma + +# Convert GORM models to Prisma +relspec --input gorm --in-file models.go --output prisma --out-file schema.prisma + +# Convert JSON to Prisma schema +relspec --input json --in-file database.json --output prisma --out-file prisma/schema.prisma +``` + +## Generated Code Example + +```prisma +datasource db { + provider = "postgresql" + url = env("DATABASE_URL") +} + +generator client { + provider = "prisma-client-js" +} + +model User { + id Int @id @default(autoincrement()) + username String @unique @db.VarChar(50) + email String @db.VarChar(100) + bio String? @db.Text + createdAt DateTime @default(now()) @map("created_at") + + posts Post[] + + @@map("users") +} + +model Post { + id Int @id @default(autoincrement()) + userId Int @map("user_id") + title String @db.VarChar(200) + content String? @db.Text + + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@map("posts") +} +``` + +## Supported Prisma Attributes + +### Field Attributes +- `@id` - Primary key +- `@unique` - Unique constraint +- `@default()` - Default value +- `@map()` - Column name mapping +- `@db.*` - Database-specific types +- `@relation()` - Relationship definition + +### Model Attributes +- `@@map()` - Table name mapping +- `@@unique()` - Composite unique constraints +- `@@index()` - Index definitions +- `@@id()` - Composite primary keys + +## Type Mapping + +| SQL Type | Prisma Type | Database Type | +|----------|-------------|---------------| +| bigint | Int | @db.BigInt | +| integer | Int | - | +| varchar(n) | String | @db.VarChar(n) | +| text | String | @db.Text | +| boolean | Boolean | - | +| timestamp | DateTime | @db.Timestamp | +| uuid | String | @db.Uuid | +| json | Json | - | + +## Notes + +- Model names are PascalCase (e.g., `User`, `Post`) +- Field names are camelCase with `@map` for snake_case columns +- Table names use `@@map` when different from model name +- Nullable fields are marked with `?` +- Relationship fields are automatically generated +- Datasource provider defaults to `postgresql` diff --git a/pkg/writers/typeorm/README.md b/pkg/writers/typeorm/README.md new file mode 100644 index 0000000..e61e47b --- /dev/null +++ b/pkg/writers/typeorm/README.md @@ -0,0 +1,169 @@ +# TypeORM Writer + +Generates TypeScript files with TypeORM entity definitions from database schema information. + +## Overview + +The TypeORM Writer converts RelSpec's internal database model representation into TypeScript source code with TypeORM entity classes, including proper decorators, relationships, and column configurations. + +## Features + +- Generates TypeORM-compatible TypeScript entities +- Creates proper decorator usage (@Entity, @Column, etc.) +- Adds relationship decorators (@OneToMany, @ManyToOne, @JoinColumn) +- Handles column types and options +- Supports constraints and indexes +- Outputs formatted TypeScript code + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/typeorm" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "entities/", + } + + writer := typeorm.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Generate TypeORM entities from PostgreSQL database +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output typeorm \ + --out-file entities/ + +# Convert GORM models to TypeORM +relspec --input gorm --in-file models.go --output typeorm --out-file src/entities/ + +# Convert JSON to TypeORM entities +relspec --input json --in-file schema.json --output typeorm --out-file entities/ +``` + +## Generated Code Example + +```typescript +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + OneToMany, + ManyToOne, + JoinColumn, + Index, +} from 'typeorm'; +import { Post } from './Post'; + +@Entity('users') +export class User { + @PrimaryGeneratedColumn('increment') + id: number; + + @Column({ type: 'varchar', length: 50, unique: true }) + @Index() + username: string; + + @Column({ type: 'varchar', length: 100 }) + email: string; + + @Column({ type: 'text', nullable: true }) + bio: string | null; + + @CreateDateColumn({ name: 'created_at' }) + createdAt: Date; + + @OneToMany(() => Post, (post) => post.user) + posts: Post[]; +} + +@Entity('posts') +export class Post { + @PrimaryGeneratedColumn('increment') + id: number; + + @Column({ name: 'user_id' }) + userId: number; + + @Column({ type: 'varchar', length: 200 }) + title: string; + + @Column({ type: 'text', nullable: true }) + content: string | null; + + @ManyToOne(() => User, (user) => user.posts, { onDelete: 'CASCADE' }) + @JoinColumn({ name: 'user_id' }) + user: User; +} +``` + +## Supported TypeORM Decorators + +### Entity Decorators +- `@Entity()` - Define entity/table +- `@PrimaryGeneratedColumn()` - Auto-increment primary key +- `@PrimaryColumn()` - Primary key +- `@Column()` - Column definition +- `@CreateDateColumn()` - Auto-set creation timestamp +- `@UpdateDateColumn()` - Auto-update timestamp + +### Relationship Decorators +- `@OneToMany()` - One-to-many relationship +- `@ManyToOne()` - Many-to-one relationship +- `@JoinColumn()` - Foreign key column specification + +### Constraint Decorators +- `@Index()` - Create index +- `@Unique()` - Unique constraint + +## Column Options + +```typescript +@Column({ + type: 'varchar', // Column type + length: 255, // Length for varchar/char + nullable: true, // Allow NULL + unique: true, // Unique constraint + default: 'value', // Default value + name: 'column_name', // Database column name +}) +``` + +## Type Mapping + +| SQL Type | TypeScript Type | TypeORM Type | +|----------|-----------------|--------------| +| bigint | number | 'bigint' | +| integer | number | 'int' | +| varchar | string | 'varchar' | +| text | string | 'text' | +| boolean | boolean | 'boolean' | +| timestamp | Date | 'timestamp' | +| json | object | 'json' | +| uuid | string | 'uuid' | + +## Notes + +- Entity class names are PascalCase +- One file per entity (named after the entity) +- Relationship imports are auto-generated +- Nullable columns use TypeScript union with `null` +- Foreign key actions (CASCADE, etc.) are included +- Schema names can be specified in `@Entity()` decorator diff --git a/pkg/writers/yaml/README.md b/pkg/writers/yaml/README.md new file mode 100644 index 0000000..4deb732 --- /dev/null +++ b/pkg/writers/yaml/README.md @@ -0,0 +1,212 @@ +# YAML Writer + +Generates database schema definitions in YAML format. + +## Overview + +The YAML Writer converts RelSpec's internal database model representation into YAML format, providing a human-readable, structured representation of the database schema. + +## Features + +- Generates RelSpec's canonical YAML schema format +- Human-readable alternative to JSON +- Complete schema representation including: + - Databases and schemas + - Tables, columns, and data types + - Constraints (PK, FK, unique, check) + - Indexes + - Relationships + - Views and sequences +- Supports comments +- Ideal for manual editing and configuration + +## Usage + +### Basic Example + +```go +package main + +import ( + "git.warky.dev/wdevs/relspecgo/pkg/models" + "git.warky.dev/wdevs/relspecgo/pkg/writers" + "git.warky.dev/wdevs/relspecgo/pkg/writers/yaml" +) + +func main() { + options := &writers.WriterOptions{ + OutputPath: "schema.yaml", + } + + writer := yaml.NewWriter(options) + err := writer.WriteDatabase(db) + if err != nil { + panic(err) + } +} +``` + +### CLI Examples + +```bash +# Export PostgreSQL database to YAML +relspec --input pgsql \ + --conn "postgres://localhost/mydb" \ + --output yaml \ + --out-file schema.yaml + +# Convert GORM models to YAML +relspec --input gorm --in-file models.go --output yaml --out-file schema.yaml + +# Convert JSON to YAML +relspec --input json --in-file schema.json --output yaml --out-file schema.yaml +``` + +## Generated YAML Example + +```yaml +name: myapp +database_type: postgresql +source_format: pgsql +schemas: + - name: public + tables: + - name: users + schema: public + columns: + id: + name: id + table: users + schema: public + type: bigint + not_null: true + is_primary_key: true + auto_increment: true + sequence: 1 + username: + name: username + table: users + schema: public + type: varchar + length: 50 + not_null: true + sequence: 2 + email: + name: email + table: users + schema: public + type: varchar + length: 100 + not_null: true + sequence: 3 + constraints: + pk_users: + name: pk_users + type: PRIMARY KEY + table: users + schema: public + columns: + - id + uq_users_username: + name: uq_users_username + type: UNIQUE + table: users + schema: public + columns: + - username + indexes: + idx_users_email: + name: idx_users_email + table: users + schema: public + columns: + - email + unique: false + type: btree + + - name: posts + schema: public + columns: + id: + name: id + type: bigint + not_null: true + is_primary_key: true + sequence: 1 + user_id: + name: user_id + type: bigint + not_null: true + sequence: 2 + title: + name: title + type: varchar + length: 200 + not_null: true + sequence: 3 + content: + name: content + type: text + not_null: false + sequence: 4 + constraints: + fk_posts_user_id: + name: fk_posts_user_id + type: FOREIGN KEY + table: posts + schema: public + columns: + - user_id + referenced_table: users + referenced_schema: public + referenced_columns: + - id + on_delete: CASCADE + on_update: NO ACTION + indexes: + idx_posts_user_id: + name: idx_posts_user_id + columns: + - user_id + unique: false + type: btree + views: [] + sequences: [] +``` + +## Schema Structure + +The YAML format mirrors the JSON structure with human-readable syntax: + +- Database level: `name`, `database_type`, `source_format`, `schemas` +- Schema level: `name`, `tables`, `views`, `sequences` +- Table level: `name`, `schema`, `columns`, `constraints`, `indexes` +- Column level: `name`, `type`, `length`, `not_null`, etc. +- Constraint level: `name`, `type`, `columns`, foreign key details +- Index level: `name`, `columns`, `unique`, `type` + +## Advantages Over JSON + +- More human-readable +- Easier to edit manually +- Supports comments +- Less verbose (no braces/brackets) +- Better for configuration files +- Natural indentation + +## Use Cases + +- **Configuration** - Schema as configuration +- **Documentation** - Human-readable schema docs +- **Version Control** - Easier to read diffs +- **Manual Editing** - Easier to modify by hand +- **Code Generation** - Template-friendly format + +## Notes + +- Output is properly indented (2 spaces) +- Preserves all schema metadata +- Can be round-tripped with YAML reader +- Compatible with YAML 1.2 +- More readable than JSON for large schemas +- Ideal for documentation and manual workflows