Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changepacks/changepack_log_WoRHR0j9DpzxX5QVCT3xp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"changes":{"crates/vespertide-naming/Cargo.toml":"Patch","crates/vespertide-query/Cargo.toml":"Patch","crates/vespertide-loader/Cargo.toml":"Patch","crates/vespertide-config/Cargo.toml":"Patch","crates/vespertide-core/Cargo.toml":"Patch","crates/vespertide-exporter/Cargo.toml":"Patch","crates/vespertide-cli/Cargo.toml":"Patch","crates/vespertide-planner/Cargo.toml":"Patch","crates/vespertide-macro/Cargo.toml":"Patch","crates/vespertide/Cargo.toml":"Patch"},"note":"Fix upper issue","date":"2026-01-15T13:48:47.690192600Z"}
20 changes: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions crates/vespertide-query/src/sql/create_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,4 +657,64 @@ mod tests {
assert_snapshot!(sql);
});
}

/// Test creating a table with timestamp column and NOW() default
/// SQLite should convert NOW() to CURRENT_TIMESTAMP
#[rstest]
#[case::timestamp_now_default_postgres(DatabaseBackend::Postgres)]
#[case::timestamp_now_default_mysql(DatabaseBackend::MySql)]
#[case::timestamp_now_default_sqlite(DatabaseBackend::Sqlite)]
fn test_create_table_with_timestamp_now_default(#[case] backend: DatabaseBackend) {
let columns = vec![
ColumnDef {
name: "id".into(),
r#type: ColumnType::Simple(SimpleColumnType::BigInt),
nullable: false,
default: None,
comment: None,
primary_key: None,
unique: None,
index: None,
foreign_key: None,
},
ColumnDef {
name: "created_at".into(),
r#type: ColumnType::Simple(SimpleColumnType::Timestamptz),
nullable: false,
default: Some("NOW()".into()), // uppercase NOW()
comment: None,
primary_key: None,
unique: None,
index: None,
foreign_key: None,
},
];

let result = build_create_table(&backend, "events", &columns, &[]);
assert!(result.is_ok(), "build_create_table failed: {:?}", result);
let queries = result.unwrap();
let sql = queries
.iter()
.map(|q| q.build(backend))
.collect::<Vec<String>>()
.join("\n");

// SQLite should NOT have NOW() - it should be converted to CURRENT_TIMESTAMP
if matches!(backend, DatabaseBackend::Sqlite) {
assert!(
!sql.contains("NOW()"),
"SQLite should not contain NOW(), got: {}",
sql
);
assert!(
sql.contains("CURRENT_TIMESTAMP"),
"SQLite should use CURRENT_TIMESTAMP, got: {}",
sql
);
}

with_settings!({ snapshot_suffix => format!("create_table_with_timestamp_now_default_{:?}", backend) }, {
assert_snapshot!(sql);
});
}
}
27 changes: 21 additions & 6 deletions crates/vespertide-query/src/sql/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,31 @@ pub fn reference_action_sql(action: &ReferenceAction) -> &'static str {

/// Convert a default value string to the appropriate backend-specific expression
pub fn convert_default_for_backend(default: &str, backend: &DatabaseBackend) -> String {
match default {
"gen_random_uuid()" | "UUID()" | "lower(hex(randomblob(16)))" => match backend {
let lower = default.to_lowercase();

// UUID generation functions
if lower == "gen_random_uuid()" || lower == "uuid()" || lower == "lower(hex(randomblob(16)))" {
return match backend {
DatabaseBackend::Postgres => "gen_random_uuid()".to_string(),
DatabaseBackend::MySql => "(UUID())".to_string(),
DatabaseBackend::Sqlite => "lower(hex(randomblob(16)))".to_string(),
},
"current_timestamp()" | "now()" | "CURRENT_TIMESTAMP" => match backend {
};
}

// Timestamp functions (case-insensitive)
if lower == "current_timestamp()"
|| lower == "now()"
|| lower == "current_timestamp"
|| lower == "getdate()"
{
return match backend {
DatabaseBackend::Postgres => "CURRENT_TIMESTAMP".to_string(),
DatabaseBackend::MySql => "CURRENT_TIMESTAMP".to_string(),
DatabaseBackend::Sqlite => "CURRENT_TIMESTAMP".to_string(),
},
other => other.to_string(),
};
}

default.to_string()
}

/// Check if the column type is an enum type
Expand Down Expand Up @@ -492,6 +504,9 @@ mod tests {
#[case::now_postgres("now()", DatabaseBackend::Postgres, "CURRENT_TIMESTAMP")]
#[case::now_mysql("now()", DatabaseBackend::MySql, "CURRENT_TIMESTAMP")]
#[case::now_sqlite("now()", DatabaseBackend::Sqlite, "CURRENT_TIMESTAMP")]
#[case::now_upper_postgres("NOW()", DatabaseBackend::Postgres, "CURRENT_TIMESTAMP")]
#[case::now_upper_mysql("NOW()", DatabaseBackend::MySql, "CURRENT_TIMESTAMP")]
#[case::now_upper_sqlite("NOW()", DatabaseBackend::Sqlite, "CURRENT_TIMESTAMP")]
#[case::current_timestamp_upper_postgres(
"CURRENT_TIMESTAMP",
DatabaseBackend::Postgres,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/vespertide-query/src/sql/create_table.rs
expression: sql
---
CREATE TABLE `events` ( `id` bigint NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP )
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/vespertide-query/src/sql/create_table.rs
expression: sql
---
CREATE TABLE "events" ( "id" bigint NOT NULL, "created_at" timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP )
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
source: crates/vespertide-query/src/sql/create_table.rs
expression: sql
---
CREATE TABLE "events" ( "id" bigint NOT NULL, "created_at" timestamp_with_timezone_text NOT NULL DEFAULT CURRENT_TIMESTAMP )