Skip to content

Commit 483cc84

Browse files
committed
fix(databases): declare --schema on create, with or without --table
`databases create` takes `--schema`, defaulting to `public`, but only sent it when `--table` was also given: `schemas` was built inside `if !tables .is_empty()`. Create a database without tables and the flag was silently discarded, leaving the database with only the engine's auto-declared `main`. Every later attempt to declare a table in `public` on it then fails with "Schema 'public' is not declared", and nothing before that point says so — `databases list` and `databases <id>` show a healthy database either way. `schemas` now always goes out, carrying at least the chosen schema name. An empty schema is a first-class request: `DatabaseDefaultSchemaDecl` documents `tables` as optional, "so you can declare just a schema name and add tables later", and skips the field when absent. Two existing tests asserted the old body — `req == {}` with no name or tables, and `schemas` absent when only a name was given — so this is not purely additive; both encoded the missing declaration as intended behaviour. The new round-trip test drives the typed builder, which deserialises into the SDK's CreateDatabaseRequest and panics on a shape the model rejects, so a wrong body fails here rather than at runtime.
1 parent c11d226 commit 483cc84

1 file changed

Lines changed: 45 additions & 11 deletions

File tree

‎src/commands/databases.rs‎

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,9 @@ fn schema_name(schema: Option<&str>) -> &str {
559559
}
560560

561561
/// Build the request body for `POST /v1/databases`.
562+
///
563+
/// The `schema` argument (the `--schema` flag, defaulting to `public`) is always
564+
/// declared, with or without `--table`.
562565
pub fn create_database_request(
563566
name: Option<&str>,
564567
catalog: Option<&str>,
@@ -579,7 +582,14 @@ pub fn create_database_request(
579582
);
580583
}
581584

582-
if !tables.is_empty() {
585+
// `schemas` always goes out, even with no `--table`: the engine only
586+
// auto-declares `main`, so a schemas-less create leaves `--schema` (default
587+
// `public`) undeclared and every later table declaration into it fails with
588+
// "Schema 'public' is not declared". `tables` is optional on a schema
589+
// declaration, so an empty schema is a first-class request.
590+
let schemas_json: Vec<serde_json::Value> = if tables.is_empty() {
591+
vec![serde_json::json!({ "name": schema })]
592+
} else {
583593
// Group tables by schema, preserving insertion order.
584594
// Dot-notation entries (e.g. "raw.raw_orders") use the named schema;
585595
// bare names fall back to the `schema` argument.
@@ -595,20 +605,20 @@ pub fn create_database_request(
595605
schema_tables.push((s, vec![table_name]));
596606
}
597607
}
598-
let schemas_json: Vec<serde_json::Value> = schema_tables
608+
schema_tables
599609
.into_iter()
600610
.map(|(s, tbls)| {
601611
serde_json::json!({
602612
"name": s,
603613
"tables": tbls.iter().map(|t| serde_json::json!({ "name": t })).collect::<Vec<_>>()
604614
})
605615
})
606-
.collect();
607-
req.insert(
608-
"schemas".to_string(),
609-
serde_json::Value::Array(schemas_json),
610-
);
611-
}
616+
.collect()
617+
};
618+
req.insert(
619+
"schemas".to_string(),
620+
serde_json::Value::Array(schemas_json),
621+
);
612622

613623
if let Some(exp) = expires_at {
614624
req.insert(
@@ -2215,16 +2225,40 @@ mod tests {
22152225
}
22162226

22172227
#[test]
2218-
fn create_database_request_empty_without_name_or_tables() {
2228+
fn create_database_request_declares_schema_without_name_or_tables() {
22192229
let req = create_database_request(None, None, "public", &[], None);
2220-
assert_eq!(req, serde_json::json!({}));
2230+
assert_eq!(
2231+
req,
2232+
serde_json::json!({"schemas": [{"name": "public"}]}),
2233+
"the --schema default must be declared even with no --table"
2234+
);
2235+
}
2236+
2237+
#[test]
2238+
fn create_database_request_declares_custom_schema_without_tables() {
2239+
let req = create_database_request(None, None, "analytics", &[], None);
2240+
assert_eq!(req["schemas"][0]["name"], "analytics");
2241+
// An empty schema declaration omits `tables` entirely — the server
2242+
// treats that as "declare the schema, add tables later".
2243+
assert!(req["schemas"][0].get("tables").is_none());
2244+
}
2245+
2246+
#[test]
2247+
fn create_database_request_typed_round_trip_without_tables() {
2248+
// The typed builder deserializes the JSON body and panics on a shape the
2249+
// SDK model rejects, so the tables-less schema declaration must survive it.
2250+
let req = create_database_typed_request(None, None, "public", &[], None);
2251+
let schemas = req.schemas.expect("schemas is always sent");
2252+
assert_eq!(schemas.len(), 1);
2253+
assert_eq!(schemas[0].name, "public");
2254+
assert!(schemas[0].tables.is_none());
22212255
}
22222256

22232257
#[test]
22242258
fn create_database_request_includes_name() {
22252259
let req = create_database_request(Some("jaffle_shop"), None, "public", &[], None);
22262260
assert_eq!(req["name"], "jaffle_shop");
2227-
assert!(req.get("schemas").is_none());
2261+
assert_eq!(req["schemas"][0]["name"], "public");
22282262
}
22292263

22302264
#[test]

0 commit comments

Comments
 (0)