mirror of
https://github.com/lancedb/lancedb.git
synced 2025-12-27 07:09:57 +00:00
Compare commits
17 Commits
python-v0.
...
python-v0.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1684940946 | ||
|
|
695813463c | ||
|
|
ed594b0f76 | ||
|
|
cee2b5ea42 | ||
|
|
f315f9665a | ||
|
|
5deb26bc8b | ||
|
|
3cc670ac38 | ||
|
|
4ade3e31e2 | ||
|
|
a222d2cd91 | ||
|
|
508e621f3d | ||
|
|
a1a0472f3f | ||
|
|
3425a6d339 | ||
|
|
af54e0ce06 | ||
|
|
089905fe8f | ||
|
|
554939e5d2 | ||
|
|
7a13814922 | ||
|
|
e9f25f6a12 |
@@ -1,5 +1,5 @@
|
|||||||
[tool.bumpversion]
|
[tool.bumpversion]
|
||||||
current_version = "0.19.0"
|
current_version = "0.19.1-beta.1"
|
||||||
parse = """(?x)
|
parse = """(?x)
|
||||||
(?P<major>0|[1-9]\\d*)\\.
|
(?P<major>0|[1-9]\\d*)\\.
|
||||||
(?P<minor>0|[1-9]\\d*)\\.
|
(?P<minor>0|[1-9]\\d*)\\.
|
||||||
|
|||||||
1
.github/workflows/python.yml
vendored
1
.github/workflows/python.yml
vendored
@@ -228,6 +228,7 @@ jobs:
|
|||||||
- name: Install lancedb
|
- name: Install lancedb
|
||||||
run: |
|
run: |
|
||||||
pip install "pydantic<2"
|
pip install "pydantic<2"
|
||||||
|
pip install pyarrow==16
|
||||||
pip install --extra-index-url https://pypi.fury.io/lancedb/ -e .[tests]
|
pip install --extra-index-url https://pypi.fury.io/lancedb/ -e .[tests]
|
||||||
pip install tantivy
|
pip install tantivy
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|||||||
215
Cargo.lock
generated
215
Cargo.lock
generated
@@ -463,7 +463,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -474,7 +474,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -602,9 +602,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-bedrockruntime"
|
name = "aws-sdk-bedrockruntime"
|
||||||
version = "1.83.0"
|
version = "1.85.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b82a56e1a0c4b145031c3a99e68127eec0a4206ad34a5653ddf04afc18053376"
|
checksum = "6f6c003cd82739447a18d7616468b047341c125efff11fdafc77a5e777a861c9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
@@ -628,9 +628,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-sdk-dynamodb"
|
name = "aws-sdk-dynamodb"
|
||||||
version = "1.72.0"
|
version = "1.72.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "412cd587b03bacb2f7b94a5446cc77dee49a8fa848e636f9545df3aadbbfaf8b"
|
checksum = "b14d5b5d6849d1caa7b404ea57cbe25ed8ba25c3c7d47f45bcbd5b51e098ceac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aws-credential-types",
|
"aws-credential-types",
|
||||||
"aws-runtime",
|
"aws-runtime",
|
||||||
@@ -1117,7 +1117,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
"shlex",
|
"shlex",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1229,9 +1229,9 @@ checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
version = "1.22.0"
|
version = "1.23.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540"
|
checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck_derive",
|
"bytemuck_derive",
|
||||||
]
|
]
|
||||||
@@ -1244,7 +1244,7 @@ checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1753,7 +1753,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1783,7 +1783,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"strsim",
|
"strsim",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1794,7 +1794,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"darling_core",
|
"darling_core",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2152,7 +2152,7 @@ checksum = "4800e1ff7ecf8f310887e9b54c9c444b8e215ccbc7b21c2f244cfae373b1ece7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"datafusion-expr",
|
"datafusion-expr",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2321,7 +2321,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2342,7 +2342,7 @@ dependencies = [
|
|||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2352,7 +2352,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_builder_core",
|
"derive_builder_core",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2416,7 +2416,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2509,7 +2509,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2521,7 +2521,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2737,9 +2737,8 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fsst"
|
name = "fsst"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "cbbb5d86fdf9f56c54cf7ec48f4471c0e901af458ee9821677dc8ba0c38bc0be"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
]
|
]
|
||||||
@@ -2815,7 +2814,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3517,7 +3516,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3681,7 +3680,7 @@ checksum = "199b7932d97e325aff3a7030e141eafe7f2c6268e1d1b24859b753a627f45254"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3728,9 +3727,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance"
|
name = "lance"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "285c3f98a7182e2f35eabc9be67927bb9167b236c6d9c45d894928cbe330067c"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-arith",
|
"arrow-arith",
|
||||||
@@ -3792,9 +3790,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-arrow"
|
name = "lance-arrow"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "0f877f217d6f93b24b54a2390a988a32f99d6608fe8af7766d93bd515e77dd2a"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-buffer",
|
"arrow-buffer",
|
||||||
@@ -3811,9 +3808,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-core"
|
name = "lance-core"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "52fa4661c532db5b53102e2b394c9735bf6e707c337dfa5b9d98baba5c0cba13"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-buffer",
|
"arrow-buffer",
|
||||||
@@ -3849,9 +3845,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-datafusion"
|
name = "lance-datafusion"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "3efa610cc1168aaf96734f2f7911fb874609304716aab3318a86193da883f700"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -3880,9 +3875,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-datagen"
|
name = "lance-datagen"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "4c61affd39495caa923f6a49a7cb0a9f36fea2d7231a039e557f908e0b3b59cf"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -3897,9 +3891,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-encoding"
|
name = "lance-encoding"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "051d65ab02790552c8790fe22915fbdd1629f3e1fa2a6ef69946e77c9d2b6f8e"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrow",
|
"arrow",
|
||||||
@@ -3938,9 +3931,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-file"
|
name = "lance-file"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "9e4aff9ff0801c82d8fcb88cacec4880b6aaf53c6480291d50a4fcc12e6853c4"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-arith",
|
"arrow-arith",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -3974,9 +3966,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-index"
|
name = "lance-index"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "3823b5147002a3115456c4dd1e2b16c645c08f4653e6e9dc624b9381ba29c87f"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -4029,9 +4020,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-io"
|
name = "lance-io"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "a401202f6a1997db4ea5e9eb1a73a352736b320808a2e8497686c44fe6badf01"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-arith",
|
"arrow-arith",
|
||||||
@@ -4069,9 +4059,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-linalg"
|
name = "lance-linalg"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "82cc5333ed9d12f1745e849ad161746da0b12ae3d4c9897d1937411e6533f504"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-ord",
|
"arrow-ord",
|
||||||
@@ -4094,9 +4083,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-table"
|
name = "lance-table"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "41a43c76277808c452135f33a6b46ca8ec6ba38167534ff5240b46098ed81e73"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -4135,9 +4123,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lance-testing"
|
name = "lance-testing"
|
||||||
version = "0.26.0"
|
version = "0.27.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/lancedb/lance.git?tag=v0.27.0-beta.2#cf903b470be1aaff2998830bd0358226f27f4185"
|
||||||
checksum = "f697b2c273e4629c782205e563282c08a74fe237ca8dd36cf10f862951887a70"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-schema",
|
"arrow-schema",
|
||||||
@@ -4148,7 +4135,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lancedb"
|
name = "lancedb"
|
||||||
version = "0.19.0-beta.11"
|
version = "0.19.1-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
@@ -4235,7 +4222,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lancedb-node"
|
name = "lancedb-node"
|
||||||
version = "0.19.0-beta.11"
|
version = "0.19.1-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-ipc",
|
"arrow-ipc",
|
||||||
@@ -4260,7 +4247,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lancedb-nodejs"
|
name = "lancedb-nodejs"
|
||||||
version = "0.19.0-beta.11"
|
version = "0.19.1-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow-array",
|
"arrow-array",
|
||||||
"arrow-ipc",
|
"arrow-ipc",
|
||||||
@@ -4279,7 +4266,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lancedb-python"
|
name = "lancedb-python"
|
||||||
version = "0.22.0-beta.11"
|
version = "0.22.1-beta.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrow",
|
"arrow",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
@@ -4681,7 +4668,7 @@ checksum = "c402a4092d5e204f32c9e155431046831fa712637043c58cb73bc6bc6c9663b5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4749,7 +4736,7 @@ dependencies = [
|
|||||||
"napi-derive-backend",
|
"napi-derive-backend",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4764,7 +4751,7 @@ dependencies = [
|
|||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
"semver 1.0.26",
|
"semver 1.0.26",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4964,7 +4951,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5231,7 +5218,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5657,7 +5644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
|
checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5704,7 +5691,7 @@ dependencies = [
|
|||||||
"prost",
|
"prost",
|
||||||
"prost-types",
|
"prost-types",
|
||||||
"regex",
|
"regex",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -5718,7 +5705,7 @@ dependencies = [
|
|||||||
"itertools 0.14.0",
|
"itertools 0.14.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5732,9 +5719,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "psm"
|
name = "psm"
|
||||||
version = "0.1.25"
|
version = "0.1.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88"
|
checksum = "6e944464ec8536cd1beb0bbfd96987eb5e3b72f2ecdafdc5c769a37f1fa2ae1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
@@ -5791,7 +5778,7 @@ checksum = "b2df2884957d2476731f987673befac5d521dff10abb0a7cbe12015bc7702fe9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5823,7 +5810,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-macros-backend",
|
"pyo3-macros-backend",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5836,14 +5823,14 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"pyo3-build-config",
|
"pyo3-build-config",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.37.4"
|
version = "0.37.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4ce8c88de324ff838700f36fb6ab86c96df0e3c4ab6ef3a9b2044465cce1369"
|
checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -6094,7 +6081,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b"
|
checksum = "76009fbe0614077fc1a2ce255e3a1881a2e3a3527097d5dc6d8212c585e7e38b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6312,7 +6299,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"relative-path",
|
"relative-path",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -6646,7 +6633,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6709,7 +6696,7 @@ dependencies = [
|
|||||||
"darling",
|
"darling",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6842,7 +6829,7 @@ dependencies = [
|
|||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6916,7 +6903,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -6927,9 +6914,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stacker"
|
name = "stacker"
|
||||||
version = "0.1.20"
|
version = "0.1.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "601f9201feb9b09c00266478bf459952b9ef9a6b94edb2f21eba14ab681a60a9"
|
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -6993,7 +6980,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7015,9 +7002,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.100"
|
version = "2.0.101"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -7052,7 +7039,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7308,7 +7295,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7319,7 +7306,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7454,7 +7441,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7503,15 +7490,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.8"
|
version = "0.6.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
version = "0.22.24"
|
version = "0.22.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
|
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.9.0",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -7564,7 +7551,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -7834,7 +7821,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -7869,7 +7856,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -7918,9 +7905,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
version = "0.26.8"
|
version = "0.26.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9"
|
checksum = "29aad86cec885cafd03e8305fd727c418e970a521322c91688414d5b8efba16b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
]
|
]
|
||||||
@@ -8031,7 +8018,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8042,7 +8029,7 @@ checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8053,7 +8040,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8064,7 +8051,7 @@ checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8479,7 +8466,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -8509,7 +8496,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8520,7 +8507,7 @@ checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -8540,7 +8527,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -8569,7 +8556,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.100",
|
"syn 2.0.101",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
16
Cargo.toml
16
Cargo.toml
@@ -21,14 +21,14 @@ categories = ["database-implementations"]
|
|||||||
rust-version = "1.78.0"
|
rust-version = "1.78.0"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
lance = { "version" = "=0.26.0", "features" = ["dynamodb"] }
|
lance = { "version" = "=0.27.0", "features" = ["dynamodb"], tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-io = "=0.26.0"
|
lance-io = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-index = "=0.26.0"
|
lance-index = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-linalg = "=0.26.0"
|
lance-linalg = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-table = "=0.26.0"
|
lance-table = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-testing = "=0.26.0"
|
lance-testing = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-datafusion = "=0.26.0"
|
lance-datafusion = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
lance-encoding = "=0.26.0"
|
lance-encoding = { version = "=0.27.0", tag = "v0.27.0-beta.2", git="https://github.com/lancedb/lance.git" }
|
||||||
# Note that this one does not include pyarrow
|
# Note that this one does not include pyarrow
|
||||||
arrow = { version = "54.1", optional = false }
|
arrow = { version = "54.1", optional = false }
|
||||||
arrow-array = "54.1"
|
arrow-array = "54.1"
|
||||||
|
|||||||
@@ -33,20 +33,20 @@ Construct a MergeInsertBuilder. __Internal use only.__
|
|||||||
### execute()
|
### execute()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
execute(data): Promise<void>
|
execute(data): Promise<MergeResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Executes the merge insert operation
|
Executes the merge insert operation
|
||||||
|
|
||||||
Nothing is returned but the `Table` is updated
|
|
||||||
|
|
||||||
#### Parameters
|
#### Parameters
|
||||||
|
|
||||||
* **data**: [`Data`](../type-aliases/Data.md)
|
* **data**: [`Data`](../type-aliases/Data.md)
|
||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`MergeResult`](../interfaces/MergeResult.md)>
|
||||||
|
|
||||||
|
the merge result
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ Returns the name of the table
|
|||||||
### add()
|
### add()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract add(data, options?): Promise<void>
|
abstract add(data, options?): Promise<AddResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Insert records into this Table.
|
Insert records into this Table.
|
||||||
@@ -54,14 +54,17 @@ Insert records into this Table.
|
|||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`AddResult`](../interfaces/AddResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the new version number of the table
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
### addColumns()
|
### addColumns()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract addColumns(newColumnTransforms): Promise<void>
|
abstract addColumns(newColumnTransforms): Promise<AddColumnsResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Add new columns with defined values.
|
Add new columns with defined values.
|
||||||
@@ -76,14 +79,17 @@ Add new columns with defined values.
|
|||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`AddColumnsResult`](../interfaces/AddColumnsResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the new version number of the table after adding the columns.
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
### alterColumns()
|
### alterColumns()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract alterColumns(columnAlterations): Promise<void>
|
abstract alterColumns(columnAlterations): Promise<AlterColumnsResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Alter the name or nullability of columns.
|
Alter the name or nullability of columns.
|
||||||
@@ -96,7 +102,10 @@ Alter the name or nullability of columns.
|
|||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`AlterColumnsResult`](../interfaces/AlterColumnsResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the new version number of the table after altering the columns.
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
@@ -252,7 +261,7 @@ await table.createIndex("my_float_col");
|
|||||||
### delete()
|
### delete()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract delete(predicate): Promise<void>
|
abstract delete(predicate): Promise<DeleteResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Delete the rows that satisfy the predicate.
|
Delete the rows that satisfy the predicate.
|
||||||
@@ -263,7 +272,10 @@ Delete the rows that satisfy the predicate.
|
|||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`DeleteResult`](../interfaces/DeleteResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the new version number of the table
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
@@ -284,7 +296,7 @@ Return a brief description of the table
|
|||||||
### dropColumns()
|
### dropColumns()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract dropColumns(columnNames): Promise<void>
|
abstract dropColumns(columnNames): Promise<DropColumnsResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Drop one or more columns from the dataset
|
Drop one or more columns from the dataset
|
||||||
@@ -303,7 +315,10 @@ then call ``cleanup_files`` to remove the old files.
|
|||||||
|
|
||||||
#### Returns
|
#### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`DropColumnsResult`](../interfaces/DropColumnsResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the new version number of the table after dropping the columns.
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
@@ -615,6 +630,22 @@ of the given query
|
|||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
### stats()
|
||||||
|
|
||||||
|
```ts
|
||||||
|
abstract stats(): Promise<TableStatistics>
|
||||||
|
```
|
||||||
|
|
||||||
|
Returns table and fragment statistics
|
||||||
|
|
||||||
|
#### Returns
|
||||||
|
|
||||||
|
`Promise`<[`TableStatistics`](../interfaces/TableStatistics.md)>
|
||||||
|
|
||||||
|
The table and fragment statistics
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
### tags()
|
### tags()
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
@@ -662,7 +693,7 @@ Return the table as an arrow table
|
|||||||
#### update(opts)
|
#### update(opts)
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract update(opts): Promise<void>
|
abstract update(opts): Promise<UpdateResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Update existing records in the Table
|
Update existing records in the Table
|
||||||
@@ -673,7 +704,10 @@ Update existing records in the Table
|
|||||||
|
|
||||||
##### Returns
|
##### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`UpdateResult`](../interfaces/UpdateResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object containing
|
||||||
|
the number of rows updated and the new version number
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -684,7 +718,7 @@ table.update({where:"x = 2", values:{"vector": [10, 10]}})
|
|||||||
#### update(opts)
|
#### update(opts)
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract update(opts): Promise<void>
|
abstract update(opts): Promise<UpdateResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Update existing records in the Table
|
Update existing records in the Table
|
||||||
@@ -695,7 +729,10 @@ Update existing records in the Table
|
|||||||
|
|
||||||
##### Returns
|
##### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`UpdateResult`](../interfaces/UpdateResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object containing
|
||||||
|
the number of rows updated and the new version number
|
||||||
|
|
||||||
##### Example
|
##### Example
|
||||||
|
|
||||||
@@ -706,7 +743,7 @@ table.update({where:"x = 2", valuesSql:{"x": "x + 1"}})
|
|||||||
#### update(updates, options)
|
#### update(updates, options)
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
abstract update(updates, options?): Promise<void>
|
abstract update(updates, options?): Promise<UpdateResult>
|
||||||
```
|
```
|
||||||
|
|
||||||
Update existing records in the Table
|
Update existing records in the Table
|
||||||
@@ -729,10 +766,6 @@ repeatedly calilng this method.
|
|||||||
* **updates**: `Record`<`string`, `string`> \| `Map`<`string`, `string`>
|
* **updates**: `Record`<`string`, `string`> \| `Map`<`string`, `string`>
|
||||||
the
|
the
|
||||||
columns to update
|
columns to update
|
||||||
Keys in the map should specify the name of the column to update.
|
|
||||||
Values in the map provide the new value of the column. These can
|
|
||||||
be SQL literal strings (e.g. "7" or "'foo'") or they can be expressions
|
|
||||||
based on the row being updated (e.g. "my_col + 1")
|
|
||||||
|
|
||||||
* **options?**: `Partial`<[`UpdateOptions`](../interfaces/UpdateOptions.md)>
|
* **options?**: `Partial`<[`UpdateOptions`](../interfaces/UpdateOptions.md)>
|
||||||
additional options to control
|
additional options to control
|
||||||
@@ -740,7 +773,15 @@ repeatedly calilng this method.
|
|||||||
|
|
||||||
##### Returns
|
##### Returns
|
||||||
|
|
||||||
`Promise`<`void`>
|
`Promise`<[`UpdateResult`](../interfaces/UpdateResult.md)>
|
||||||
|
|
||||||
|
A promise that resolves to an object
|
||||||
|
containing the number of rows updated and the new version number
|
||||||
|
|
||||||
|
Keys in the map should specify the name of the column to update.
|
||||||
|
Values in the map provide the new value of the column. These can
|
||||||
|
be SQL literal strings (e.g. "7" or "'foo'") or they can be expressions
|
||||||
|
based on the row being updated (e.g. "my_col + 1")
|
||||||
|
|
||||||
***
|
***
|
||||||
|
|
||||||
|
|||||||
@@ -34,14 +34,21 @@
|
|||||||
|
|
||||||
## Interfaces
|
## Interfaces
|
||||||
|
|
||||||
|
- [AddColumnsResult](interfaces/AddColumnsResult.md)
|
||||||
- [AddColumnsSql](interfaces/AddColumnsSql.md)
|
- [AddColumnsSql](interfaces/AddColumnsSql.md)
|
||||||
- [AddDataOptions](interfaces/AddDataOptions.md)
|
- [AddDataOptions](interfaces/AddDataOptions.md)
|
||||||
|
- [AddResult](interfaces/AddResult.md)
|
||||||
|
- [AlterColumnsResult](interfaces/AlterColumnsResult.md)
|
||||||
- [ClientConfig](interfaces/ClientConfig.md)
|
- [ClientConfig](interfaces/ClientConfig.md)
|
||||||
- [ColumnAlteration](interfaces/ColumnAlteration.md)
|
- [ColumnAlteration](interfaces/ColumnAlteration.md)
|
||||||
- [CompactionStats](interfaces/CompactionStats.md)
|
- [CompactionStats](interfaces/CompactionStats.md)
|
||||||
- [ConnectionOptions](interfaces/ConnectionOptions.md)
|
- [ConnectionOptions](interfaces/ConnectionOptions.md)
|
||||||
- [CreateTableOptions](interfaces/CreateTableOptions.md)
|
- [CreateTableOptions](interfaces/CreateTableOptions.md)
|
||||||
|
- [DeleteResult](interfaces/DeleteResult.md)
|
||||||
|
- [DropColumnsResult](interfaces/DropColumnsResult.md)
|
||||||
- [ExecutableQuery](interfaces/ExecutableQuery.md)
|
- [ExecutableQuery](interfaces/ExecutableQuery.md)
|
||||||
|
- [FragmentStatistics](interfaces/FragmentStatistics.md)
|
||||||
|
- [FragmentSummaryStats](interfaces/FragmentSummaryStats.md)
|
||||||
- [FtsOptions](interfaces/FtsOptions.md)
|
- [FtsOptions](interfaces/FtsOptions.md)
|
||||||
- [FullTextQuery](interfaces/FullTextQuery.md)
|
- [FullTextQuery](interfaces/FullTextQuery.md)
|
||||||
- [FullTextSearchOptions](interfaces/FullTextSearchOptions.md)
|
- [FullTextSearchOptions](interfaces/FullTextSearchOptions.md)
|
||||||
@@ -52,6 +59,7 @@
|
|||||||
- [IndexStatistics](interfaces/IndexStatistics.md)
|
- [IndexStatistics](interfaces/IndexStatistics.md)
|
||||||
- [IvfFlatOptions](interfaces/IvfFlatOptions.md)
|
- [IvfFlatOptions](interfaces/IvfFlatOptions.md)
|
||||||
- [IvfPqOptions](interfaces/IvfPqOptions.md)
|
- [IvfPqOptions](interfaces/IvfPqOptions.md)
|
||||||
|
- [MergeResult](interfaces/MergeResult.md)
|
||||||
- [OpenTableOptions](interfaces/OpenTableOptions.md)
|
- [OpenTableOptions](interfaces/OpenTableOptions.md)
|
||||||
- [OptimizeOptions](interfaces/OptimizeOptions.md)
|
- [OptimizeOptions](interfaces/OptimizeOptions.md)
|
||||||
- [OptimizeStats](interfaces/OptimizeStats.md)
|
- [OptimizeStats](interfaces/OptimizeStats.md)
|
||||||
@@ -59,8 +67,10 @@
|
|||||||
- [RemovalStats](interfaces/RemovalStats.md)
|
- [RemovalStats](interfaces/RemovalStats.md)
|
||||||
- [RetryConfig](interfaces/RetryConfig.md)
|
- [RetryConfig](interfaces/RetryConfig.md)
|
||||||
- [TableNamesOptions](interfaces/TableNamesOptions.md)
|
- [TableNamesOptions](interfaces/TableNamesOptions.md)
|
||||||
|
- [TableStatistics](interfaces/TableStatistics.md)
|
||||||
- [TimeoutConfig](interfaces/TimeoutConfig.md)
|
- [TimeoutConfig](interfaces/TimeoutConfig.md)
|
||||||
- [UpdateOptions](interfaces/UpdateOptions.md)
|
- [UpdateOptions](interfaces/UpdateOptions.md)
|
||||||
|
- [UpdateResult](interfaces/UpdateResult.md)
|
||||||
- [Version](interfaces/Version.md)
|
- [Version](interfaces/Version.md)
|
||||||
|
|
||||||
## Type Aliases
|
## Type Aliases
|
||||||
|
|||||||
15
docs/src/js/interfaces/AddColumnsResult.md
Normal file
15
docs/src/js/interfaces/AddColumnsResult.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / AddColumnsResult
|
||||||
|
|
||||||
|
# Interface: AddColumnsResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
15
docs/src/js/interfaces/AddResult.md
Normal file
15
docs/src/js/interfaces/AddResult.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / AddResult
|
||||||
|
|
||||||
|
# Interface: AddResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
15
docs/src/js/interfaces/AlterColumnsResult.md
Normal file
15
docs/src/js/interfaces/AlterColumnsResult.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / AlterColumnsResult
|
||||||
|
|
||||||
|
# Interface: AlterColumnsResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
15
docs/src/js/interfaces/DeleteResult.md
Normal file
15
docs/src/js/interfaces/DeleteResult.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / DeleteResult
|
||||||
|
|
||||||
|
# Interface: DeleteResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
15
docs/src/js/interfaces/DropColumnsResult.md
Normal file
15
docs/src/js/interfaces/DropColumnsResult.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / DropColumnsResult
|
||||||
|
|
||||||
|
# Interface: DropColumnsResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
37
docs/src/js/interfaces/FragmentStatistics.md
Normal file
37
docs/src/js/interfaces/FragmentStatistics.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / FragmentStatistics
|
||||||
|
|
||||||
|
# Interface: FragmentStatistics
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### lengths
|
||||||
|
|
||||||
|
```ts
|
||||||
|
lengths: FragmentSummaryStats;
|
||||||
|
```
|
||||||
|
|
||||||
|
Statistics on the number of rows in the table fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numFragments
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numFragments: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of fragments in the table
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numSmallFragments
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numSmallFragments: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of uncompacted fragments in the table
|
||||||
77
docs/src/js/interfaces/FragmentSummaryStats.md
Normal file
77
docs/src/js/interfaces/FragmentSummaryStats.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / FragmentSummaryStats
|
||||||
|
|
||||||
|
# Interface: FragmentSummaryStats
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### max
|
||||||
|
|
||||||
|
```ts
|
||||||
|
max: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of rows in the fragment with the most rows
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### mean
|
||||||
|
|
||||||
|
```ts
|
||||||
|
mean: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The mean number of rows in the fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### min
|
||||||
|
|
||||||
|
```ts
|
||||||
|
min: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of rows in the fragment with the fewest rows
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### p25
|
||||||
|
|
||||||
|
```ts
|
||||||
|
p25: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The 25th percentile of number of rows in the fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### p50
|
||||||
|
|
||||||
|
```ts
|
||||||
|
p50: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The 50th percentile of number of rows in the fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### p75
|
||||||
|
|
||||||
|
```ts
|
||||||
|
p75: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The 75th percentile of number of rows in the fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### p99
|
||||||
|
|
||||||
|
```ts
|
||||||
|
p99: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The 99th percentile of number of rows in the fragments
|
||||||
39
docs/src/js/interfaces/MergeResult.md
Normal file
39
docs/src/js/interfaces/MergeResult.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / MergeResult
|
||||||
|
|
||||||
|
# Interface: MergeResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### numDeletedRows
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numDeletedRows: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numInsertedRows
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numInsertedRows: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numUpdatedRows
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numUpdatedRows: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
47
docs/src/js/interfaces/TableStatistics.md
Normal file
47
docs/src/js/interfaces/TableStatistics.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / TableStatistics
|
||||||
|
|
||||||
|
# Interface: TableStatistics
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### fragmentStats
|
||||||
|
|
||||||
|
```ts
|
||||||
|
fragmentStats: FragmentStatistics;
|
||||||
|
```
|
||||||
|
|
||||||
|
Statistics on table fragments
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numIndices
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numIndices: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of indices in the table
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### numRows
|
||||||
|
|
||||||
|
```ts
|
||||||
|
numRows: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The number of rows in the table
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### totalBytes
|
||||||
|
|
||||||
|
```ts
|
||||||
|
totalBytes: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
The total number of bytes in the table
|
||||||
23
docs/src/js/interfaces/UpdateResult.md
Normal file
23
docs/src/js/interfaces/UpdateResult.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
[**@lancedb/lancedb**](../README.md) • **Docs**
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
[@lancedb/lancedb](../globals.md) / UpdateResult
|
||||||
|
|
||||||
|
# Interface: UpdateResult
|
||||||
|
|
||||||
|
## Properties
|
||||||
|
|
||||||
|
### rowsUpdated
|
||||||
|
|
||||||
|
```ts
|
||||||
|
rowsUpdated: number;
|
||||||
|
```
|
||||||
|
|
||||||
|
***
|
||||||
|
|
||||||
|
### version
|
||||||
|
|
||||||
|
```ts
|
||||||
|
version: number;
|
||||||
|
```
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>com.lancedb</groupId>
|
<groupId>com.lancedb</groupId>
|
||||||
<artifactId>lancedb-parent</artifactId>
|
<artifactId>lancedb-parent</artifactId>
|
||||||
<version>0.19.0-final.0</version>
|
<version>0.19.1-beta.1</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.lancedb</groupId>
|
<groupId>com.lancedb</groupId>
|
||||||
<artifactId>lancedb-parent</artifactId>
|
<artifactId>lancedb-parent</artifactId>
|
||||||
<version>0.19.0-final.0</version>
|
<version>0.19.1-beta.1</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|
||||||
<name>LanceDB Parent</name>
|
<name>LanceDB Parent</name>
|
||||||
|
|||||||
44
node/package-lock.json
generated
44
node/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64",
|
"x64",
|
||||||
"arm64"
|
"arm64"
|
||||||
@@ -52,11 +52,11 @@
|
|||||||
"uuid": "^9.0.0"
|
"uuid": "^9.0.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@lancedb/vectordb-darwin-arm64": "0.19.0",
|
"@lancedb/vectordb-darwin-arm64": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-darwin-x64": "0.19.0",
|
"@lancedb/vectordb-darwin-x64": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-linux-arm64-gnu": "0.19.0",
|
"@lancedb/vectordb-linux-arm64-gnu": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-linux-x64-gnu": "0.19.0",
|
"@lancedb/vectordb-linux-x64-gnu": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-win32-x64-msvc": "0.19.0"
|
"@lancedb/vectordb-win32-x64-msvc": "0.19.1-beta.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@apache-arrow/ts": "^14.0.2",
|
"@apache-arrow/ts": "^14.0.2",
|
||||||
@@ -327,9 +327,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-darwin-arm64": {
|
"node_modules/@lancedb/vectordb-darwin-arm64": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.19.1-beta.1.tgz",
|
||||||
"integrity": "sha512-cR04V8azbrEfJ3FX5WJjwvkmKySI+dS4laBWqtXaMyLDSX034E3P3Ve8jKfYdP4NaBSGlGZlySpGawEEBLH92A==",
|
"integrity": "sha512-Epvel0pF5TM6MtIWQ2KhqezqSSHTL3Wr7a2rGAwz6X/XY23i6DbMPpPs0HyeIDzDrhxNfE3cz3S+SiCA6xpR0g==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -340,9 +340,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-darwin-x64": {
|
"node_modules/@lancedb/vectordb-darwin-x64": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.19.1-beta.1.tgz",
|
||||||
"integrity": "sha512-qDrui0LR4f2QqFovDx8VcbVY5So5gi0HgHWeh6kypl4R4SS+pYfW3jTPVDz1YpxxlB9GHACM5qBdul6KFpnoug==",
|
"integrity": "sha512-hOiUSlIoISbiXytp46hToi/r6sF5pImAsfbzCsIq8ExDV4TPa8fjbhcIT80vxxOwc2mpSSK4HsVJYod95RSbEQ==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -353,9 +353,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-linux-arm64-gnu": {
|
"node_modules/@lancedb/vectordb-linux-arm64-gnu": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.19.1-beta.1.tgz",
|
||||||
"integrity": "sha512-peoq/Mh9ml2h6xSngbfVt0yeuIO3ln4/dG9mfubXPJyNlM7tANzD+IY0Xs+B03m+fXbJ7LFZ8de4aIP9pWh4iQ==",
|
"integrity": "sha512-/1JhGVDEngwrlM8o2TNW8G6nJ9U/VgHKAORmj/cTA7O30helJIoo9jfvUAUy+vZ4VoEwRXQbMI+gaYTg0l3MTg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"arm64"
|
"arm64"
|
||||||
],
|
],
|
||||||
@@ -366,9 +366,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-linux-x64-gnu": {
|
"node_modules/@lancedb/vectordb-linux-x64-gnu": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.19.1-beta.1.tgz",
|
||||||
"integrity": "sha512-MUsOXk+InI0ywuygcHvYG8+awrJUnsbrUstTPETN2+QAV7QOX+TlafupLUUrfp1/pUOPt/ZraHEaqFRw1Vdxqg==",
|
"integrity": "sha512-zNRGSSUt8nTJMmll4NdxhQjwxR8Rezq3T4dsRoiDts5ienMam5HFjYiZ3FkDZQo16rgq2BcbFuH1G8u1chywlg==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
@@ -379,9 +379,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/@lancedb/vectordb-win32-x64-msvc": {
|
"node_modules/@lancedb/vectordb-win32-x64-msvc": {
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.19.1-beta.1.tgz",
|
||||||
"integrity": "sha512-stk3uqMAbHxTodmzqMPKUl54GBfVKNDMR3EIo3d299QcXyOdSuEeHgeZa+iy0hHeIFL0TqHi4o8tStNzFLBAHg==",
|
"integrity": "sha512-yV550AJGlsIFdm1KoHQPJ1TZx121ZXCIdebBtBZj3wOObIhyB/i0kZAtGvwjkmr7EYyfzt1EHZzbjSGVdehIAA==",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64"
|
"x64"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "vectordb",
|
"name": "vectordb",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"description": " Serverless, low-latency vector database for AI applications",
|
"description": " Serverless, low-latency vector database for AI applications",
|
||||||
"private": false,
|
"private": false,
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
@@ -89,10 +89,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"@lancedb/vectordb-darwin-x64": "0.19.0",
|
"@lancedb/vectordb-darwin-x64": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-darwin-arm64": "0.19.0",
|
"@lancedb/vectordb-darwin-arm64": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-linux-x64-gnu": "0.19.0",
|
"@lancedb/vectordb-linux-x64-gnu": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-linux-arm64-gnu": "0.19.0",
|
"@lancedb/vectordb-linux-arm64-gnu": "0.19.1-beta.1",
|
||||||
"@lancedb/vectordb-win32-x64-msvc": "0.19.0"
|
"@lancedb/vectordb-win32-x64-msvc": "0.19.1-beta.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-nodejs"
|
name = "lancedb-nodejs"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
version = "0.19.0"
|
version = "0.19.1-beta.1"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
description.workspace = true
|
description.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
|
|||||||
@@ -374,6 +374,71 @@ describe.each([arrow15, arrow16, arrow17, arrow18])(
|
|||||||
expect(table2.numRows).toBe(4);
|
expect(table2.numRows).toBe(4);
|
||||||
expect(table2.schema).toEqual(schema);
|
expect(table2.schema).toEqual(schema);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should correctly retain values in nested struct fields", async function () {
|
||||||
|
// Define test data with nested struct
|
||||||
|
const testData = [
|
||||||
|
{
|
||||||
|
id: "doc1",
|
||||||
|
vector: [1, 2, 3],
|
||||||
|
metadata: {
|
||||||
|
filePath: "/path/to/file1.ts",
|
||||||
|
startLine: 10,
|
||||||
|
endLine: 20,
|
||||||
|
text: "function test() { return true; }",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "doc2",
|
||||||
|
vector: [4, 5, 6],
|
||||||
|
metadata: {
|
||||||
|
filePath: "/path/to/file2.ts",
|
||||||
|
startLine: 30,
|
||||||
|
endLine: 40,
|
||||||
|
text: "function test2() { return false; }",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// Create Arrow table from the data
|
||||||
|
const table = makeArrowTable(testData);
|
||||||
|
|
||||||
|
// Verify schema has the nested struct fields
|
||||||
|
const metadataField = table.schema.fields.find(
|
||||||
|
(f) => f.name === "metadata",
|
||||||
|
);
|
||||||
|
expect(metadataField).toBeDefined();
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: accessing fields in different Arrow versions
|
||||||
|
const childNames = metadataField?.type.children.map((c: any) => c.name);
|
||||||
|
expect(childNames).toEqual([
|
||||||
|
"filePath",
|
||||||
|
"startLine",
|
||||||
|
"endLine",
|
||||||
|
"text",
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Convert to buffer and back (simulating storage and retrieval)
|
||||||
|
const buf = await fromTableToBuffer(table);
|
||||||
|
const retrievedTable = tableFromIPC(buf);
|
||||||
|
|
||||||
|
// Verify the retrieved table has the same structure
|
||||||
|
const rows = [];
|
||||||
|
for (let i = 0; i < retrievedTable.numRows; i++) {
|
||||||
|
rows.push(retrievedTable.get(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check values in the first row
|
||||||
|
const firstRow = rows[0];
|
||||||
|
expect(firstRow.id).toBe("doc1");
|
||||||
|
expect(firstRow.vector.toJSON()).toEqual([1, 2, 3]);
|
||||||
|
|
||||||
|
// Verify metadata values are preserved (this is where the bug is)
|
||||||
|
expect(firstRow.metadata).toBeDefined();
|
||||||
|
expect(firstRow.metadata.filePath).toBe("/path/to/file1.ts");
|
||||||
|
expect(firstRow.metadata.startLine).toBe(10);
|
||||||
|
expect(firstRow.metadata.endLine).toBe(20);
|
||||||
|
expect(firstRow.metadata.text).toBe("function test() { return true; }");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
class DummyEmbedding extends EmbeddingFunction<string> {
|
class DummyEmbedding extends EmbeddingFunction<string> {
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import {
|
|||||||
} from "../lancedb/embedding";
|
} from "../lancedb/embedding";
|
||||||
import { Index } from "../lancedb/indices";
|
import { Index } from "../lancedb/indices";
|
||||||
import { instanceOfFullTextQuery } from "../lancedb/query";
|
import { instanceOfFullTextQuery } from "../lancedb/query";
|
||||||
|
import exp = require("constants");
|
||||||
|
|
||||||
describe.each([arrow15, arrow16, arrow17, arrow18])(
|
describe.each([arrow15, arrow16, arrow17, arrow18])(
|
||||||
"Given a table",
|
"Given a table",
|
||||||
@@ -71,8 +72,33 @@ describe.each([arrow15, arrow16, arrow17, arrow18])(
|
|||||||
await expect(table.countRows()).resolves.toBe(3);
|
await expect(table.countRows()).resolves.toBe(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should overwrite data if asked", async () => {
|
it("should show table stats", async () => {
|
||||||
await table.add([{ id: 1 }, { id: 2 }]);
|
await table.add([{ id: 1 }, { id: 2 }]);
|
||||||
|
await table.add([{ id: 1 }]);
|
||||||
|
await expect(table.stats()).resolves.toEqual({
|
||||||
|
fragmentStats: {
|
||||||
|
lengths: {
|
||||||
|
max: 2,
|
||||||
|
mean: 1,
|
||||||
|
min: 1,
|
||||||
|
p25: 1,
|
||||||
|
p50: 2,
|
||||||
|
p75: 2,
|
||||||
|
p99: 2,
|
||||||
|
},
|
||||||
|
numFragments: 2,
|
||||||
|
numSmallFragments: 2,
|
||||||
|
},
|
||||||
|
numIndices: 0,
|
||||||
|
numRows: 3,
|
||||||
|
totalBytes: 24,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should overwrite data if asked", async () => {
|
||||||
|
const addRes = await table.add([{ id: 1 }, { id: 2 }]);
|
||||||
|
expect(addRes).toHaveProperty("version");
|
||||||
|
expect(addRes.version).toBe(2);
|
||||||
await table.add([{ id: 1 }], { mode: "overwrite" });
|
await table.add([{ id: 1 }], { mode: "overwrite" });
|
||||||
await expect(table.countRows()).resolves.toBe(1);
|
await expect(table.countRows()).resolves.toBe(1);
|
||||||
});
|
});
|
||||||
@@ -88,7 +114,11 @@ describe.each([arrow15, arrow16, arrow17, arrow18])(
|
|||||||
await table.add([{ id: 1 }]);
|
await table.add([{ id: 1 }]);
|
||||||
expect(await table.countRows("id == 1")).toBe(1);
|
expect(await table.countRows("id == 1")).toBe(1);
|
||||||
expect(await table.countRows("id == 7")).toBe(0);
|
expect(await table.countRows("id == 7")).toBe(0);
|
||||||
await table.update({ id: "7" });
|
const updateRes = await table.update({ id: "7" });
|
||||||
|
expect(updateRes).toHaveProperty("version");
|
||||||
|
expect(updateRes.version).toBe(3);
|
||||||
|
expect(updateRes).toHaveProperty("rowsUpdated");
|
||||||
|
expect(updateRes.rowsUpdated).toBe(1);
|
||||||
expect(await table.countRows("id == 1")).toBe(0);
|
expect(await table.countRows("id == 1")).toBe(0);
|
||||||
expect(await table.countRows("id == 7")).toBe(1);
|
expect(await table.countRows("id == 7")).toBe(1);
|
||||||
await table.add([{ id: 2 }]);
|
await table.add([{ id: 2 }]);
|
||||||
@@ -315,11 +345,17 @@ describe("merge insert", () => {
|
|||||||
{ a: 3, b: "y" },
|
{ a: 3, b: "y" },
|
||||||
{ a: 4, b: "z" },
|
{ a: 4, b: "z" },
|
||||||
];
|
];
|
||||||
await table
|
const mergeInsertRes = await table
|
||||||
.mergeInsert("a")
|
.mergeInsert("a")
|
||||||
.whenMatchedUpdateAll()
|
.whenMatchedUpdateAll()
|
||||||
.whenNotMatchedInsertAll()
|
.whenNotMatchedInsertAll()
|
||||||
.execute(newData);
|
.execute(newData);
|
||||||
|
expect(mergeInsertRes).toHaveProperty("version");
|
||||||
|
expect(mergeInsertRes.version).toBe(2);
|
||||||
|
expect(mergeInsertRes.numInsertedRows).toBe(1);
|
||||||
|
expect(mergeInsertRes.numUpdatedRows).toBe(2);
|
||||||
|
expect(mergeInsertRes.numDeletedRows).toBe(0);
|
||||||
|
|
||||||
const expected = [
|
const expected = [
|
||||||
{ a: 1, b: "a" },
|
{ a: 1, b: "a" },
|
||||||
{ a: 2, b: "x" },
|
{ a: 2, b: "x" },
|
||||||
@@ -337,10 +373,12 @@ describe("merge insert", () => {
|
|||||||
{ a: 3, b: "y" },
|
{ a: 3, b: "y" },
|
||||||
{ a: 4, b: "z" },
|
{ a: 4, b: "z" },
|
||||||
];
|
];
|
||||||
await table
|
const mergeInsertRes = await table
|
||||||
.mergeInsert("a")
|
.mergeInsert("a")
|
||||||
.whenMatchedUpdateAll({ where: "target.b = 'b'" })
|
.whenMatchedUpdateAll({ where: "target.b = 'b'" })
|
||||||
.execute(newData);
|
.execute(newData);
|
||||||
|
expect(mergeInsertRes).toHaveProperty("version");
|
||||||
|
expect(mergeInsertRes.version).toBe(2);
|
||||||
|
|
||||||
const expected = [
|
const expected = [
|
||||||
{ a: 1, b: "a" },
|
{ a: 1, b: "a" },
|
||||||
@@ -1000,15 +1038,19 @@ describe("schema evolution", function () {
|
|||||||
{ id: 1n, vector: [0.1, 0.2] },
|
{ id: 1n, vector: [0.1, 0.2] },
|
||||||
]);
|
]);
|
||||||
// Can create a non-nullable column only through addColumns at the moment.
|
// Can create a non-nullable column only through addColumns at the moment.
|
||||||
await table.addColumns([
|
const addColumnsRes = await table.addColumns([
|
||||||
{ name: "price", valueSql: "cast(10.0 as double)" },
|
{ name: "price", valueSql: "cast(10.0 as double)" },
|
||||||
]);
|
]);
|
||||||
|
expect(addColumnsRes).toHaveProperty("version");
|
||||||
|
expect(addColumnsRes.version).toBe(2);
|
||||||
expect(await table.schema()).toEqual(schema);
|
expect(await table.schema()).toEqual(schema);
|
||||||
|
|
||||||
await table.alterColumns([
|
const alterColumnsRes = await table.alterColumns([
|
||||||
{ path: "id", rename: "new_id" },
|
{ path: "id", rename: "new_id" },
|
||||||
{ path: "price", nullable: true },
|
{ path: "price", nullable: true },
|
||||||
]);
|
]);
|
||||||
|
expect(alterColumnsRes).toHaveProperty("version");
|
||||||
|
expect(alterColumnsRes.version).toBe(3);
|
||||||
|
|
||||||
const expectedSchema = new Schema([
|
const expectedSchema = new Schema([
|
||||||
new Field("new_id", new Int64(), true),
|
new Field("new_id", new Int64(), true),
|
||||||
@@ -1126,7 +1168,9 @@ describe("schema evolution", function () {
|
|||||||
const table = await con.createTable("vectors", [
|
const table = await con.createTable("vectors", [
|
||||||
{ id: 1n, vector: [0.1, 0.2] },
|
{ id: 1n, vector: [0.1, 0.2] },
|
||||||
]);
|
]);
|
||||||
await table.dropColumns(["vector"]);
|
const dropColumnsRes = await table.dropColumns(["vector"]);
|
||||||
|
expect(dropColumnsRes).toHaveProperty("version");
|
||||||
|
expect(dropColumnsRes.version).toBe(2);
|
||||||
|
|
||||||
const expectedSchema = new Schema([new Field("id", new Int64(), true)]);
|
const expectedSchema = new Schema([new Field("id", new Int64(), true)]);
|
||||||
expect(await table.schema()).toEqual(expectedSchema);
|
expect(await table.schema()).toEqual(expectedSchema);
|
||||||
|
|||||||
@@ -639,8 +639,9 @@ function transposeData(
|
|||||||
): Vector {
|
): Vector {
|
||||||
if (field.type instanceof Struct) {
|
if (field.type instanceof Struct) {
|
||||||
const childFields = field.type.children;
|
const childFields = field.type.children;
|
||||||
|
const fullPath = [...path, field.name];
|
||||||
const childVectors = childFields.map((child) => {
|
const childVectors = childFields.map((child) => {
|
||||||
return transposeData(data, child, [...path, child.name]);
|
return transposeData(data, child, fullPath);
|
||||||
});
|
});
|
||||||
const structData = makeData({
|
const structData = makeData({
|
||||||
type: field.type,
|
type: field.type,
|
||||||
@@ -652,7 +653,14 @@ function transposeData(
|
|||||||
const values = data.map((datum) => {
|
const values = data.map((datum) => {
|
||||||
let current: unknown = datum;
|
let current: unknown = datum;
|
||||||
for (const key of valuesPath) {
|
for (const key of valuesPath) {
|
||||||
if (isObject(current) && Object.hasOwn(current, key)) {
|
if (current == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
isObject(current) &&
|
||||||
|
(Object.hasOwn(current, key) || key in current)
|
||||||
|
) {
|
||||||
current = current[key];
|
current = current[key];
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -23,8 +23,18 @@ export {
|
|||||||
OptimizeStats,
|
OptimizeStats,
|
||||||
CompactionStats,
|
CompactionStats,
|
||||||
RemovalStats,
|
RemovalStats,
|
||||||
|
TableStatistics,
|
||||||
|
FragmentStatistics,
|
||||||
|
FragmentSummaryStats,
|
||||||
Tags,
|
Tags,
|
||||||
TagContents,
|
TagContents,
|
||||||
|
MergeResult,
|
||||||
|
AddResult,
|
||||||
|
AddColumnsResult,
|
||||||
|
AlterColumnsResult,
|
||||||
|
DeleteResult,
|
||||||
|
DropColumnsResult,
|
||||||
|
UpdateResult,
|
||||||
} from "./native.js";
|
} from "./native.js";
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
// SPDX-FileCopyrightText: Copyright The LanceDB Authors
|
// SPDX-FileCopyrightText: Copyright The LanceDB Authors
|
||||||
import { Data, Schema, fromDataToBuffer } from "./arrow";
|
import { Data, Schema, fromDataToBuffer } from "./arrow";
|
||||||
import { NativeMergeInsertBuilder } from "./native";
|
import { MergeResult, NativeMergeInsertBuilder } from "./native";
|
||||||
|
|
||||||
/** A builder used to create and run a merge insert operation */
|
/** A builder used to create and run a merge insert operation */
|
||||||
export class MergeInsertBuilder {
|
export class MergeInsertBuilder {
|
||||||
@@ -73,9 +73,9 @@ export class MergeInsertBuilder {
|
|||||||
/**
|
/**
|
||||||
* Executes the merge insert operation
|
* Executes the merge insert operation
|
||||||
*
|
*
|
||||||
* Nothing is returned but the `Table` is updated
|
* @returns {Promise<MergeResult>} the merge result
|
||||||
*/
|
*/
|
||||||
async execute(data: Data): Promise<void> {
|
async execute(data: Data): Promise<MergeResult> {
|
||||||
let schema: Schema;
|
let schema: Schema;
|
||||||
if (this.#schema instanceof Promise) {
|
if (this.#schema instanceof Promise) {
|
||||||
schema = await this.#schema;
|
schema = await this.#schema;
|
||||||
@@ -84,6 +84,6 @@ export class MergeInsertBuilder {
|
|||||||
schema = this.#schema;
|
schema = this.#schema;
|
||||||
}
|
}
|
||||||
const buffer = await fromDataToBuffer(data, undefined, schema);
|
const buffer = await fromDataToBuffer(data, undefined, schema);
|
||||||
await this.#native.execute(buffer);
|
return await this.#native.execute(buffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,18 @@ import { EmbeddingFunctionConfig, getRegistry } from "./embedding/registry";
|
|||||||
import { IndexOptions } from "./indices";
|
import { IndexOptions } from "./indices";
|
||||||
import { MergeInsertBuilder } from "./merge";
|
import { MergeInsertBuilder } from "./merge";
|
||||||
import {
|
import {
|
||||||
|
AddColumnsResult,
|
||||||
AddColumnsSql,
|
AddColumnsSql,
|
||||||
|
AddResult,
|
||||||
|
AlterColumnsResult,
|
||||||
|
DeleteResult,
|
||||||
|
DropColumnsResult,
|
||||||
IndexConfig,
|
IndexConfig,
|
||||||
IndexStatistics,
|
IndexStatistics,
|
||||||
OptimizeStats,
|
OptimizeStats,
|
||||||
|
TableStatistics,
|
||||||
Tags,
|
Tags,
|
||||||
|
UpdateResult,
|
||||||
Table as _NativeTable,
|
Table as _NativeTable,
|
||||||
} from "./native";
|
} from "./native";
|
||||||
import {
|
import {
|
||||||
@@ -125,12 +132,19 @@ export abstract class Table {
|
|||||||
/**
|
/**
|
||||||
* Insert records into this Table.
|
* Insert records into this Table.
|
||||||
* @param {Data} data Records to be inserted into the Table
|
* @param {Data} data Records to be inserted into the Table
|
||||||
|
* @returns {Promise<AddResult>} A promise that resolves to an object
|
||||||
|
* containing the new version number of the table
|
||||||
*/
|
*/
|
||||||
abstract add(data: Data, options?: Partial<AddDataOptions>): Promise<void>;
|
abstract add(
|
||||||
|
data: Data,
|
||||||
|
options?: Partial<AddDataOptions>,
|
||||||
|
): Promise<AddResult>;
|
||||||
/**
|
/**
|
||||||
* Update existing records in the Table
|
* Update existing records in the Table
|
||||||
* @param opts.values The values to update. The keys are the column names and the values
|
* @param opts.values The values to update. The keys are the column names and the values
|
||||||
* are the values to set.
|
* are the values to set.
|
||||||
|
* @returns {Promise<UpdateResult>} A promise that resolves to an object containing
|
||||||
|
* the number of rows updated and the new version number
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* table.update({where:"x = 2", values:{"vector": [10, 10]}})
|
* table.update({where:"x = 2", values:{"vector": [10, 10]}})
|
||||||
@@ -140,11 +154,13 @@ export abstract class Table {
|
|||||||
opts: {
|
opts: {
|
||||||
values: Map<string, IntoSql> | Record<string, IntoSql>;
|
values: Map<string, IntoSql> | Record<string, IntoSql>;
|
||||||
} & Partial<UpdateOptions>,
|
} & Partial<UpdateOptions>,
|
||||||
): Promise<void>;
|
): Promise<UpdateResult>;
|
||||||
/**
|
/**
|
||||||
* Update existing records in the Table
|
* Update existing records in the Table
|
||||||
* @param opts.valuesSql The values to update. The keys are the column names and the values
|
* @param opts.valuesSql The values to update. The keys are the column names and the values
|
||||||
* are the values to set. The values are SQL expressions.
|
* are the values to set. The values are SQL expressions.
|
||||||
|
* @returns {Promise<UpdateResult>} A promise that resolves to an object containing
|
||||||
|
* the number of rows updated and the new version number
|
||||||
* @example
|
* @example
|
||||||
* ```ts
|
* ```ts
|
||||||
* table.update({where:"x = 2", valuesSql:{"x": "x + 1"}})
|
* table.update({where:"x = 2", valuesSql:{"x": "x + 1"}})
|
||||||
@@ -154,7 +170,7 @@ export abstract class Table {
|
|||||||
opts: {
|
opts: {
|
||||||
valuesSql: Map<string, string> | Record<string, string>;
|
valuesSql: Map<string, string> | Record<string, string>;
|
||||||
} & Partial<UpdateOptions>,
|
} & Partial<UpdateOptions>,
|
||||||
): Promise<void>;
|
): Promise<UpdateResult>;
|
||||||
/**
|
/**
|
||||||
* Update existing records in the Table
|
* Update existing records in the Table
|
||||||
*
|
*
|
||||||
@@ -172,6 +188,8 @@ export abstract class Table {
|
|||||||
* repeatedly calilng this method.
|
* repeatedly calilng this method.
|
||||||
* @param {Map<string, string> | Record<string, string>} updates - the
|
* @param {Map<string, string> | Record<string, string>} updates - the
|
||||||
* columns to update
|
* columns to update
|
||||||
|
* @returns {Promise<UpdateResult>} A promise that resolves to an object
|
||||||
|
* containing the number of rows updated and the new version number
|
||||||
*
|
*
|
||||||
* Keys in the map should specify the name of the column to update.
|
* Keys in the map should specify the name of the column to update.
|
||||||
* Values in the map provide the new value of the column. These can
|
* Values in the map provide the new value of the column. These can
|
||||||
@@ -183,12 +201,16 @@ export abstract class Table {
|
|||||||
abstract update(
|
abstract update(
|
||||||
updates: Map<string, string> | Record<string, string>,
|
updates: Map<string, string> | Record<string, string>,
|
||||||
options?: Partial<UpdateOptions>,
|
options?: Partial<UpdateOptions>,
|
||||||
): Promise<void>;
|
): Promise<UpdateResult>;
|
||||||
|
|
||||||
/** Count the total number of rows in the dataset. */
|
/** Count the total number of rows in the dataset. */
|
||||||
abstract countRows(filter?: string): Promise<number>;
|
abstract countRows(filter?: string): Promise<number>;
|
||||||
/** Delete the rows that satisfy the predicate. */
|
/**
|
||||||
abstract delete(predicate: string): Promise<void>;
|
* Delete the rows that satisfy the predicate.
|
||||||
|
* @returns {Promise<DeleteResult>} A promise that resolves to an object
|
||||||
|
* containing the new version number of the table
|
||||||
|
*/
|
||||||
|
abstract delete(predicate: string): Promise<DeleteResult>;
|
||||||
/**
|
/**
|
||||||
* Create an index to speed up queries.
|
* Create an index to speed up queries.
|
||||||
*
|
*
|
||||||
@@ -342,15 +364,23 @@ export abstract class Table {
|
|||||||
* the SQL expression to use to calculate the value of the new column. These
|
* the SQL expression to use to calculate the value of the new column. These
|
||||||
* expressions will be evaluated for each row in the table, and can
|
* expressions will be evaluated for each row in the table, and can
|
||||||
* reference existing columns in the table.
|
* reference existing columns in the table.
|
||||||
|
* @returns {Promise<AddColumnsResult>} A promise that resolves to an object
|
||||||
|
* containing the new version number of the table after adding the columns.
|
||||||
*/
|
*/
|
||||||
abstract addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void>;
|
abstract addColumns(
|
||||||
|
newColumnTransforms: AddColumnsSql[],
|
||||||
|
): Promise<AddColumnsResult>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Alter the name or nullability of columns.
|
* Alter the name or nullability of columns.
|
||||||
* @param {ColumnAlteration[]} columnAlterations One or more alterations to
|
* @param {ColumnAlteration[]} columnAlterations One or more alterations to
|
||||||
* apply to columns.
|
* apply to columns.
|
||||||
|
* @returns {Promise<AlterColumnsResult>} A promise that resolves to an object
|
||||||
|
* containing the new version number of the table after altering the columns.
|
||||||
*/
|
*/
|
||||||
abstract alterColumns(columnAlterations: ColumnAlteration[]): Promise<void>;
|
abstract alterColumns(
|
||||||
|
columnAlterations: ColumnAlteration[],
|
||||||
|
): Promise<AlterColumnsResult>;
|
||||||
/**
|
/**
|
||||||
* Drop one or more columns from the dataset
|
* Drop one or more columns from the dataset
|
||||||
*
|
*
|
||||||
@@ -361,8 +391,10 @@ export abstract class Table {
|
|||||||
* @param {string[]} columnNames The names of the columns to drop. These can
|
* @param {string[]} columnNames The names of the columns to drop. These can
|
||||||
* be nested column references (e.g. "a.b.c") or top-level column names
|
* be nested column references (e.g. "a.b.c") or top-level column names
|
||||||
* (e.g. "a").
|
* (e.g. "a").
|
||||||
|
* @returns {Promise<DropColumnsResult>} A promise that resolves to an object
|
||||||
|
* containing the new version number of the table after dropping the columns.
|
||||||
*/
|
*/
|
||||||
abstract dropColumns(columnNames: string[]): Promise<void>;
|
abstract dropColumns(columnNames: string[]): Promise<DropColumnsResult>;
|
||||||
/** Retrieve the version of the table */
|
/** Retrieve the version of the table */
|
||||||
|
|
||||||
abstract version(): Promise<number>;
|
abstract version(): Promise<number>;
|
||||||
@@ -482,6 +514,13 @@ export abstract class Table {
|
|||||||
* Use {@link Table.listIndices} to find the names of the indices.
|
* Use {@link Table.listIndices} to find the names of the indices.
|
||||||
*/
|
*/
|
||||||
abstract indexStats(name: string): Promise<IndexStatistics | undefined>;
|
abstract indexStats(name: string): Promise<IndexStatistics | undefined>;
|
||||||
|
|
||||||
|
/** Returns table and fragment statistics
|
||||||
|
*
|
||||||
|
* @returns {TableStatistics} The table and fragment statistics
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
abstract stats(): Promise<TableStatistics>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LocalTable extends Table {
|
export class LocalTable extends Table {
|
||||||
@@ -521,12 +560,12 @@ export class LocalTable extends Table {
|
|||||||
return tbl.schema;
|
return tbl.schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
async add(data: Data, options?: Partial<AddDataOptions>): Promise<void> {
|
async add(data: Data, options?: Partial<AddDataOptions>): Promise<AddResult> {
|
||||||
const mode = options?.mode ?? "append";
|
const mode = options?.mode ?? "append";
|
||||||
const schema = await this.schema();
|
const schema = await this.schema();
|
||||||
|
|
||||||
const buffer = await fromDataToBuffer(data, undefined, schema);
|
const buffer = await fromDataToBuffer(data, undefined, schema);
|
||||||
await this.inner.add(buffer, mode);
|
return await this.inner.add(buffer, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(
|
async update(
|
||||||
@@ -539,7 +578,7 @@ export class LocalTable extends Table {
|
|||||||
valuesSql: Map<string, string> | Record<string, string>;
|
valuesSql: Map<string, string> | Record<string, string>;
|
||||||
} & Partial<UpdateOptions>),
|
} & Partial<UpdateOptions>),
|
||||||
options?: Partial<UpdateOptions>,
|
options?: Partial<UpdateOptions>,
|
||||||
) {
|
): Promise<UpdateResult> {
|
||||||
const isValues =
|
const isValues =
|
||||||
"values" in optsOrUpdates && typeof optsOrUpdates.values !== "string";
|
"values" in optsOrUpdates && typeof optsOrUpdates.values !== "string";
|
||||||
const isValuesSql =
|
const isValuesSql =
|
||||||
@@ -586,15 +625,15 @@ export class LocalTable extends Table {
|
|||||||
columns = Object.entries(optsOrUpdates as Record<string, string>);
|
columns = Object.entries(optsOrUpdates as Record<string, string>);
|
||||||
predicate = options?.where;
|
predicate = options?.where;
|
||||||
}
|
}
|
||||||
await this.inner.update(predicate, columns);
|
return await this.inner.update(predicate, columns);
|
||||||
}
|
}
|
||||||
|
|
||||||
async countRows(filter?: string): Promise<number> {
|
async countRows(filter?: string): Promise<number> {
|
||||||
return await this.inner.countRows(filter);
|
return await this.inner.countRows(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(predicate: string): Promise<void> {
|
async delete(predicate: string): Promise<DeleteResult> {
|
||||||
await this.inner.delete(predicate);
|
return await this.inner.delete(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
async createIndex(column: string, options?: Partial<IndexOptions>) {
|
async createIndex(column: string, options?: Partial<IndexOptions>) {
|
||||||
@@ -682,11 +721,15 @@ export class LocalTable extends Table {
|
|||||||
|
|
||||||
// TODO: Support BatchUDF
|
// TODO: Support BatchUDF
|
||||||
|
|
||||||
async addColumns(newColumnTransforms: AddColumnsSql[]): Promise<void> {
|
async addColumns(
|
||||||
await this.inner.addColumns(newColumnTransforms);
|
newColumnTransforms: AddColumnsSql[],
|
||||||
|
): Promise<AddColumnsResult> {
|
||||||
|
return await this.inner.addColumns(newColumnTransforms);
|
||||||
}
|
}
|
||||||
|
|
||||||
async alterColumns(columnAlterations: ColumnAlteration[]): Promise<void> {
|
async alterColumns(
|
||||||
|
columnAlterations: ColumnAlteration[],
|
||||||
|
): Promise<AlterColumnsResult> {
|
||||||
const processedAlterations = columnAlterations.map((alteration) => {
|
const processedAlterations = columnAlterations.map((alteration) => {
|
||||||
if (typeof alteration.dataType === "string") {
|
if (typeof alteration.dataType === "string") {
|
||||||
return {
|
return {
|
||||||
@@ -707,11 +750,11 @@ export class LocalTable extends Table {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await this.inner.alterColumns(processedAlterations);
|
return await this.inner.alterColumns(processedAlterations);
|
||||||
}
|
}
|
||||||
|
|
||||||
async dropColumns(columnNames: string[]): Promise<void> {
|
async dropColumns(columnNames: string[]): Promise<DropColumnsResult> {
|
||||||
await this.inner.dropColumns(columnNames);
|
return await this.inner.dropColumns(columnNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
async version(): Promise<number> {
|
async version(): Promise<number> {
|
||||||
@@ -775,6 +818,11 @@ export class LocalTable extends Table {
|
|||||||
}
|
}
|
||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async stats(): Promise<TableStatistics> {
|
||||||
|
return await this.inner.stats();
|
||||||
|
}
|
||||||
|
|
||||||
mergeInsert(on: string | string[]): MergeInsertBuilder {
|
mergeInsert(on: string | string[]): MergeInsertBuilder {
|
||||||
on = Array.isArray(on) ? on : [on];
|
on = Array.isArray(on) ? on : [on];
|
||||||
return new MergeInsertBuilder(this.inner.mergeInsert(on), this.schema());
|
return new MergeInsertBuilder(this.inner.mergeInsert(on), this.schema());
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-darwin-arm64",
|
"name": "@lancedb/lancedb-darwin-arm64",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["darwin"],
|
"os": ["darwin"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.darwin-arm64.node",
|
"main": "lancedb.darwin-arm64.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-darwin-x64",
|
"name": "@lancedb/lancedb-darwin-x64",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["darwin"],
|
"os": ["darwin"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.darwin-x64.node",
|
"main": "lancedb.darwin-x64.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-arm64-gnu",
|
"name": "@lancedb/lancedb-linux-arm64-gnu",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.linux-arm64-gnu.node",
|
"main": "lancedb.linux-arm64-gnu.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-arm64-musl",
|
"name": "@lancedb/lancedb-linux-arm64-musl",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["arm64"],
|
"cpu": ["arm64"],
|
||||||
"main": "lancedb.linux-arm64-musl.node",
|
"main": "lancedb.linux-arm64-musl.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-x64-gnu",
|
"name": "@lancedb/lancedb-linux-x64-gnu",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.linux-x64-gnu.node",
|
"main": "lancedb.linux-x64-gnu.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-linux-x64-musl",
|
"name": "@lancedb/lancedb-linux-x64-musl",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["linux"],
|
"os": ["linux"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.linux-x64-musl.node",
|
"main": "lancedb.linux-x64-musl.node",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-win32-arm64-msvc",
|
"name": "@lancedb/lancedb-win32-arm64-msvc",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": [
|
"os": [
|
||||||
"win32"
|
"win32"
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb-win32-x64-msvc",
|
"name": "@lancedb/lancedb-win32-x64-msvc",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"os": ["win32"],
|
"os": ["win32"],
|
||||||
"cpu": ["x64"],
|
"cpu": ["x64"],
|
||||||
"main": "lancedb.win32-x64-msvc.node",
|
"main": "lancedb.win32-x64-msvc.node",
|
||||||
|
|||||||
4
nodejs/package-lock.json
generated
4
nodejs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@lancedb/lancedb",
|
"name": "@lancedb/lancedb",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@lancedb/lancedb",
|
"name": "@lancedb/lancedb",
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"cpu": [
|
"cpu": [
|
||||||
"x64",
|
"x64",
|
||||||
"arm64"
|
"arm64"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"ann"
|
"ann"
|
||||||
],
|
],
|
||||||
"private": false,
|
"private": false,
|
||||||
"version": "0.19.0",
|
"version": "0.19.1-beta.1",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"exports": {
|
"exports": {
|
||||||
".": "./dist/index.js",
|
".": "./dist/index.js",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use lancedb::{arrow::IntoArrow, ipc::ipc_file_to_batches, table::merge::MergeIns
|
|||||||
use napi::bindgen_prelude::*;
|
use napi::bindgen_prelude::*;
|
||||||
use napi_derive::napi;
|
use napi_derive::napi;
|
||||||
|
|
||||||
use crate::error::convert_error;
|
use crate::{error::convert_error, table::MergeResult};
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -37,7 +37,7 @@ impl NativeMergeInsertBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn execute(&self, buf: Buffer) -> napi::Result<()> {
|
pub async fn execute(&self, buf: Buffer) -> napi::Result<MergeResult> {
|
||||||
let data = ipc_file_to_batches(buf.to_vec())
|
let data = ipc_file_to_batches(buf.to_vec())
|
||||||
.and_then(IntoArrow::into_arrow)
|
.and_then(IntoArrow::into_arrow)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
@@ -46,12 +46,13 @@ impl NativeMergeInsertBuilder {
|
|||||||
|
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
|
|
||||||
this.inner.execute(data).await.map_err(|e| {
|
let res = this.inner.execute(data).await.map_err(|e| {
|
||||||
napi::Error::from_reason(format!(
|
napi::Error::from_reason(format!(
|
||||||
"Failed to execute merge insert: {}",
|
"Failed to execute merge insert: {}",
|
||||||
convert_error(&e)
|
convert_error(&e)
|
||||||
))
|
))
|
||||||
})
|
})?;
|
||||||
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn add(&self, buf: Buffer, mode: String) -> napi::Result<()> {
|
pub async fn add(&self, buf: Buffer, mode: String) -> napi::Result<AddResult> {
|
||||||
let batches = ipc_file_to_batches(buf.to_vec())
|
let batches = ipc_file_to_batches(buf.to_vec())
|
||||||
.map_err(|e| napi::Error::from_reason(format!("Failed to read IPC file: {}", e)))?;
|
.map_err(|e| napi::Error::from_reason(format!("Failed to read IPC file: {}", e)))?;
|
||||||
let mut op = self.inner_ref()?.add(batches);
|
let mut op = self.inner_ref()?.add(batches);
|
||||||
@@ -88,7 +88,8 @@ impl Table {
|
|||||||
return Err(napi::Error::from_reason(format!("Invalid mode: {}", mode)));
|
return Err(napi::Error::from_reason(format!("Invalid mode: {}", mode)));
|
||||||
};
|
};
|
||||||
|
|
||||||
op.execute().await.default_error()
|
let res = op.execute().await.default_error()?;
|
||||||
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
@@ -101,8 +102,9 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn delete(&self, predicate: String) -> napi::Result<()> {
|
pub async fn delete(&self, predicate: String) -> napi::Result<DeleteResult> {
|
||||||
self.inner_ref()?.delete(&predicate).await.default_error()
|
let res = self.inner_ref()?.delete(&predicate).await.default_error()?;
|
||||||
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
@@ -157,12 +159,18 @@ impl Table {
|
|||||||
.default_error()
|
.default_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(catch_unwind)]
|
||||||
|
pub async fn stats(&self) -> Result<TableStatistics> {
|
||||||
|
let stats = self.inner_ref()?.stats().await.default_error()?;
|
||||||
|
Ok(stats.into())
|
||||||
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
&self,
|
&self,
|
||||||
only_if: Option<String>,
|
only_if: Option<String>,
|
||||||
columns: Vec<(String, String)>,
|
columns: Vec<(String, String)>,
|
||||||
) -> napi::Result<u64> {
|
) -> napi::Result<UpdateResult> {
|
||||||
let mut op = self.inner_ref()?.update();
|
let mut op = self.inner_ref()?.update();
|
||||||
if let Some(only_if) = only_if {
|
if let Some(only_if) = only_if {
|
||||||
op = op.only_if(only_if);
|
op = op.only_if(only_if);
|
||||||
@@ -170,7 +178,8 @@ impl Table {
|
|||||||
for (column_name, value) in columns {
|
for (column_name, value) in columns {
|
||||||
op = op.column(column_name, value);
|
op = op.column(column_name, value);
|
||||||
}
|
}
|
||||||
op.execute().await.default_error()
|
let res = op.execute().await.default_error()?;
|
||||||
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
@@ -184,21 +193,28 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn add_columns(&self, transforms: Vec<AddColumnsSql>) -> napi::Result<()> {
|
pub async fn add_columns(
|
||||||
|
&self,
|
||||||
|
transforms: Vec<AddColumnsSql>,
|
||||||
|
) -> napi::Result<AddColumnsResult> {
|
||||||
let transforms = transforms
|
let transforms = transforms
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|sql| (sql.name, sql.value_sql))
|
.map(|sql| (sql.name, sql.value_sql))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let transforms = NewColumnTransform::SqlExpressions(transforms);
|
let transforms = NewColumnTransform::SqlExpressions(transforms);
|
||||||
self.inner_ref()?
|
let res = self
|
||||||
|
.inner_ref()?
|
||||||
.add_columns(transforms, None)
|
.add_columns(transforms, None)
|
||||||
.await
|
.await
|
||||||
.default_error()?;
|
.default_error()?;
|
||||||
Ok(())
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn alter_columns(&self, alterations: Vec<ColumnAlteration>) -> napi::Result<()> {
|
pub async fn alter_columns(
|
||||||
|
&self,
|
||||||
|
alterations: Vec<ColumnAlteration>,
|
||||||
|
) -> napi::Result<AlterColumnsResult> {
|
||||||
for alteration in &alterations {
|
for alteration in &alterations {
|
||||||
if alteration.rename.is_none()
|
if alteration.rename.is_none()
|
||||||
&& alteration.nullable.is_none()
|
&& alteration.nullable.is_none()
|
||||||
@@ -215,21 +231,23 @@ impl Table {
|
|||||||
.collect::<std::result::Result<Vec<_>, String>>()
|
.collect::<std::result::Result<Vec<_>, String>>()
|
||||||
.map_err(napi::Error::from_reason)?;
|
.map_err(napi::Error::from_reason)?;
|
||||||
|
|
||||||
self.inner_ref()?
|
let res = self
|
||||||
|
.inner_ref()?
|
||||||
.alter_columns(&alterations)
|
.alter_columns(&alterations)
|
||||||
.await
|
.await
|
||||||
.default_error()?;
|
.default_error()?;
|
||||||
Ok(())
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
pub async fn drop_columns(&self, columns: Vec<String>) -> napi::Result<()> {
|
pub async fn drop_columns(&self, columns: Vec<String>) -> napi::Result<DropColumnsResult> {
|
||||||
let col_refs = columns.iter().map(String::as_str).collect::<Vec<_>>();
|
let col_refs = columns.iter().map(String::as_str).collect::<Vec<_>>();
|
||||||
self.inner_ref()?
|
let res = self
|
||||||
|
.inner_ref()?
|
||||||
.drop_columns(&col_refs)
|
.drop_columns(&col_refs)
|
||||||
.await
|
.await
|
||||||
.default_error()?;
|
.default_error()?;
|
||||||
Ok(())
|
Ok(res.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[napi(catch_unwind)]
|
#[napi(catch_unwind)]
|
||||||
@@ -555,6 +573,80 @@ impl From<lancedb::index::IndexStatistics> for IndexStatistics {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct TableStatistics {
|
||||||
|
/// The total number of bytes in the table
|
||||||
|
pub total_bytes: i64,
|
||||||
|
|
||||||
|
/// The number of rows in the table
|
||||||
|
pub num_rows: i64,
|
||||||
|
|
||||||
|
/// The number of indices in the table
|
||||||
|
pub num_indices: i64,
|
||||||
|
|
||||||
|
/// Statistics on table fragments
|
||||||
|
pub fragment_stats: FragmentStatistics,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct FragmentStatistics {
|
||||||
|
/// The number of fragments in the table
|
||||||
|
pub num_fragments: i64,
|
||||||
|
|
||||||
|
/// The number of uncompacted fragments in the table
|
||||||
|
pub num_small_fragments: i64,
|
||||||
|
|
||||||
|
/// Statistics on the number of rows in the table fragments
|
||||||
|
pub lengths: FragmentSummaryStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct FragmentSummaryStats {
|
||||||
|
/// The number of rows in the fragment with the fewest rows
|
||||||
|
pub min: i64,
|
||||||
|
|
||||||
|
/// The number of rows in the fragment with the most rows
|
||||||
|
pub max: i64,
|
||||||
|
|
||||||
|
/// The mean number of rows in the fragments
|
||||||
|
pub mean: i64,
|
||||||
|
|
||||||
|
/// The 25th percentile of number of rows in the fragments
|
||||||
|
pub p25: i64,
|
||||||
|
|
||||||
|
/// The 50th percentile of number of rows in the fragments
|
||||||
|
pub p50: i64,
|
||||||
|
|
||||||
|
/// The 75th percentile of number of rows in the fragments
|
||||||
|
pub p75: i64,
|
||||||
|
|
||||||
|
/// The 99th percentile of number of rows in the fragments
|
||||||
|
pub p99: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::TableStatistics> for TableStatistics {
|
||||||
|
fn from(v: lancedb::table::TableStatistics) -> Self {
|
||||||
|
Self {
|
||||||
|
total_bytes: v.total_bytes as i64,
|
||||||
|
num_rows: v.num_rows as i64,
|
||||||
|
num_indices: v.num_indices as i64,
|
||||||
|
fragment_stats: FragmentStatistics {
|
||||||
|
num_fragments: v.fragment_stats.num_fragments as i64,
|
||||||
|
num_small_fragments: v.fragment_stats.num_small_fragments as i64,
|
||||||
|
lengths: FragmentSummaryStats {
|
||||||
|
min: v.fragment_stats.lengths.min as i64,
|
||||||
|
max: v.fragment_stats.lengths.max as i64,
|
||||||
|
mean: v.fragment_stats.lengths.mean as i64,
|
||||||
|
p25: v.fragment_stats.lengths.p25 as i64,
|
||||||
|
p50: v.fragment_stats.lengths.p50 as i64,
|
||||||
|
p75: v.fragment_stats.lengths.p75 as i64,
|
||||||
|
p99: v.fragment_stats.lengths.p99 as i64,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[napi(object)]
|
#[napi(object)]
|
||||||
pub struct Version {
|
pub struct Version {
|
||||||
pub version: i64,
|
pub version: i64,
|
||||||
@@ -562,6 +654,105 @@ pub struct Version {
|
|||||||
pub metadata: HashMap<String, String>,
|
pub metadata: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct UpdateResult {
|
||||||
|
pub rows_updated: i64,
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::UpdateResult> for UpdateResult {
|
||||||
|
fn from(value: lancedb::table::UpdateResult) -> Self {
|
||||||
|
Self {
|
||||||
|
rows_updated: value.rows_updated as i64,
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct AddResult {
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AddResult> for AddResult {
|
||||||
|
fn from(value: lancedb::table::AddResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct DeleteResult {
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::DeleteResult> for DeleteResult {
|
||||||
|
fn from(value: lancedb::table::DeleteResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct MergeResult {
|
||||||
|
pub version: i64,
|
||||||
|
pub num_inserted_rows: i64,
|
||||||
|
pub num_updated_rows: i64,
|
||||||
|
pub num_deleted_rows: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::MergeResult> for MergeResult {
|
||||||
|
fn from(value: lancedb::table::MergeResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
num_inserted_rows: value.num_inserted_rows as i64,
|
||||||
|
num_updated_rows: value.num_updated_rows as i64,
|
||||||
|
num_deleted_rows: value.num_deleted_rows as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct AddColumnsResult {
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AddColumnsResult> for AddColumnsResult {
|
||||||
|
fn from(value: lancedb::table::AddColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct AlterColumnsResult {
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AlterColumnsResult> for AlterColumnsResult {
|
||||||
|
fn from(value: lancedb::table::AlterColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[napi(object)]
|
||||||
|
pub struct DropColumnsResult {
|
||||||
|
pub version: i64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::DropColumnsResult> for DropColumnsResult {
|
||||||
|
fn from(value: lancedb::table::DropColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: value.version as i64,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[napi]
|
#[napi]
|
||||||
pub struct TagContents {
|
pub struct TagContents {
|
||||||
pub version: i64,
|
pub version: i64,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[tool.bumpversion]
|
[tool.bumpversion]
|
||||||
current_version = "0.22.1-beta.0"
|
current_version = "0.22.1-beta.2"
|
||||||
parse = """(?x)
|
parse = """(?x)
|
||||||
(?P<major>0|[1-9]\\d*)\\.
|
(?P<major>0|[1-9]\\d*)\\.
|
||||||
(?P<minor>0|[1-9]\\d*)\\.
|
(?P<minor>0|[1-9]\\d*)\\.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-python"
|
name = "lancedb-python"
|
||||||
version = "0.22.1-beta.0"
|
version = "0.22.1-beta.2"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
description = "Python bindings for LanceDB"
|
description = "Python bindings for LanceDB"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ dependencies = [
|
|||||||
"numpy",
|
"numpy",
|
||||||
"overrides>=0.7",
|
"overrides>=0.7",
|
||||||
"packaging",
|
"packaging",
|
||||||
"pyarrow>=14",
|
"pyarrow>=16",
|
||||||
"pydantic>=1.10",
|
"pydantic>=1.10",
|
||||||
"tqdm>=4.27.0",
|
"tqdm>=4.27.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ class Table:
|
|||||||
async def schema(self) -> pa.Schema: ...
|
async def schema(self) -> pa.Schema: ...
|
||||||
async def add(
|
async def add(
|
||||||
self, data: pa.RecordBatchReader, mode: Literal["append", "overwrite"]
|
self, data: pa.RecordBatchReader, mode: Literal["append", "overwrite"]
|
||||||
) -> None: ...
|
) -> AddResult: ...
|
||||||
async def update(self, updates: Dict[str, str], where: Optional[str]) -> None: ...
|
async def update(
|
||||||
|
self, updates: Dict[str, str], where: Optional[str]
|
||||||
|
) -> UpdateResult: ...
|
||||||
async def count_rows(self, filter: Optional[str]) -> int: ...
|
async def count_rows(self, filter: Optional[str]) -> int: ...
|
||||||
async def create_index(
|
async def create_index(
|
||||||
self,
|
self,
|
||||||
@@ -51,10 +53,12 @@ class Table:
|
|||||||
async def checkout_latest(self): ...
|
async def checkout_latest(self): ...
|
||||||
async def restore(self, version: Optional[int] = None): ...
|
async def restore(self, version: Optional[int] = None): ...
|
||||||
async def list_indices(self) -> list[IndexConfig]: ...
|
async def list_indices(self) -> list[IndexConfig]: ...
|
||||||
async def delete(self, filter: str): ...
|
async def delete(self, filter: str) -> DeleteResult: ...
|
||||||
async def add_columns(self, columns: list[tuple[str, str]]) -> None: ...
|
async def add_columns(self, columns: list[tuple[str, str]]) -> AddColumnsResult: ...
|
||||||
async def add_columns_with_schema(self, schema: pa.Schema) -> None: ...
|
async def add_columns_with_schema(self, schema: pa.Schema) -> AddColumnsResult: ...
|
||||||
async def alter_columns(self, columns: list[dict[str, Any]]) -> None: ...
|
async def alter_columns(
|
||||||
|
self, columns: list[dict[str, Any]]
|
||||||
|
) -> AlterColumnsResult: ...
|
||||||
async def optimize(
|
async def optimize(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -208,3 +212,28 @@ class OptimizeStats:
|
|||||||
class Tag(TypedDict):
|
class Tag(TypedDict):
|
||||||
version: int
|
version: int
|
||||||
manifest_size: int
|
manifest_size: int
|
||||||
|
|
||||||
|
class AddResult:
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class DeleteResult:
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class UpdateResult:
|
||||||
|
rows_updated: int
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class MergeResult:
|
||||||
|
version: int
|
||||||
|
num_updated_rows: int
|
||||||
|
num_inserted_rows: int
|
||||||
|
num_deleted_rows: int
|
||||||
|
|
||||||
|
class AddColumnsResult:
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class AlterColumnsResult:
|
||||||
|
version: int
|
||||||
|
|
||||||
|
class DropColumnsResult:
|
||||||
|
version: int
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ from typing import TYPE_CHECKING, List, Optional
|
|||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .common import DATA
|
from .common import DATA
|
||||||
|
from ._lancedb import (
|
||||||
|
MergeInsertResult,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class LanceMergeInsertBuilder(object):
|
class LanceMergeInsertBuilder(object):
|
||||||
@@ -78,7 +81,7 @@ class LanceMergeInsertBuilder(object):
|
|||||||
new_data: DATA,
|
new_data: DATA,
|
||||||
on_bad_vectors: str = "error",
|
on_bad_vectors: str = "error",
|
||||||
fill_value: float = 0.0,
|
fill_value: float = 0.0,
|
||||||
):
|
) -> MergeInsertResult:
|
||||||
"""
|
"""
|
||||||
Executes the merge insert operation
|
Executes the merge insert operation
|
||||||
|
|
||||||
@@ -95,5 +98,10 @@ class LanceMergeInsertBuilder(object):
|
|||||||
One of "error", "drop", "fill".
|
One of "error", "drop", "fill".
|
||||||
fill_value: float, default 0.
|
fill_value: float, default 0.
|
||||||
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
MergeInsertResult
|
||||||
|
version: the new version number of the table after doing merge insert.
|
||||||
"""
|
"""
|
||||||
return self._table._do_merge(self, new_data, on_bad_vectors, fill_value)
|
return self._table._do_merge(self, new_data, on_bad_vectors, fill_value)
|
||||||
|
|||||||
@@ -415,6 +415,7 @@ class LanceModel(pydantic.BaseModel):
|
|||||||
>>> table.add([
|
>>> table.add([
|
||||||
... TestModel(name="test", vector=[1.0, 2.0])
|
... TestModel(name="test", vector=[1.0, 2.0])
|
||||||
... ])
|
... ])
|
||||||
|
AddResult(version=2)
|
||||||
>>> table.search([0., 0.]).limit(1).to_pydantic(TestModel)
|
>>> table.search([0., 0.]).limit(1).to_pydantic(TestModel)
|
||||||
[TestModel(name='test', vector=FixedSizeList(dim=2))]
|
[TestModel(name='test', vector=FixedSizeList(dim=2))]
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -7,7 +7,16 @@ from functools import cached_property
|
|||||||
from typing import Dict, Iterable, List, Optional, Union, Literal
|
from typing import Dict, Iterable, List, Optional, Union, Literal
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
from lancedb._lancedb import IndexConfig
|
from lancedb._lancedb import (
|
||||||
|
AddColumnsResult,
|
||||||
|
AddResult,
|
||||||
|
AlterColumnsResult,
|
||||||
|
DeleteResult,
|
||||||
|
DropColumnsResult,
|
||||||
|
IndexConfig,
|
||||||
|
MergeResult,
|
||||||
|
UpdateResult,
|
||||||
|
)
|
||||||
from lancedb.embeddings.base import EmbeddingFunctionConfig
|
from lancedb.embeddings.base import EmbeddingFunctionConfig
|
||||||
from lancedb.index import FTS, BTree, Bitmap, HnswPq, HnswSq, IvfFlat, IvfPq, LabelList
|
from lancedb.index import FTS, BTree, Bitmap, HnswPq, HnswSq, IvfFlat, IvfPq, LabelList
|
||||||
from lancedb.remote.db import LOOP
|
from lancedb.remote.db import LOOP
|
||||||
@@ -263,7 +272,7 @@ class RemoteTable(Table):
|
|||||||
mode: str = "append",
|
mode: str = "append",
|
||||||
on_bad_vectors: str = "error",
|
on_bad_vectors: str = "error",
|
||||||
fill_value: float = 0.0,
|
fill_value: float = 0.0,
|
||||||
) -> int:
|
) -> AddResult:
|
||||||
"""Add more data to the [Table](Table). It has the same API signature as
|
"""Add more data to the [Table](Table). It has the same API signature as
|
||||||
the OSS version.
|
the OSS version.
|
||||||
|
|
||||||
@@ -286,8 +295,12 @@ class RemoteTable(Table):
|
|||||||
fill_value: float, default 0.
|
fill_value: float, default 0.
|
||||||
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AddResult
|
||||||
|
An object containing the new version number of the table after adding data.
|
||||||
"""
|
"""
|
||||||
LOOP.run(
|
return LOOP.run(
|
||||||
self._table.add(
|
self._table.add(
|
||||||
data, mode=mode, on_bad_vectors=on_bad_vectors, fill_value=fill_value
|
data, mode=mode, on_bad_vectors=on_bad_vectors, fill_value=fill_value
|
||||||
)
|
)
|
||||||
@@ -413,10 +426,12 @@ class RemoteTable(Table):
|
|||||||
new_data: DATA,
|
new_data: DATA,
|
||||||
on_bad_vectors: str,
|
on_bad_vectors: str,
|
||||||
fill_value: float,
|
fill_value: float,
|
||||||
):
|
) -> MergeResult:
|
||||||
LOOP.run(self._table._do_merge(merge, new_data, on_bad_vectors, fill_value))
|
return LOOP.run(
|
||||||
|
self._table._do_merge(merge, new_data, on_bad_vectors, fill_value)
|
||||||
|
)
|
||||||
|
|
||||||
def delete(self, predicate: str):
|
def delete(self, predicate: str) -> DeleteResult:
|
||||||
"""Delete rows from the table.
|
"""Delete rows from the table.
|
||||||
|
|
||||||
This can be used to delete a single row, many rows, all rows, or
|
This can be used to delete a single row, many rows, all rows, or
|
||||||
@@ -431,6 +446,11 @@ class RemoteTable(Table):
|
|||||||
|
|
||||||
The filter must not be empty, or it will error.
|
The filter must not be empty, or it will error.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
DeleteResult
|
||||||
|
An object containing the new version number of the table after deletion.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import lancedb
|
>>> import lancedb
|
||||||
@@ -463,7 +483,7 @@ class RemoteTable(Table):
|
|||||||
x vector _distance # doctest: +SKIP
|
x vector _distance # doctest: +SKIP
|
||||||
0 2 [3.0, 4.0] 85.0 # doctest: +SKIP
|
0 2 [3.0, 4.0] 85.0 # doctest: +SKIP
|
||||||
"""
|
"""
|
||||||
LOOP.run(self._table.delete(predicate))
|
return LOOP.run(self._table.delete(predicate))
|
||||||
|
|
||||||
def update(
|
def update(
|
||||||
self,
|
self,
|
||||||
@@ -471,7 +491,7 @@ class RemoteTable(Table):
|
|||||||
values: Optional[dict] = None,
|
values: Optional[dict] = None,
|
||||||
*,
|
*,
|
||||||
values_sql: Optional[Dict[str, str]] = None,
|
values_sql: Optional[Dict[str, str]] = None,
|
||||||
):
|
) -> UpdateResult:
|
||||||
"""
|
"""
|
||||||
This can be used to update zero to all rows depending on how many
|
This can be used to update zero to all rows depending on how many
|
||||||
rows match the where clause.
|
rows match the where clause.
|
||||||
@@ -489,6 +509,12 @@ class RemoteTable(Table):
|
|||||||
reference existing columns. For example, {"x": "x + 1"} will increment
|
reference existing columns. For example, {"x": "x + 1"} will increment
|
||||||
the x column by 1.
|
the x column by 1.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
UpdateResult
|
||||||
|
- rows_updated: The number of rows that were updated
|
||||||
|
- version: The new version number of the table after the update
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import lancedb
|
>>> import lancedb
|
||||||
@@ -513,7 +539,7 @@ class RemoteTable(Table):
|
|||||||
2 2 [10.0, 10.0] # doctest: +SKIP
|
2 2 [10.0, 10.0] # doctest: +SKIP
|
||||||
|
|
||||||
"""
|
"""
|
||||||
LOOP.run(
|
return LOOP.run(
|
||||||
self._table.update(where=where, updates=values, updates_sql=values_sql)
|
self._table.update(where=where, updates=values, updates_sql=values_sql)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -561,13 +587,15 @@ class RemoteTable(Table):
|
|||||||
def count_rows(self, filter: Optional[str] = None) -> int:
|
def count_rows(self, filter: Optional[str] = None) -> int:
|
||||||
return LOOP.run(self._table.count_rows(filter))
|
return LOOP.run(self._table.count_rows(filter))
|
||||||
|
|
||||||
def add_columns(self, transforms: Dict[str, str]):
|
def add_columns(self, transforms: Dict[str, str]) -> AddColumnsResult:
|
||||||
return LOOP.run(self._table.add_columns(transforms))
|
return LOOP.run(self._table.add_columns(transforms))
|
||||||
|
|
||||||
def alter_columns(self, *alterations: Iterable[Dict[str, str]]):
|
def alter_columns(
|
||||||
|
self, *alterations: Iterable[Dict[str, str]]
|
||||||
|
) -> AlterColumnsResult:
|
||||||
return LOOP.run(self._table.alter_columns(*alterations))
|
return LOOP.run(self._table.alter_columns(*alterations))
|
||||||
|
|
||||||
def drop_columns(self, columns: Iterable[str]):
|
def drop_columns(self, columns: Iterable[str]) -> DropColumnsResult:
|
||||||
return LOOP.run(self._table.drop_columns(columns))
|
return LOOP.run(self._table.drop_columns(columns))
|
||||||
|
|
||||||
def drop_index(self, index_name: str):
|
def drop_index(self, index_name: str):
|
||||||
@@ -578,6 +606,9 @@ class RemoteTable(Table):
|
|||||||
):
|
):
|
||||||
return LOOP.run(self._table.wait_for_index(index_names, timeout))
|
return LOOP.run(self._table.wait_for_index(index_names, timeout))
|
||||||
|
|
||||||
|
def stats(self):
|
||||||
|
return LOOP.run(self._table.stats())
|
||||||
|
|
||||||
def uses_v2_manifest_paths(self) -> bool:
|
def uses_v2_manifest_paths(self) -> bool:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"uses_v2_manifest_paths() is not supported on the LanceDB Cloud"
|
"uses_v2_manifest_paths() is not supported on the LanceDB Cloud"
|
||||||
|
|||||||
@@ -78,6 +78,13 @@ if TYPE_CHECKING:
|
|||||||
CleanupStats,
|
CleanupStats,
|
||||||
CompactionStats,
|
CompactionStats,
|
||||||
Tag,
|
Tag,
|
||||||
|
AddColumnsResult,
|
||||||
|
AddResult,
|
||||||
|
AlterColumnsResult,
|
||||||
|
DeleteResult,
|
||||||
|
DropColumnsResult,
|
||||||
|
MergeResult,
|
||||||
|
UpdateResult,
|
||||||
)
|
)
|
||||||
from .db import LanceDBConnection
|
from .db import LanceDBConnection
|
||||||
from .index import IndexConfig
|
from .index import IndexConfig
|
||||||
@@ -550,6 +557,7 @@ class Table(ABC):
|
|||||||
Can append new data with [Table.add()][lancedb.table.Table.add].
|
Can append new data with [Table.add()][lancedb.table.Table.add].
|
||||||
|
|
||||||
>>> table.add([{"vector": [0.5, 1.3], "b": 4}])
|
>>> table.add([{"vector": [0.5, 1.3], "b": 4}])
|
||||||
|
AddResult(version=2)
|
||||||
|
|
||||||
Can query the table with [Table.search][lancedb.table.Table.search].
|
Can query the table with [Table.search][lancedb.table.Table.search].
|
||||||
|
|
||||||
@@ -739,6 +747,13 @@ class Table(ABC):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def stats(self) -> TableStatistics:
|
||||||
|
"""
|
||||||
|
Retrieve table and fragment statistics.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def create_scalar_index(
|
def create_scalar_index(
|
||||||
self,
|
self,
|
||||||
@@ -887,7 +902,7 @@ class Table(ABC):
|
|||||||
mode: AddMode = "append",
|
mode: AddMode = "append",
|
||||||
on_bad_vectors: OnBadVectorsType = "error",
|
on_bad_vectors: OnBadVectorsType = "error",
|
||||||
fill_value: float = 0.0,
|
fill_value: float = 0.0,
|
||||||
):
|
) -> AddResult:
|
||||||
"""Add more data to the [Table](Table).
|
"""Add more data to the [Table](Table).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@@ -909,6 +924,10 @@ class Table(ABC):
|
|||||||
fill_value: float, default 0.
|
fill_value: float, default 0.
|
||||||
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
The value to use when filling vectors. Only used if on_bad_vectors="fill".
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AddResult
|
||||||
|
An object containing the new version number of the table after adding data.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@@ -955,10 +974,12 @@ class Table(ABC):
|
|||||||
>>> table = db.create_table("my_table", data)
|
>>> table = db.create_table("my_table", data)
|
||||||
>>> new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
>>> new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
||||||
>>> # Perform a "upsert" operation
|
>>> # Perform a "upsert" operation
|
||||||
>>> table.merge_insert("a") \\
|
>>> res = table.merge_insert("a") \\
|
||||||
... .when_matched_update_all() \\
|
... .when_matched_update_all() \\
|
||||||
... .when_not_matched_insert_all() \\
|
... .when_not_matched_insert_all() \\
|
||||||
... .execute(new_data)
|
... .execute(new_data)
|
||||||
|
>>> res
|
||||||
|
MergeResult(version=2, num_updated_rows=2, num_inserted_rows=1, num_deleted_rows=0)
|
||||||
>>> # The order of new rows is non-deterministic since we use
|
>>> # The order of new rows is non-deterministic since we use
|
||||||
>>> # a hash-join as part of this operation and so we sort here
|
>>> # a hash-join as part of this operation and so we sort here
|
||||||
>>> table.to_arrow().sort_by("a").to_pandas()
|
>>> table.to_arrow().sort_by("a").to_pandas()
|
||||||
@@ -967,7 +988,7 @@ class Table(ABC):
|
|||||||
1 2 x
|
1 2 x
|
||||||
2 3 y
|
2 3 y
|
||||||
3 4 z
|
3 4 z
|
||||||
"""
|
""" # noqa: E501
|
||||||
on = [on] if isinstance(on, str) else list(iter(on))
|
on = [on] if isinstance(on, str) else list(iter(on))
|
||||||
|
|
||||||
return LanceMergeInsertBuilder(self, on)
|
return LanceMergeInsertBuilder(self, on)
|
||||||
@@ -1082,10 +1103,10 @@ class Table(ABC):
|
|||||||
new_data: DATA,
|
new_data: DATA,
|
||||||
on_bad_vectors: OnBadVectorsType,
|
on_bad_vectors: OnBadVectorsType,
|
||||||
fill_value: float,
|
fill_value: float,
|
||||||
): ...
|
) -> MergeResult: ...
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def delete(self, where: str):
|
def delete(self, where: str) -> DeleteResult:
|
||||||
"""Delete rows from the table.
|
"""Delete rows from the table.
|
||||||
|
|
||||||
This can be used to delete a single row, many rows, all rows, or
|
This can be used to delete a single row, many rows, all rows, or
|
||||||
@@ -1100,6 +1121,11 @@ class Table(ABC):
|
|||||||
|
|
||||||
The filter must not be empty, or it will error.
|
The filter must not be empty, or it will error.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
DeleteResult
|
||||||
|
An object containing the new version number of the table after deletion.
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import lancedb
|
>>> import lancedb
|
||||||
@@ -1116,6 +1142,7 @@ class Table(ABC):
|
|||||||
1 2 [3.0, 4.0]
|
1 2 [3.0, 4.0]
|
||||||
2 3 [5.0, 6.0]
|
2 3 [5.0, 6.0]
|
||||||
>>> table.delete("x = 2")
|
>>> table.delete("x = 2")
|
||||||
|
DeleteResult(version=2)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 1 [1.0, 2.0]
|
0 1 [1.0, 2.0]
|
||||||
@@ -1129,6 +1156,7 @@ class Table(ABC):
|
|||||||
>>> to_remove
|
>>> to_remove
|
||||||
'1, 5'
|
'1, 5'
|
||||||
>>> table.delete(f"x IN ({to_remove})")
|
>>> table.delete(f"x IN ({to_remove})")
|
||||||
|
DeleteResult(version=3)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 3 [5.0, 6.0]
|
0 3 [5.0, 6.0]
|
||||||
@@ -1142,7 +1170,7 @@ class Table(ABC):
|
|||||||
values: Optional[dict] = None,
|
values: Optional[dict] = None,
|
||||||
*,
|
*,
|
||||||
values_sql: Optional[Dict[str, str]] = None,
|
values_sql: Optional[Dict[str, str]] = None,
|
||||||
):
|
) -> UpdateResult:
|
||||||
"""
|
"""
|
||||||
This can be used to update zero to all rows depending on how many
|
This can be used to update zero to all rows depending on how many
|
||||||
rows match the where clause. If no where clause is provided, then
|
rows match the where clause. If no where clause is provided, then
|
||||||
@@ -1164,6 +1192,12 @@ class Table(ABC):
|
|||||||
reference existing columns. For example, {"x": "x + 1"} will increment
|
reference existing columns. For example, {"x": "x + 1"} will increment
|
||||||
the x column by 1.
|
the x column by 1.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
UpdateResult
|
||||||
|
- rows_updated: The number of rows that were updated
|
||||||
|
- version: The new version number of the table after the update
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import lancedb
|
>>> import lancedb
|
||||||
@@ -1177,12 +1211,14 @@ class Table(ABC):
|
|||||||
1 2 [3.0, 4.0]
|
1 2 [3.0, 4.0]
|
||||||
2 3 [5.0, 6.0]
|
2 3 [5.0, 6.0]
|
||||||
>>> table.update(where="x = 2", values={"vector": [10.0, 10]})
|
>>> table.update(where="x = 2", values={"vector": [10.0, 10]})
|
||||||
|
UpdateResult(rows_updated=1, version=2)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 1 [1.0, 2.0]
|
0 1 [1.0, 2.0]
|
||||||
1 3 [5.0, 6.0]
|
1 3 [5.0, 6.0]
|
||||||
2 2 [10.0, 10.0]
|
2 2 [10.0, 10.0]
|
||||||
>>> table.update(values_sql={"x": "x + 1"})
|
>>> table.update(values_sql={"x": "x + 1"})
|
||||||
|
UpdateResult(rows_updated=3, version=3)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 2 [1.0, 2.0]
|
0 2 [1.0, 2.0]
|
||||||
@@ -1345,6 +1381,11 @@ class Table(ABC):
|
|||||||
Alternatively, a pyarrow Field or Schema can be provided to add
|
Alternatively, a pyarrow Field or Schema can be provided to add
|
||||||
new columns with the specified data types. The new columns will
|
new columns with the specified data types. The new columns will
|
||||||
be initialized with null values.
|
be initialized with null values.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AddColumnsResult
|
||||||
|
version: the new version number of the table after adding columns.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -1370,10 +1411,15 @@ class Table(ABC):
|
|||||||
nullability is not changed. Only non-nullable columns can be changed
|
nullability is not changed. Only non-nullable columns can be changed
|
||||||
to nullable. Currently, you cannot change a nullable column to
|
to nullable. Currently, you cannot change a nullable column to
|
||||||
non-nullable.
|
non-nullable.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AlterColumnsResult
|
||||||
|
version: the new version number of the table after the alteration.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def drop_columns(self, columns: Iterable[str]):
|
def drop_columns(self, columns: Iterable[str]) -> DropColumnsResult:
|
||||||
"""
|
"""
|
||||||
Drop columns from the table.
|
Drop columns from the table.
|
||||||
|
|
||||||
@@ -1381,6 +1427,11 @@ class Table(ABC):
|
|||||||
----------
|
----------
|
||||||
columns : Iterable[str]
|
columns : Iterable[str]
|
||||||
The names of the columns to drop.
|
The names of the columns to drop.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
DropColumnsResult
|
||||||
|
version: the new version number of the table dropping the columns.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -1602,6 +1653,7 @@ class LanceTable(Table):
|
|||||||
... [{"vector": [1.1, 0.9], "type": "vector"}])
|
... [{"vector": [1.1, 0.9], "type": "vector"}])
|
||||||
>>> table.tags.create("v1", table.version)
|
>>> table.tags.create("v1", table.version)
|
||||||
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
||||||
|
AddResult(version=2)
|
||||||
>>> tags = table.tags.list()
|
>>> tags = table.tags.list()
|
||||||
>>> print(tags["v1"]["version"])
|
>>> print(tags["v1"]["version"])
|
||||||
1
|
1
|
||||||
@@ -1640,6 +1692,7 @@ class LanceTable(Table):
|
|||||||
vector type
|
vector type
|
||||||
0 [1.1, 0.9] vector
|
0 [1.1, 0.9] vector
|
||||||
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
||||||
|
AddResult(version=2)
|
||||||
>>> table.version
|
>>> table.version
|
||||||
2
|
2
|
||||||
>>> table.checkout(1)
|
>>> table.checkout(1)
|
||||||
@@ -1682,6 +1735,7 @@ class LanceTable(Table):
|
|||||||
vector type
|
vector type
|
||||||
0 [1.1, 0.9] vector
|
0 [1.1, 0.9] vector
|
||||||
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
>>> table.add([{"vector": [0.5, 0.2], "type": "vector"}])
|
||||||
|
AddResult(version=2)
|
||||||
>>> table.version
|
>>> table.version
|
||||||
2
|
2
|
||||||
>>> table.restore(1)
|
>>> table.restore(1)
|
||||||
@@ -1876,6 +1930,9 @@ class LanceTable(Table):
|
|||||||
) -> None:
|
) -> None:
|
||||||
return LOOP.run(self._table.wait_for_index(index_names, timeout))
|
return LOOP.run(self._table.wait_for_index(index_names, timeout))
|
||||||
|
|
||||||
|
def stats(self) -> TableStatistics:
|
||||||
|
return LOOP.run(self._table.stats())
|
||||||
|
|
||||||
def create_scalar_index(
|
def create_scalar_index(
|
||||||
self,
|
self,
|
||||||
column: str,
|
column: str,
|
||||||
@@ -2043,7 +2100,7 @@ class LanceTable(Table):
|
|||||||
mode: AddMode = "append",
|
mode: AddMode = "append",
|
||||||
on_bad_vectors: OnBadVectorsType = "error",
|
on_bad_vectors: OnBadVectorsType = "error",
|
||||||
fill_value: float = 0.0,
|
fill_value: float = 0.0,
|
||||||
):
|
) -> AddResult:
|
||||||
"""Add data to the table.
|
"""Add data to the table.
|
||||||
If vector columns are missing and the table
|
If vector columns are missing and the table
|
||||||
has embedding functions, then the vector columns
|
has embedding functions, then the vector columns
|
||||||
@@ -2067,7 +2124,7 @@ class LanceTable(Table):
|
|||||||
int
|
int
|
||||||
The number of vectors in the table.
|
The number of vectors in the table.
|
||||||
"""
|
"""
|
||||||
LOOP.run(
|
return LOOP.run(
|
||||||
self._table.add(
|
self._table.add(
|
||||||
data, mode=mode, on_bad_vectors=on_bad_vectors, fill_value=fill_value
|
data, mode=mode, on_bad_vectors=on_bad_vectors, fill_value=fill_value
|
||||||
)
|
)
|
||||||
@@ -2397,8 +2454,8 @@ class LanceTable(Table):
|
|||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def delete(self, where: str):
|
def delete(self, where: str) -> DeleteResult:
|
||||||
LOOP.run(self._table.delete(where))
|
return LOOP.run(self._table.delete(where))
|
||||||
|
|
||||||
def update(
|
def update(
|
||||||
self,
|
self,
|
||||||
@@ -2406,7 +2463,7 @@ class LanceTable(Table):
|
|||||||
values: Optional[dict] = None,
|
values: Optional[dict] = None,
|
||||||
*,
|
*,
|
||||||
values_sql: Optional[Dict[str, str]] = None,
|
values_sql: Optional[Dict[str, str]] = None,
|
||||||
):
|
) -> UpdateResult:
|
||||||
"""
|
"""
|
||||||
This can be used to update zero to all rows depending on how many
|
This can be used to update zero to all rows depending on how many
|
||||||
rows match the where clause.
|
rows match the where clause.
|
||||||
@@ -2424,6 +2481,12 @@ class LanceTable(Table):
|
|||||||
reference existing columns. For example, {"x": "x + 1"} will increment
|
reference existing columns. For example, {"x": "x + 1"} will increment
|
||||||
the x column by 1.
|
the x column by 1.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
UpdateResult
|
||||||
|
- rows_updated: The number of rows that were updated
|
||||||
|
- version: The new version number of the table after the update
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import lancedb
|
>>> import lancedb
|
||||||
@@ -2437,6 +2500,7 @@ class LanceTable(Table):
|
|||||||
1 2 [3.0, 4.0]
|
1 2 [3.0, 4.0]
|
||||||
2 3 [5.0, 6.0]
|
2 3 [5.0, 6.0]
|
||||||
>>> table.update(where="x = 2", values={"vector": [10.0, 10]})
|
>>> table.update(where="x = 2", values={"vector": [10.0, 10]})
|
||||||
|
UpdateResult(rows_updated=1, version=2)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 1 [1.0, 2.0]
|
0 1 [1.0, 2.0]
|
||||||
@@ -2444,7 +2508,7 @@ class LanceTable(Table):
|
|||||||
2 2 [10.0, 10.0]
|
2 2 [10.0, 10.0]
|
||||||
|
|
||||||
"""
|
"""
|
||||||
LOOP.run(self._table.update(values, where=where, updates_sql=values_sql))
|
return LOOP.run(self._table.update(values, where=where, updates_sql=values_sql))
|
||||||
|
|
||||||
def _execute_query(
|
def _execute_query(
|
||||||
self,
|
self,
|
||||||
@@ -2478,8 +2542,10 @@ class LanceTable(Table):
|
|||||||
new_data: DATA,
|
new_data: DATA,
|
||||||
on_bad_vectors: OnBadVectorsType,
|
on_bad_vectors: OnBadVectorsType,
|
||||||
fill_value: float,
|
fill_value: float,
|
||||||
):
|
) -> MergeResult:
|
||||||
LOOP.run(self._table._do_merge(merge, new_data, on_bad_vectors, fill_value))
|
return LOOP.run(
|
||||||
|
self._table._do_merge(merge, new_data, on_bad_vectors, fill_value)
|
||||||
|
)
|
||||||
|
|
||||||
@deprecation.deprecated(
|
@deprecation.deprecated(
|
||||||
deprecated_in="0.21.0",
|
deprecated_in="0.21.0",
|
||||||
@@ -2621,14 +2687,16 @@ class LanceTable(Table):
|
|||||||
|
|
||||||
def add_columns(
|
def add_columns(
|
||||||
self, transforms: Dict[str, str] | pa.field | List[pa.field] | pa.Schema
|
self, transforms: Dict[str, str] | pa.field | List[pa.field] | pa.Schema
|
||||||
):
|
) -> AddColumnsResult:
|
||||||
LOOP.run(self._table.add_columns(transforms))
|
return LOOP.run(self._table.add_columns(transforms))
|
||||||
|
|
||||||
def alter_columns(self, *alterations: Iterable[Dict[str, str]]):
|
def alter_columns(
|
||||||
LOOP.run(self._table.alter_columns(*alterations))
|
self, *alterations: Iterable[Dict[str, str]]
|
||||||
|
) -> AlterColumnsResult:
|
||||||
|
return LOOP.run(self._table.alter_columns(*alterations))
|
||||||
|
|
||||||
def drop_columns(self, columns: Iterable[str]):
|
def drop_columns(self, columns: Iterable[str]) -> DropColumnsResult:
|
||||||
LOOP.run(self._table.drop_columns(columns))
|
return LOOP.run(self._table.drop_columns(columns))
|
||||||
|
|
||||||
def uses_v2_manifest_paths(self) -> bool:
|
def uses_v2_manifest_paths(self) -> bool:
|
||||||
"""
|
"""
|
||||||
@@ -3170,6 +3238,12 @@ class AsyncTable:
|
|||||||
"""
|
"""
|
||||||
await self._inner.wait_for_index(index_names, timeout)
|
await self._inner.wait_for_index(index_names, timeout)
|
||||||
|
|
||||||
|
async def stats(self) -> TableStatistics:
|
||||||
|
"""
|
||||||
|
Retrieve table and fragment statistics.
|
||||||
|
"""
|
||||||
|
return await self._inner.stats()
|
||||||
|
|
||||||
async def add(
|
async def add(
|
||||||
self,
|
self,
|
||||||
data: DATA,
|
data: DATA,
|
||||||
@@ -3177,7 +3251,7 @@ class AsyncTable:
|
|||||||
mode: Optional[Literal["append", "overwrite"]] = "append",
|
mode: Optional[Literal["append", "overwrite"]] = "append",
|
||||||
on_bad_vectors: Optional[OnBadVectorsType] = None,
|
on_bad_vectors: Optional[OnBadVectorsType] = None,
|
||||||
fill_value: Optional[float] = None,
|
fill_value: Optional[float] = None,
|
||||||
):
|
) -> AddResult:
|
||||||
"""Add more data to the [Table](Table).
|
"""Add more data to the [Table](Table).
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
@@ -3216,7 +3290,7 @@ class AsyncTable:
|
|||||||
if isinstance(data, pa.Table):
|
if isinstance(data, pa.Table):
|
||||||
data = data.to_reader()
|
data = data.to_reader()
|
||||||
|
|
||||||
await self._inner.add(data, mode or "append")
|
return await self._inner.add(data, mode or "append")
|
||||||
|
|
||||||
def merge_insert(self, on: Union[str, Iterable[str]]) -> LanceMergeInsertBuilder:
|
def merge_insert(self, on: Union[str, Iterable[str]]) -> LanceMergeInsertBuilder:
|
||||||
"""
|
"""
|
||||||
@@ -3261,10 +3335,12 @@ class AsyncTable:
|
|||||||
>>> table = db.create_table("my_table", data)
|
>>> table = db.create_table("my_table", data)
|
||||||
>>> new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
>>> new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
||||||
>>> # Perform a "upsert" operation
|
>>> # Perform a "upsert" operation
|
||||||
>>> table.merge_insert("a") \\
|
>>> res = table.merge_insert("a") \\
|
||||||
... .when_matched_update_all() \\
|
... .when_matched_update_all() \\
|
||||||
... .when_not_matched_insert_all() \\
|
... .when_not_matched_insert_all() \\
|
||||||
... .execute(new_data)
|
... .execute(new_data)
|
||||||
|
>>> res
|
||||||
|
MergeResult(version=2, num_updated_rows=2, num_inserted_rows=1, num_deleted_rows=0)
|
||||||
>>> # The order of new rows is non-deterministic since we use
|
>>> # The order of new rows is non-deterministic since we use
|
||||||
>>> # a hash-join as part of this operation and so we sort here
|
>>> # a hash-join as part of this operation and so we sort here
|
||||||
>>> table.to_arrow().sort_by("a").to_pandas()
|
>>> table.to_arrow().sort_by("a").to_pandas()
|
||||||
@@ -3273,7 +3349,7 @@ class AsyncTable:
|
|||||||
1 2 x
|
1 2 x
|
||||||
2 3 y
|
2 3 y
|
||||||
3 4 z
|
3 4 z
|
||||||
"""
|
""" # noqa: E501
|
||||||
on = [on] if isinstance(on, str) else list(iter(on))
|
on = [on] if isinstance(on, str) else list(iter(on))
|
||||||
|
|
||||||
return LanceMergeInsertBuilder(self, on)
|
return LanceMergeInsertBuilder(self, on)
|
||||||
@@ -3604,7 +3680,7 @@ class AsyncTable:
|
|||||||
new_data: DATA,
|
new_data: DATA,
|
||||||
on_bad_vectors: OnBadVectorsType,
|
on_bad_vectors: OnBadVectorsType,
|
||||||
fill_value: float,
|
fill_value: float,
|
||||||
):
|
) -> MergeResult:
|
||||||
schema = await self.schema()
|
schema = await self.schema()
|
||||||
if on_bad_vectors is None:
|
if on_bad_vectors is None:
|
||||||
on_bad_vectors = "error"
|
on_bad_vectors = "error"
|
||||||
@@ -3620,7 +3696,7 @@ class AsyncTable:
|
|||||||
)
|
)
|
||||||
if isinstance(data, pa.Table):
|
if isinstance(data, pa.Table):
|
||||||
data = pa.RecordBatchReader.from_batches(data.schema, data.to_batches())
|
data = pa.RecordBatchReader.from_batches(data.schema, data.to_batches())
|
||||||
await self._inner.execute_merge_insert(
|
return await self._inner.execute_merge_insert(
|
||||||
data,
|
data,
|
||||||
dict(
|
dict(
|
||||||
on=merge._on,
|
on=merge._on,
|
||||||
@@ -3632,7 +3708,7 @@ class AsyncTable:
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
async def delete(self, where: str):
|
async def delete(self, where: str) -> DeleteResult:
|
||||||
"""Delete rows from the table.
|
"""Delete rows from the table.
|
||||||
|
|
||||||
This can be used to delete a single row, many rows, all rows, or
|
This can be used to delete a single row, many rows, all rows, or
|
||||||
@@ -3663,6 +3739,7 @@ class AsyncTable:
|
|||||||
1 2 [3.0, 4.0]
|
1 2 [3.0, 4.0]
|
||||||
2 3 [5.0, 6.0]
|
2 3 [5.0, 6.0]
|
||||||
>>> table.delete("x = 2")
|
>>> table.delete("x = 2")
|
||||||
|
DeleteResult(version=2)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 1 [1.0, 2.0]
|
0 1 [1.0, 2.0]
|
||||||
@@ -3676,6 +3753,7 @@ class AsyncTable:
|
|||||||
>>> to_remove
|
>>> to_remove
|
||||||
'1, 5'
|
'1, 5'
|
||||||
>>> table.delete(f"x IN ({to_remove})")
|
>>> table.delete(f"x IN ({to_remove})")
|
||||||
|
DeleteResult(version=3)
|
||||||
>>> table.to_pandas()
|
>>> table.to_pandas()
|
||||||
x vector
|
x vector
|
||||||
0 3 [5.0, 6.0]
|
0 3 [5.0, 6.0]
|
||||||
@@ -3688,7 +3766,7 @@ class AsyncTable:
|
|||||||
*,
|
*,
|
||||||
where: Optional[str] = None,
|
where: Optional[str] = None,
|
||||||
updates_sql: Optional[Dict[str, str]] = None,
|
updates_sql: Optional[Dict[str, str]] = None,
|
||||||
):
|
) -> UpdateResult:
|
||||||
"""
|
"""
|
||||||
This can be used to update zero to all rows in the table.
|
This can be used to update zero to all rows in the table.
|
||||||
|
|
||||||
@@ -3710,6 +3788,13 @@ class AsyncTable:
|
|||||||
literals (e.g. "7" or "'foo'") or they can be expressions based on the
|
literals (e.g. "7" or "'foo'") or they can be expressions based on the
|
||||||
previous value of the row (e.g. "x + 1" to increment the x column by 1)
|
previous value of the row (e.g. "x + 1" to increment the x column by 1)
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
UpdateResult
|
||||||
|
An object containing:
|
||||||
|
- rows_updated: The number of rows that were updated
|
||||||
|
- version: The new version number of the table after the update
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
--------
|
--------
|
||||||
>>> import asyncio
|
>>> import asyncio
|
||||||
@@ -3738,7 +3823,7 @@ class AsyncTable:
|
|||||||
|
|
||||||
async def add_columns(
|
async def add_columns(
|
||||||
self, transforms: dict[str, str] | pa.field | List[pa.field] | pa.Schema
|
self, transforms: dict[str, str] | pa.field | List[pa.field] | pa.Schema
|
||||||
):
|
) -> AddColumnsResult:
|
||||||
"""
|
"""
|
||||||
Add new columns with defined values.
|
Add new columns with defined values.
|
||||||
|
|
||||||
@@ -3750,6 +3835,12 @@ class AsyncTable:
|
|||||||
each row in the table, and can reference existing columns.
|
each row in the table, and can reference existing columns.
|
||||||
Alternatively, you can pass a pyarrow field or schema to add
|
Alternatively, you can pass a pyarrow field or schema to add
|
||||||
new columns with NULLs.
|
new columns with NULLs.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AddColumnsResult
|
||||||
|
version: the new version number of the table after adding columns.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if isinstance(transforms, pa.Field):
|
if isinstance(transforms, pa.Field):
|
||||||
transforms = [transforms]
|
transforms = [transforms]
|
||||||
@@ -3758,11 +3849,13 @@ class AsyncTable:
|
|||||||
):
|
):
|
||||||
transforms = pa.schema(transforms)
|
transforms = pa.schema(transforms)
|
||||||
if isinstance(transforms, pa.Schema):
|
if isinstance(transforms, pa.Schema):
|
||||||
await self._inner.add_columns_with_schema(transforms)
|
return await self._inner.add_columns_with_schema(transforms)
|
||||||
else:
|
else:
|
||||||
await self._inner.add_columns(list(transforms.items()))
|
return await self._inner.add_columns(list(transforms.items()))
|
||||||
|
|
||||||
async def alter_columns(self, *alterations: Iterable[dict[str, Any]]):
|
async def alter_columns(
|
||||||
|
self, *alterations: Iterable[dict[str, Any]]
|
||||||
|
) -> AlterColumnsResult:
|
||||||
"""
|
"""
|
||||||
Alter column names and nullability.
|
Alter column names and nullability.
|
||||||
|
|
||||||
@@ -3782,8 +3875,13 @@ class AsyncTable:
|
|||||||
nullability is not changed. Only non-nullable columns can be changed
|
nullability is not changed. Only non-nullable columns can be changed
|
||||||
to nullable. Currently, you cannot change a nullable column to
|
to nullable. Currently, you cannot change a nullable column to
|
||||||
non-nullable.
|
non-nullable.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
AlterColumnsResult
|
||||||
|
version: the new version number of the table after the alteration.
|
||||||
"""
|
"""
|
||||||
await self._inner.alter_columns(alterations)
|
return await self._inner.alter_columns(alterations)
|
||||||
|
|
||||||
async def drop_columns(self, columns: Iterable[str]):
|
async def drop_columns(self, columns: Iterable[str]):
|
||||||
"""
|
"""
|
||||||
@@ -3794,7 +3892,7 @@ class AsyncTable:
|
|||||||
columns : Iterable[str]
|
columns : Iterable[str]
|
||||||
The names of the columns to drop.
|
The names of the columns to drop.
|
||||||
"""
|
"""
|
||||||
await self._inner.drop_columns(columns)
|
return await self._inner.drop_columns(columns)
|
||||||
|
|
||||||
async def version(self) -> int:
|
async def version(self) -> int:
|
||||||
"""
|
"""
|
||||||
@@ -4068,6 +4166,82 @@ class IndexStatistics:
|
|||||||
return getattr(self, key)
|
return getattr(self, key)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TableStatistics:
|
||||||
|
"""
|
||||||
|
Statistics about a table and fragments.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
total_bytes: int
|
||||||
|
The total number of bytes in the table.
|
||||||
|
num_rows: int
|
||||||
|
The total number of rows in the table.
|
||||||
|
num_indices: int
|
||||||
|
The total number of indices in the table.
|
||||||
|
fragment_stats: FragmentStatistics
|
||||||
|
Statistics about fragments in the table.
|
||||||
|
"""
|
||||||
|
|
||||||
|
total_bytes: int
|
||||||
|
num_rows: int
|
||||||
|
num_indices: int
|
||||||
|
fragment_stats: FragmentStatistics
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FragmentStatistics:
|
||||||
|
"""
|
||||||
|
Statistics about fragments.
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
num_fragments: int
|
||||||
|
The total number of fragments in the table.
|
||||||
|
num_small_fragments: int
|
||||||
|
The total number of small fragments in the table.
|
||||||
|
Small fragments have low row counts and may need to be compacted.
|
||||||
|
lengths: FragmentSummaryStats
|
||||||
|
Statistics about the number of rows in the table fragments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
num_fragments: int
|
||||||
|
num_small_fragments: int
|
||||||
|
lengths: FragmentSummaryStats
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class FragmentSummaryStats:
|
||||||
|
"""
|
||||||
|
Statistics about fragments sizes
|
||||||
|
|
||||||
|
Attributes
|
||||||
|
----------
|
||||||
|
min: int
|
||||||
|
The number of rows in the fragment with the fewest rows.
|
||||||
|
max: int
|
||||||
|
The number of rows in the fragment with the most rows.
|
||||||
|
mean: int
|
||||||
|
The mean number of rows in the fragments.
|
||||||
|
p25: int
|
||||||
|
The 25th percentile of number of rows in the fragments.
|
||||||
|
p50: int
|
||||||
|
The 50th percentile of number of rows in the fragments.
|
||||||
|
p75: int
|
||||||
|
The 75th percentile of number of rows in the fragments.
|
||||||
|
p99: int
|
||||||
|
The 99th percentile of number of rows in the fragments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
min: int
|
||||||
|
max: int
|
||||||
|
mean: int
|
||||||
|
p25: int
|
||||||
|
p50: int
|
||||||
|
p75: int
|
||||||
|
p99: int
|
||||||
|
|
||||||
|
|
||||||
class Tags:
|
class Tags:
|
||||||
"""
|
"""
|
||||||
Table tag manager.
|
Table tag manager.
|
||||||
|
|||||||
@@ -18,15 +18,19 @@ def test_upsert(mem_db):
|
|||||||
{"id": 1, "name": "Bobby"},
|
{"id": 1, "name": "Bobby"},
|
||||||
{"id": 2, "name": "Charlie"},
|
{"id": 2, "name": "Charlie"},
|
||||||
]
|
]
|
||||||
(
|
res = (
|
||||||
table.merge_insert("id")
|
table.merge_insert("id")
|
||||||
.when_matched_update_all()
|
.when_matched_update_all()
|
||||||
.when_not_matched_insert_all()
|
.when_not_matched_insert_all()
|
||||||
.execute(new_users)
|
.execute(new_users)
|
||||||
)
|
)
|
||||||
table.count_rows() # 3
|
table.count_rows() # 3
|
||||||
|
res # {'num_inserted_rows': 1, 'num_updated_rows': 1, 'num_deleted_rows': 0}
|
||||||
# --8<-- [end:upsert_basic]
|
# --8<-- [end:upsert_basic]
|
||||||
assert table.count_rows() == 3
|
assert table.count_rows() == 3
|
||||||
|
assert res.num_inserted_rows == 1
|
||||||
|
assert res.num_deleted_rows == 0
|
||||||
|
assert res.num_updated_rows == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -44,15 +48,22 @@ async def test_upsert_async(mem_db_async):
|
|||||||
{"id": 1, "name": "Bobby"},
|
{"id": 1, "name": "Bobby"},
|
||||||
{"id": 2, "name": "Charlie"},
|
{"id": 2, "name": "Charlie"},
|
||||||
]
|
]
|
||||||
await (
|
res = await (
|
||||||
table.merge_insert("id")
|
table.merge_insert("id")
|
||||||
.when_matched_update_all()
|
.when_matched_update_all()
|
||||||
.when_not_matched_insert_all()
|
.when_not_matched_insert_all()
|
||||||
.execute(new_users)
|
.execute(new_users)
|
||||||
)
|
)
|
||||||
await table.count_rows() # 3
|
await table.count_rows() # 3
|
||||||
|
res
|
||||||
|
# MergeResult(version=2, num_updated_rows=1,
|
||||||
|
# num_inserted_rows=1, num_deleted_rows=0)
|
||||||
# --8<-- [end:upsert_basic_async]
|
# --8<-- [end:upsert_basic_async]
|
||||||
assert await table.count_rows() == 3
|
assert await table.count_rows() == 3
|
||||||
|
assert res.version == 2
|
||||||
|
assert res.num_inserted_rows == 1
|
||||||
|
assert res.num_deleted_rows == 0
|
||||||
|
assert res.num_updated_rows == 1
|
||||||
|
|
||||||
|
|
||||||
def test_insert_if_not_exists(mem_db):
|
def test_insert_if_not_exists(mem_db):
|
||||||
@@ -69,10 +80,19 @@ def test_insert_if_not_exists(mem_db):
|
|||||||
{"domain": "google.com", "name": "Google"},
|
{"domain": "google.com", "name": "Google"},
|
||||||
{"domain": "facebook.com", "name": "Facebook"},
|
{"domain": "facebook.com", "name": "Facebook"},
|
||||||
]
|
]
|
||||||
(table.merge_insert("domain").when_not_matched_insert_all().execute(new_domains))
|
res = (
|
||||||
|
table.merge_insert("domain").when_not_matched_insert_all().execute(new_domains)
|
||||||
|
)
|
||||||
table.count_rows() # 3
|
table.count_rows() # 3
|
||||||
|
res
|
||||||
|
# MergeResult(version=2, num_updated_rows=0,
|
||||||
|
# num_inserted_rows=1, num_deleted_rows=0)
|
||||||
# --8<-- [end:insert_if_not_exists]
|
# --8<-- [end:insert_if_not_exists]
|
||||||
assert table.count_rows() == 3
|
assert table.count_rows() == 3
|
||||||
|
assert res.version == 2
|
||||||
|
assert res.num_inserted_rows == 1
|
||||||
|
assert res.num_deleted_rows == 0
|
||||||
|
assert res.num_updated_rows == 0
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -90,12 +110,19 @@ async def test_insert_if_not_exists_async(mem_db_async):
|
|||||||
{"domain": "google.com", "name": "Google"},
|
{"domain": "google.com", "name": "Google"},
|
||||||
{"domain": "facebook.com", "name": "Facebook"},
|
{"domain": "facebook.com", "name": "Facebook"},
|
||||||
]
|
]
|
||||||
await (
|
res = await (
|
||||||
table.merge_insert("domain").when_not_matched_insert_all().execute(new_domains)
|
table.merge_insert("domain").when_not_matched_insert_all().execute(new_domains)
|
||||||
)
|
)
|
||||||
await table.count_rows() # 3
|
await table.count_rows() # 3
|
||||||
# --8<-- [end:insert_if_not_exists_async]
|
res
|
||||||
|
# MergeResult(version=2, num_updated_rows=0,
|
||||||
|
# num_inserted_rows=1, num_deleted_rows=0)
|
||||||
|
# --8<-- [end:insert_if_not_exists]
|
||||||
assert await table.count_rows() == 3
|
assert await table.count_rows() == 3
|
||||||
|
assert res.version == 2
|
||||||
|
assert res.num_inserted_rows == 1
|
||||||
|
assert res.num_deleted_rows == 0
|
||||||
|
assert res.num_updated_rows == 0
|
||||||
|
|
||||||
|
|
||||||
def test_replace_range(mem_db):
|
def test_replace_range(mem_db):
|
||||||
@@ -113,7 +140,7 @@ def test_replace_range(mem_db):
|
|||||||
new_chunks = [
|
new_chunks = [
|
||||||
{"doc_id": 1, "chunk_id": 0, "text": "Baz"},
|
{"doc_id": 1, "chunk_id": 0, "text": "Baz"},
|
||||||
]
|
]
|
||||||
(
|
res = (
|
||||||
table.merge_insert(["doc_id", "chunk_id"])
|
table.merge_insert(["doc_id", "chunk_id"])
|
||||||
.when_matched_update_all()
|
.when_matched_update_all()
|
||||||
.when_not_matched_insert_all()
|
.when_not_matched_insert_all()
|
||||||
@@ -121,8 +148,15 @@ def test_replace_range(mem_db):
|
|||||||
.execute(new_chunks)
|
.execute(new_chunks)
|
||||||
)
|
)
|
||||||
table.count_rows("doc_id = 1") # 1
|
table.count_rows("doc_id = 1") # 1
|
||||||
# --8<-- [end:replace_range]
|
res
|
||||||
|
# MergeResult(version=2, num_updated_rows=1,
|
||||||
|
# num_inserted_rows=0, num_deleted_rows=1)
|
||||||
|
# --8<-- [end:insert_if_not_exists]
|
||||||
assert table.count_rows("doc_id = 1") == 1
|
assert table.count_rows("doc_id = 1") == 1
|
||||||
|
assert res.version == 2
|
||||||
|
assert res.num_inserted_rows == 0
|
||||||
|
assert res.num_deleted_rows == 1
|
||||||
|
assert res.num_updated_rows == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@@ -141,7 +175,7 @@ async def test_replace_range_async(mem_db_async):
|
|||||||
new_chunks = [
|
new_chunks = [
|
||||||
{"doc_id": 1, "chunk_id": 0, "text": "Baz"},
|
{"doc_id": 1, "chunk_id": 0, "text": "Baz"},
|
||||||
]
|
]
|
||||||
await (
|
res = await (
|
||||||
table.merge_insert(["doc_id", "chunk_id"])
|
table.merge_insert(["doc_id", "chunk_id"])
|
||||||
.when_matched_update_all()
|
.when_matched_update_all()
|
||||||
.when_not_matched_insert_all()
|
.when_not_matched_insert_all()
|
||||||
@@ -149,5 +183,12 @@ async def test_replace_range_async(mem_db_async):
|
|||||||
.execute(new_chunks)
|
.execute(new_chunks)
|
||||||
)
|
)
|
||||||
await table.count_rows("doc_id = 1") # 1
|
await table.count_rows("doc_id = 1") # 1
|
||||||
# --8<-- [end:replace_range_async]
|
res
|
||||||
|
# MergeResult(version=2, num_updated_rows=1,
|
||||||
|
# num_inserted_rows=0, num_deleted_rows=1)
|
||||||
|
# --8<-- [end:insert_if_not_exists]
|
||||||
assert await table.count_rows("doc_id = 1") == 1
|
assert await table.count_rows("doc_id = 1") == 1
|
||||||
|
assert res.version == 2
|
||||||
|
assert res.num_inserted_rows == 0
|
||||||
|
assert res.num_deleted_rows == 1
|
||||||
|
assert res.num_updated_rows == 1
|
||||||
|
|||||||
@@ -389,6 +389,50 @@ def test_table_wait_for_index_timeout():
|
|||||||
table.wait_for_index(["id_idx"], timedelta(seconds=1))
|
table.wait_for_index(["id_idx"], timedelta(seconds=1))
|
||||||
|
|
||||||
|
|
||||||
|
def test_stats():
|
||||||
|
stats = {
|
||||||
|
"total_bytes": 38,
|
||||||
|
"num_rows": 2,
|
||||||
|
"num_indices": 0,
|
||||||
|
"fragment_stats": {
|
||||||
|
"num_fragments": 1,
|
||||||
|
"num_small_fragments": 1,
|
||||||
|
"lengths": {
|
||||||
|
"min": 2,
|
||||||
|
"max": 2,
|
||||||
|
"mean": 2,
|
||||||
|
"p25": 2,
|
||||||
|
"p50": 2,
|
||||||
|
"p75": 2,
|
||||||
|
"p99": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
def handler(request):
|
||||||
|
if request.path == "/v1/table/test/create/?mode=create":
|
||||||
|
request.send_response(200)
|
||||||
|
request.send_header("Content-Type", "application/json")
|
||||||
|
request.end_headers()
|
||||||
|
request.wfile.write(b"{}")
|
||||||
|
elif request.path == "/v1/table/test/stats/":
|
||||||
|
request.send_response(200)
|
||||||
|
request.send_header("Content-Type", "application/json")
|
||||||
|
request.end_headers()
|
||||||
|
payload = json.dumps(stats)
|
||||||
|
request.wfile.write(payload.encode())
|
||||||
|
else:
|
||||||
|
print(request.path)
|
||||||
|
request.send_response(404)
|
||||||
|
request.end_headers()
|
||||||
|
|
||||||
|
with mock_lancedb_connection(handler) as db:
|
||||||
|
table = db.create_table("test", [{"id": 1}])
|
||||||
|
res = table.stats()
|
||||||
|
print(f"{res=}")
|
||||||
|
assert res == stats
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def query_test_table(query_handler, *, server_version=Version("0.1.0")):
|
def query_test_table(query_handler, *, server_version=Version("0.1.0")):
|
||||||
def handler(request):
|
def handler(request):
|
||||||
|
|||||||
@@ -106,15 +106,22 @@ async def test_update_async(mem_db_async: AsyncConnection):
|
|||||||
table = await mem_db_async.create_table("some_table", data=[{"id": 0}])
|
table = await mem_db_async.create_table("some_table", data=[{"id": 0}])
|
||||||
assert await table.count_rows("id == 0") == 1
|
assert await table.count_rows("id == 0") == 1
|
||||||
assert await table.count_rows("id == 7") == 0
|
assert await table.count_rows("id == 7") == 0
|
||||||
await table.update({"id": 7})
|
update_res = await table.update({"id": 7})
|
||||||
|
assert update_res.rows_updated == 1
|
||||||
|
assert update_res.version == 2
|
||||||
assert await table.count_rows("id == 7") == 1
|
assert await table.count_rows("id == 7") == 1
|
||||||
assert await table.count_rows("id == 0") == 0
|
assert await table.count_rows("id == 0") == 0
|
||||||
await table.add([{"id": 2}])
|
add_res = await table.add([{"id": 2}])
|
||||||
await table.update(where="id % 2 == 0", updates_sql={"id": "5"})
|
assert add_res.version == 3
|
||||||
|
update_res = await table.update(where="id % 2 == 0", updates_sql={"id": "5"})
|
||||||
|
assert update_res.rows_updated == 1
|
||||||
|
assert update_res.version == 4
|
||||||
assert await table.count_rows("id == 7") == 1
|
assert await table.count_rows("id == 7") == 1
|
||||||
assert await table.count_rows("id == 2") == 0
|
assert await table.count_rows("id == 2") == 0
|
||||||
assert await table.count_rows("id == 5") == 1
|
assert await table.count_rows("id == 5") == 1
|
||||||
await table.update({"id": 10}, where="id == 5")
|
update_res = await table.update({"id": 10}, where="id == 5")
|
||||||
|
assert update_res.rows_updated == 1
|
||||||
|
assert update_res.version == 5
|
||||||
assert await table.count_rows("id == 10") == 1
|
assert await table.count_rows("id == 10") == 1
|
||||||
|
|
||||||
|
|
||||||
@@ -437,7 +444,8 @@ def test_add_pydantic_model(mem_db: DBConnection):
|
|||||||
content="foo", meta=Metadata(source="bar", timestamp=datetime.now())
|
content="foo", meta=Metadata(source="bar", timestamp=datetime.now())
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
tbl.add([expected])
|
add_res = tbl.add([expected])
|
||||||
|
assert add_res.version == 2
|
||||||
|
|
||||||
result = tbl.search([0.0, 0.0]).limit(1).to_pydantic(LanceSchema)[0]
|
result = tbl.search([0.0, 0.0]).limit(1).to_pydantic(LanceSchema)[0]
|
||||||
assert result == expected
|
assert result == expected
|
||||||
@@ -459,11 +467,12 @@ async def test_add_async(mem_db_async: AsyncConnection):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
assert await table.count_rows() == 2
|
assert await table.count_rows() == 2
|
||||||
await table.add(
|
add_res = await table.add(
|
||||||
data=[
|
data=[
|
||||||
{"vector": [10.0, 11.0], "item": "baz", "price": 30.0},
|
{"vector": [10.0, 11.0], "item": "baz", "price": 30.0},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
assert add_res.version == 2
|
||||||
assert await table.count_rows() == 3
|
assert await table.count_rows() == 3
|
||||||
|
|
||||||
|
|
||||||
@@ -795,7 +804,8 @@ def test_delete(mem_db: DBConnection):
|
|||||||
)
|
)
|
||||||
assert len(table) == 2
|
assert len(table) == 2
|
||||||
assert len(table.list_versions()) == 1
|
assert len(table.list_versions()) == 1
|
||||||
table.delete("id=0")
|
delete_res = table.delete("id=0")
|
||||||
|
assert delete_res.version == 2
|
||||||
assert len(table.list_versions()) == 2
|
assert len(table.list_versions()) == 2
|
||||||
assert table.version == 2
|
assert table.version == 2
|
||||||
assert len(table) == 1
|
assert len(table) == 1
|
||||||
@@ -809,7 +819,9 @@ def test_update(mem_db: DBConnection):
|
|||||||
)
|
)
|
||||||
assert len(table) == 2
|
assert len(table) == 2
|
||||||
assert len(table.list_versions()) == 1
|
assert len(table.list_versions()) == 1
|
||||||
table.update(where="id=0", values={"vector": [1.1, 1.1]})
|
update_res = table.update(where="id=0", values={"vector": [1.1, 1.1]})
|
||||||
|
assert update_res.version == 2
|
||||||
|
assert update_res.rows_updated == 1
|
||||||
assert len(table.list_versions()) == 2
|
assert len(table.list_versions()) == 2
|
||||||
assert table.version == 2
|
assert table.version == 2
|
||||||
assert len(table) == 2
|
assert len(table) == 2
|
||||||
@@ -898,9 +910,16 @@ def test_merge_insert(mem_db: DBConnection):
|
|||||||
new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
new_data = pa.table({"a": [2, 3, 4], "b": ["x", "y", "z"]})
|
||||||
|
|
||||||
# upsert
|
# upsert
|
||||||
table.merge_insert(
|
merge_insert_res = (
|
||||||
"a"
|
table.merge_insert("a")
|
||||||
).when_matched_update_all().when_not_matched_insert_all().execute(new_data)
|
.when_matched_update_all()
|
||||||
|
.when_not_matched_insert_all()
|
||||||
|
.execute(new_data)
|
||||||
|
)
|
||||||
|
assert merge_insert_res.version == 2
|
||||||
|
assert merge_insert_res.num_inserted_rows == 1
|
||||||
|
assert merge_insert_res.num_updated_rows == 2
|
||||||
|
assert merge_insert_res.num_deleted_rows == 0
|
||||||
|
|
||||||
expected = pa.table({"a": [1, 2, 3, 4], "b": ["a", "x", "y", "z"]})
|
expected = pa.table({"a": [1, 2, 3, 4], "b": ["a", "x", "y", "z"]})
|
||||||
assert table.to_arrow().sort_by("a") == expected
|
assert table.to_arrow().sort_by("a") == expected
|
||||||
@@ -908,17 +927,28 @@ def test_merge_insert(mem_db: DBConnection):
|
|||||||
table.restore(version)
|
table.restore(version)
|
||||||
|
|
||||||
# conditional update
|
# conditional update
|
||||||
table.merge_insert("a").when_matched_update_all(where="target.b = 'b'").execute(
|
merge_insert_res = (
|
||||||
new_data
|
table.merge_insert("a")
|
||||||
|
.when_matched_update_all(where="target.b = 'b'")
|
||||||
|
.execute(new_data)
|
||||||
)
|
)
|
||||||
|
assert merge_insert_res.version == 4
|
||||||
|
assert merge_insert_res.num_inserted_rows == 0
|
||||||
|
assert merge_insert_res.num_updated_rows == 1
|
||||||
|
assert merge_insert_res.num_deleted_rows == 0
|
||||||
expected = pa.table({"a": [1, 2, 3], "b": ["a", "x", "c"]})
|
expected = pa.table({"a": [1, 2, 3], "b": ["a", "x", "c"]})
|
||||||
assert table.to_arrow().sort_by("a") == expected
|
assert table.to_arrow().sort_by("a") == expected
|
||||||
|
|
||||||
table.restore(version)
|
table.restore(version)
|
||||||
|
|
||||||
# insert-if-not-exists
|
# insert-if-not-exists
|
||||||
table.merge_insert("a").when_not_matched_insert_all().execute(new_data)
|
merge_insert_res = (
|
||||||
|
table.merge_insert("a").when_not_matched_insert_all().execute(new_data)
|
||||||
|
)
|
||||||
|
assert merge_insert_res.version == 6
|
||||||
|
assert merge_insert_res.num_inserted_rows == 1
|
||||||
|
assert merge_insert_res.num_updated_rows == 0
|
||||||
|
assert merge_insert_res.num_deleted_rows == 0
|
||||||
expected = pa.table({"a": [1, 2, 3, 4], "b": ["a", "b", "c", "z"]})
|
expected = pa.table({"a": [1, 2, 3, 4], "b": ["a", "b", "c", "z"]})
|
||||||
assert table.to_arrow().sort_by("a") == expected
|
assert table.to_arrow().sort_by("a") == expected
|
||||||
|
|
||||||
@@ -927,13 +957,17 @@ def test_merge_insert(mem_db: DBConnection):
|
|||||||
new_data = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
new_data = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
||||||
|
|
||||||
# replace-range
|
# replace-range
|
||||||
(
|
merge_insert_res = (
|
||||||
table.merge_insert("a")
|
table.merge_insert("a")
|
||||||
.when_matched_update_all()
|
.when_matched_update_all()
|
||||||
.when_not_matched_insert_all()
|
.when_not_matched_insert_all()
|
||||||
.when_not_matched_by_source_delete("a > 2")
|
.when_not_matched_by_source_delete("a > 2")
|
||||||
.execute(new_data)
|
.execute(new_data)
|
||||||
)
|
)
|
||||||
|
assert merge_insert_res.version == 8
|
||||||
|
assert merge_insert_res.num_inserted_rows == 1
|
||||||
|
assert merge_insert_res.num_updated_rows == 1
|
||||||
|
assert merge_insert_res.num_deleted_rows == 1
|
||||||
|
|
||||||
expected = pa.table({"a": [1, 2, 4], "b": ["a", "x", "z"]})
|
expected = pa.table({"a": [1, 2, 4], "b": ["a", "x", "z"]})
|
||||||
assert table.to_arrow().sort_by("a") == expected
|
assert table.to_arrow().sort_by("a") == expected
|
||||||
@@ -941,11 +975,17 @@ def test_merge_insert(mem_db: DBConnection):
|
|||||||
table.restore(version)
|
table.restore(version)
|
||||||
|
|
||||||
# replace-range no condition
|
# replace-range no condition
|
||||||
table.merge_insert(
|
merge_insert_res = (
|
||||||
"a"
|
table.merge_insert("a")
|
||||||
).when_matched_update_all().when_not_matched_insert_all().when_not_matched_by_source_delete().execute(
|
.when_matched_update_all()
|
||||||
new_data
|
.when_not_matched_insert_all()
|
||||||
|
.when_not_matched_by_source_delete()
|
||||||
|
.execute(new_data)
|
||||||
)
|
)
|
||||||
|
assert merge_insert_res.version == 10
|
||||||
|
assert merge_insert_res.num_inserted_rows == 1
|
||||||
|
assert merge_insert_res.num_updated_rows == 1
|
||||||
|
assert merge_insert_res.num_deleted_rows == 2
|
||||||
|
|
||||||
expected = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
expected = pa.table({"a": [2, 4], "b": ["x", "z"]})
|
||||||
assert table.to_arrow().sort_by("a") == expected
|
assert table.to_arrow().sort_by("a") == expected
|
||||||
@@ -1478,11 +1518,13 @@ def test_restore_consistency(tmp_path):
|
|||||||
def test_add_columns(mem_db: DBConnection):
|
def test_add_columns(mem_db: DBConnection):
|
||||||
data = pa.table({"id": [0, 1]})
|
data = pa.table({"id": [0, 1]})
|
||||||
table = LanceTable.create(mem_db, "my_table", data=data)
|
table = LanceTable.create(mem_db, "my_table", data=data)
|
||||||
table.add_columns({"new_col": "id + 2"})
|
add_columns_res = table.add_columns({"new_col": "id + 2"})
|
||||||
|
assert add_columns_res.version == 2
|
||||||
assert table.to_arrow().column_names == ["id", "new_col"]
|
assert table.to_arrow().column_names == ["id", "new_col"]
|
||||||
assert table.to_arrow()["new_col"].to_pylist() == [2, 3]
|
assert table.to_arrow()["new_col"].to_pylist() == [2, 3]
|
||||||
|
|
||||||
table.add_columns({"null_int": "cast(null as bigint)"})
|
add_columns_res = table.add_columns({"null_int": "cast(null as bigint)"})
|
||||||
|
assert add_columns_res.version == 3
|
||||||
assert table.schema.field("null_int").type == pa.int64()
|
assert table.schema.field("null_int").type == pa.int64()
|
||||||
|
|
||||||
|
|
||||||
@@ -1490,7 +1532,8 @@ def test_add_columns(mem_db: DBConnection):
|
|||||||
async def test_add_columns_async(mem_db_async: AsyncConnection):
|
async def test_add_columns_async(mem_db_async: AsyncConnection):
|
||||||
data = pa.table({"id": [0, 1]})
|
data = pa.table({"id": [0, 1]})
|
||||||
table = await mem_db_async.create_table("my_table", data=data)
|
table = await mem_db_async.create_table("my_table", data=data)
|
||||||
await table.add_columns({"new_col": "id + 2"})
|
add_columns_res = await table.add_columns({"new_col": "id + 2"})
|
||||||
|
assert add_columns_res.version == 2
|
||||||
data = await table.to_arrow()
|
data = await table.to_arrow()
|
||||||
assert data.column_names == ["id", "new_col"]
|
assert data.column_names == ["id", "new_col"]
|
||||||
assert data["new_col"].to_pylist() == [2, 3]
|
assert data["new_col"].to_pylist() == [2, 3]
|
||||||
@@ -1500,9 +1543,10 @@ async def test_add_columns_async(mem_db_async: AsyncConnection):
|
|||||||
async def test_add_columns_with_schema(mem_db_async: AsyncConnection):
|
async def test_add_columns_with_schema(mem_db_async: AsyncConnection):
|
||||||
data = pa.table({"id": [0, 1]})
|
data = pa.table({"id": [0, 1]})
|
||||||
table = await mem_db_async.create_table("my_table", data=data)
|
table = await mem_db_async.create_table("my_table", data=data)
|
||||||
await table.add_columns(
|
add_columns_res = await table.add_columns(
|
||||||
[pa.field("x", pa.int64()), pa.field("vector", pa.list_(pa.float32(), 8))]
|
[pa.field("x", pa.int64()), pa.field("vector", pa.list_(pa.float32(), 8))]
|
||||||
)
|
)
|
||||||
|
assert add_columns_res.version == 2
|
||||||
|
|
||||||
assert await table.schema() == pa.schema(
|
assert await table.schema() == pa.schema(
|
||||||
[
|
[
|
||||||
@@ -1513,11 +1557,12 @@ async def test_add_columns_with_schema(mem_db_async: AsyncConnection):
|
|||||||
)
|
)
|
||||||
|
|
||||||
table = await mem_db_async.create_table("table2", data=data)
|
table = await mem_db_async.create_table("table2", data=data)
|
||||||
await table.add_columns(
|
add_columns_res = await table.add_columns(
|
||||||
pa.schema(
|
pa.schema(
|
||||||
[pa.field("y", pa.int64()), pa.field("emb", pa.list_(pa.float32(), 8))]
|
[pa.field("y", pa.int64()), pa.field("emb", pa.list_(pa.float32(), 8))]
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
assert add_columns_res.version == 2
|
||||||
assert await table.schema() == pa.schema(
|
assert await table.schema() == pa.schema(
|
||||||
[
|
[
|
||||||
pa.field("id", pa.int64()),
|
pa.field("id", pa.int64()),
|
||||||
@@ -1530,7 +1575,8 @@ async def test_add_columns_with_schema(mem_db_async: AsyncConnection):
|
|||||||
def test_alter_columns(mem_db: DBConnection):
|
def test_alter_columns(mem_db: DBConnection):
|
||||||
data = pa.table({"id": [0, 1]})
|
data = pa.table({"id": [0, 1]})
|
||||||
table = mem_db.create_table("my_table", data=data)
|
table = mem_db.create_table("my_table", data=data)
|
||||||
table.alter_columns({"path": "id", "rename": "new_id"})
|
alter_columns_res = table.alter_columns({"path": "id", "rename": "new_id"})
|
||||||
|
assert alter_columns_res.version == 2
|
||||||
assert table.to_arrow().column_names == ["new_id"]
|
assert table.to_arrow().column_names == ["new_id"]
|
||||||
|
|
||||||
|
|
||||||
@@ -1538,9 +1584,13 @@ def test_alter_columns(mem_db: DBConnection):
|
|||||||
async def test_alter_columns_async(mem_db_async: AsyncConnection):
|
async def test_alter_columns_async(mem_db_async: AsyncConnection):
|
||||||
data = pa.table({"id": [0, 1]})
|
data = pa.table({"id": [0, 1]})
|
||||||
table = await mem_db_async.create_table("my_table", data=data)
|
table = await mem_db_async.create_table("my_table", data=data)
|
||||||
await table.alter_columns({"path": "id", "rename": "new_id"})
|
alter_columns_res = await table.alter_columns({"path": "id", "rename": "new_id"})
|
||||||
|
assert alter_columns_res.version == 2
|
||||||
assert (await table.to_arrow()).column_names == ["new_id"]
|
assert (await table.to_arrow()).column_names == ["new_id"]
|
||||||
await table.alter_columns(dict(path="new_id", data_type=pa.int16(), nullable=True))
|
alter_columns_res = await table.alter_columns(
|
||||||
|
dict(path="new_id", data_type=pa.int16(), nullable=True)
|
||||||
|
)
|
||||||
|
assert alter_columns_res.version == 3
|
||||||
data = await table.to_arrow()
|
data = await table.to_arrow()
|
||||||
assert data.column(0).type == pa.int16()
|
assert data.column(0).type == pa.int16()
|
||||||
assert data.schema.field(0).nullable
|
assert data.schema.field(0).nullable
|
||||||
@@ -1549,7 +1599,8 @@ async def test_alter_columns_async(mem_db_async: AsyncConnection):
|
|||||||
def test_drop_columns(mem_db: DBConnection):
|
def test_drop_columns(mem_db: DBConnection):
|
||||||
data = pa.table({"id": [0, 1], "category": ["a", "b"]})
|
data = pa.table({"id": [0, 1], "category": ["a", "b"]})
|
||||||
table = mem_db.create_table("my_table", data=data)
|
table = mem_db.create_table("my_table", data=data)
|
||||||
table.drop_columns(["category"])
|
drop_columns_res = table.drop_columns(["category"])
|
||||||
|
assert drop_columns_res.version == 2
|
||||||
assert table.to_arrow().column_names == ["id"]
|
assert table.to_arrow().column_names == ["id"]
|
||||||
|
|
||||||
|
|
||||||
@@ -1557,7 +1608,8 @@ def test_drop_columns(mem_db: DBConnection):
|
|||||||
async def test_drop_columns_async(mem_db_async: AsyncConnection):
|
async def test_drop_columns_async(mem_db_async: AsyncConnection):
|
||||||
data = pa.table({"id": [0, 1], "category": ["a", "b"]})
|
data = pa.table({"id": [0, 1], "category": ["a", "b"]})
|
||||||
table = await mem_db_async.create_table("my_table", data=data)
|
table = await mem_db_async.create_table("my_table", data=data)
|
||||||
await table.drop_columns(["category"])
|
drop_columns_res = await table.drop_columns(["category"])
|
||||||
|
assert drop_columns_res.version == 2
|
||||||
assert (await table.to_arrow()).column_names == ["id"]
|
assert (await table.to_arrow()).column_names == ["id"]
|
||||||
|
|
||||||
|
|
||||||
@@ -1695,3 +1747,31 @@ def test_replace_field_metadata(tmp_path):
|
|||||||
schema = table.schema
|
schema = table.schema
|
||||||
field = schema[0].metadata
|
field = schema[0].metadata
|
||||||
assert field == {b"foo": b"bar"}
|
assert field == {b"foo": b"bar"}
|
||||||
|
|
||||||
|
|
||||||
|
def test_stats(mem_db: DBConnection):
|
||||||
|
table = mem_db.create_table(
|
||||||
|
"my_table",
|
||||||
|
data=[{"text": "foo", "id": 0}, {"text": "bar", "id": 1}],
|
||||||
|
)
|
||||||
|
assert len(table) == 2
|
||||||
|
stats = table.stats()
|
||||||
|
print(f"{stats=}")
|
||||||
|
assert stats == {
|
||||||
|
"total_bytes": 38,
|
||||||
|
"num_rows": 2,
|
||||||
|
"num_indices": 0,
|
||||||
|
"fragment_stats": {
|
||||||
|
"num_fragments": 1,
|
||||||
|
"num_small_fragments": 1,
|
||||||
|
"lengths": {
|
||||||
|
"min": 2,
|
||||||
|
"max": 2,
|
||||||
|
"mean": 2,
|
||||||
|
"p25": 2,
|
||||||
|
"p50": 2,
|
||||||
|
"p75": 2,
|
||||||
|
"p99": 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,7 +11,10 @@ use pyo3::{
|
|||||||
wrap_pyfunction, Bound, PyResult, Python,
|
wrap_pyfunction, Bound, PyResult, Python,
|
||||||
};
|
};
|
||||||
use query::{FTSQuery, HybridQuery, Query, VectorQuery};
|
use query::{FTSQuery, HybridQuery, Query, VectorQuery};
|
||||||
use table::Table;
|
use table::{
|
||||||
|
AddColumnsResult, AddResult, AlterColumnsResult, DeleteResult, DropColumnsResult, MergeResult,
|
||||||
|
Table, UpdateResult,
|
||||||
|
};
|
||||||
|
|
||||||
pub mod arrow;
|
pub mod arrow;
|
||||||
pub mod connection;
|
pub mod connection;
|
||||||
@@ -35,6 +38,13 @@ pub fn _lancedb(_py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> {
|
|||||||
m.add_class::<HybridQuery>()?;
|
m.add_class::<HybridQuery>()?;
|
||||||
m.add_class::<VectorQuery>()?;
|
m.add_class::<VectorQuery>()?;
|
||||||
m.add_class::<RecordBatchStream>()?;
|
m.add_class::<RecordBatchStream>()?;
|
||||||
|
m.add_class::<AddColumnsResult>()?;
|
||||||
|
m.add_class::<AlterColumnsResult>()?;
|
||||||
|
m.add_class::<AddResult>()?;
|
||||||
|
m.add_class::<MergeResult>()?;
|
||||||
|
m.add_class::<DeleteResult>()?;
|
||||||
|
m.add_class::<DropColumnsResult>()?;
|
||||||
|
m.add_class::<UpdateResult>()?;
|
||||||
m.add_function(wrap_pyfunction!(connect, m)?)?;
|
m.add_function(wrap_pyfunction!(connect, m)?)?;
|
||||||
m.add_function(wrap_pyfunction!(util::validate_table_name, m)?)?;
|
m.add_function(wrap_pyfunction!(util::validate_table_name, m)?)?;
|
||||||
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
|
m.add("__version__", env!("CARGO_PKG_VERSION"))?;
|
||||||
|
|||||||
@@ -58,6 +58,170 @@ pub struct OptimizeStats {
|
|||||||
pub prune: RemovalStats,
|
pub prune: RemovalStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct UpdateResult {
|
||||||
|
pub rows_updated: u64,
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl UpdateResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"UpdateResult(rows_updated={}, version={})",
|
||||||
|
self.rows_updated, self.version
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::UpdateResult> for UpdateResult {
|
||||||
|
fn from(result: lancedb::table::UpdateResult) -> Self {
|
||||||
|
Self {
|
||||||
|
rows_updated: result.rows_updated,
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct AddResult {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl AddResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!("AddResult(version={})", self.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AddResult> for AddResult {
|
||||||
|
fn from(result: lancedb::table::AddResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DeleteResult {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl DeleteResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!("DeleteResult(version={})", self.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::DeleteResult> for DeleteResult {
|
||||||
|
fn from(result: lancedb::table::DeleteResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MergeResult {
|
||||||
|
pub version: u64,
|
||||||
|
pub num_updated_rows: u64,
|
||||||
|
pub num_inserted_rows: u64,
|
||||||
|
pub num_deleted_rows: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl MergeResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"MergeResult(version={}, num_updated_rows={}, num_inserted_rows={}, num_deleted_rows={})",
|
||||||
|
self.version,
|
||||||
|
self.num_updated_rows,
|
||||||
|
self.num_inserted_rows,
|
||||||
|
self.num_deleted_rows
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::MergeResult> for MergeResult {
|
||||||
|
fn from(result: lancedb::table::MergeResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
num_updated_rows: result.num_updated_rows,
|
||||||
|
num_inserted_rows: result.num_inserted_rows,
|
||||||
|
num_deleted_rows: result.num_deleted_rows,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct AddColumnsResult {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl AddColumnsResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!("AddColumnsResult(version={})", self.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AddColumnsResult> for AddColumnsResult {
|
||||||
|
fn from(result: lancedb::table::AddColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct AlterColumnsResult {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl AlterColumnsResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!("AlterColumnsResult(version={})", self.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::AlterColumnsResult> for AlterColumnsResult {
|
||||||
|
fn from(result: lancedb::table::AlterColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass(get_all)]
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DropColumnsResult {
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl DropColumnsResult {
|
||||||
|
pub fn __repr__(&self) -> String {
|
||||||
|
format!("DropColumnsResult(version={})", self.version)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<lancedb::table::DropColumnsResult> for DropColumnsResult {
|
||||||
|
fn from(result: lancedb::table::DropColumnsResult) -> Self {
|
||||||
|
Self {
|
||||||
|
version: result.version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[pyclass]
|
#[pyclass]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
// We keep a copy of the name to use if the inner table is dropped
|
// We keep a copy of the name to use if the inner table is dropped
|
||||||
@@ -132,15 +296,16 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
op.execute().await.infer_error()?;
|
let result = op.execute().await.infer_error()?;
|
||||||
Ok(())
|
Ok(AddResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete(self_: PyRef<'_, Self>, condition: String) -> PyResult<Bound<'_, PyAny>> {
|
pub fn delete(self_: PyRef<'_, Self>, condition: String) -> PyResult<Bound<'_, PyAny>> {
|
||||||
let inner = self_.inner_ref()?.clone();
|
let inner = self_.inner_ref()?.clone();
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
inner.delete(&condition).await.infer_error()
|
let result = inner.delete(&condition).await.infer_error()?;
|
||||||
|
Ok(DeleteResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,8 +325,8 @@ impl Table {
|
|||||||
op = op.column(column_name, value);
|
op = op.column(column_name, value);
|
||||||
}
|
}
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
op.execute().await.infer_error()?;
|
let result = op.execute().await.infer_error()?;
|
||||||
Ok(())
|
Ok(UpdateResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,6 +444,40 @@ impl Table {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stats(self_: PyRef<'_, Self>) -> PyResult<Bound<'_, PyAny>> {
|
||||||
|
let inner = self_.inner_ref()?.clone();
|
||||||
|
future_into_py(self_.py(), async move {
|
||||||
|
let stats = inner.stats().await.infer_error()?;
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let dict = PyDict::new(py);
|
||||||
|
dict.set_item("total_bytes", stats.total_bytes)?;
|
||||||
|
dict.set_item("num_rows", stats.num_rows)?;
|
||||||
|
dict.set_item("num_indices", stats.num_indices)?;
|
||||||
|
|
||||||
|
let fragment_stats = PyDict::new(py);
|
||||||
|
fragment_stats.set_item("num_fragments", stats.fragment_stats.num_fragments)?;
|
||||||
|
fragment_stats.set_item(
|
||||||
|
"num_small_fragments",
|
||||||
|
stats.fragment_stats.num_small_fragments,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let fragment_lengths = PyDict::new(py);
|
||||||
|
fragment_lengths.set_item("min", stats.fragment_stats.lengths.min)?;
|
||||||
|
fragment_lengths.set_item("max", stats.fragment_stats.lengths.max)?;
|
||||||
|
fragment_lengths.set_item("mean", stats.fragment_stats.lengths.mean)?;
|
||||||
|
fragment_lengths.set_item("p25", stats.fragment_stats.lengths.p25)?;
|
||||||
|
fragment_lengths.set_item("p50", stats.fragment_stats.lengths.p50)?;
|
||||||
|
fragment_lengths.set_item("p75", stats.fragment_stats.lengths.p75)?;
|
||||||
|
fragment_lengths.set_item("p99", stats.fragment_stats.lengths.p99)?;
|
||||||
|
|
||||||
|
fragment_stats.set_item("lengths", fragment_lengths)?;
|
||||||
|
dict.set_item("fragment_stats", fragment_stats)?;
|
||||||
|
|
||||||
|
Ok(Some(dict.unbind()))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn __repr__(&self) -> String {
|
pub fn __repr__(&self) -> String {
|
||||||
match &self.inner {
|
match &self.inner {
|
||||||
None => format!("ClosedTable({})", self.name),
|
None => format!("ClosedTable({})", self.name),
|
||||||
@@ -455,8 +654,8 @@ impl Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
builder.execute(Box::new(batches)).await.infer_error()?;
|
let res = builder.execute(Box::new(batches)).await.infer_error()?;
|
||||||
Ok(())
|
Ok(MergeResult::from(res))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,8 +691,8 @@ impl Table {
|
|||||||
|
|
||||||
let inner = self_.inner_ref()?.clone();
|
let inner = self_.inner_ref()?.clone();
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
inner.add_columns(definitions, None).await.infer_error()?;
|
let result = inner.add_columns(definitions, None).await.infer_error()?;
|
||||||
Ok(())
|
Ok(AddColumnsResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -506,8 +705,8 @@ impl Table {
|
|||||||
|
|
||||||
let inner = self_.inner_ref()?.clone();
|
let inner = self_.inner_ref()?.clone();
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
inner.add_columns(transform, None).await.infer_error()?;
|
let result = inner.add_columns(transform, None).await.infer_error()?;
|
||||||
Ok(())
|
Ok(AddColumnsResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -550,8 +749,8 @@ impl Table {
|
|||||||
|
|
||||||
let inner = self_.inner_ref()?.clone();
|
let inner = self_.inner_ref()?.clone();
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
inner.alter_columns(&alterations).await.infer_error()?;
|
let result = inner.alter_columns(&alterations).await.infer_error()?;
|
||||||
Ok(())
|
Ok(AlterColumnsResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -559,8 +758,8 @@ impl Table {
|
|||||||
let inner = self_.inner_ref()?.clone();
|
let inner = self_.inner_ref()?.clone();
|
||||||
future_into_py(self_.py(), async move {
|
future_into_py(self_.py(), async move {
|
||||||
let column_refs = columns.iter().map(String::as_str).collect::<Vec<&str>>();
|
let column_refs = columns.iter().map(String::as_str).collect::<Vec<&str>>();
|
||||||
inner.drop_columns(&column_refs).await.infer_error()?;
|
let result = inner.drop_columns(&column_refs).await.infer_error()?;
|
||||||
Ok(())
|
Ok(DropColumnsResult::from(result))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb-node"
|
name = "lancedb-node"
|
||||||
version = "0.19.0"
|
version = "0.19.1-beta.1"
|
||||||
description = "Serverless, low-latency vector database for AI applications"
|
description = "Serverless, low-latency vector database for AI applications"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "lancedb"
|
name = "lancedb"
|
||||||
version = "0.19.0"
|
version = "0.19.1-beta.1"
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
description = "LanceDB: A serverless, low-latency vector database for AI applications"
|
description = "LanceDB: A serverless, low-latency vector database for AI applications"
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
|
|||||||
@@ -4,8 +4,15 @@
|
|||||||
use crate::index::Index;
|
use crate::index::Index;
|
||||||
use crate::index::IndexStatistics;
|
use crate::index::IndexStatistics;
|
||||||
use crate::query::{QueryFilter, QueryRequest, Select, VectorQueryRequest};
|
use crate::query::{QueryFilter, QueryRequest, Select, VectorQueryRequest};
|
||||||
|
use crate::table::AddColumnsResult;
|
||||||
|
use crate::table::AddResult;
|
||||||
|
use crate::table::AlterColumnsResult;
|
||||||
|
use crate::table::DeleteResult;
|
||||||
|
use crate::table::DropColumnsResult;
|
||||||
|
use crate::table::MergeResult;
|
||||||
use crate::table::Tags;
|
use crate::table::Tags;
|
||||||
use crate::table::{AddDataMode, AnyQuery, Filter};
|
use crate::table::UpdateResult;
|
||||||
|
use crate::table::{AddDataMode, AnyQuery, Filter, TableStatistics};
|
||||||
use crate::utils::{supported_btree_data_type, supported_vector_data_type};
|
use crate::utils::{supported_btree_data_type, supported_vector_data_type};
|
||||||
use crate::{DistanceType, Error, Table};
|
use crate::{DistanceType, Error, Table};
|
||||||
use arrow_array::{RecordBatch, RecordBatchIterator, RecordBatchReader};
|
use arrow_array::{RecordBatch, RecordBatchIterator, RecordBatchReader};
|
||||||
@@ -734,7 +741,7 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
&self,
|
&self,
|
||||||
add: AddDataBuilder<NoData>,
|
add: AddDataBuilder<NoData>,
|
||||||
data: Box<dyn RecordBatchReader + Send>,
|
data: Box<dyn RecordBatchReader + Send>,
|
||||||
) -> Result<()> {
|
) -> Result<AddResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
let mut request = self
|
let mut request = self
|
||||||
.client
|
.client
|
||||||
@@ -749,9 +756,20 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (request_id, response) = self.send_streaming(request, data, true).await?;
|
let (request_id, response) = self.send_streaming(request, data, true).await?;
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
Ok(())
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(AddResult { version: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let add_response: AddResult = serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse add response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
Ok(add_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_plan(
|
async fn create_plan(
|
||||||
@@ -884,7 +902,7 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
Ok(final_analyze)
|
Ok(final_analyze)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(&self, update: UpdateBuilder) -> Result<u64> {
|
async fn update(&self, update: UpdateBuilder) -> Result<UpdateResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
let request = self
|
let request = self
|
||||||
.client
|
.client
|
||||||
@@ -901,13 +919,28 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
let (request_id, response) = self.send(request, true).await?;
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
self.check_table_response(&request_id, response).await?;
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(UpdateResult {
|
||||||
|
rows_updated: 0,
|
||||||
|
version: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(0) // TODO: support returning number of modified rows once supported in SaaS.
|
let update_response: UpdateResult =
|
||||||
|
serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse update response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(update_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete(&self, predicate: &str) -> Result<()> {
|
async fn delete(&self, predicate: &str) -> Result<DeleteResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
let body = serde_json::json!({ "predicate": predicate });
|
let body = serde_json::json!({ "predicate": predicate });
|
||||||
let request = self
|
let request = self
|
||||||
@@ -915,8 +948,21 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
.post(&format!("/v1/table/{}/delete/", self.name))
|
.post(&format!("/v1/table/{}/delete/", self.name))
|
||||||
.json(&body);
|
.json(&body);
|
||||||
let (request_id, response) = self.send(request, true).await?;
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
Ok(())
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
|
if body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(DeleteResult { version: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let delete_response: DeleteResult =
|
||||||
|
serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse delete response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
Ok(delete_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_index(&self, mut index: IndexBuilder) -> Result<()> {
|
async fn create_index(&self, mut index: IndexBuilder) -> Result<()> {
|
||||||
@@ -1022,7 +1068,7 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
&self,
|
&self,
|
||||||
params: MergeInsertBuilder,
|
params: MergeInsertBuilder,
|
||||||
new_data: Box<dyn RecordBatchReader + Send>,
|
new_data: Box<dyn RecordBatchReader + Send>,
|
||||||
) -> Result<()> {
|
) -> Result<MergeResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
|
|
||||||
let query = MergeInsertRequest::try_from(params)?;
|
let query = MergeInsertRequest::try_from(params)?;
|
||||||
@@ -1034,9 +1080,27 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
|
|
||||||
let (request_id, response) = self.send_streaming(request, new_data, true).await?;
|
let (request_id, response) = self.send_streaming(request, new_data, true).await?;
|
||||||
|
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
Ok(())
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(MergeResult {
|
||||||
|
version: 0,
|
||||||
|
num_deleted_rows: 0,
|
||||||
|
num_inserted_rows: 0,
|
||||||
|
num_updated_rows: 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let merge_insert_response: MergeResult =
|
||||||
|
serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse merge_insert response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(merge_insert_response)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tags(&self) -> Result<Box<dyn Tags + '_>> {
|
async fn tags(&self) -> Result<Box<dyn Tags + '_>> {
|
||||||
@@ -1059,7 +1123,7 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
&self,
|
&self,
|
||||||
transforms: NewColumnTransform,
|
transforms: NewColumnTransform,
|
||||||
_read_columns: Option<Vec<String>>,
|
_read_columns: Option<Vec<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<AddColumnsResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
match transforms {
|
match transforms {
|
||||||
NewColumnTransform::SqlExpressions(expressions) => {
|
NewColumnTransform::SqlExpressions(expressions) => {
|
||||||
@@ -1077,9 +1141,23 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
.client
|
.client
|
||||||
.post(&format!("/v1/table/{}/add_columns/", self.name))
|
.post(&format!("/v1/table/{}/add_columns/", self.name))
|
||||||
.json(&body);
|
.json(&body);
|
||||||
let (request_id, response) = self.send(request, true).await?; // todo:
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
Ok(())
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(AddColumnsResult { version: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: AddColumnsResult =
|
||||||
|
serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse add_columns response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
return Err(Error::NotSupported {
|
return Err(Error::NotSupported {
|
||||||
@@ -1089,7 +1167,7 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<()> {
|
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<AlterColumnsResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
let body = alterations
|
let body = alterations
|
||||||
.iter()
|
.iter()
|
||||||
@@ -1117,11 +1195,24 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
.post(&format!("/v1/table/{}/alter_columns/", self.name))
|
.post(&format!("/v1/table/{}/alter_columns/", self.name))
|
||||||
.json(&body);
|
.json(&body);
|
||||||
let (request_id, response) = self.send(request, true).await?;
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
Ok(())
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(AlterColumnsResult { version: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: AlterColumnsResult = serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse alter_columns response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop_columns(&self, columns: &[&str]) -> Result<()> {
|
async fn drop_columns(&self, columns: &[&str]) -> Result<DropColumnsResult> {
|
||||||
self.check_mutable().await?;
|
self.check_mutable().await?;
|
||||||
let body = serde_json::json!({ "columns": columns });
|
let body = serde_json::json!({ "columns": columns });
|
||||||
let request = self
|
let request = self
|
||||||
@@ -1129,8 +1220,21 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
.post(&format!("/v1/table/{}/drop_columns/", self.name))
|
.post(&format!("/v1/table/{}/drop_columns/", self.name))
|
||||||
.json(&body);
|
.json(&body);
|
||||||
let (request_id, response) = self.send(request, true).await?;
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
self.check_table_response(&request_id, response).await?;
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
Ok(())
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
|
if body.trim().is_empty() || body == "{}" {
|
||||||
|
// Backward compatible with old servers
|
||||||
|
return Ok(DropColumnsResult { version: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
let result: DropColumnsResult = serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse drop_columns response: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
||||||
@@ -1242,6 +1346,20 @@ impl<S: HttpSend> BaseTable for RemoteTable<S> {
|
|||||||
fn dataset_uri(&self) -> &str {
|
fn dataset_uri(&self) -> &str {
|
||||||
"NOT_SUPPORTED"
|
"NOT_SUPPORTED"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn stats(&self) -> Result<TableStatistics> {
|
||||||
|
let request = self.client.post(&format!("/v1/table/{}/stats/", self.name));
|
||||||
|
let (request_id, response) = self.send(request, true).await?;
|
||||||
|
let response = self.check_table_response(&request_id, response).await?;
|
||||||
|
let body = response.text().await.err_to_http(request_id.clone())?;
|
||||||
|
|
||||||
|
let stats = serde_json::from_str(&body).map_err(|e| Error::Http {
|
||||||
|
source: format!("Failed to parse table statistics: {}", e).into(),
|
||||||
|
request_id,
|
||||||
|
status_code: None,
|
||||||
|
})?;
|
||||||
|
Ok(stats)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -1334,17 +1452,26 @@ mod tests {
|
|||||||
Box::pin(table.count_rows(None).map_ok(|_| ())),
|
Box::pin(table.count_rows(None).map_ok(|_| ())),
|
||||||
Box::pin(table.update().column("a", "a + 1").execute().map_ok(|_| ())),
|
Box::pin(table.update().column("a", "a + 1").execute().map_ok(|_| ())),
|
||||||
Box::pin(table.add(example_data()).execute().map_ok(|_| ())),
|
Box::pin(table.add(example_data()).execute().map_ok(|_| ())),
|
||||||
Box::pin(table.merge_insert(&["test"]).execute(example_data())),
|
Box::pin(
|
||||||
Box::pin(table.delete("false")),
|
table
|
||||||
Box::pin(table.add_columns(
|
.merge_insert(&["test"])
|
||||||
NewColumnTransform::SqlExpressions(vec![("x".into(), "y".into())]),
|
.execute(example_data())
|
||||||
None,
|
.map_ok(|_| ()),
|
||||||
)),
|
),
|
||||||
|
Box::pin(table.delete("false").map_ok(|_| ())),
|
||||||
|
Box::pin(
|
||||||
|
table
|
||||||
|
.add_columns(
|
||||||
|
NewColumnTransform::SqlExpressions(vec![("x".into(), "y".into())]),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.map_ok(|_| ()),
|
||||||
|
),
|
||||||
Box::pin(async {
|
Box::pin(async {
|
||||||
let alterations = vec![ColumnAlteration::new("x".into()).rename("y".into())];
|
let alterations = vec![ColumnAlteration::new("x".into()).rename("y".into())];
|
||||||
table.alter_columns(&alterations).await
|
table.alter_columns(&alterations).await.map(|_| ())
|
||||||
}),
|
}),
|
||||||
Box::pin(table.drop_columns(&["a"])),
|
Box::pin(table.drop_columns(&["a"]).map_ok(|_| ())),
|
||||||
// TODO: other endpoints.
|
// TODO: other endpoints.
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1475,8 +1602,11 @@ mod tests {
|
|||||||
body
|
body
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_add_append() {
|
async fn test_add_append(#[case] old_server: bool) {
|
||||||
let data = RecordBatch::try_new(
|
let data = RecordBatch::try_new(
|
||||||
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
||||||
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
||||||
@@ -1485,42 +1615,55 @@ mod tests {
|
|||||||
|
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
let (sender, receiver) = std::sync::mpsc::channel();
|
||||||
let table = Table::new_with_handler("my_table", move |mut request| {
|
let table = Table::new_with_handler("my_table", move |mut request| {
|
||||||
assert_eq!(request.method(), "POST");
|
if request.url().path() == "/v1/table/my_table/insert/" {
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/insert/");
|
assert_eq!(request.method(), "POST");
|
||||||
// If mode is specified, it should be "append". Append is default
|
assert!(request
|
||||||
// so it's not required.
|
.url()
|
||||||
assert!(request
|
.query_pairs()
|
||||||
.url()
|
.filter(|(k, _)| k == "mode")
|
||||||
.query_pairs()
|
.all(|(_, v)| v == "append"));
|
||||||
.filter(|(k, _)| k == "mode")
|
|
||||||
.all(|(_, v)| v == "append"));
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request.headers().get("Content-Type").unwrap(),
|
request.headers().get("Content-Type").unwrap(),
|
||||||
ARROW_STREAM_CONTENT_TYPE
|
ARROW_STREAM_CONTENT_TYPE
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut body_out = reqwest::Body::from(Vec::new());
|
let mut body_out = reqwest::Body::from(Vec::new());
|
||||||
std::mem::swap(request.body_mut().as_mut().unwrap(), &mut body_out);
|
std::mem::swap(request.body_mut().as_mut().unwrap(), &mut body_out);
|
||||||
sender.send(body_out).unwrap();
|
sender.send(body_out).unwrap();
|
||||||
|
|
||||||
http::Response::builder().status(200).body("").unwrap()
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
table
|
let result = table
|
||||||
.add(RecordBatchIterator::new([Ok(data.clone())], data.schema()))
|
.add(RecordBatchIterator::new([Ok(data.clone())], data.schema()))
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
|
|
||||||
let body = receiver.recv().unwrap();
|
let body = receiver.recv().unwrap();
|
||||||
let body = collect_body(body).await;
|
let body = collect_body(body).await;
|
||||||
let expected_body = write_ipc_stream(&data);
|
let expected_body = write_ipc_stream(&data);
|
||||||
assert_eq!(&body, &expected_body);
|
assert_eq!(&body, &expected_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_add_overwrite() {
|
async fn test_add_overwrite(#[case] old_server: bool) {
|
||||||
let data = RecordBatch::try_new(
|
let data = RecordBatch::try_new(
|
||||||
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
||||||
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
||||||
@@ -1551,56 +1694,78 @@ mod tests {
|
|||||||
std::mem::swap(request.body_mut().as_mut().unwrap(), &mut body_out);
|
std::mem::swap(request.body_mut().as_mut().unwrap(), &mut body_out);
|
||||||
sender.send(body_out).unwrap();
|
sender.send(body_out).unwrap();
|
||||||
|
|
||||||
http::Response::builder().status(200).body("").unwrap()
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
table
|
let result = table
|
||||||
.add(RecordBatchIterator::new([Ok(data.clone())], data.schema()))
|
.add(RecordBatchIterator::new([Ok(data.clone())], data.schema()))
|
||||||
.mode(AddDataMode::Overwrite)
|
.mode(AddDataMode::Overwrite)
|
||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
|
|
||||||
let body = receiver.recv().unwrap();
|
let body = receiver.recv().unwrap();
|
||||||
let body = collect_body(body).await;
|
let body = collect_body(body).await;
|
||||||
let expected_body = write_ipc_stream(&data);
|
let expected_body = write_ipc_stream(&data);
|
||||||
assert_eq!(&body, &expected_body);
|
assert_eq!(&body, &expected_body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_update() {
|
async fn test_update(#[case] old_server: bool) {
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
assert_eq!(request.method(), "POST");
|
if request.url().path() == "/v1/table/my_table/update/" {
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/update/");
|
assert_eq!(request.method(), "POST");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request.headers().get("Content-Type").unwrap(),
|
request.headers().get("Content-Type").unwrap(),
|
||||||
JSON_CONTENT_TYPE
|
JSON_CONTENT_TYPE
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some(body) = request.body().unwrap().as_bytes() {
|
if let Some(body) = request.body().unwrap().as_bytes() {
|
||||||
let body = std::str::from_utf8(body).unwrap();
|
let body = std::str::from_utf8(body).unwrap();
|
||||||
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
||||||
let updates = value.get("updates").unwrap().as_array().unwrap();
|
let updates = value.get("updates").unwrap().as_array().unwrap();
|
||||||
assert!(updates.len() == 2);
|
assert!(updates.len() == 2);
|
||||||
|
|
||||||
let col_name = updates[0][0].as_str().unwrap();
|
let col_name = updates[0][0].as_str().unwrap();
|
||||||
let expression = updates[0][1].as_str().unwrap();
|
let expression = updates[0][1].as_str().unwrap();
|
||||||
assert_eq!(col_name, "a");
|
assert_eq!(col_name, "a");
|
||||||
assert_eq!(expression, "a + 1");
|
assert_eq!(expression, "a + 1");
|
||||||
|
|
||||||
let col_name = updates[1][0].as_str().unwrap();
|
let col_name = updates[1][0].as_str().unwrap();
|
||||||
let expression = updates[1][1].as_str().unwrap();
|
let expression = updates[1][1].as_str().unwrap();
|
||||||
assert_eq!(col_name, "b");
|
assert_eq!(col_name, "b");
|
||||||
assert_eq!(expression, "b - 1");
|
assert_eq!(expression, "b - 1");
|
||||||
|
|
||||||
let only_if = value.get("predicate").unwrap().as_str().unwrap();
|
let only_if = value.get("predicate").unwrap().as_str().unwrap();
|
||||||
assert_eq!(only_if, "b > 10");
|
assert_eq!(only_if, "b > 10");
|
||||||
|
}
|
||||||
|
|
||||||
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"rows_updated": 5, "version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
}
|
}
|
||||||
|
|
||||||
http::Response::builder().status(200).body("{}").unwrap()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
table
|
let result = table
|
||||||
.update()
|
.update()
|
||||||
.column("a", "a + 1")
|
.column("a", "a + 1")
|
||||||
.column("b", "b - 1")
|
.column("b", "b - 1")
|
||||||
@@ -1608,10 +1773,73 @@ mod tests {
|
|||||||
.execute()
|
.execute()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
|
assert_eq!(result.rows_updated, if old_server { 0 } else { 5 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_merge_insert() {
|
async fn test_alter_columns(#[case] old_server: bool) {
|
||||||
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
|
if request.url().path() == "/v1/table/my_table/alter_columns/" {
|
||||||
|
assert_eq!(request.method(), "POST");
|
||||||
|
assert_eq!(
|
||||||
|
request.headers().get("Content-Type").unwrap(),
|
||||||
|
JSON_CONTENT_TYPE
|
||||||
|
);
|
||||||
|
|
||||||
|
let body = request.body().unwrap().as_bytes().unwrap();
|
||||||
|
let body = std::str::from_utf8(body).unwrap();
|
||||||
|
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
||||||
|
let alterations = value.get("alterations").unwrap().as_array().unwrap();
|
||||||
|
assert!(alterations.len() == 2);
|
||||||
|
|
||||||
|
let path = alterations[0]["path"].as_str().unwrap();
|
||||||
|
let data_type = alterations[0]["data_type"]["type"].as_str().unwrap();
|
||||||
|
assert_eq!(path, "b.c");
|
||||||
|
assert_eq!(data_type, "int32");
|
||||||
|
|
||||||
|
let path = alterations[1]["path"].as_str().unwrap();
|
||||||
|
let nullable = alterations[1]["nullable"].as_bool().unwrap();
|
||||||
|
let rename = alterations[1]["rename"].as_str().unwrap();
|
||||||
|
assert_eq!(path, "x");
|
||||||
|
assert!(nullable);
|
||||||
|
assert_eq!(rename, "y");
|
||||||
|
|
||||||
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("{}").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = table
|
||||||
|
.alter_columns(&[
|
||||||
|
ColumnAlteration::new("b.c".into()).cast_to(DataType::Int32),
|
||||||
|
ColumnAlteration::new("x".into())
|
||||||
|
.rename("y".into())
|
||||||
|
.set_nullable(true),
|
||||||
|
])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_merge_insert(#[case] old_server: bool) {
|
||||||
let batch = RecordBatch::try_new(
|
let batch = RecordBatch::try_new(
|
||||||
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
Arc::new(Schema::new(vec![Field::new("a", DataType::Int32, false)])),
|
||||||
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
vec![Arc::new(Int32Array::from(vec![1, 2, 3]))],
|
||||||
@@ -1622,66 +1850,43 @@ mod tests {
|
|||||||
batch.schema(),
|
batch.schema(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// Default parameters
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
if request.url().path() == "/v1/table/my_table/merge_insert/" {
|
||||||
assert_eq!(request.method(), "POST");
|
assert_eq!(request.method(), "POST");
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/merge_insert/");
|
|
||||||
|
|
||||||
let params = request.url().query_pairs().collect::<HashMap<_, _>>();
|
let params = request.url().query_pairs().collect::<HashMap<_, _>>();
|
||||||
assert_eq!(params["on"], "some_col");
|
assert_eq!(params["on"], "some_col");
|
||||||
assert_eq!(params["when_matched_update_all"], "false");
|
assert_eq!(params["when_matched_update_all"], "false");
|
||||||
assert_eq!(params["when_not_matched_insert_all"], "false");
|
assert_eq!(params["when_not_matched_insert_all"], "false");
|
||||||
assert_eq!(params["when_not_matched_by_source_delete"], "false");
|
assert_eq!(params["when_not_matched_by_source_delete"], "false");
|
||||||
assert!(!params.contains_key("when_matched_update_all_filt"));
|
assert!(!params.contains_key("when_matched_update_all_filt"));
|
||||||
assert!(!params.contains_key("when_not_matched_by_source_delete_filt"));
|
assert!(!params.contains_key("when_not_matched_by_source_delete_filt"));
|
||||||
|
|
||||||
http::Response::builder().status(200).body("").unwrap()
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("{}").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43, "num_deleted_rows": 0, "num_inserted_rows": 3, "num_updated_rows": 0}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
table
|
let result = table
|
||||||
.merge_insert(&["some_col"])
|
.merge_insert(&["some_col"])
|
||||||
.execute(data)
|
.execute(data)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// All parameters specified
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
if !old_server {
|
||||||
let table = Table::new_with_handler("my_table", move |mut request| {
|
assert_eq!(result.num_deleted_rows, 0);
|
||||||
assert_eq!(request.method(), "POST");
|
assert_eq!(result.num_inserted_rows, 3);
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/merge_insert/");
|
assert_eq!(result.num_updated_rows, 0);
|
||||||
assert_eq!(
|
}
|
||||||
request.headers().get("Content-Type").unwrap(),
|
|
||||||
ARROW_STREAM_CONTENT_TYPE
|
|
||||||
);
|
|
||||||
|
|
||||||
let params = request.url().query_pairs().collect::<HashMap<_, _>>();
|
|
||||||
assert_eq!(params["on"], "some_col");
|
|
||||||
assert_eq!(params["when_matched_update_all"], "true");
|
|
||||||
assert_eq!(params["when_not_matched_insert_all"], "false");
|
|
||||||
assert_eq!(params["when_not_matched_by_source_delete"], "true");
|
|
||||||
assert_eq!(params["when_matched_update_all_filt"], "a = 1");
|
|
||||||
assert_eq!(params["when_not_matched_by_source_delete_filt"], "b = 2");
|
|
||||||
|
|
||||||
let mut body_out = reqwest::Body::from(Vec::new());
|
|
||||||
std::mem::swap(request.body_mut().as_mut().unwrap(), &mut body_out);
|
|
||||||
sender.send(body_out).unwrap();
|
|
||||||
|
|
||||||
http::Response::builder().status(200).body("").unwrap()
|
|
||||||
});
|
|
||||||
let mut builder = table.merge_insert(&["some_col"]);
|
|
||||||
builder
|
|
||||||
.when_matched_update_all(Some("a = 1".into()))
|
|
||||||
.when_not_matched_by_source_delete(Some("b = 2".into()));
|
|
||||||
let data = Box::new(RecordBatchIterator::new(
|
|
||||||
[Ok(batch.clone())],
|
|
||||||
batch.schema(),
|
|
||||||
));
|
|
||||||
builder.execute(data).await.unwrap();
|
|
||||||
|
|
||||||
let body = receiver.recv().unwrap();
|
|
||||||
let body = collect_body(body).await;
|
|
||||||
let expected_body = write_ipc_stream(&batch);
|
|
||||||
assert_eq!(&body, &expected_body);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1720,25 +1925,80 @@ mod tests {
|
|||||||
assert!(e.to_string().contains("Hit retry limit"));
|
assert!(e.to_string().contains("Hit retry limit"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_delete() {
|
async fn test_delete(#[case] old_server: bool) {
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
assert_eq!(request.method(), "POST");
|
if request.url().path() == "/v1/table/my_table/delete/" {
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/delete/");
|
assert_eq!(request.method(), "POST");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request.headers().get("Content-Type").unwrap(),
|
request.headers().get("Content-Type").unwrap(),
|
||||||
JSON_CONTENT_TYPE
|
JSON_CONTENT_TYPE
|
||||||
);
|
);
|
||||||
|
|
||||||
let body = request.body().unwrap().as_bytes().unwrap();
|
let body = request.body().unwrap().as_bytes().unwrap();
|
||||||
let body: serde_json::Value = serde_json::from_slice(body).unwrap();
|
let body: serde_json::Value = serde_json::from_slice(body).unwrap();
|
||||||
let predicate = body.get("predicate").unwrap().as_str().unwrap();
|
let predicate = body.get("predicate").unwrap().as_str().unwrap();
|
||||||
assert_eq!(predicate, "id in (1, 2, 3)");
|
assert_eq!(predicate, "id in (1, 2, 3)");
|
||||||
|
|
||||||
http::Response::builder().status(200).body("").unwrap()
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("{}").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
table.delete("id in (1, 2, 3)").await.unwrap();
|
let result = table.delete("id in (1, 2, 3)").await.unwrap();
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_drop_columns(#[case] old_server: bool) {
|
||||||
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
|
if request.url().path() == "/v1/table/my_table/drop_columns/" {
|
||||||
|
assert_eq!(request.method(), "POST");
|
||||||
|
assert_eq!(
|
||||||
|
request.headers().get("Content-Type").unwrap(),
|
||||||
|
JSON_CONTENT_TYPE
|
||||||
|
);
|
||||||
|
|
||||||
|
let body = request.body().unwrap().as_bytes().unwrap();
|
||||||
|
let body = std::str::from_utf8(body).unwrap();
|
||||||
|
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
||||||
|
let columns = value.get("columns").unwrap().as_array().unwrap();
|
||||||
|
assert!(columns.len() == 2);
|
||||||
|
|
||||||
|
let col1 = columns[0].as_str().unwrap();
|
||||||
|
let col2 = columns[1].as_str().unwrap();
|
||||||
|
assert_eq!(col1, "a");
|
||||||
|
assert_eq!(col2, "b");
|
||||||
|
|
||||||
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("{}").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = table.drop_columns(&["a", "b"]).await.unwrap();
|
||||||
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -2555,36 +2815,49 @@ mod tests {
|
|||||||
assert!(matches!(res, Err(Error::NotSupported { .. })));
|
assert!(matches!(res, Err(Error::NotSupported { .. })));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(true)]
|
||||||
|
#[case(false)]
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_add_columns() {
|
async fn test_add_columns(#[case] old_server: bool) {
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
let table = Table::new_with_handler("my_table", move |request| {
|
||||||
assert_eq!(request.method(), "POST");
|
if request.url().path() == "/v1/table/my_table/add_columns/" {
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/add_columns/");
|
assert_eq!(request.method(), "POST");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
request.headers().get("Content-Type").unwrap(),
|
request.headers().get("Content-Type").unwrap(),
|
||||||
JSON_CONTENT_TYPE
|
JSON_CONTENT_TYPE
|
||||||
);
|
);
|
||||||
|
|
||||||
let body = request.body().unwrap().as_bytes().unwrap();
|
let body = request.body().unwrap().as_bytes().unwrap();
|
||||||
let body = std::str::from_utf8(body).unwrap();
|
let body = std::str::from_utf8(body).unwrap();
|
||||||
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
||||||
let new_columns = value.get("new_columns").unwrap().as_array().unwrap();
|
let new_columns = value.get("new_columns").unwrap().as_array().unwrap();
|
||||||
assert!(new_columns.len() == 2);
|
assert!(new_columns.len() == 2);
|
||||||
|
|
||||||
let col_name = new_columns[0]["name"].as_str().unwrap();
|
let col_name = new_columns[0]["name"].as_str().unwrap();
|
||||||
let expression = new_columns[0]["expression"].as_str().unwrap();
|
let expression = new_columns[0]["expression"].as_str().unwrap();
|
||||||
assert_eq!(col_name, "b");
|
assert_eq!(col_name, "b");
|
||||||
assert_eq!(expression, "a + 1");
|
assert_eq!(expression, "a + 1");
|
||||||
|
|
||||||
let col_name = new_columns[1]["name"].as_str().unwrap();
|
let col_name = new_columns[1]["name"].as_str().unwrap();
|
||||||
let expression = new_columns[1]["expression"].as_str().unwrap();
|
let expression = new_columns[1]["expression"].as_str().unwrap();
|
||||||
assert_eq!(col_name, "x");
|
assert_eq!(col_name, "x");
|
||||||
assert_eq!(expression, "cast(NULL as int32)");
|
assert_eq!(expression, "cast(NULL as int32)");
|
||||||
|
|
||||||
http::Response::builder().status(200).body("{}").unwrap()
|
if old_server {
|
||||||
|
http::Response::builder().status(200).body("{}").unwrap()
|
||||||
|
} else {
|
||||||
|
http::Response::builder()
|
||||||
|
.status(200)
|
||||||
|
.body(r#"{"version": 43}"#)
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Unexpected request path: {}", request.url().path());
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
table
|
let result = table
|
||||||
.add_columns(
|
.add_columns(
|
||||||
NewColumnTransform::SqlExpressions(vec![
|
NewColumnTransform::SqlExpressions(vec![
|
||||||
("b".into(), "a + 1".into()),
|
("b".into(), "a + 1".into()),
|
||||||
@@ -2594,75 +2867,8 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
assert_eq!(result.version, if old_server { 0 } else { 43 });
|
||||||
async fn test_alter_columns() {
|
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
|
||||||
assert_eq!(request.method(), "POST");
|
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/alter_columns/");
|
|
||||||
assert_eq!(
|
|
||||||
request.headers().get("Content-Type").unwrap(),
|
|
||||||
JSON_CONTENT_TYPE
|
|
||||||
);
|
|
||||||
|
|
||||||
let body = request.body().unwrap().as_bytes().unwrap();
|
|
||||||
let body = std::str::from_utf8(body).unwrap();
|
|
||||||
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
|
||||||
let alterations = value.get("alterations").unwrap().as_array().unwrap();
|
|
||||||
assert!(alterations.len() == 2);
|
|
||||||
|
|
||||||
let path = alterations[0]["path"].as_str().unwrap();
|
|
||||||
let data_type = alterations[0]["data_type"]["type"].as_str().unwrap();
|
|
||||||
assert_eq!(path, "b.c");
|
|
||||||
assert_eq!(data_type, "int32");
|
|
||||||
|
|
||||||
let path = alterations[1]["path"].as_str().unwrap();
|
|
||||||
let nullable = alterations[1]["nullable"].as_bool().unwrap();
|
|
||||||
let rename = alterations[1]["rename"].as_str().unwrap();
|
|
||||||
assert_eq!(path, "x");
|
|
||||||
assert!(nullable);
|
|
||||||
assert_eq!(rename, "y");
|
|
||||||
|
|
||||||
http::Response::builder().status(200).body("{}").unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
table
|
|
||||||
.alter_columns(&[
|
|
||||||
ColumnAlteration::new("b.c".into()).cast_to(DataType::Int32),
|
|
||||||
ColumnAlteration::new("x".into())
|
|
||||||
.rename("y".into())
|
|
||||||
.set_nullable(true),
|
|
||||||
])
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn test_drop_columns() {
|
|
||||||
let table = Table::new_with_handler("my_table", |request| {
|
|
||||||
assert_eq!(request.method(), "POST");
|
|
||||||
assert_eq!(request.url().path(), "/v1/table/my_table/drop_columns/");
|
|
||||||
assert_eq!(
|
|
||||||
request.headers().get("Content-Type").unwrap(),
|
|
||||||
JSON_CONTENT_TYPE
|
|
||||||
);
|
|
||||||
|
|
||||||
let body = request.body().unwrap().as_bytes().unwrap();
|
|
||||||
let body = std::str::from_utf8(body).unwrap();
|
|
||||||
let value: serde_json::Value = serde_json::from_str(body).unwrap();
|
|
||||||
let columns = value.get("columns").unwrap().as_array().unwrap();
|
|
||||||
assert!(columns.len() == 2);
|
|
||||||
|
|
||||||
let col1 = columns[0].as_str().unwrap();
|
|
||||||
let col2 = columns[1].as_str().unwrap();
|
|
||||||
assert_eq!(col1, "a");
|
|
||||||
assert_eq!(col2, "b");
|
|
||||||
|
|
||||||
http::Response::builder().status(200).body("{}").unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
table.drop_columns(&["a", "b"]).await.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -80,10 +80,13 @@ pub mod merge;
|
|||||||
|
|
||||||
use crate::index::waiter::wait_for_index;
|
use crate::index::waiter::wait_for_index;
|
||||||
pub use chrono::Duration;
|
pub use chrono::Duration;
|
||||||
|
use futures::future::join_all;
|
||||||
pub use lance::dataset::optimize::CompactionOptions;
|
pub use lance::dataset::optimize::CompactionOptions;
|
||||||
pub use lance::dataset::refs::{TagContents, Tags as LanceTags};
|
pub use lance::dataset::refs::{TagContents, Tags as LanceTags};
|
||||||
pub use lance::dataset::scanner::DatasetRecordBatchStream;
|
pub use lance::dataset::scanner::DatasetRecordBatchStream;
|
||||||
|
use lance::dataset::statistics::DatasetStatisticsExt;
|
||||||
pub use lance_index::optimize::OptimizeOptions;
|
pub use lance_index::optimize::OptimizeOptions;
|
||||||
|
use serde_with::skip_serializing_none;
|
||||||
|
|
||||||
/// Defines the type of column
|
/// Defines the type of column
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
@@ -308,7 +311,7 @@ impl<T: IntoArrow> AddDataBuilder<T> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute(self) -> Result<()> {
|
pub async fn execute(self) -> Result<AddResult> {
|
||||||
let parent = self.parent.clone();
|
let parent = self.parent.clone();
|
||||||
let data = self.data.into_arrow()?;
|
let data = self.data.into_arrow()?;
|
||||||
let without_data = AddDataBuilder::<NoData> {
|
let without_data = AddDataBuilder::<NoData> {
|
||||||
@@ -376,8 +379,8 @@ impl UpdateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Executes the update operation.
|
/// Executes the update operation.
|
||||||
/// Returns the number of rows that were updated.
|
/// Returns the update result
|
||||||
pub async fn execute(self) -> Result<u64> {
|
pub async fn execute(self) -> Result<UpdateResult> {
|
||||||
if self.columns.is_empty() {
|
if self.columns.is_empty() {
|
||||||
Err(Error::InvalidInput {
|
Err(Error::InvalidInput {
|
||||||
message: "at least one column must be specified in an update operation".to_string(),
|
message: "at least one column must be specified in an update operation".to_string(),
|
||||||
@@ -420,6 +423,71 @@ pub trait Tags: Send + Sync {
|
|||||||
async fn update(&mut self, tag: &str, version: u64) -> Result<()>;
|
async fn update(&mut self, tag: &str, version: u64) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct UpdateResult {
|
||||||
|
pub rows_updated: u64,
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AddResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct DeleteResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct MergeResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
/// Number of inserted rows (for user statistics)
|
||||||
|
pub num_inserted_rows: u64,
|
||||||
|
/// Number of updated rows (for user statistics)
|
||||||
|
pub num_updated_rows: u64,
|
||||||
|
/// Number of deleted rows (for user statistics)
|
||||||
|
/// Note: This is different from internal references to 'deleted_rows', since we technically "delete" updated rows during processing.
|
||||||
|
/// However those rows are not shared with the user.
|
||||||
|
pub num_deleted_rows: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AddColumnsResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct AlterColumnsResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
pub struct DropColumnsResult {
|
||||||
|
// The commit version associated with the operation.
|
||||||
|
// A version of `0` indicates compatibility with legacy servers that do not return
|
||||||
|
/// a commit version.
|
||||||
|
pub version: u64,
|
||||||
|
}
|
||||||
|
|
||||||
/// A trait for anything "table-like". This is used for both native tables (which target
|
/// A trait for anything "table-like". This is used for both native tables (which target
|
||||||
/// Lance datasets) and remote tables (which target LanceDB cloud)
|
/// Lance datasets) and remote tables (which target LanceDB cloud)
|
||||||
///
|
///
|
||||||
@@ -464,11 +532,11 @@ pub trait BaseTable: std::fmt::Display + std::fmt::Debug + Send + Sync {
|
|||||||
&self,
|
&self,
|
||||||
add: AddDataBuilder<NoData>,
|
add: AddDataBuilder<NoData>,
|
||||||
data: Box<dyn arrow_array::RecordBatchReader + Send>,
|
data: Box<dyn arrow_array::RecordBatchReader + Send>,
|
||||||
) -> Result<()>;
|
) -> Result<AddResult>;
|
||||||
/// Delete rows from the table.
|
/// Delete rows from the table.
|
||||||
async fn delete(&self, predicate: &str) -> Result<()>;
|
async fn delete(&self, predicate: &str) -> Result<DeleteResult>;
|
||||||
/// Update rows in the table.
|
/// Update rows in the table.
|
||||||
async fn update(&self, update: UpdateBuilder) -> Result<u64>;
|
async fn update(&self, update: UpdateBuilder) -> Result<UpdateResult>;
|
||||||
/// Create an index on the provided column(s).
|
/// Create an index on the provided column(s).
|
||||||
async fn create_index(&self, index: IndexBuilder) -> Result<()>;
|
async fn create_index(&self, index: IndexBuilder) -> Result<()>;
|
||||||
/// List the indices on the table.
|
/// List the indices on the table.
|
||||||
@@ -484,7 +552,7 @@ pub trait BaseTable: std::fmt::Display + std::fmt::Debug + Send + Sync {
|
|||||||
&self,
|
&self,
|
||||||
params: MergeInsertBuilder,
|
params: MergeInsertBuilder,
|
||||||
new_data: Box<dyn RecordBatchReader + Send>,
|
new_data: Box<dyn RecordBatchReader + Send>,
|
||||||
) -> Result<()>;
|
) -> Result<MergeResult>;
|
||||||
/// Gets the table tag manager.
|
/// Gets the table tag manager.
|
||||||
async fn tags(&self) -> Result<Box<dyn Tags + '_>>;
|
async fn tags(&self) -> Result<Box<dyn Tags + '_>>;
|
||||||
/// Optimize the dataset.
|
/// Optimize the dataset.
|
||||||
@@ -494,11 +562,11 @@ pub trait BaseTable: std::fmt::Display + std::fmt::Debug + Send + Sync {
|
|||||||
&self,
|
&self,
|
||||||
transforms: NewColumnTransform,
|
transforms: NewColumnTransform,
|
||||||
read_columns: Option<Vec<String>>,
|
read_columns: Option<Vec<String>>,
|
||||||
) -> Result<()>;
|
) -> Result<AddColumnsResult>;
|
||||||
/// Alter columns in the table.
|
/// Alter columns in the table.
|
||||||
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<()>;
|
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<AlterColumnsResult>;
|
||||||
/// Drop columns from the table.
|
/// Drop columns from the table.
|
||||||
async fn drop_columns(&self, columns: &[&str]) -> Result<()>;
|
async fn drop_columns(&self, columns: &[&str]) -> Result<DropColumnsResult>;
|
||||||
/// Get the version of the table.
|
/// Get the version of the table.
|
||||||
async fn version(&self) -> Result<u64>;
|
async fn version(&self) -> Result<u64>;
|
||||||
/// Checkout a specific version of the table.
|
/// Checkout a specific version of the table.
|
||||||
@@ -523,6 +591,8 @@ pub trait BaseTable: std::fmt::Display + std::fmt::Debug + Send + Sync {
|
|||||||
index_names: &[&str],
|
index_names: &[&str],
|
||||||
timeout: std::time::Duration,
|
timeout: std::time::Duration,
|
||||||
) -> Result<()>;
|
) -> Result<()>;
|
||||||
|
/// Get statistics on the table
|
||||||
|
async fn stats(&self) -> Result<TableStatistics>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A Table is a collection of strong typed Rows.
|
/// A Table is a collection of strong typed Rows.
|
||||||
@@ -725,7 +795,7 @@ impl Table {
|
|||||||
/// tbl.delete("id > 5").await.unwrap();
|
/// tbl.delete("id > 5").await.unwrap();
|
||||||
/// # });
|
/// # });
|
||||||
/// ```
|
/// ```
|
||||||
pub async fn delete(&self, predicate: &str) -> Result<()> {
|
pub async fn delete(&self, predicate: &str) -> Result<DeleteResult> {
|
||||||
self.inner.delete(predicate).await
|
self.inner.delete(predicate).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1040,17 +1110,20 @@ impl Table {
|
|||||||
&self,
|
&self,
|
||||||
transforms: NewColumnTransform,
|
transforms: NewColumnTransform,
|
||||||
read_columns: Option<Vec<String>>,
|
read_columns: Option<Vec<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<AddColumnsResult> {
|
||||||
self.inner.add_columns(transforms, read_columns).await
|
self.inner.add_columns(transforms, read_columns).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change a column's name or nullability.
|
/// Change a column's name or nullability.
|
||||||
pub async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<()> {
|
pub async fn alter_columns(
|
||||||
|
&self,
|
||||||
|
alterations: &[ColumnAlteration],
|
||||||
|
) -> Result<AlterColumnsResult> {
|
||||||
self.inner.alter_columns(alterations).await
|
self.inner.alter_columns(alterations).await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove columns from the table.
|
/// Remove columns from the table.
|
||||||
pub async fn drop_columns(&self, columns: &[&str]) -> Result<()> {
|
pub async fn drop_columns(&self, columns: &[&str]) -> Result<DropColumnsResult> {
|
||||||
self.inner.drop_columns(columns).await
|
self.inner.drop_columns(columns).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1241,6 +1314,11 @@ impl Table {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
Ok(Arc::new(repartitioned))
|
Ok(Arc::new(repartitioned))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Retrieve statistics on the table
|
||||||
|
pub async fn stats(&self) -> Result<TableStatistics> {
|
||||||
|
self.inner.stats().await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct NativeTags {
|
pub struct NativeTags {
|
||||||
@@ -2078,7 +2156,7 @@ impl BaseTable for NativeTable {
|
|||||||
&self,
|
&self,
|
||||||
add: AddDataBuilder<NoData>,
|
add: AddDataBuilder<NoData>,
|
||||||
data: Box<dyn RecordBatchReader + Send>,
|
data: Box<dyn RecordBatchReader + Send>,
|
||||||
) -> Result<()> {
|
) -> Result<AddResult> {
|
||||||
let data = Box::new(MaybeEmbedded::try_new(
|
let data = Box::new(MaybeEmbedded::try_new(
|
||||||
data,
|
data,
|
||||||
self.table_definition().await?,
|
self.table_definition().await?,
|
||||||
@@ -2101,9 +2179,9 @@ impl BaseTable for NativeTable {
|
|||||||
.execute_stream(data)
|
.execute_stream(data)
|
||||||
.await?
|
.await?
|
||||||
};
|
};
|
||||||
|
let version = dataset.manifest().version;
|
||||||
self.dataset.set_latest(dataset).await;
|
self.dataset.set_latest(dataset).await;
|
||||||
Ok(())
|
Ok(AddResult { version })
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_index(&self, opts: IndexBuilder) -> Result<()> {
|
async fn create_index(&self, opts: IndexBuilder) -> Result<()> {
|
||||||
@@ -2149,7 +2227,7 @@ impl BaseTable for NativeTable {
|
|||||||
Ok(dataset.prewarm_index(index_name).await?)
|
Ok(dataset.prewarm_index(index_name).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(&self, update: UpdateBuilder) -> Result<u64> {
|
async fn update(&self, update: UpdateBuilder) -> Result<UpdateResult> {
|
||||||
let dataset = self.dataset.get().await?.clone();
|
let dataset = self.dataset.get().await?.clone();
|
||||||
let mut builder = LanceUpdateBuilder::new(Arc::new(dataset));
|
let mut builder = LanceUpdateBuilder::new(Arc::new(dataset));
|
||||||
if let Some(predicate) = update.filter {
|
if let Some(predicate) = update.filter {
|
||||||
@@ -2165,7 +2243,10 @@ impl BaseTable for NativeTable {
|
|||||||
self.dataset
|
self.dataset
|
||||||
.set_latest(res.new_dataset.as_ref().clone())
|
.set_latest(res.new_dataset.as_ref().clone())
|
||||||
.await;
|
.await;
|
||||||
Ok(res.rows_updated)
|
Ok(UpdateResult {
|
||||||
|
rows_updated: res.rows_updated,
|
||||||
|
version: res.new_dataset.version().version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_plan(
|
async fn create_plan(
|
||||||
@@ -2357,7 +2438,7 @@ impl BaseTable for NativeTable {
|
|||||||
&self,
|
&self,
|
||||||
params: MergeInsertBuilder,
|
params: MergeInsertBuilder,
|
||||||
new_data: Box<dyn RecordBatchReader + Send>,
|
new_data: Box<dyn RecordBatchReader + Send>,
|
||||||
) -> Result<()> {
|
) -> Result<MergeResult> {
|
||||||
let dataset = Arc::new(self.dataset.get().await?.clone());
|
let dataset = Arc::new(self.dataset.get().await?.clone());
|
||||||
let mut builder = LanceMergeInsertBuilder::try_new(dataset.clone(), params.on)?;
|
let mut builder = LanceMergeInsertBuilder::try_new(dataset.clone(), params.on)?;
|
||||||
match (
|
match (
|
||||||
@@ -2384,15 +2465,24 @@ impl BaseTable for NativeTable {
|
|||||||
builder.when_not_matched_by_source(WhenNotMatchedBySource::Keep);
|
builder.when_not_matched_by_source(WhenNotMatchedBySource::Keep);
|
||||||
}
|
}
|
||||||
let job = builder.try_build()?;
|
let job = builder.try_build()?;
|
||||||
let (new_dataset, _stats) = job.execute_reader(new_data).await?;
|
let (new_dataset, stats) = job.execute_reader(new_data).await?;
|
||||||
|
let version = new_dataset.manifest().version;
|
||||||
self.dataset.set_latest(new_dataset.as_ref().clone()).await;
|
self.dataset.set_latest(new_dataset.as_ref().clone()).await;
|
||||||
Ok(())
|
Ok(MergeResult {
|
||||||
|
version,
|
||||||
|
num_updated_rows: stats.num_updated_rows,
|
||||||
|
num_inserted_rows: stats.num_inserted_rows,
|
||||||
|
num_deleted_rows: stats.num_deleted_rows,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete rows from the table
|
/// Delete rows from the table
|
||||||
async fn delete(&self, predicate: &str) -> Result<()> {
|
async fn delete(&self, predicate: &str) -> Result<DeleteResult> {
|
||||||
self.dataset.get_mut().await?.delete(predicate).await?;
|
let mut dataset = self.dataset.get_mut().await?;
|
||||||
Ok(())
|
dataset.delete(predicate).await?;
|
||||||
|
Ok(DeleteResult {
|
||||||
|
version: dataset.version().version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn tags(&self) -> Result<Box<dyn Tags + '_>> {
|
async fn tags(&self) -> Result<Box<dyn Tags + '_>> {
|
||||||
@@ -2459,27 +2549,28 @@ impl BaseTable for NativeTable {
|
|||||||
&self,
|
&self,
|
||||||
transforms: NewColumnTransform,
|
transforms: NewColumnTransform,
|
||||||
read_columns: Option<Vec<String>>,
|
read_columns: Option<Vec<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<AddColumnsResult> {
|
||||||
self.dataset
|
let mut dataset = self.dataset.get_mut().await?;
|
||||||
.get_mut()
|
dataset.add_columns(transforms, read_columns, None).await?;
|
||||||
.await?
|
Ok(AddColumnsResult {
|
||||||
.add_columns(transforms, read_columns, None)
|
version: dataset.version().version,
|
||||||
.await?;
|
})
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<()> {
|
async fn alter_columns(&self, alterations: &[ColumnAlteration]) -> Result<AlterColumnsResult> {
|
||||||
self.dataset
|
let mut dataset = self.dataset.get_mut().await?;
|
||||||
.get_mut()
|
dataset.alter_columns(alterations).await?;
|
||||||
.await?
|
Ok(AlterColumnsResult {
|
||||||
.alter_columns(alterations)
|
version: dataset.version().version,
|
||||||
.await?;
|
})
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn drop_columns(&self, columns: &[&str]) -> Result<()> {
|
async fn drop_columns(&self, columns: &[&str]) -> Result<DropColumnsResult> {
|
||||||
self.dataset.get_mut().await?.drop_columns(columns).await?;
|
let mut dataset = self.dataset.get_mut().await?;
|
||||||
Ok(())
|
dataset.drop_columns(columns).await?;
|
||||||
|
Ok(DropColumnsResult {
|
||||||
|
version: dataset.version().version,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
async fn list_indices(&self) -> Result<Vec<IndexConfig>> {
|
||||||
@@ -2568,6 +2659,108 @@ impl BaseTable for NativeTable {
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
wait_for_index(self, index_names, timeout).await
|
wait_for_index(self, index_names, timeout).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn stats(&self) -> Result<TableStatistics> {
|
||||||
|
let num_rows = self.count_rows(None).await?;
|
||||||
|
let num_indices = self.list_indices().await?.len();
|
||||||
|
let ds = self.dataset.get().await?;
|
||||||
|
let ds_clone = (*ds).clone();
|
||||||
|
let ds_stats = Arc::new(ds_clone).calculate_data_stats().await?;
|
||||||
|
let total_bytes = ds_stats.fields.iter().map(|f| f.bytes_on_disk).sum::<u64>() as usize;
|
||||||
|
|
||||||
|
let frags = ds.get_fragments();
|
||||||
|
let mut sorted_sizes = join_all(
|
||||||
|
frags
|
||||||
|
.iter()
|
||||||
|
.map(|frag| async move { frag.physical_rows().await.unwrap_or(0) }),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
sorted_sizes.sort();
|
||||||
|
|
||||||
|
let small_frag_threshold = 100000;
|
||||||
|
let num_fragments = sorted_sizes.len();
|
||||||
|
let num_small_fragments = sorted_sizes
|
||||||
|
.iter()
|
||||||
|
.filter(|&&size| size < small_frag_threshold)
|
||||||
|
.count();
|
||||||
|
|
||||||
|
let p25 = *sorted_sizes.get(num_fragments / 4).unwrap_or(&0);
|
||||||
|
let p50 = *sorted_sizes.get(num_fragments / 2).unwrap_or(&0);
|
||||||
|
let p75 = *sorted_sizes.get(num_fragments * 3 / 4).unwrap_or(&0);
|
||||||
|
let p99 = *sorted_sizes.get(num_fragments * 99 / 100).unwrap_or(&0);
|
||||||
|
let min = sorted_sizes.first().copied().unwrap_or(0);
|
||||||
|
let max = sorted_sizes.last().copied().unwrap_or(0);
|
||||||
|
let mean = if num_fragments == 0 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
sorted_sizes.iter().copied().sum::<usize>() / num_fragments
|
||||||
|
};
|
||||||
|
|
||||||
|
let frag_stats = FragmentStatistics {
|
||||||
|
num_fragments,
|
||||||
|
num_small_fragments,
|
||||||
|
lengths: FragmentSummaryStats {
|
||||||
|
min,
|
||||||
|
max,
|
||||||
|
mean,
|
||||||
|
p25,
|
||||||
|
p50,
|
||||||
|
p75,
|
||||||
|
p99,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let stats = TableStatistics {
|
||||||
|
total_bytes,
|
||||||
|
num_rows,
|
||||||
|
num_indices,
|
||||||
|
fragment_stats: frag_stats,
|
||||||
|
};
|
||||||
|
Ok(stats)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
pub struct TableStatistics {
|
||||||
|
/// The total number of bytes in the table
|
||||||
|
pub total_bytes: usize,
|
||||||
|
|
||||||
|
/// The number of rows in the table
|
||||||
|
pub num_rows: usize,
|
||||||
|
|
||||||
|
/// The number of indices in the table
|
||||||
|
pub num_indices: usize,
|
||||||
|
|
||||||
|
/// Statistics on table fragments
|
||||||
|
pub fragment_stats: FragmentStatistics,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
pub struct FragmentStatistics {
|
||||||
|
/// The number of fragments in the table
|
||||||
|
pub num_fragments: usize,
|
||||||
|
|
||||||
|
/// The number of uncompacted fragments in the table
|
||||||
|
pub num_small_fragments: usize,
|
||||||
|
|
||||||
|
/// Statistics on the number of rows in the table fragments
|
||||||
|
pub lengths: FragmentSummaryStats,
|
||||||
|
// todo: add size statistics
|
||||||
|
// /// Statistics on the number of bytes in the table fragments
|
||||||
|
// sizes: FragmentStats,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[skip_serializing_none]
|
||||||
|
#[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
pub struct FragmentSummaryStats {
|
||||||
|
pub min: usize,
|
||||||
|
pub max: usize,
|
||||||
|
pub mean: usize,
|
||||||
|
pub p25: usize,
|
||||||
|
pub p50: usize,
|
||||||
|
pub p75: usize,
|
||||||
|
pub p99: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -3945,4 +4138,108 @@ mod tests {
|
|||||||
Some(&"test_field_val1".to_string())
|
Some(&"test_field_val1".to_string())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
pub async fn test_stats() {
|
||||||
|
let tmp_dir = tempdir().unwrap();
|
||||||
|
let uri = tmp_dir.path().to_str().unwrap();
|
||||||
|
|
||||||
|
let conn = ConnectBuilder::new(uri).execute().await.unwrap();
|
||||||
|
|
||||||
|
let schema = Arc::new(Schema::new(vec![
|
||||||
|
Field::new("id", DataType::Int32, false),
|
||||||
|
Field::new("foo", DataType::Int32, true),
|
||||||
|
]));
|
||||||
|
let batch = RecordBatch::try_new(
|
||||||
|
schema.clone(),
|
||||||
|
vec![
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..100)),
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..100)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let table = conn
|
||||||
|
.create_table(
|
||||||
|
"test_stats",
|
||||||
|
RecordBatchIterator::new(vec![Ok(batch.clone())], batch.schema()),
|
||||||
|
)
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
for _ in 0..10 {
|
||||||
|
let batch = RecordBatch::try_new(
|
||||||
|
schema.clone(),
|
||||||
|
vec![
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..15)),
|
||||||
|
Arc::new(Int32Array::from_iter_values(0..15)),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
table
|
||||||
|
.add(RecordBatchIterator::new(
|
||||||
|
vec![Ok(batch.clone())],
|
||||||
|
batch.schema(),
|
||||||
|
))
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let empty_table = conn
|
||||||
|
.create_table(
|
||||||
|
"test_stats_empty",
|
||||||
|
RecordBatchIterator::new(vec![], batch.schema()),
|
||||||
|
)
|
||||||
|
.execute()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let res = table.stats().await.unwrap();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
TableStatistics {
|
||||||
|
num_rows: 250,
|
||||||
|
num_indices: 0,
|
||||||
|
total_bytes: 2000,
|
||||||
|
fragment_stats: FragmentStatistics {
|
||||||
|
num_fragments: 11,
|
||||||
|
num_small_fragments: 11,
|
||||||
|
lengths: FragmentSummaryStats {
|
||||||
|
min: 15,
|
||||||
|
max: 100,
|
||||||
|
mean: 22,
|
||||||
|
p25: 15,
|
||||||
|
p50: 15,
|
||||||
|
p75: 15,
|
||||||
|
p99: 100,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let res = empty_table.stats().await.unwrap();
|
||||||
|
println!("{:#?}", res);
|
||||||
|
assert_eq!(
|
||||||
|
res,
|
||||||
|
TableStatistics {
|
||||||
|
num_rows: 0,
|
||||||
|
num_indices: 0,
|
||||||
|
total_bytes: 0,
|
||||||
|
fragment_stats: FragmentStatistics {
|
||||||
|
num_fragments: 0,
|
||||||
|
num_small_fragments: 0,
|
||||||
|
lengths: FragmentSummaryStats {
|
||||||
|
min: 0,
|
||||||
|
max: 0,
|
||||||
|
mean: 0,
|
||||||
|
p25: 0,
|
||||||
|
p50: 0,
|
||||||
|
p75: 0,
|
||||||
|
p99: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use arrow_array::RecordBatchReader;
|
|||||||
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
|
|
||||||
use super::BaseTable;
|
use super::{BaseTable, MergeResult};
|
||||||
|
|
||||||
/// A builder used to create and run a merge insert operation
|
/// A builder used to create and run a merge insert operation
|
||||||
///
|
///
|
||||||
@@ -86,8 +86,9 @@ impl MergeInsertBuilder {
|
|||||||
|
|
||||||
/// Executes the merge insert operation
|
/// Executes the merge insert operation
|
||||||
///
|
///
|
||||||
/// Nothing is returned but the [`super::Table`] is updated
|
/// Returns version and statistics about the merge operation including the number of rows
|
||||||
pub async fn execute(self, new_data: Box<dyn RecordBatchReader + Send>) -> Result<()> {
|
/// inserted, updated, and deleted.
|
||||||
|
pub async fn execute(self, new_data: Box<dyn RecordBatchReader + Send>) -> Result<MergeResult> {
|
||||||
self.table.clone().merge_insert(self, new_data).await
|
self.table.clone().merge_insert(self, new_data).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user