Skip to content

## Bug: V ORM default: attribute strips string quotes, generating invalid SQL #27987

Description

@Jengro777

Minimal Reproduction

Model (model.v):

module main
import time

@[table: 'demo_default']
pub struct DemoDefault {
    id        string    @[primary; sql_type: 'CHAR(36)']
    home_path string    @[default: '/dashboard'; sql_type: 'VARCHAR(255)']
    tags      string    @[default: '["all"]'; sql_type: 'VARCHAR(1000)']
    name      string    @[default: '"我的团队"'; sql_type: 'VARCHAR(100)']
    method    string    @[default: 'POST'; sql_type: 'VARCHAR(32)']
    created_at time.Time @[sql_type: 'TIMESTAMP']
}

Init (main.v):

module main
import db.pg

fn main() {
    mut db := pg.connect(host: 'localhost', user: 'test', password: 'test', dbname: 'test')!

    sql db {
        create table DemoDefault
    }!
    println('OK')
}

Generated DDL (from -d trace_orm):

CREATE TABLE IF NOT EXISTS "demo_default" (
    "id" CHAR(36) NOT NULL,
    "home_path" VARCHAR(255) DEFAULT /dashboard NOT NULL,   -- ← unquoted, syntax error
    "tags" VARCHAR(1000) DEFAULT ["all"] NOT NULL,           -- ← unquoted, syntax error
    "name" VARCHAR(100) DEFAULT "我的团队" NOT NULL,          -- ← unquoted, syntax error
    "method" VARCHAR(32) DEFAULT POST NOT NULL,              -- ← treated as column ref
    "created_at" TIMESTAMP NOT NULL,
    PRIMARY KEY("id")
);

Error (PostgreSQL):

ERROR:  syntax error at or near "/"
LINE 1: ... VARCHAR(255) DEFAULT /dashboard NOT NULL...

Root Cause

V ORM's default: attribute renders the V expression value directly into SQL without SQL string escaping:

  • default: '/dashboard'DEFAULT /dashboard (missing quotes around string)
  • default: 'POST'DEFAULT POST (treated as column reference in PG)
  • default: 0DEFAULT 0 (works because numbers don't need quoting)

The default: value is a V expression (V string literal '/dashboard'), but it needs to be rendered as a SQL literal ('/dashboard' with quotes) in the DDL.

Expected Behavior

V string defaults should be properly quoted in generated SQL:

"home_path" VARCHAR(255) DEFAULT '/dashboard' NOT NULL
"tags" VARCHAR(1000) DEFAULT '["all"]' NOT NULL

Or alternatively, support default: sql('/dashboard') for raw SQL expressions.

Workaround

Move the default into sql_type:

home_path string @[sql_type: "VARCHAR(255) DEFAULT '/dashboard'"]

This works because sql_type is rendered as raw SQL — but it's fragile and mixes type definition with default value.

Note

You can use the 👍 reaction to increase the issue's priority for developers.

Please note that only the 👍 reaction to the issue itself counts as a vote.
Other reactions and those to comments will not be taken into account.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions