Updated Readme files
This commit is contained in:
54
README.md
54
README.md
@@ -16,19 +16,47 @@ RelSpec provides bidirectional conversion and comparison between various databas
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
### Input Formats
|
### Readers (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
|
|
||||||
|
|
||||||
### Output Formats
|
RelSpec can read database schemas from multiple sources:
|
||||||
- **GORM Models** - Generate GORM-compatible Go structs
|
|
||||||
- **Bun Models** - Generate Bun-compatible Go structs
|
#### ORM Models
|
||||||
- **JSON** - Standard JSON schema output
|
- [GORM](pkg/readers/gorm/README.md) - Go GORM model definitions
|
||||||
- **YAML** - Human-readable YAML format
|
- [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
|
## Use of AI
|
||||||
@@ -98,7 +126,7 @@ go test ./...
|
|||||||
|
|
||||||
Apache License 2.0 - See [LICENSE](LICENSE) for details.
|
Apache License 2.0 - See [LICENSE](LICENSE) for details.
|
||||||
|
|
||||||
Copyright 2025 wdevs
|
Copyright 2025 Warky Devs
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
|||||||
106
pkg/readers/bun/README.md
Normal file
106
pkg/readers/bun/README.md
Normal file
@@ -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
|
||||||
101
pkg/readers/dbml/README.md
Normal file
101
pkg/readers/dbml/README.md
Normal file
@@ -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
|
||||||
96
pkg/readers/dctx/README.md
Normal file
96
pkg/readers/dctx/README.md
Normal file
@@ -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
|
||||||
96
pkg/readers/drawdb/README.md
Normal file
96
pkg/readers/drawdb/README.md
Normal file
@@ -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`
|
||||||
90
pkg/readers/drizzle/README.md
Normal file
90
pkg/readers/drizzle/README.md
Normal file
@@ -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
|
||||||
141
pkg/readers/gorm/README.md
Normal file
141
pkg/readers/gorm/README.md
Normal file
@@ -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
|
||||||
152
pkg/readers/json/README.md
Normal file
152
pkg/readers/json/README.md
Normal file
@@ -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
|
||||||
138
pkg/readers/pgsql/README.md
Normal file
138
pkg/readers/pgsql/README.md
Normal file
@@ -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
|
||||||
103
pkg/readers/prisma/README.md
Normal file
103
pkg/readers/prisma/README.md
Normal file
@@ -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
|
||||||
122
pkg/readers/typeorm/README.md
Normal file
122
pkg/readers/typeorm/README.md
Normal file
@@ -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
|
||||||
159
pkg/readers/yaml/README.md
Normal file
159
pkg/readers/yaml/README.md
Normal file
@@ -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
|
||||||
129
pkg/writers/bun/README.md
Normal file
129
pkg/writers/bun/README.md
Normal file
@@ -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
|
||||||
161
pkg/writers/dbml/README.md
Normal file
161
pkg/writers/dbml/README.md
Normal file
@@ -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
|
||||||
111
pkg/writers/dctx/README.md
Normal file
111
pkg/writers/dctx/README.md
Normal file
@@ -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
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<dictionary>
|
||||||
|
<file name="USERS" driver="TOPSPEED">
|
||||||
|
<record>
|
||||||
|
<field name="ID" type="LONG" />
|
||||||
|
<field name="USERNAME" type="STRING" bytes="50" />
|
||||||
|
<field name="EMAIL" type="STRING" bytes="100" />
|
||||||
|
</record>
|
||||||
|
<key name="KEY_PRIMARY" primary="true">
|
||||||
|
<field name="ID" />
|
||||||
|
</key>
|
||||||
|
</file>
|
||||||
|
</dictionary>
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
182
pkg/writers/drawdb/README.md
Normal file
182
pkg/writers/drawdb/README.md
Normal file
@@ -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
|
||||||
120
pkg/writers/drizzle/README.md
Normal file
120
pkg/writers/drizzle/README.md
Normal file
@@ -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
|
||||||
176
pkg/writers/gorm/README.md
Normal file
176
pkg/writers/gorm/README.md
Normal file
@@ -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
|
||||||
277
pkg/writers/json/README.md
Normal file
277
pkg/writers/json/README.md
Normal file
@@ -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
|
||||||
195
pkg/writers/pgsql/README.md
Normal file
195
pkg/writers/pgsql/README.md
Normal file
@@ -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+
|
||||||
135
pkg/writers/prisma/README.md
Normal file
135
pkg/writers/prisma/README.md
Normal file
@@ -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`
|
||||||
169
pkg/writers/typeorm/README.md
Normal file
169
pkg/writers/typeorm/README.md
Normal file
@@ -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
|
||||||
212
pkg/writers/yaml/README.md
Normal file
212
pkg/writers/yaml/README.md
Normal file
@@ -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
|
||||||
Reference in New Issue
Block a user