# gormcol

Type-safe GORM column descriptors and model generation utilities.

## Library

The library provides [Field](#field) for type-safe column references and helper functions to extract column/table names.

### Field

`Field` represents a GORM column descriptor with table context. Define package-level variables to get type-safe column references:

```go
var PsAccess = struct {
    IDProfile           gormcol.Field
    IDAuthorizationRole gormcol.Field
}{
    IDProfile:           gormcol.Field{Table: "ps_access", Column: "id_profile"},
    IDAuthorizationRole: gormcol.Field{Table: "ps_access", Column: "id_authorization_role"},
}
```

### Helper Functions

#### Column

Returns just the column name from a Field descriptor.

```go
gormcol.Column(dbmodel.PsAccess.IDAuthorizationRole) // "id_authorization_role"
```

#### ColumnOnTable

Returns "table.column" format from a Field descriptor.

```go
gormcol.ColumnOnTable(dbmodel.PsAccess.IDAuthorizationRole) // "ps_access.id_authorization_role"
```

#### TableField

Returns the table name from a Field descriptor.

```go
gormcol.TableField(dbmodel.PsAccess.IDAuthorizationRole) // "ps_access"
```

## CLI

The `cmd/` directory contains a standalone tool that generates GORM model files with column descriptors.

### Install

```bash
go install git.ma-al.com/goc_marek/gormcol/cmd/gormcol@latest
```

Or from source:

```bash
go install ./cmd/gormcol
```

### Prerequisites

- [fzf](https://github.com/junegunn/fzf) - required for interactive mode (optional for `--all`)

### Usage

```
gormcol [options]
```

DSN can be provided via `--dsn` flag or `DSN` env var (from `.env` file).

**Modes:**
- **Interactive (default)**: select tables with fzf
- **Batch (`--filter` or `--all`)**: generate matching tables with confirmation

| Flag     | Default                | Description                                      |
|----------|------------------------|--------------------------------------------------|
| `--dsn`  | *(from DSN env)*       | MySQL/MariaDB DSN, e.g. `user:pass@tcp(localhost:3306)/dbname` |
| `--filter` | *(interactive)*       | Regex matching table names to generate (triggers batch mode) |
| `--all`  | *(interactive)*       | Generate all tables matching filter (shows confirmation) |
| `--out`  | `./app/model/dbmodel` | Output directory for generated files            |
| `--pkg`  | `dbmodel`              | Go package name for generated files              |

### Interactive Mode (Default)

Without flags, the tool launches an interactive table selector:

```bash
gormcol --dsn "user:pass@tcp(localhost:3306)/mydb"
```

Features:
- **Fuzzy search** as you type
- **Tab** - toggle table selection (multi-select)
- **Enter** - confirm selection
- **Esc** - cancel

### Batch Mode (--filter)

Use `--filter` to generate all tables matching a regex pattern:

```bash
gormcol --dsn "user:pass@tcp(localhost:3306)/mydb" --filter "ps_product.*"
```

### Generate All Tables (--all)

Use `--all` to generate all tables matching the default filter `(ps_|b2b_).*`:

```bash
gormcol --dsn "user:pass@tcp(localhost:3306)/mydb" --all
```

A confirmation prompt appears:
```
WARNING: Generate all 325 tables? [Enter] confirm / [Esc] cancel
```

- **Enter** - confirm and generate
- **Esc** - cancel

### Example

```bash
./gormcol --dsn "user:pass@tcp(localhost:3306)/mydb" --filter "ps_.*" --out ./internal/model --pkg model
```

This connects to the database, generates a `.go` model file for each matching table, and appends `<Model>Cols` variables with typed `gormcol.Field` descriptors to each file.

### Configuration File (.env)

Create a `.env` file in your project root for default values:

```env
# Database connection
DSN=user:pass@tcp(localhost:3306)/mydb

# Table filter (regex)
FILTER=(ps_|b2b_).*

# Output settings
OUT=./app/model/dbmodel
PKG=dbmodel
```

Command-line flags override `.env` values.

## Library Functions Reference

### ConnectDSN

Opens a MySQL/MariaDB connection from a DSN string.

```go
db, err := gormcol.ConnectDSN("user:pass@tcp(localhost:3306)/dbname")
```

### New

Creates a new GormGen with default configuration.

```go
gg := gormcol.New(db)
```

### NewWithConfig

Creates a new GormGen with custom configuration.

```go
gg := gormcol.NewWithConfig(db, gormcol.GenConfig{
    OutputDir:   "./models",
    PkgName:     "models",
    TableFilter: "ps_.*",
})
```

### GenModels

Generates GORM model files and column descriptors for matched tables.

```go
ctx := context.Background()
err := gg.GenModels(ctx)
```

## Generated Models

After generation, each model file contains a struct and a `Cols` variable:

```go
// model/product.go
type Product struct {
    ID    uint    `gorm:"column:id_product;primaryKey"`
    Name  string  `gorm:"column:name"`
    Price float32 `gorm:"column:price;type:decimal(20,6)"`
}

var ProductCols = struct {
    ID    Field
    Name  Field
    Price Field
}{
    ID:    Field{Table: "ps_product", Column: "id_product"},
    Name:  Field{Table: "ps_product", Column: "name"},
    Price: Field{Table: "ps_product", Column: "price"},
}
```

## Using Generated Models

### GORM queries with type-safe columns

Use `ColumnOnTable` for table-qualified column references in GORM clauses:

```go
import "git.ma-al.com/goc_marek/gormcol"

// Where clauses
db.Where(
    gormcol.ColumnOnTable(model.ProductCols.Price) + " > ?",
    100.0,
).Find(&products)

// Order
db.Order(gormcol.ColumnOnTable(model.ProductCols.Name) + " ASC").Find(&products)

// Joins
db.Joins("JOIN ps_category ON " +
    gormcol.ColumnOnTable(model.ProductCols.ID) + " = ps_category.id_product",
).Find(&products)
```

### Unqualified column names

Use `Column` when the table is already scoped:

```go
db.Select(gormcol.Column(model.ProductCols.Name)).Find(&products)

// Raw queries
db.Raw("SELECT " + gormcol.Column(model.ProductCols.Name) + " FROM ps_product").Scan(&names)
```

### Table name

Use `TableField` to get the table name from a column descriptor:

```go
table := gormcol.TableField(model.ProductCols.ID) // "ps_product"
```

## Dependencies

- `gorm.io/gorm`
- `gorm.io/gen`
- `gorm.io/driver/mysql`
