Support non-destructive custom field injection in generated models (for computed/scan-only columns) #4

Open
opened 2026-04-26 15:40:59 +00:00 by warkanum · 0 comments
Owner

When using ResolveSpec + relspec code generation for Bun models, we need a stable way to add custom fields (like computed columns) that are not present in DB schema tables, without those changes being overwritten on regeneration.

Current generated models are fully replaced each run, so teams must maintain local patch scripts. This is brittle and easy to miss in CI/CD.

Problem / Motivation
A common UI/API pattern is requesting computed columns, e.g.:

  • thought_count = COALESCE((SELECT COUNT(*) FROM thoughts t WHERE t.project_id = projects.guid), 0)

ResolveSpec returns this column, but Bun scan fails unless the target model includes a matching field.
Without first-class extension points, generated model edits are lost after each relspec convert.

Current Failure Example

{
  "error": {
    "code": "query_error",
    "message": "Error executing query",
    "detail": "sql: Scan error on column index 5, name \"thought_count\": bun: ModelPublicProjects does not have column \"thought_count\""
  }
}

Minimal Repro

  1. Generate Bun models from DBML (relspec convert --to bun ...).
  2. Register ModelPublicProjects in ResolveSpec.
  3. Query projects with a computed column named thought_count.
  4. Observe scan error because generated model lacks field.
  5. Manually add:
    • ThoughtCount spectypes.SqlInt64 \bun:"thought_count,scanonly" json:"thought_count"``
  6. Query succeeds.
  7. Regenerate models; field is removed again.

Expected Behavior
ResolveSpec/relspec should provide a supported mechanism to preserve custom model additions across regeneration.

Feature Request (Preferred Options)

  1. Embedding/partial extension points in generated model output

    • Generate each model split into:
      • base/generated struct file (fully managed)
      • user extension file (never overwritten)
    • Or generate a companion embedded extension struct/hooks section.
  2. Generator-level custom field config

    • Allow config for per-model extra fields:
      • name
      • Go type
      • tags (bun:"...,scanonly", json:"...")
    • Example use: computed scan-only fields.
  3. Schema annotation support

    • Let DBML/metadata define non-table computed fields for generator output.
    • Mark as read-only/scan-only in emitted Bun tags.
  4. Post-generation patch hook support

    • Official --post-hook / patch plugin pipeline so customizations are first-class and repeatable.

Why This Matters

  • Avoids local one-off patch scripts.
  • Improves reliability and reproducibility in CI.
  • Enables common computed-column workflows safely.
  • Reduces friction for ResolveSpec-based admin UIs.

Environment

  • ResolveSpec: v1.0.86
  • Bun models generated from DBML via relspec converter
  • Backend: Go + Bun + ResolveSpec routes
  • Use case: ResolveSpec read with computedColumns on projects entity
When using ResolveSpec + relspec code generation for Bun models, we need a stable way to add custom fields (like computed columns) that are not present in DB schema tables, without those changes being overwritten on regeneration. Current generated models are fully replaced each run, so teams must maintain local patch scripts. This is brittle and easy to miss in CI/CD. **Problem / Motivation** A common UI/API pattern is requesting computed columns, e.g.: - `thought_count = COALESCE((SELECT COUNT(*) FROM thoughts t WHERE t.project_id = projects.guid), 0)` ResolveSpec returns this column, but Bun scan fails unless the target model includes a matching field. Without first-class extension points, generated model edits are lost after each `relspec convert`. **Current Failure Example** ```json { "error": { "code": "query_error", "message": "Error executing query", "detail": "sql: Scan error on column index 5, name \"thought_count\": bun: ModelPublicProjects does not have column \"thought_count\"" } } ``` **Minimal Repro** 1. Generate Bun models from DBML (`relspec convert --to bun ...`). 2. Register `ModelPublicProjects` in ResolveSpec. 3. Query projects with a computed column named `thought_count`. 4. Observe scan error because generated model lacks field. 5. Manually add: - `ThoughtCount spectypes.SqlInt64 \`bun:"thought_count,scanonly" json:"thought_count"\`` 6. Query succeeds. 7. Regenerate models; field is removed again. **Expected Behavior** ResolveSpec/relspec should provide a supported mechanism to preserve custom model additions across regeneration. **Feature Request (Preferred Options)** 1. **Embedding/partial extension points in generated model output** - Generate each model split into: - base/generated struct file (fully managed) - user extension file (never overwritten) - Or generate a companion embedded extension struct/hooks section. 2. **Generator-level custom field config** - Allow config for per-model extra fields: - name - Go type - tags (`bun:"...,scanonly"`, `json:"..."`) - Example use: computed scan-only fields. 3. **Schema annotation support** - Let DBML/metadata define non-table computed fields for generator output. - Mark as read-only/scan-only in emitted Bun tags. 4. **Post-generation patch hook support** - Official `--post-hook` / patch plugin pipeline so customizations are first-class and repeatable. **Why This Matters** - Avoids local one-off patch scripts. - Improves reliability and reproducibility in CI. - Enables common computed-column workflows safely. - Reduces friction for ResolveSpec-based admin UIs. **Environment** - ResolveSpec: `v1.0.86` - Bun models generated from DBML via relspec converter - Backend: Go + Bun + ResolveSpec routes - Use case: ResolveSpec read with `computedColumns` on `projects` entity
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: wdevs/relspecgo#4