mirror of
https://github.com/lancedb/lancedb.git
synced 2026-09-12 16:22:24 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
477a49cecb | ||
|
|
bd86cc5aa6 |
@@ -50,7 +50,7 @@ If this is false, and another index already exists on the same columns
|
|||||||
and the same name, then an error will be returned. This is true even if
|
and the same name, then an error will be returned. This is true even if
|
||||||
that index is out of date.
|
that index is out of date.
|
||||||
|
|
||||||
The default is true
|
The default is false
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
|||||||
@@ -1526,11 +1526,7 @@ describe("When creating an index", () => {
|
|||||||
|
|
||||||
it("should allow me to replace (or not) an existing index", async () => {
|
it("should allow me to replace (or not) an existing index", async () => {
|
||||||
await tbl.createIndex("id");
|
await tbl.createIndex("id");
|
||||||
// Default is replace=true
|
await expect(tbl.createIndex("id")).rejects.toThrow("already exists");
|
||||||
await tbl.createIndex("id");
|
|
||||||
await expect(tbl.createIndex("id", { replace: false })).rejects.toThrow(
|
|
||||||
"already exists",
|
|
||||||
);
|
|
||||||
await tbl.createIndex("id", { replace: true });
|
await tbl.createIndex("id", { replace: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -841,7 +841,7 @@ export interface IndexOptions {
|
|||||||
* and the same name, then an error will be returned. This is true even if
|
* and the same name, then an error will be returned. This is true even if
|
||||||
* that index is out of date.
|
* that index is out of date.
|
||||||
*
|
*
|
||||||
* The default is true
|
* The default is false
|
||||||
*/
|
*/
|
||||||
replace?: boolean;
|
replace?: boolean;
|
||||||
|
|
||||||
|
|||||||
@@ -402,6 +402,7 @@ class RemoteTable(Table):
|
|||||||
/,
|
/,
|
||||||
*,
|
*,
|
||||||
config: IndexConfigType,
|
config: IndexConfigType,
|
||||||
|
replace: bool = ...,
|
||||||
wait_timeout: Optional[timedelta] = ...,
|
wait_timeout: Optional[timedelta] = ...,
|
||||||
name: Optional[str] = ...,
|
name: Optional[str] = ...,
|
||||||
train: bool = ...,
|
train: bool = ...,
|
||||||
@@ -416,7 +417,7 @@ class RemoteTable(Table):
|
|||||||
index_cache_size: Optional[int] = ...,
|
index_cache_size: Optional[int] = ...,
|
||||||
num_partitions: Optional[int] = ...,
|
num_partitions: Optional[int] = ...,
|
||||||
num_sub_vectors: Optional[int] = ...,
|
num_sub_vectors: Optional[int] = ...,
|
||||||
replace: Optional[bool] = ...,
|
replace: bool = ...,
|
||||||
accelerator: Optional[str] = ...,
|
accelerator: Optional[str] = ...,
|
||||||
index_type: Literal[
|
index_type: Literal[
|
||||||
"VECTOR", "IVF_FLAT", "IVF_SQ", "IVF_PQ", "IVF_HNSW_SQ", "IVF_HNSW_PQ"
|
"VECTOR", "IVF_FLAT", "IVF_SQ", "IVF_PQ", "IVF_HNSW_SQ", "IVF_HNSW_PQ"
|
||||||
@@ -435,7 +436,7 @@ class RemoteTable(Table):
|
|||||||
index_cache_size: Optional[int] = None,
|
index_cache_size: Optional[int] = None,
|
||||||
num_partitions: Optional[int] = None,
|
num_partitions: Optional[int] = None,
|
||||||
num_sub_vectors: Optional[int] = None,
|
num_sub_vectors: Optional[int] = None,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
accelerator: Optional[str] = None,
|
accelerator: Optional[str] = None,
|
||||||
index_type="vector",
|
index_type="vector",
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
@@ -479,7 +480,6 @@ class RemoteTable(Table):
|
|||||||
vector_column_name,
|
vector_column_name,
|
||||||
accelerator,
|
accelerator,
|
||||||
index_cache_size,
|
index_cache_size,
|
||||||
replace,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_legacy:
|
if is_legacy:
|
||||||
@@ -503,12 +503,6 @@ class RemoteTable(Table):
|
|||||||
"If you have 100M+ vectors to index,"
|
"If you have 100M+ vectors to index,"
|
||||||
"please contact us at contact@lancedb.com"
|
"please contact us at contact@lancedb.com"
|
||||||
)
|
)
|
||||||
if replace is not None:
|
|
||||||
logging.warning(
|
|
||||||
"replace is not supported on LanceDB cloud."
|
|
||||||
"Existing indexes will always be replaced."
|
|
||||||
)
|
|
||||||
|
|
||||||
idx_type = index_type.upper()
|
idx_type = index_type.upper()
|
||||||
if idx_type == "VECTOR" or idx_type == "IVF_PQ":
|
if idx_type == "VECTOR" or idx_type == "IVF_PQ":
|
||||||
config = IvfPq(
|
config = IvfPq(
|
||||||
@@ -561,7 +555,7 @@ class RemoteTable(Table):
|
|||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
config: IndexConfigType,
|
config: IndexConfigType,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
train: bool = True,
|
train: bool = True,
|
||||||
@@ -593,7 +587,6 @@ class RemoteTable(Table):
|
|||||||
vector_column_name: str,
|
vector_column_name: str,
|
||||||
accelerator: Optional[str],
|
accelerator: Optional[str],
|
||||||
index_cache_size: Optional[int],
|
index_cache_size: Optional[int],
|
||||||
replace: Optional[bool],
|
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Detect if this is a legacy create_index call."""
|
"""Detect if this is a legacy create_index call."""
|
||||||
if config is not None:
|
if config is not None:
|
||||||
@@ -605,7 +598,6 @@ class RemoteTable(Table):
|
|||||||
num_sub_vectors,
|
num_sub_vectors,
|
||||||
accelerator,
|
accelerator,
|
||||||
index_cache_size,
|
index_cache_size,
|
||||||
replace,
|
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -1132,7 +1132,7 @@ class Table(ABC):
|
|||||||
num_partitions: Optional[int] = None,
|
num_partitions: Optional[int] = None,
|
||||||
num_sub_vectors: Optional[int] = None,
|
num_sub_vectors: Optional[int] = None,
|
||||||
vector_column_name: str = VECTOR_COLUMN_NAME,
|
vector_column_name: str = VECTOR_COLUMN_NAME,
|
||||||
replace: bool = True,
|
replace: bool = False,
|
||||||
accelerator: Optional[str] = None,
|
accelerator: Optional[str] = None,
|
||||||
index_cache_size: Optional[int] = None,
|
index_cache_size: Optional[int] = None,
|
||||||
*,
|
*,
|
||||||
@@ -1166,7 +1166,7 @@ class Table(ABC):
|
|||||||
The index configuration object. If provided, uses the new unified API.
|
The index configuration object. If provided, uses the new unified API.
|
||||||
Can be one of: IvfFlat, IvfPq, IvfSq, IvfRq, HnswPq, HnswSq,
|
Can be one of: IvfFlat, IvfPq, IvfSq, IvfRq, HnswPq, HnswSq,
|
||||||
BTree, Bitmap, LabelList, Fm, FTS.
|
BTree, Bitmap, LabelList, Fm, FTS.
|
||||||
replace : bool, default True
|
replace : bool, default False
|
||||||
Whether to replace an existing index on this column.
|
Whether to replace an existing index on this column.
|
||||||
wait_timeout : timedelta, optional
|
wait_timeout : timedelta, optional
|
||||||
Timeout to wait for async indexing to complete.
|
Timeout to wait for async indexing to complete.
|
||||||
@@ -1198,7 +1198,7 @@ class Table(ABC):
|
|||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
config: IndexConfigType,
|
config: IndexConfigType,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
train: bool = True,
|
train: bool = True,
|
||||||
@@ -1260,7 +1260,7 @@ class Table(ABC):
|
|||||||
self,
|
self,
|
||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
replace: bool = True,
|
replace: bool = False,
|
||||||
index_type: ScalarIndexType = "BTREE",
|
index_type: ScalarIndexType = "BTREE",
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
@@ -1272,7 +1272,7 @@ class Table(ABC):
|
|||||||
column : str
|
column : str
|
||||||
The column to be indexed. Must be a boolean, integer, float,
|
The column to be indexed. Must be a boolean, integer, float,
|
||||||
or string column.
|
or string column.
|
||||||
replace : bool, default True
|
replace : bool, default False
|
||||||
Replace the existing index if it exists.
|
Replace the existing index if it exists.
|
||||||
index_type: Literal["BTREE", "BITMAP", "LABEL_LIST"], default "BTREE"
|
index_type: Literal["BTREE", "BITMAP", "LABEL_LIST"], default "BTREE"
|
||||||
The type of index to create.
|
The type of index to create.
|
||||||
@@ -2988,7 +2988,7 @@ class LanceTable(Table):
|
|||||||
num_partitions: Optional[int] = None,
|
num_partitions: Optional[int] = None,
|
||||||
num_sub_vectors: Optional[int] = None,
|
num_sub_vectors: Optional[int] = None,
|
||||||
vector_column_name: str = VECTOR_COLUMN_NAME,
|
vector_column_name: str = VECTOR_COLUMN_NAME,
|
||||||
replace: bool = True,
|
replace: bool = False,
|
||||||
accelerator: Optional[str] = None,
|
accelerator: Optional[str] = None,
|
||||||
index_cache_size: Optional[int] = None,
|
index_cache_size: Optional[int] = None,
|
||||||
num_bits: int = 8,
|
num_bits: int = 8,
|
||||||
@@ -3030,7 +3030,7 @@ class LanceTable(Table):
|
|||||||
The index configuration object. If provided, uses the new unified API.
|
The index configuration object. If provided, uses the new unified API.
|
||||||
Can be one of: IvfFlat, IvfPq, IvfSq, IvfRq, HnswPq, HnswSq,
|
Can be one of: IvfFlat, IvfPq, IvfSq, IvfRq, HnswPq, HnswSq,
|
||||||
BTree, Bitmap, LabelList, Fm, FTS.
|
BTree, Bitmap, LabelList, Fm, FTS.
|
||||||
replace : bool, default True
|
replace : bool, default False
|
||||||
Whether to replace an existing index on this column.
|
Whether to replace an existing index on this column.
|
||||||
wait_timeout : timedelta, optional
|
wait_timeout : timedelta, optional
|
||||||
Timeout to wait for async indexing to complete.
|
Timeout to wait for async indexing to complete.
|
||||||
@@ -3169,7 +3169,7 @@ class LanceTable(Table):
|
|||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
config: IndexConfigType,
|
config: IndexConfigType,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
wait_timeout: Optional[timedelta] = None,
|
wait_timeout: Optional[timedelta] = None,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
train: bool = True,
|
train: bool = True,
|
||||||
@@ -3424,7 +3424,7 @@ class LanceTable(Table):
|
|||||||
self,
|
self,
|
||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
replace: bool = True,
|
replace: bool = False,
|
||||||
index_type: ScalarIndexType = "BTREE",
|
index_type: ScalarIndexType = "BTREE",
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
):
|
):
|
||||||
@@ -5313,7 +5313,7 @@ class AsyncTable:
|
|||||||
self,
|
self,
|
||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
config: Optional[
|
config: Optional[
|
||||||
Union[
|
Union[
|
||||||
IvfFlat,
|
IvfFlat,
|
||||||
@@ -5344,14 +5344,14 @@ class AsyncTable:
|
|||||||
----------
|
----------
|
||||||
column: str
|
column: str
|
||||||
The column to index.
|
The column to index.
|
||||||
replace: bool, default True
|
replace: bool, default False
|
||||||
Whether to replace the existing index
|
Whether to replace the existing index
|
||||||
|
|
||||||
If this is false, and another index already exists on the same columns
|
If this is false, and another index already exists on the same columns
|
||||||
and the same name, then an error will be returned. This is true even if
|
and the same name, then an error will be returned. This is true even if
|
||||||
that index is out of date.
|
that index is out of date.
|
||||||
|
|
||||||
The default is True
|
The default is False
|
||||||
config: default None
|
config: default None
|
||||||
For advanced configuration you can specify the type of index you would
|
For advanced configuration you can specify the type of index you would
|
||||||
like to create. You can also specify index-specific parameters when
|
like to create. You can also specify index-specific parameters when
|
||||||
@@ -5409,7 +5409,7 @@ class AsyncTable:
|
|||||||
self,
|
self,
|
||||||
column: str,
|
column: str,
|
||||||
*,
|
*,
|
||||||
replace: Optional[bool] = None,
|
replace: bool = False,
|
||||||
config: Optional[
|
config: Optional[
|
||||||
Union[
|
Union[
|
||||||
IvfFlat,
|
IvfFlat,
|
||||||
|
|||||||
@@ -97,6 +97,9 @@ async def test_create_index_async_returns_done_job(some_table: AsyncTable):
|
|||||||
async def test_create_scalar_index(some_table: AsyncTable):
|
async def test_create_scalar_index(some_table: AsyncTable):
|
||||||
# Can create
|
# Can create
|
||||||
await some_table.create_index("id")
|
await some_table.create_index("id")
|
||||||
|
# Can't recreate by default
|
||||||
|
with pytest.raises(RuntimeError, match="already exists"):
|
||||||
|
await some_table.create_index("id")
|
||||||
# Can recreate if replace=True
|
# Can recreate if replace=True
|
||||||
await some_table.create_index("id", replace=True)
|
await some_table.create_index("id", replace=True)
|
||||||
indices = await some_table.list_indices()
|
indices = await some_table.list_indices()
|
||||||
@@ -110,7 +113,7 @@ async def test_create_scalar_index(some_table: AsyncTable):
|
|||||||
with pytest.raises(RuntimeError, match="already exists"):
|
with pytest.raises(RuntimeError, match="already exists"):
|
||||||
await some_table.create_index("id", replace=False)
|
await some_table.create_index("id", replace=False)
|
||||||
# can also specify index type
|
# can also specify index type
|
||||||
await some_table.create_index("id", config=BTree())
|
await some_table.create_index("id", config=BTree(), replace=True)
|
||||||
|
|
||||||
await some_table.drop_index("id_idx")
|
await some_table.drop_index("id_idx")
|
||||||
indices = await some_table.list_indices()
|
indices = await some_table.list_indices()
|
||||||
@@ -351,13 +354,18 @@ async def test_full_text_search_index(some_table: AsyncTable):
|
|||||||
async def test_create_vector_index(some_table: AsyncTable):
|
async def test_create_vector_index(some_table: AsyncTable):
|
||||||
# Can create
|
# Can create
|
||||||
await some_table.create_index("vector")
|
await some_table.create_index("vector")
|
||||||
|
# Can't recreate by default
|
||||||
|
with pytest.raises(RuntimeError, match="already exists"):
|
||||||
|
await some_table.create_index("vector")
|
||||||
# Can recreate if replace=True
|
# Can recreate if replace=True
|
||||||
await some_table.create_index("vector", replace=True)
|
await some_table.create_index("vector", replace=True)
|
||||||
# Can't recreate if replace=False
|
# Can't recreate if replace=False
|
||||||
with pytest.raises(RuntimeError, match="already exists"):
|
with pytest.raises(RuntimeError, match="already exists"):
|
||||||
await some_table.create_index("vector", replace=False)
|
await some_table.create_index("vector", replace=False)
|
||||||
# Can also specify index type
|
# Can also specify index type
|
||||||
await some_table.create_index("vector", config=IvfPq(num_partitions=100))
|
await some_table.create_index(
|
||||||
|
"vector", config=IvfPq(num_partitions=100), replace=True
|
||||||
|
)
|
||||||
indices = await some_table.list_indices()
|
indices = await some_table.list_indices()
|
||||||
assert len(indices) == 1
|
assert len(indices) == 1
|
||||||
assert indices[0].index_type == "IvfPq"
|
assert indices[0].index_type == "IvfPq"
|
||||||
|
|||||||
@@ -834,7 +834,7 @@ def test_table_create_indices():
|
|||||||
vector_req = received_requests[2]
|
vector_req = received_requests[2]
|
||||||
assert "name" in vector_req
|
assert "name" in vector_req
|
||||||
assert vector_req["name"] == "custom_vector_idx"
|
assert vector_req["name"] == "custom_vector_idx"
|
||||||
assert "replace" not in vector_req
|
assert vector_req["replace"] is False
|
||||||
|
|
||||||
table.wait_for_index(["custom_scalar_idx"], timedelta(seconds=2))
|
table.wait_for_index(["custom_scalar_idx"], timedelta(seconds=2))
|
||||||
table.wait_for_index(
|
table.wait_for_index(
|
||||||
|
|||||||
@@ -1600,7 +1600,7 @@ def test_create_index_method(mock_create_index, mem_db: DBConnection):
|
|||||||
)
|
)
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"my_vector",
|
"my_vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=expected_config,
|
config=expected_config,
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
@@ -1620,7 +1620,7 @@ def test_create_index_method(mock_create_index, mem_db: DBConnection):
|
|||||||
)
|
)
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"my_vector",
|
"my_vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=expected_config,
|
config=expected_config,
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
@@ -1646,7 +1646,7 @@ def test_create_index_name_and_train_parameters(
|
|||||||
expected_config = IvfPq() # Default config
|
expected_config = IvfPq() # Default config
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"vector",
|
"vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=expected_config,
|
config=expected_config,
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name="my_custom_index",
|
name="my_custom_index",
|
||||||
@@ -1657,7 +1657,7 @@ def test_create_index_name_and_train_parameters(
|
|||||||
table.create_index(vector_column_name="vector", train=False)
|
table.create_index(vector_column_name="vector", train=False)
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"vector",
|
"vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=expected_config,
|
config=expected_config,
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
@@ -1668,7 +1668,7 @@ def test_create_index_name_and_train_parameters(
|
|||||||
table.create_index(vector_column_name="vector", name="my_index_name", train=True)
|
table.create_index(vector_column_name="vector", name="my_index_name", train=True)
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"vector",
|
"vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=expected_config,
|
config=expected_config,
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name="my_index_name",
|
name="my_index_name",
|
||||||
@@ -1705,7 +1705,7 @@ def test_create_index_new_api(mock_create_index, mem_db: DBConnection):
|
|||||||
table.create_index("vector", config=IvfPq(distance_type="l2"))
|
table.create_index("vector", config=IvfPq(distance_type="l2"))
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"vector",
|
"vector",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=IvfPq(distance_type="l2"),
|
config=IvfPq(distance_type="l2"),
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
@@ -1716,7 +1716,7 @@ def test_create_index_new_api(mock_create_index, mem_db: DBConnection):
|
|||||||
table.create_index("category", config=BTree())
|
table.create_index("category", config=BTree())
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"category",
|
"category",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=BTree(),
|
config=BTree(),
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
@@ -1727,7 +1727,7 @@ def test_create_index_new_api(mock_create_index, mem_db: DBConnection):
|
|||||||
table.create_index("text", config=FTS(with_position=True))
|
table.create_index("text", config=FTS(with_position=True))
|
||||||
mock_create_index.assert_called_with(
|
mock_create_index.assert_called_with(
|
||||||
"text",
|
"text",
|
||||||
replace=True,
|
replace=False,
|
||||||
config=FTS(with_position=True),
|
config=FTS(with_position=True),
|
||||||
wait_timeout=None,
|
wait_timeout=None,
|
||||||
name=None,
|
name=None,
|
||||||
|
|||||||
@@ -200,14 +200,14 @@ impl IndexBuilder {
|
|||||||
parent,
|
parent,
|
||||||
index,
|
index,
|
||||||
columns,
|
columns,
|
||||||
replace: true,
|
replace: false,
|
||||||
train: true,
|
train: true,
|
||||||
wait_timeout: None,
|
wait_timeout: None,
|
||||||
name: None,
|
name: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to replace the existing index, the default is `true`.
|
/// Whether to replace the existing index, the default is `false`.
|
||||||
///
|
///
|
||||||
/// If this is false, and another index already exists on the same columns
|
/// If this is false, and another index already exists on the same columns
|
||||||
/// and the same name, then an error will be returned. This is true even if
|
/// and the same name, then an error will be returned. This is true even if
|
||||||
|
|||||||
+35
-17
@@ -40,6 +40,7 @@ impl TerminalResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "remote")]
|
||||||
pub(crate) fn remote(value: Option<Value>, request_id: String) -> Self {
|
pub(crate) fn remote(value: Option<Value>, request_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
value,
|
value,
|
||||||
@@ -47,30 +48,46 @@ impl TerminalResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "remote")]
|
||||||
pub(crate) fn value(&self) -> Option<&Value> {
|
pub(crate) fn value(&self) -> Option<&Value> {
|
||||||
self.value.as_ref()
|
self.value.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode<T: DeserializeOwned>(self) -> Result<T> {
|
fn decode<T: DeserializeOwned>(self) -> Result<T> {
|
||||||
let value = self.value.ok_or_else(|| match &self.request_id {
|
let value = self.value.ok_or_else(|| {
|
||||||
Some(request_id) => Error::Http {
|
#[cfg(feature = "remote")]
|
||||||
source: "successful typed job response did not contain a result".into(),
|
if let Some(request_id) = &self.request_id {
|
||||||
request_id: request_id.clone(),
|
return Error::Http {
|
||||||
status_code: None,
|
source: "successful typed job response did not contain a result".into(),
|
||||||
},
|
request_id: request_id.clone(),
|
||||||
None => Error::Runtime {
|
status_code: None,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Error::Runtime {
|
||||||
message: "successful typed job did not contain a result".to_string(),
|
message: "successful typed job did not contain a result".to_string(),
|
||||||
},
|
}
|
||||||
})?;
|
})?;
|
||||||
serde_json::from_value(value).map_err(|error| match self.request_id {
|
serde_json::from_value(value).map_err(|error| {
|
||||||
Some(request_id) => Error::Http {
|
#[cfg(feature = "remote")]
|
||||||
source: format!("failed to parse typed job result: {error}").into(),
|
{
|
||||||
request_id,
|
match self.request_id {
|
||||||
status_code: None,
|
Some(request_id) => Error::Http {
|
||||||
},
|
source: format!("failed to parse typed job result: {error}").into(),
|
||||||
None => Error::Runtime {
|
request_id,
|
||||||
message: format!("failed to parse typed job result: {error}"),
|
status_code: None,
|
||||||
},
|
},
|
||||||
|
None => Error::Runtime {
|
||||||
|
message: format!("failed to parse typed job result: {error}"),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "remote"))]
|
||||||
|
{
|
||||||
|
let _ = self.request_id;
|
||||||
|
Error::Runtime {
|
||||||
|
message: format!("failed to parse typed job result: {error}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,6 +134,7 @@ impl Job<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "remote")]
|
||||||
pub(crate) fn new(handle: Box<dyn JobHandle>) -> Self {
|
pub(crate) fn new(handle: Box<dyn JobHandle>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: JobInner::Handle {
|
inner: JobInner::Handle {
|
||||||
|
|||||||
@@ -524,13 +524,10 @@ impl<S: HttpSend> RemoteTable<S> {
|
|||||||
_ => resolve_arrow_field_path(&schema, &column)?,
|
_ => resolve_arrow_field_path(&schema, &column)?,
|
||||||
};
|
};
|
||||||
let mut body = serde_json::json!({
|
let mut body = serde_json::json!({
|
||||||
"column": canonical_column
|
"column": canonical_column,
|
||||||
|
"replace": index.replace,
|
||||||
});
|
});
|
||||||
|
|
||||||
if !index.replace {
|
|
||||||
body["replace"] = false.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add name parameter if provided (for backwards compatibility, only include if Some)
|
// Add name parameter if provided (for backwards compatibility, only include if Some)
|
||||||
if let Some(ref name) = index.name {
|
if let Some(ref name) = index.name {
|
||||||
body["name"] = serde_json::Value::String(name.clone());
|
body["name"] = serde_json::Value::String(name.clone());
|
||||||
@@ -6309,6 +6306,7 @@ mod tests {
|
|||||||
let mut expected_body = expected_body.clone();
|
let mut expected_body = expected_body.clone();
|
||||||
expected_body["column"] = "a".into();
|
expected_body["column"] = "a".into();
|
||||||
expected_body[INDEX_TYPE_KEY] = index_type.into();
|
expected_body[INDEX_TYPE_KEY] = index_type.into();
|
||||||
|
expected_body["replace"] = false.into();
|
||||||
|
|
||||||
assert_eq!(body, expected_body);
|
assert_eq!(body, expected_body);
|
||||||
|
|
||||||
@@ -6327,7 +6325,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_create_index_forwards_replace_false_on_existing_route() {
|
async fn test_create_index_forwards_default_replace_false_on_existing_route() {
|
||||||
let table = Table::new_with_handler("my_table", move |request| {
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
assert_eq!(request.method(), "POST");
|
assert_eq!(request.method(), "POST");
|
||||||
match request.url().path() {
|
match request.url().path() {
|
||||||
@@ -6354,7 +6352,40 @@ mod tests {
|
|||||||
|
|
||||||
table
|
table
|
||||||
.create_index(&["a"], Index::BTree(Default::default()))
|
.create_index(&["a"], Index::BTree(Default::default()))
|
||||||
.replace(false)
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_create_index_forwards_explicit_replace_true_on_existing_route() {
|
||||||
|
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!(true));
|
||||||
|
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body("{}".to_string())
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
path => panic!("Unexpected path: {}", path),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
table
|
||||||
|
.create_index(&["a"], Index::BTree(Default::default()))
|
||||||
|
.replace(true)
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -6585,38 +6616,46 @@ mod tests {
|
|||||||
json!({
|
json!({
|
||||||
"column": "rowId",
|
"column": "rowId",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "`row-id`",
|
"column": "`row-id`",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "userId",
|
"column": "userId",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "MetaData.userId",
|
"column": "MetaData.userId",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "metadata.user_id",
|
"column": "metadata.user_id",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "image.embedding",
|
"column": "image.embedding",
|
||||||
"index_type": "IVF_PQ",
|
"index_type": "IVF_PQ",
|
||||||
"metric_type": "l2",
|
"metric_type": "l2",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
let mut body = serde_json::to_value(InvertedIndexParams::default()).unwrap();
|
let mut body = serde_json::to_value(InvertedIndexParams::default()).unwrap();
|
||||||
body["column"] = "payload.text".into();
|
body["column"] = "payload.text".into();
|
||||||
body["index_type"] = "FTS".into();
|
body["index_type"] = "FTS".into();
|
||||||
|
body["replace"] = false.into();
|
||||||
body
|
body
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
let mut body = serde_json::to_value(InvertedIndexParams::default()).unwrap();
|
let mut body = serde_json::to_value(InvertedIndexParams::default()).unwrap();
|
||||||
body["column"] = "docs.content".into();
|
body["column"] = "docs.content".into();
|
||||||
body["index_type"] = "FTS".into();
|
body["index_type"] = "FTS".into();
|
||||||
|
body["replace"] = false.into();
|
||||||
body
|
body
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -6624,15 +6663,18 @@ mod tests {
|
|||||||
body["column"] = "docs.content".into();
|
body["column"] = "docs.content".into();
|
||||||
body["index_type"] = "FTS".into();
|
body["index_type"] = "FTS".into();
|
||||||
body["document_granularity"] = "list_element".into();
|
body["document_granularity"] = "list_element".into();
|
||||||
|
body["replace"] = false.into();
|
||||||
body
|
body
|
||||||
},
|
},
|
||||||
json!({
|
json!({
|
||||||
"column": "`meta-data`.`user-id`",
|
"column": "`meta-data`.`user-id`",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
json!({
|
json!({
|
||||||
"column": "literal.`a.b`",
|
"column": "literal.`a.b`",
|
||||||
"index_type": "BTREE",
|
"index_type": "BTREE",
|
||||||
|
"replace": false,
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
let request_idx = Arc::new(AtomicUsize::new(0));
|
let request_idx = Arc::new(AtomicUsize::new(0));
|
||||||
|
|||||||
@@ -725,12 +725,11 @@ mod tests {
|
|||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// Rebuilding the same index without replace fails once the build
|
// Rebuilding the same index without explicit replace fails once the build
|
||||||
// starts, so the failure reaches the job rather than execute_async.
|
// starts, so the failure reaches the job rather than execute_async.
|
||||||
let job = Arc::new(
|
let job = Arc::new(
|
||||||
table
|
table
|
||||||
.create_index(&["id"], Index::BTree(BTreeIndexBuilder::default()))
|
.create_index(&["id"], Index::BTree(BTreeIndexBuilder::default()))
|
||||||
.replace(false)
|
|
||||||
.execute_async()
|
.execute_async()
|
||||||
.await
|
.await
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
@@ -769,7 +768,6 @@ mod tests {
|
|||||||
|
|
||||||
let job = table
|
let job = table
|
||||||
.create_index(&["id"], Index::BTree(BTreeIndexBuilder::default()))
|
.create_index(&["id"], Index::BTree(BTreeIndexBuilder::default()))
|
||||||
.replace(false)
|
|
||||||
.execute_async()
|
.execute_async()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -1106,6 +1104,7 @@ mod tests {
|
|||||||
// Can also specify btree
|
// Can also specify btree
|
||||||
table
|
table
|
||||||
.create_index(&["i"], Index::BTree(BTreeIndexBuilder::default()))
|
.create_index(&["i"], Index::BTree(BTreeIndexBuilder::default()))
|
||||||
|
.replace(true)
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user