fix(remote): gate create-only index requests by server version

This commit is contained in:
ChilePiquin
2026-08-29 14:55:23 -07:00
parent c4e1d0866c
commit 652de751ae
2 changed files with 55 additions and 21 deletions
+4
View File
@@ -91,6 +91,10 @@ impl ServerVersion {
pub fn support_fts_document_granularity(&self) -> bool {
self.0 >= semver::Version::new(0, 6, 0)
}
pub fn support_create_index_replace_false(&self) -> bool {
self.0 >= semver::Version::new(0, 5, 1)
}
}
pub const OPT_REMOTE_PREFIX: &str = "remote_database_";
+51 -21
View File
@@ -508,6 +508,12 @@ impl<S: HttpSend> RemoteTable<S> {
});
}
};
if !index.replace && !self.server_version.support_create_index_replace_false() {
return Err(Error::NotSupported {
message: "create-index replace=false requires remote server version 0.5.1 or later"
.into(),
});
}
if matches!(
&index.index,
Index::FTS(params) if params.get_document_granularity().is_list_element()
@@ -6083,29 +6089,33 @@ mod tests {
#[tokio::test]
async fn test_create_index_forwards_replace_false() {
let table = Table::new_with_handler("my_table", move |request| {
assert_eq!(request.method(), "POST");
match request.url().path() {
"/v1/table/my_table/describe/" => {
let schema = Schema::new(vec![Field::new("a", DataType::Int32, false)]);
http::Response::builder()
.status(200)
.body(describe_response(&schema))
.unwrap()
}
"/v1/table/my_table/create_index/" => {
let body = request.body().unwrap().as_bytes().unwrap();
let body: serde_json::Value = serde_json::from_slice(body).unwrap();
assert_eq!(body["replace"], json!(false));
let table = Table::new_with_handler_version(
"my_table",
semver::Version::new(0, 5, 1),
move |request| {
assert_eq!(request.method(), "POST");
match request.url().path() {
"/v1/table/my_table/describe/" => {
let schema = Schema::new(vec![Field::new("a", DataType::Int32, false)]);
http::Response::builder()
.status(200)
.body(describe_response(&schema))
.unwrap()
}
"/v1/table/my_table/create_index/" => {
let body = request.body().unwrap().as_bytes().unwrap();
let body: serde_json::Value = serde_json::from_slice(body).unwrap();
assert_eq!(body["replace"], json!(false));
http::Response::builder()
.status(200)
.body("{}".to_string())
.unwrap()
http::Response::builder()
.status(200)
.body("{}".to_string())
.unwrap()
}
path => panic!("Unexpected path: {}", path),
}
path => panic!("Unexpected path: {}", path),
}
});
},
);
table
.create_index(&["a"], Index::BTree(Default::default()))
@@ -6115,6 +6125,26 @@ mod tests {
.unwrap();
}
#[tokio::test]
async fn test_create_index_replace_false_rejects_unsupported_server() {
let table = Table::new_with_handler("my_table", |_| -> http::Response<String> {
panic!("unsupported replace=false should be rejected before issuing remote requests")
});
let err = table
.create_index(&["a"], Index::BTree(Default::default()))
.replace(false)
.execute()
.await
.unwrap_err();
assert!(
matches!(&err, Error::NotSupported { message }
if message.contains("replace=false requires remote server version 0.5.1")),
"got {err:?}"
);
}
#[tokio::test]
async fn test_create_index_returns_job() {
let describe_calls = std::sync::Arc::new(std::sync::atomic::AtomicUsize::new(0));