# relspecgo - DBML to BUN Model Generator

## Overview

relspecgo is a code generator that converts DBML (Database Markup Language) schema files into BUN ORM models for Go. It automates the creation of model structs with proper BUN tags, relationships, and indexes.

Repository: https://git.warky.dev/wdevs/relspecgo

## Installation

```bash
go install git.warky.dev/wdevs/relspecgo@latest
```

Or via Makefile:
```bash
make install-relspecgo
```

## Usage

### Basic Command

```bash
relspecgo generate --input=sql/schema.dbml --output=pkg/models --orm=bun
```

### Via Makefile

```bash
make generate-models
```

This will:
1. Read `sql/schema.dbml`
2. Generate BUN models in `pkg/models/`
3. Create proper Go structs with BUN tags

## DBML Schema Format

### Table Definition

```dbml
Table users {
  id varchar(36) [primary key]
  username varchar(255) [unique, not null]
  email varchar(255) [unique, not null]
  password varchar(255) [not null]
  role varchar(50) [not null, default: 'user']
  active boolean [not null, default: true]
  created_at timestamp [not null, default: `now()`]
  updated_at timestamp [not null, default: `now()`]
  deleted_at timestamp [null]
  
  indexes {
    (deleted_at) [name: 'idx_users_deleted_at']
  }
}
```

### Relationships

```dbml
Table api_keys {
  id varchar(36) [primary key]
  user_id varchar(36) [not null, ref: > users.id]
  ...
}

// Explicit relationship with cascade delete
Ref: api_keys.user_id > users.id [delete: cascade]
```

### Supported Field Types

- `varchar(n)` → `string`
- `text` → `string`
- `int`, `integer` → `int`
- `bigint` → `int64`
- `boolean`, `bool` → `bool`
- `timestamp`, `datetime` → `time.Time`
- `json`, `jsonb` → `json.RawMessage` or custom type

### Field Attributes

- `[primary key]` → BUN primary key tag
- `[not null]` → Required field
- `[unique]` → Unique constraint
- `[default: value]` → Default value
- `[note: 'text']` → Documentation comment
- `[ref: > table.column]` → Foreign key relationship

## Generated BUN Models

### Example Output

```go
package models

import (
    "time"
    "github.com/uptrace/bun"
)

type User struct {
    bun.BaseModel `bun:"table:users,alias:u"`
    
    ID        string    `bun:"id,pk,type:varchar(36)" json:"id"`
    Username  string    `bun:"username,unique,notnull,type:varchar(255)" json:"username"`
    Email     string    `bun:"email,unique,notnull,type:varchar(255)" json:"email"`
    Password  string    `bun:"password,notnull,type:varchar(255)" json:"-"`
    FullName  string    `bun:"full_name,type:varchar(255)" json:"full_name,omitempty"`
    Role      string    `bun:"role,notnull,default:'user',type:varchar(50)" json:"role"`
    Active    bool      `bun:"active,notnull,default:true" json:"active"`
    CreatedAt time.Time `bun:"created_at,notnull,default:now()" json:"created_at"`
    UpdatedAt time.Time `bun:"updated_at,notnull,default:now()" json:"updated_at"`
    DeletedAt time.Time `bun:"deleted_at,soft_delete" json:"deleted_at,omitempty"`
    
    // Relationships
    APIKeys          []*APIKey          `bun:"rel:has-many,join:id=user_id" json:"api_keys,omitempty"`
    Hooks            []*Hook            `bun:"rel:has-many,join:id=user_id" json:"hooks,omitempty"`
    WhatsAppAccounts []*WhatsAppAccount `bun:"rel:has-many,join:id=user_id" json:"whatsapp_accounts,omitempty"`
}
```

### BUN Tags

- `bun:"table:users,alias:u"` - Table name and alias
- `bun:"id,pk"` - Primary key
- `bun:"username,unique"` - Unique constraint
- `bun:"password,notnull"` - NOT NULL constraint
- `bun:"role,default:'user'"` - Default value
- `bun:"type:varchar(255)"` - Explicit column type
- `bun:"deleted_at,soft_delete"` - Soft delete support
- `bun:"rel:has-many,join:id=user_id"` - Has-many relationship

## Project Structure

```
sql/
├── schema.dbml          # Main schema definition
├── postgres/            # PostgreSQL specific migrations
│   ├── 20240101_init.up.sql
│   └── 20240101_init.down.sql
└── sqlite/              # SQLite specific migrations
    ├── 20240101_init.up.sql
    └── 20240101_init.down.sql

pkg/
└── models/              # Generated BUN models
    ├── user.go
    ├── api_key.go
    ├── hook.go
    └── ...
```

## Workflow

### 1. Define Schema

Create or update `sql/schema.dbml`:

```dbml
Table products {
  id int [primary key, increment]
  name varchar(255) [not null]
  price decimal(10,2) [not null]
  created_at timestamp [not null, default: `now()`]
}
```

### 2. Generate Models

```bash
make generate-models
```

### 3. Create Migrations

```bash
make migrate-create NAME=add_products_table
```

Edit generated migration files in `sql/postgres/` and `sql/sqlite/`

### 4. Run Migrations

```bash
make migrate-up
```

### 5. Use in Code

```go
import "git.warky.dev/wdevs/whatshooked/pkg/models"

// Query with BUN
var users []models.User
err := db.NewSelect().
    Model(&users).
    Relation("APIKeys").
    Where("active = ?", true).
    Scan(ctx)
```

## Best Practices

1. **Single Source of Truth**: Keep DBML as the source of truth for schema
2. **Regenerate After Changes**: Always run `make generate-models` after DBML changes
3. **Don't Edit Generated Files**: Modify DBML instead, then regenerate
4. **Version Control**: Commit both DBML and generated models
5. **Migrations**: Create migrations for schema changes
6. **Relationships**: Define relationships in DBML for proper code generation
7. **Indexes**: Specify indexes in DBML for performance

## Common Commands

```bash
# Generate models from DBML
make generate-models

# Create new migration
make migrate-create NAME=add_users_table

# Run migrations
make migrate-up

# Rollback migrations
make migrate-down

# Install relspecgo
make install-relspecgo
```

## DBML to SQL Conversion

relspecgo can also generate SQL from DBML:

```bash
relspecgo sql --input=sql/schema.dbml --output=sql/postgres/schema.sql --dialect=postgres
relspecgo sql --input=sql/schema.dbml --output=sql/sqlite/schema.sql --dialect=sqlite
```

## Advantages

1. **Type Safety**: Generated Go structs are type-safe
2. **Consistency**: Same schema definition for all models
3. **Documentation**: DBML serves as schema documentation
4. **Validation**: Catches schema errors before runtime
5. **IDE Support**: Full IDE autocomplete and type checking
6. **Relationships**: Automatic relationship setup
7. **Migration Friendly**: Easy to track schema changes

## Integration with ResolveSpec

Generated BUN models work seamlessly with ResolveSpec:

```go
import (
    "github.com/bitechdev/ResolveSpec/pkg/restheadspec"
    "git.warky.dev/wdevs/whatshooked/pkg/models"
)

// Create handler with BUN
handler := restheadspec.NewHandlerWithBun(db)

// Models are automatically discovered from BUN's table names
```

## Troubleshooting

### Models Not Generated

- Check DBML syntax
- Ensure relspecgo is installed: `make install-relspecgo`
- Verify input/output paths

### Compilation Errors

- Run `go mod tidy` to update dependencies
- Check for missing imports
- Verify BUN version compatibility

### Relationship Issues

- Ensure foreign keys are properly defined in DBML
- Check `Ref:` declarations
- Verify join conditions

## References

- relspecgo: https://git.warky.dev/wdevs/relspecgo
- DBML Syntax: https://dbml.dbdiagram.io/docs/
- BUN ORM: https://bun.uptrace.dev/
- ResolveSpec: https://github.com/bitechdev/ResolveSpec
