Skip to content

Commit 89f1109

Browse files
authored
Merge pull request #105 from dev-five-git/json-convert-issue
Fix json convert issue
2 parents 9c6c7ca + dca1f3c commit 89f1109

11 files changed

Lines changed: 385 additions & 15 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"changes":{"crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide/Cargo.toml":"Patch"},"note":"Fix json convert issue","date":"2026-02-09T07:54:00.243061300Z"}

Cargo.lock

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/vespertide-query/src/sql/add_column.rs

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use vespertide_core::{ColumnDef, TableDef};
44

55
use super::helpers::{
66
build_create_enum_type_sql, build_sea_column_def_with_table, build_sqlite_temp_table_create,
7-
normalize_enum_default, normalize_fill_with, recreate_indexes_after_rebuild,
7+
convert_default_for_backend, normalize_enum_default, normalize_fill_with,
8+
recreate_indexes_after_rebuild,
89
};
910
use super::rename_table::build_rename_table;
1011
use super::types::{BuiltQuery, DatabaseBackend};
@@ -66,9 +67,11 @@ pub fn build_add_column(
6667
}
6768
let normalized_fill = normalize_fill_with(fill_with);
6869
let fill_expr = if let Some(fill) = normalized_fill.as_deref() {
69-
Expr::cust(normalize_enum_default(&column.r#type, fill))
70+
let converted = convert_default_for_backend(fill, backend);
71+
Expr::cust(normalize_enum_default(&column.r#type, &converted))
7072
} else if let Some(def) = &column.default {
71-
Expr::cust(normalize_enum_default(&column.r#type, &def.to_sql()))
73+
let converted = convert_default_for_backend(&def.to_sql(), backend);
74+
Expr::cust(normalize_enum_default(&column.r#type, &converted))
7275
} else {
7376
Expr::cust("NULL")
7477
};
@@ -124,6 +127,7 @@ pub fn build_add_column(
124127

125128
// Backfill with provided value
126129
if let Some(fill) = normalize_fill_with(fill_with) {
130+
let fill = convert_default_for_backend(&fill, backend);
127131
let update_stmt = Query::update()
128132
.table(Alias::new(table))
129133
.value(Alias::new(&column.name), Expr::cust(fill))
@@ -604,6 +608,70 @@ mod tests {
604608
});
605609
}
606610

611+
/// Test adding NOT NULL column with '[]'::json default on SQLite
612+
/// SQLite should strip the ::json cast, MySQL should use CAST(... AS JSON)
613+
#[rstest]
614+
#[case::postgres(DatabaseBackend::Postgres)]
615+
#[case::mysql(DatabaseBackend::MySql)]
616+
#[case::sqlite(DatabaseBackend::Sqlite)]
617+
fn test_add_column_with_pg_type_cast_default(#[case] backend: DatabaseBackend) {
618+
let column = ColumnDef {
619+
name: "story_index".into(),
620+
r#type: ColumnType::Simple(SimpleColumnType::Json),
621+
nullable: false,
622+
default: Some("'[]'::json".into()),
623+
comment: None,
624+
primary_key: None,
625+
unique: None,
626+
index: None,
627+
foreign_key: None,
628+
};
629+
let current_schema = vec![TableDef {
630+
name: "project".into(),
631+
description: None,
632+
columns: vec![ColumnDef {
633+
name: "id".into(),
634+
r#type: ColumnType::Simple(SimpleColumnType::Integer),
635+
nullable: false,
636+
default: None,
637+
comment: None,
638+
primary_key: None,
639+
unique: None,
640+
index: None,
641+
foreign_key: None,
642+
}],
643+
constraints: vec![],
644+
}];
645+
let result = build_add_column(&backend, "project", &column, None, &current_schema).unwrap();
646+
let sql = result
647+
.iter()
648+
.map(|q| q.build(backend))
649+
.collect::<Vec<String>>()
650+
.join("\n");
651+
652+
// SQLite must NOT contain ::json syntax
653+
if backend == DatabaseBackend::Sqlite {
654+
assert!(
655+
!sql.contains("::json"),
656+
"SQLite SQL should not contain ::json cast, got: {}",
657+
sql
658+
);
659+
}
660+
661+
// MySQL should use CAST syntax
662+
if backend == DatabaseBackend::MySql {
663+
assert!(
664+
!sql.contains("::json"),
665+
"MySQL SQL should not contain ::json cast, got: {}",
666+
sql
667+
);
668+
}
669+
670+
with_settings!({ snapshot_suffix => format!("pg_type_cast_default_{:?}", backend) }, {
671+
assert_snapshot!(sql);
672+
});
673+
}
674+
607675
#[rstest]
608676
#[case::postgres(DatabaseBackend::Postgres)]
609677
#[case::mysql(DatabaseBackend::MySql)]

0 commit comments

Comments
 (0)