From cba63a6656e96cd40b9f97c7d6a6196db123f9a0 Mon Sep 17 00:00:00 2001 From: Vova Kolmakov Date: Tue, 31 Mar 2026 12:59:25 +0700 Subject: [PATCH] feat: add Rust BaseLanceNamespace that provides an implementation of all APIs through the Lance core SDK --- rust/Cargo.lock | 5645 +++++++++++++++++++++++-- rust/Cargo.toml | 5 +- rust/lance-namespace-base/Cargo.toml | 44 + rust/lance-namespace-base/src/base.rs | 5091 ++++++++++++++++++++++ rust/lance-namespace-base/src/lib.rs | 31 + 5 files changed, 10371 insertions(+), 445 deletions(-) create mode 100644 rust/lance-namespace-base/Cargo.toml create mode 100644 rust/lance-namespace-base/src/base.rs create mode 100644 rust/lance-namespace-base/src/lib.rs diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e1e9bb03..c07b2c2f 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -18,681 +9,4161 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] -name = "async-compression" -version = "0.4.30" +name = "aes" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "977eb15ea9efd848bb8a4a1a2500347ed7f0bf794edf0dc3ddcf439f43d36b23" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ - "compression-codecs", - "compression-core", - "futures-core", - "pin-project-lite", - "tokio", + "cfg-if", + "cipher", + "cpufeatures", ] [[package]] -name = "atomic-waker" -version = "1.1.2" +name = "ahash" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "const-random", + "getrandom 0.3.3", + "once_cell", + "version_check", + "zerocopy", +] [[package]] -name = "backtrace" -version = "0.3.75" +name = "aho-corasick" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", + "memchr", ] [[package]] -name = "base64" -version = "0.22.1" +name = "alloc-no-stdlib" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" [[package]] -name = "bitflags" -version = "2.9.4" +name = "alloc-stdlib" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] [[package]] -name = "bumpalo" -version = "3.19.0" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] -name = "bytes" -version = "1.10.1" +name = "android_system_properties" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] [[package]] -name = "cc" -version = "1.2.38" +name = "anyhow" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arc-swap" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a07d1f37ff60921c83bdfc7407723bdefe89b44b98a9b772f225c8f9d67141a6" dependencies = [ - "find-msvc-tools", - "shlex", + "rustversion", ] [[package]] -name = "cfg-if" -version = "1.0.3" +name = "arrayref" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] -name = "cfg_aliases" -version = "0.2.1" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "compression-codecs" -version = "0.4.30" +name = "arrow" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64" +checksum = "e4754a624e5ae42081f464514be454b39711daae0458906dacde5f4c632f33a8" dependencies = [ - "compression-core", - "flate2", - "memchr", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", ] [[package]] -name = "compression-core" -version = "0.4.29" +name = "arrow-arith" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" +checksum = "f7b3141e0ec5145a22d8694ea8b6d6f69305971c4fa1c1a13ef0195aef2d678b" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "num-traits", +] [[package]] -name = "core-foundation" -version = "0.10.1" +name = "arrow-array" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +checksum = "4c8955af33b25f3b175ee10af580577280b4bd01f7e823d94c7cdef7cf8c9aef" dependencies = [ - "core-foundation-sys", - "libc", + "ahash", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "chrono-tz", + "half", + "hashbrown 0.16.1", + "num-complex", + "num-integer", + "num-traits", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "arrow-buffer" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "c697ddca96183182f35b3a18e50b9110b11e916d7b7799cbfd4d34662f2c56c2" +dependencies = [ + "bytes", + "half", + "num-bigint", + "num-traits", +] [[package]] -name = "crc32fast" -version = "1.5.0" +name = "arrow-cast" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "646bbb821e86fd57189c10b4fcdaa941deaf4181924917b0daa92735baa6ada5" dependencies = [ - "cfg-if", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "atoi", + "base64", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num-traits", + "ryu", ] [[package]] -name = "displaydoc" -version = "0.2.5" +name = "arrow-csv" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "8da746f4180004e3ce7b83c977daf6394d768332349d3d913998b10a120b790a" dependencies = [ - "proc-macro2", - "quote", - "syn", + "arrow-array", + "arrow-cast", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "regex", ] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "arrow-data" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "1fdd994a9d28e6365aa78e15da3f3950c0fdcea6b963a12fa1c391afb637b304" dependencies = [ - "cfg-if", + "arrow-buffer", + "arrow-schema", + "half", + "num-integer", + "num-traits", ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "arrow-ipc" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "abf7df950701ab528bf7c0cf7eeadc0445d03ef5d6ffc151eaae6b38a58feff1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "flatbuffers", + "lz4_flex 0.12.1", + "zstd", +] [[package]] -name = "find-msvc-tools" -version = "0.1.2" +name = "arrow-json" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "0ff8357658bedc49792b13e2e862b80df908171275f8e6e075c460da5ee4bf86" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap", + "itoa", + "lexical-core", + "memchr", + "num-traits", + "ryu", + "serde_core", + "serde_json", + "simdutf8", +] [[package]] -name = "flate2" -version = "1.1.2" +name = "arrow-ord" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "f7d8f1870e03d4cbed632959498bcc84083b5a24bded52905ae1695bd29da45b" dependencies = [ - "crc32fast", - "miniz_oxide", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "arrow-row" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "18228633bad92bff92a95746bbeb16e5fc318e8382b75619dec26db79e4de4c0" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "arrow-schema" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "8c872d36b7bf2a6a6a2b40de9156265f0242910791db366a2c17476ba8330d68" dependencies = [ - "percent-encoding", + "bitflags", + "serde_core", + "serde_json", ] [[package]] -name = "futures-channel" -version = "0.3.31" +name = "arrow-select" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "68bf3e3efbd1278f770d67e5dc410257300b161b93baedb3aae836144edcaf4b" dependencies = [ - "futures-core", + "ahash", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num-traits", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "arrow-string" +version = "57.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "85e968097061b3c0e9fe3079cf2e703e487890700546b5b0647f60fca1b5a8d8" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num-traits", + "regex", + "regex-syntax", +] [[package]] -name = "futures-io" -version = "0.3.31" +name = "async-channel" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] [[package]] -name = "futures-macro" -version = "0.3.31" +name = "async-compression" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "977eb15ea9efd848bb8a4a1a2500347ed7f0bf794edf0dc3ddcf439f43d36b23" dependencies = [ - "proc-macro2", - "quote", - "syn", + "compression-codecs", + "compression-core", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "futures-sink" -version = "0.3.31" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] [[package]] -name = "futures-task" -version = "0.3.31" +name = "async-recursion" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "futures-util" -version = "0.3.31" +name = "async-trait" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "getrandom" -version = "0.2.16" +name = "async_cell" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "447ab28afbb345f5408b120702a44e5529ebf90b1796ec76e9528df8e288e6c2" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", + "loom", ] [[package]] -name = "getrandom" -version = "0.3.3" +name = "atoi" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.7+wasi-0.2.4", - "wasm-bindgen", + "num-traits", ] [[package]] -name = "gimli" -version = "0.31.1" +name = "atomic-waker" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] -name = "h2" -version = "0.4.12" +name = "autocfg" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "aws-config" +version = "1.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8fc176d53d6fe85017f230405e3255cedb4a02221cb55ed6d76dccbbb099b2" dependencies = [ - "atomic-waker", + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", + "fastrand", + "hex", + "http 1.3.1", + "ring", + "time", "tokio", - "tokio-util", "tracing", + "url", + "zeroize", ] [[package]] -name = "hashbrown" -version = "0.16.0" +name = "aws-credential-types" +version = "1.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +checksum = "e26bbf46abc608f2dc61fd6cb3b7b0665497cc259a21520151ed98f8b37d2c79" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] [[package]] -name = "http" -version = "1.3.1" +name = "aws-lc-rs" +version = "1.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "a054912289d18629dc78375ba2c3726a3afe3ff71b4edba9dedfca0e3446d1fc" dependencies = [ - "bytes", - "fnv", - "itoa", + "aws-lc-sys", + "zeroize", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "aws-lc-sys" +version = "0.39.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "83a25cf98105baa966497416dbd42565ce3a8cf8dbfd59803ec9ad46f3126399" dependencies = [ - "bytes", - "http", + "cc", + "cmake", + "dunce", + "fs_extra", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "aws-runtime" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "b0f92058d22a46adf53ec57a6a96f34447daf02bff52e8fb956c66bcd5c6ac12" dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "futures-core", - "http", - "http-body", + "bytes-utils", + "fastrand", + "http 1.3.1", + "http-body 1.0.1", + "percent-encoding", "pin-project-lite", + "tracing", + "uuid", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "aws-sdk-sso" +version = "1.94.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "699da1961a289b23842d88fe2984c6ff68735fdf9bdcbc69ceaeb2491c9bf434" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.3.1", + "regex-lite", + "tracing", +] [[package]] -name = "hyper" -version = "1.7.0" +name = "aws-sdk-ssooidc" +version = "1.96.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +checksum = "e3e3a4cb3b124833eafea9afd1a6cc5f8ddf3efefffc6651ef76a03cbc6b4981" dependencies = [ - "atomic-waker", + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", + "fastrand", + "http 0.2.12", + "http 1.3.1", + "regex-lite", + "tracing", ] [[package]] -name = "hyper-rustls" -version = "0.27.7" +name = "aws-sdk-sts" +version = "1.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +checksum = "89c4f19655ab0856375e169865c91264de965bd74c407c7f1e403184b1049409" dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-native-certs", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-observability", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand", + "http 0.2.12", + "http 1.3.1", + "regex-lite", + "tracing", ] [[package]] -name = "hyper-util" -version = "0.1.17" +name = "aws-sigv4" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +checksum = "68f6ae9b71597dc5fd115d52849d7a5556ad9265885ad3492ea8d73b93bbc46e" dependencies = [ - "base64", + "aws-credential-types", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.3.1", "percent-encoding", + "sha2", + "time", + "tracing", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffcaf626bdda484571968400c326a244598634dc75fd451325a54ad1a59acfc" +dependencies = [ + "futures-util", "pin-project-lite", - "socket2", "tokio", - "tower-service", - "tracing", ] [[package]] -name = "icu_collections" -version = "2.0.0" +name = "aws-smithy-http" +version = "0.63.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "af4a8a5fe3e4ac7ee871237c340bbce13e982d37543b65700f4419e039f5d78e" dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", ] [[package]] -name = "icu_locale_core" -version = "2.0.0" +name = "aws-smithy-http-client" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "0709f0083aa19b704132684bc26d3c868e06bd428ccc4373b0b55c3e8748a58b" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2", + "http 1.3.1", + "hyper", + "hyper-rustls", + "hyper-util", + "pin-project-lite", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower", + "tracing", ] [[package]] -name = "icu_normalizer" -version = "2.0.0" +name = "aws-smithy-json" +version = "0.62.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "27b3a779093e18cad88bbae08dc4261e1d95018c4c5b9356a52bcae7c0b6e9bb" dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", + "aws-smithy-types", ] [[package]] -name = "icu_normalizer_data" -version = "2.0.0" +name = "aws-smithy-observability" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "4d3f39d5bb871aaf461d59144557f16d5927a5248a983a40654d9cf3b9ba183b" +dependencies = [ + "aws-smithy-runtime-api", +] [[package]] -name = "icu_properties" -version = "2.0.1" +name = "aws-smithy-query" +version = "0.60.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "05f76a580e3d8f8961e5d48763214025a2af65c2fa4cd1fb7f270a0e107a71b0" dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", + "aws-smithy-types", + "urlencoding", ] [[package]] -name = "icu_properties_data" -version = "2.0.1" +name = "aws-smithy-runtime" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "8fd3dfc18c1ce097cf81fced7192731e63809829c6cbf933c1ec47452d08e1aa" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] [[package]] -name = "icu_provider" -version = "2.0.0" +name = "aws-smithy-runtime-api" +version = "1.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "8c55e0837e9b8526f49e0b9bfa9ee18ddee70e853f5bc09c5d11ebceddcb0fec" dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.3.1", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", ] [[package]] -name = "idna" -version = "1.1.0" +name = "aws-smithy-types" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "576b0d6991c9c32bc14fc340582ef148311f924d41815f641a308b5d11e8e7cd" dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", + "base64-simd", + "bytes", + "bytes-utils", + "http 0.2.12", + "http 1.3.1", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", ] [[package]] -name = "idna_adapter" -version = "1.2.1" +name = "aws-smithy-xml" +version = "0.60.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "0ce02add1aa3677d022f8adf81dcbe3046a95f17a1b1e8979c145cd21d3d22b3" dependencies = [ - "icu_normalizer", - "icu_properties", + "xmlparser", ] [[package]] -name = "indexmap" -version = "2.11.4" +name = "aws-types" +version = "1.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" +checksum = "6c50f3cdf47caa8d01f2be4a6663ea02418e892f9bbfd82c7b9a3a37eaccdd3a" dependencies = [ - "equivalent", - "hashbrown", + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", ] [[package]] -name = "io-uring" -version = "0.7.10" +name = "backon" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046fa2d4d00aea763528b4950358d0ead425372445dc8ff86312b3c69ff7727b" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ - "bitflags", - "cfg-if", - "libc", + "fastrand", + "gloo-timers", + "tokio", ] [[package]] -name = "ipnet" -version = "2.11.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "iri-string" -version = "0.7.8" +name = "base64-simd" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" dependencies = [ - "memchr", - "serde", + "outref", + "vsimd", ] [[package]] -name = "itoa" -version = "1.0.15" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] -name = "js-sys" -version = "0.3.80" +name = "bigdecimal" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" dependencies = [ - "once_cell", - "wasm-bindgen", + "autocfg", + "libm", + "num-bigint", + "num-integer", + "num-traits", ] [[package]] -name = "lance-namespace-reqwest-client" -version = "0.6.1" -dependencies = [ - "reqwest", - "serde", - "serde_json", - "serde_repr", - "url", -] +name = "bitflags" +version = "2.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] -name = "libc" -version = "0.2.176" +name = "bitpacking" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" +checksum = "96a7139abd3d9cebf8cd6f920a389cf3dc9576172e32f4563f188cae3c3eb019" +dependencies = [ + "crunchy", +] [[package]] -name = "litemap" -version = "0.8.0" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] [[package]] -name = "log" -version = "0.4.28" +name = "blake2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] [[package]] -name = "lru-slab" -version = "0.1.2" +name = "blake3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] [[package]] -name = "memchr" -version = "2.7.5" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] [[package]] -name = "mime" -version = "0.3.17" +name = "block-padding" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] [[package]] -name = "mime_guess" -version = "2.0.5" +name = "bon" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" dependencies = [ - "mime", - "unicase", + "bon-macros", + "rustversion", ] [[package]] -name = "miniz_oxide" -version = "0.8.9" +name = "bon-macros" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" dependencies = [ - "adler2", + "darling", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", ] [[package]] -name = "mio" -version = "1.0.4" +name = "brotli" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", ] [[package]] -name = "object" -version = "0.36.7" +name = "brotli-decompressor" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ - "memchr", + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "bumpalo" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] -name = "openssl-probe" +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "census" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4c707c6a209cbe82d10abd08e1ea8995e9ea937d2550646e02798948992be0" + +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link 0.2.0", +] + +[[package]] +name = "chrono-tz" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6139a8597ed92cf816dfb33f5dd6cf0bb93a6adc938f11039f371bc5bcd26c3" +dependencies = [ + "chrono", + "phf", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "cmake" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0f78a02292a74a88ac736019ab962ece0bc380e3f977bf72e376c5d78ff0678" +dependencies = [ + "cc", +] + +[[package]] +name = "comfy-table" +version = "7.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" +dependencies = [ + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "compression-codecs" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "485abf41ac0c8047c07c87c72c8fb3eb5197f6e9d7ded615dfd1a00ae00a0f64" +dependencies = [ + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.16", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde_core", +] + +[[package]] +name = "csv-core" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +dependencies = [ + "memchr", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "datafusion" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c18ba387f9c05ac1f3be32a73f8f3cc6c1cfc43e5d4b7a8e5b0d3a5eb48dc7" +dependencies = [ + "arrow", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "datafusion-catalog", + "datafusion-catalog-listing", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-datasource-arrow", + "datafusion-datasource-csv", + "datafusion-datasource-json", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-nested", + "datafusion-functions-table", + "datafusion-functions-window", + "datafusion-optimizer", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-optimizer", + "datafusion-physical-plan", + "datafusion-session", + "datafusion-sql", + "futures", + "itertools 0.14.0", + "log", + "object_store", + "parking_lot", + "rand 0.9.2", + "regex", + "sqlparser", + "tempfile", + "tokio", + "url", + "uuid", +] + +[[package]] +name = "datafusion-catalog" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c75a4ce672b27fb8423810efb92a3600027717a1664d06a2c307eeeabcec694" +dependencies = [ + "arrow", + "async-trait", + "dashmap", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "itertools 0.14.0", + "log", + "object_store", + "parking_lot", + "tokio", +] + +[[package]] +name = "datafusion-catalog-listing" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8b9a3795ffb46bf4957a34c67d89a67558b311ae455c8d4295ff2115eeea50" +dependencies = [ + "arrow", + "async-trait", + "datafusion-catalog", + "datafusion-common", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "futures", + "itertools 0.14.0", + "log", + "object_store", +] + +[[package]] +name = "datafusion-common" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "205dc1e20441973f470e6b7ef87626a3b9187970e5106058fef1b713047f770c" +dependencies = [ + "ahash", + "arrow", + "arrow-ipc", + "chrono", + "half", + "hashbrown 0.16.1", + "indexmap", + "libc", + "log", + "object_store", + "paste", + "sqlparser", + "tokio", + "web-time", +] + +[[package]] +name = "datafusion-common-runtime" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf5880c02ff6f5f11fb5bc19211789fb32fd3c53d79b7d6cb2b12e401312ba0" +dependencies = [ + "futures", + "log", + "tokio", +] + +[[package]] +name = "datafusion-datasource" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc614d6e709450e29b7b032a42c1bdb705f166a6b2edef7bed7c7897eb905499" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "chrono", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-physical-expr-adapter", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "glob", + "itertools 0.14.0", + "log", + "object_store", + "rand 0.9.2", + "tokio", + "url", +] + +[[package]] +name = "datafusion-datasource-arrow" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e497d5fc48dac7ce86f6b4fb09a3a494385774af301ff20ec91aebfae9b05b4" +dependencies = [ + "arrow", + "arrow-ipc", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "itertools 0.14.0", + "object_store", + "tokio", +] + +[[package]] +name = "datafusion-datasource-csv" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dfc250cad940d0327ca2e9109dc98830892d17a3d6b2ca11d68570e872cf379" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "object_store", + "regex", + "tokio", +] + +[[package]] +name = "datafusion-datasource-json" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91e9677ed62833b0e8129dec0d1a8f3c9bb7590bd6dd714a43e4c3b663e4aa0" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-datasource", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-session", + "futures", + "object_store", + "tokio", +] + +[[package]] +name = "datafusion-doc" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e13e5fe3447baa0584b61ee8644086e007e1ef6e58f4be48bc8a72417854729" + +[[package]] +name = "datafusion-execution" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48a6cc03e34899a54546b229235f7b192634c8e832f78a267f0989b18216c56d" +dependencies = [ + "arrow", + "async-trait", + "chrono", + "dashmap", + "datafusion-common", + "datafusion-expr", + "futures", + "log", + "object_store", + "parking_lot", + "rand 0.9.2", + "tempfile", + "url", +] + +[[package]] +name = "datafusion-expr" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee3315d87eca7a7df58e52a1fb43b4c4171b545fd30ffc3102945c162a9f6ddb" +dependencies = [ + "arrow", + "async-trait", + "chrono", + "datafusion-common", + "datafusion-doc", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-functions-window-common", + "datafusion-physical-expr-common", + "indexmap", + "itertools 0.14.0", + "paste", + "serde_json", + "sqlparser", +] + +[[package]] +name = "datafusion-expr-common" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c6d83feae0753799f933a2c47dfd15980c6947960cb95ed60f5c1f885548b3" +dependencies = [ + "arrow", + "datafusion-common", + "indexmap", + "itertools 0.14.0", + "paste", +] + +[[package]] +name = "datafusion-functions" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b82962015cc3db4d7662459c9f7fcda0591b5edacb8af1cf3bc3031f274800" +dependencies = [ + "arrow", + "arrow-buffer", + "base64", + "blake2", + "blake3", + "chrono", + "chrono-tz", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-macros", + "hex", + "itertools 0.14.0", + "log", + "md-5", + "num-traits", + "rand 0.9.2", + "regex", + "sha2", + "unicode-segmentation", + "uuid", +] + +[[package]] +name = "datafusion-functions-aggregate" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e42c227d9e55a6c8041785d4a8a117e4de531033d480aae10984247ac62e27e" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions-aggregate-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "half", + "log", + "paste", +] + +[[package]] +name = "datafusion-functions-aggregate-common" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cead3cfed825b0b688700f4338d281cd7857e4907775a5b9554c083edd5f3f95" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr-common", + "datafusion-physical-expr-common", +] + +[[package]] +name = "datafusion-functions-nested" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ea99612970aebab8cf864d02eb3d296bbab7f4881e1023d282b57fe431b201" +dependencies = [ + "arrow", + "arrow-ord", + "datafusion-common", + "datafusion-doc", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions", + "datafusion-functions-aggregate", + "datafusion-functions-aggregate-common", + "datafusion-macros", + "datafusion-physical-expr-common", + "itertools 0.14.0", + "log", + "paste", +] + +[[package]] +name = "datafusion-functions-table" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83dbf3ab8b9af6f209b068825a7adbd3b88bf276f2a1ec14ba09567b97f5674" +dependencies = [ + "arrow", + "async-trait", + "datafusion-catalog", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", + "paste", +] + +[[package]] +name = "datafusion-functions-window" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732edabe07496e2fc5a1e57a284d7a36edcea445a2821119770a0dea624b472c" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-doc", + "datafusion-expr", + "datafusion-functions-window-common", + "datafusion-macros", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "log", + "paste", +] + +[[package]] +name = "datafusion-functions-window-common" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c6e30e09700799bd52adce8c377ab03dda96e73a623e4803a31ad94fe7ce14" +dependencies = [ + "datafusion-common", + "datafusion-physical-expr-common", +] + +[[package]] +name = "datafusion-macros" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "402f2a8ed70fb99a18f71580a1fe338604222a3d32ddeac6e72c5b34feea2d4d" +dependencies = [ + "datafusion-doc", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "datafusion-optimizer" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99f32edb8ba12f08138f86c09b80fae3d4a320551262fa06b91d8a8cb3065a5b" +dependencies = [ + "arrow", + "chrono", + "datafusion-common", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-physical-expr", + "indexmap", + "itertools 0.14.0", + "log", + "regex", + "regex-syntax", +] + +[[package]] +name = "datafusion-physical-expr" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "987c5e29e96186589301b42e25aa7d11bbe319a73eb02ef8d755edc55b5b89fc" +dependencies = [ + "ahash", + "arrow", + "datafusion-common", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-functions-aggregate-common", + "datafusion-physical-expr-common", + "half", + "hashbrown 0.16.1", + "indexmap", + "itertools 0.14.0", + "parking_lot", + "paste", + "petgraph", + "tokio", +] + +[[package]] +name = "datafusion-physical-expr-adapter" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de89d0afa08b6686697bd8a6bac4ba2cd44c7003356e1bce6114d5a93f94b5c" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-expr", + "datafusion-functions", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "itertools 0.14.0", +] + +[[package]] +name = "datafusion-physical-expr-common" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602d1970c0fe87f1c3a36665d131fbfe1c4379d35f8fc5ec43a362229ad2954d" +dependencies = [ + "ahash", + "arrow", + "chrono", + "datafusion-common", + "datafusion-expr-common", + "hashbrown 0.16.1", + "indexmap", + "itertools 0.14.0", + "parking_lot", +] + +[[package]] +name = "datafusion-physical-optimizer" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b24d704b6385ebe27c756a12e5ba15684576d3b47aeca79cc9fb09480236dc32" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-expr-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "datafusion-pruning", + "itertools 0.14.0", +] + +[[package]] +name = "datafusion-physical-plan" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c21d94141ea5043e98793f170798e9c1887095813b8291c5260599341e383a38" +dependencies = [ + "ahash", + "arrow", + "arrow-ord", + "arrow-schema", + "async-trait", + "datafusion-common", + "datafusion-common-runtime", + "datafusion-execution", + "datafusion-expr", + "datafusion-functions", + "datafusion-functions-aggregate-common", + "datafusion-functions-window-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "futures", + "half", + "hashbrown 0.16.1", + "indexmap", + "itertools 0.14.0", + "log", + "parking_lot", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "datafusion-pruning" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a68cce43d18c0dfac95cacd74e70565f7e2fb12b9ed41e2d312f0fa837626b1" +dependencies = [ + "arrow", + "datafusion-common", + "datafusion-datasource", + "datafusion-expr-common", + "datafusion-physical-expr", + "datafusion-physical-expr-common", + "datafusion-physical-plan", + "itertools 0.14.0", + "log", +] + +[[package]] +name = "datafusion-session" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4e1c40a0b1896aed4a4504145c2eb7fa9b9da13c2d04b40a4767a09f076199" +dependencies = [ + "async-trait", + "datafusion-common", + "datafusion-execution", + "datafusion-expr", + "datafusion-physical-plan", + "parking_lot", +] + +[[package]] +name = "datafusion-sql" +version = "52.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f1891e5b106d1d73c7fe403bd8a265d19c3977edc17f60808daf26c2fe65ffb" +dependencies = [ + "arrow", + "bigdecimal", + "chrono", + "datafusion-common", + "datafusion-expr", + "indexmap", + "log", + "regex", + "sqlparser", +] + +[[package]] +name = "deepsize" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cdb987ec36f6bf7bfbea3f928b75590b736fc42af8e54d97592481351b2b96c" +dependencies = [ + "deepsize_derive", +] + +[[package]] +name = "deepsize_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990101d41f3bc8c1a45641024377ee284ecc338e5ecf3ea0f0e236d897c72796" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +dependencies = [ + "powerfmt", + "serde_core", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + +[[package]] +name = "downcast-rs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117240f60069e65410b3ae1bb213295bd828f707b5bec6596a1afc8793ce0cbc" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.0", +] + +[[package]] +name = "ethnum" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca81e6b4777c89fd810c25a4be2b1bd93ea034fbe58e6a75216a34c6b82c539b" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fast-float2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8eb564c5c7423d25c886fb561d1e4ee69f72354d16918afa32c08811f6b6a55" + +[[package]] +name = "fastdivide" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afc2bd4d5a73106dd53d10d73d3401c2f32730ba2c0b93ddb888a8983680471" + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flatbuffers" +version = "25.12.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35f6839d7b3b98adde531effaf34f0c2badc6f4735d26fe74709d8e513a96ef3" +dependencies = [ + "bitflags", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs4" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7e180ac76c23b45e767bd7ae9579bc0bb458618c4bc71835926e098e61d15f8" +dependencies = [ + "rustix 0.38.44", + "windows-sys 0.52.0", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "fsst" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-array", + "rand 0.9.2", +] + +[[package]] +name = "fst" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a" +dependencies = [ + "utf8-ranges", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generator" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link 0.2.0", + "windows-result", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi 5.3.0", + "wasi 0.14.7+wasi-0.2.4", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "h2" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.3.1", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.1.5", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash 0.2.0", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "htmlescape" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9025058dae765dee5070ec375f591e2ba14638c63feff74f13805a72e523163" + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.3.1", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.3.1", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hyper" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2", + "http 1.3.1", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.3.1", + "hyper", + "hyper-util", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-util" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" +dependencies = [ + "base64", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "hyper", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "hyperloglogplus" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "621debdf94dcac33e50475fdd76d34d5ea9c0362a834b9db08c3024696c1fbe3" +dependencies = [ + "serde", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" + +[[package]] +name = "icu_properties" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "potential_utf", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" + +[[package]] +name = "icu_provider" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +dependencies = [ + "displaydoc", + "icu_locale_core", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +dependencies = [ + "jiff-static", + "jiff-tzdb-platform", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", + "windows-sys 0.61.0", +] + +[[package]] +name = "jiff-static" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jiff-tzdb" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c900ef84826f1338a557697dc8fc601df9ca9af4ac137c7fb61d4c6f2dfd3076" + +[[package]] +name = "jiff-tzdb-platform" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8" +dependencies = [ + "jiff-tzdb", +] + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.3", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonb" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb98fb29636087c40ad0d1274d9a30c0c1e83e03ae93f6e7e89247b37fcc6953" +dependencies = [ + "byteorder", + "ethnum", + "fast-float2", + "itoa", + "jiff", + "nom 8.0.0", + "num-traits", + "ordered-float", + "rand 0.9.2", + "serde", + "serde_json", + "zmij", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "lance" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-ipc", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "async_cell", + "aws-credential-types", + "byteorder", + "bytes", + "chrono", + "crossbeam-skiplist", + "dashmap", + "datafusion", + "datafusion-expr", + "datafusion-functions", + "datafusion-physical-expr", + "datafusion-physical-plan", + "deepsize", + "either", + "futures", + "half", + "humantime", + "itertools 0.13.0", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-encoding", + "lance-file", + "lance-index", + "lance-io", + "lance-linalg", + "lance-namespace", + "lance-table", + "log", + "moka", + "object_store", + "permutation", + "pin-project", + "prost", + "prost-types", + "rand 0.9.2", + "roaring", + "semver", + "serde", + "serde_json", + "snafu", + "tantivy", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "lance-arrow" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-ord", + "arrow-schema", + "arrow-select", + "bytes", + "futures", + "getrandom 0.2.16", + "half", + "jsonb", + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "lance-bitpacking" +version = "5.0.0-beta.1" +dependencies = [ + "arrayref", + "paste", + "seq-macro", +] + +[[package]] +name = "lance-core" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-schema", + "async-trait", + "byteorder", + "bytes", + "chrono", + "datafusion-common", + "datafusion-sql", + "deepsize", + "futures", + "itertools 0.13.0", + "lance-arrow", + "libc", + "log", + "mock_instant", + "moka", + "num_cpus", + "object_store", + "pin-project", + "prost", + "rand 0.9.2", + "roaring", + "serde_json", + "snafu", + "tempfile", + "tokio", + "tokio-stream", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "lance-datafusion" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-trait", + "chrono", + "datafusion", + "datafusion-common", + "datafusion-functions", + "datafusion-physical-expr", + "futures", + "jsonb", + "lance-arrow", + "lance-core", + "lance-datagen", + "log", + "pin-project", + "prost", + "prost-build", + "snafu", + "tokio", + "tracing", +] + +[[package]] +name = "lance-datagen" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-array", + "arrow-cast", + "arrow-schema", + "chrono", + "futures", + "half", + "hex", + "rand 0.9.2", + "rand_distr 0.5.1", + "rand_xoshiro", + "random_word", +] + +[[package]] +name = "lance-encoding" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "bytemuck", + "byteorder", + "bytes", + "fsst", + "futures", + "hex", + "hyperloglogplus", + "itertools 0.13.0", + "lance-arrow", + "lance-bitpacking", + "lance-core", + "log", + "lz4", + "num-traits", + "prost", + "prost-build", + "prost-types", + "rand 0.9.2", + "snafu", + "strum", + "tokio", + "tracing", + "xxhash-rust", + "zstd", +] + +[[package]] +name = "lance-file" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "byteorder", + "bytes", + "datafusion-common", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-encoding", + "lance-io", + "log", + "num-traits", + "object_store", + "prost", + "prost-build", + "prost-types", + "snafu", + "tokio", + "tracing", +] + +[[package]] +name = "lance-index" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-arith", + "arrow-array", + "arrow-ord", + "arrow-schema", + "arrow-select", + "async-channel", + "async-recursion", + "async-trait", + "bitpacking", + "bitvec", + "bytes", + "chrono", + "crossbeam-queue", + "datafusion", + "datafusion-common", + "datafusion-expr", + "datafusion-physical-expr", + "datafusion-sql", + "deepsize", + "dirs", + "fst", + "futures", + "half", + "itertools 0.13.0", + "jsonb", + "lance-arrow", + "lance-core", + "lance-datafusion", + "lance-datagen", + "lance-encoding", + "lance-file", + "lance-io", + "lance-linalg", + "lance-table", + "libm", + "log", + "ndarray", + "num-traits", + "object_store", + "prost", + "prost-build", + "prost-types", + "rand 0.9.2", + "rand_distr 0.5.1", + "rangemap", + "rayon", + "roaring", + "serde", + "serde_json", + "smallvec", + "snafu", + "tantivy", + "tempfile", + "tokio", + "tracing", + "twox-hash", + "uuid", +] + +[[package]] +name = "lance-io" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "arrow-select", + "async-recursion", + "async-trait", + "aws-config", + "aws-credential-types", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "http 1.3.1", + "lance-arrow", + "lance-core", + "lance-namespace", + "log", + "object_store", + "object_store_opendal", + "opendal", + "path_abs", + "pin-project", + "prost", + "rand 0.9.2", + "serde", + "snafu", + "tempfile", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "lance-linalg" +version = "5.0.0-beta.1" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-schema", + "cc", + "deepsize", + "half", + "lance-arrow", + "lance-core", + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "lance-namespace" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "async-trait", + "bytes", + "lance-core", + "lance-namespace-reqwest-client 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", + "snafu", +] + +[[package]] +name = "lance-namespace-base" +version = "0.1.0" +dependencies = [ + "arrow", + "arrow-ipc", + "arrow-schema", + "async-trait", + "bytes", + "chrono", + "futures", + "lance", + "lance-core", + "lance-index", + "lance-io", + "lance-linalg", + "lance-namespace", + "lance-table", + "log", + "object_store", + "serde_json", + "snafu", + "tempfile", + "tokio", +] + +[[package]] +name = "lance-namespace-reqwest-client" +version = "0.6.1" +dependencies = [ + "reqwest", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "lance-namespace-reqwest-client" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee2e48de899e2931afb67fcddd0a08e439bf5d8b6ea2a2ed9cb8f4df669bd5cc" +dependencies = [ + "reqwest", + "serde", + "serde_json", + "serde_repr", + "url", +] + +[[package]] +name = "lance-table" +version = "5.0.0-beta.1" +dependencies = [ + "arrow", + "arrow-array", + "arrow-buffer", + "arrow-ipc", + "arrow-schema", + "async-trait", + "byteorder", + "bytes", + "chrono", + "deepsize", + "futures", + "lance-arrow", + "lance-core", + "lance-file", + "lance-io", + "log", + "object_store", + "prost", + "prost-build", + "prost-types", + "rand 0.9.2", + "rangemap", + "roaring", + "semver", + "serde", + "serde_json", + "snafu", + "tokio", + "tracing", + "url", + "uuid", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "levenshtein_automata" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c2cdeb66e45e9f36bfad5bbdb4d2384e70936afbee843c6f6543f0c551ebb25" + +[[package]] +name = "lexical-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d8d125a277f807e55a77304455eb7b1cb52f2b18c143b60e766c120bd64a594" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a9f232fbd6f550bc0137dcb5f99ab674071ac2d690ac69704593cb4abbea56" +dependencies = [ + "lexical-parse-integer", + "lexical-util", +] + +[[package]] +name = "lexical-parse-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7a039f8fb9c19c996cd7b2fcce303c1b2874fe1aca544edc85c4a5f8489b34" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "lexical-util" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2604dd126bb14f13fb5d1bd6a66155079cb9fa655b37f875b3a742c705dbed17" + +[[package]] +name = "lexical-write-float" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50c438c87c013188d415fbabbb1dceb44249ab81664efbd31b14ae55dabb6361" +dependencies = [ + "lexical-util", + "lexical-write-integer", +] + +[[package]] +name = "lexical-write-integer" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "409851a618475d2d5796377cad353802345cba92c867d9fbcde9cf4eac4e14df" +dependencies = [ + "lexical-util", +] + +[[package]] +name = "libc" +version = "0.2.183" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddbf48fd451246b1f8c2610bd3b4ac0cc6e149d89832867093ab69a17194f08" +dependencies = [ + "libc", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "lz4" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" +dependencies = [ + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.11.1+lz4-1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "lz4_flex" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373f5eceeeab7925e0c1098212f2fbc4d416adec9d35051a6ab251e824c1854a" + +[[package]] +name = "lz4_flex" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c23545df7ecf1b16c303910a69b079e8e251d60f7dd2cc9b4177f2afaf1746" +dependencies = [ + "twox-hash", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "num_cpus", + "once_cell", + "rawpointer", + "thread-tree", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "measure_time" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c55d61e72fc3ab704396c5fa16f4c184db37978ae4e94ca8959693a235fc0e" +dependencies = [ + "log", +] + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +dependencies = [ + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.59.0", +] + +[[package]] +name = "mock_instant" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6" + +[[package]] +name = "moka" +version = "0.12.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957228ad12042ee839f93c8f257b62b4c0ab5eaae1d4fa60de53b27c9d7c5046" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "multimap" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" + +[[package]] +name = "murmurhash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2195bf6aa996a481483b29d62a7663eed3fe39600c460e323f8ff41e90bdd89b" + +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nom" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" +dependencies = [ + "memchr", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object_store" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbfbfff40aeccab00ec8a910b57ca8ecf4319b335c542f2edcd19dd25a1e2a00" +dependencies = [ + "async-trait", + "base64", + "bytes", + "chrono", + "form_urlencoded", + "futures", + "http 1.3.1", + "http-body-util", + "httparse", + "humantime", + "hyper", + "itertools 0.14.0", + "md-5", + "parking_lot", + "percent-encoding", + "quick-xml 0.38.4", + "rand 0.9.2", + "reqwest", + "ring", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror", + "tokio", + "tracing", + "url", + "walkdir", + "wasm-bindgen-futures", + "web-time", +] + +[[package]] +name = "object_store_opendal" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "113ab0769e972eee585e57407b98de08bda5354fa28e8ba4d89038d6cb6a8991" +dependencies = [ + "async-trait", + "bytes", + "chrono", + "futures", + "object_store", + "opendal", + "pin-project", + "tokio", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "oneshot" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269bca4c2591a28585d6bf10d9ed0332b7d76900a1b02bec41bdc3a2cdcda107" + +[[package]] +name = "opendal" +version = "0.55.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d075ab8a203a6ab4bc1bce0a4b9fe486a72bf8b939037f4b78d95386384bc80a" +dependencies = [ + "anyhow", + "backon", + "base64", + "bytes", + "crc32c", + "futures", + "getrandom 0.2.16", + "http 1.3.1", + "http-body 1.0.1", + "jiff", + "log", + "md-5", + "percent-encoding", + "quick-xml 0.38.4", + "reqsign", + "reqwest", + "serde", + "serde_json", + "sha2", + "tokio", + "url", + "uuid", +] + +[[package]] +name = "openssl-probe" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7d950ca161dc355eaf28f82b11345ed76c6e1f6eb1f4f4479e0323b9e2fbd0e" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-multimap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" +dependencies = [ + "dlv-list", + "hashbrown 0.14.5", +] + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "ownedbytes" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fbd56f7631767e61784dc43f8580f403f4475bd4aaa4da003e6295e1bab4a7e" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link 0.2.0", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path_abs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" +dependencies = [ + "serde", + "serde_derive", + "std_prelude", + "stfu8", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64", + "serde_core", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "permutation" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df202b0b0f5b8e389955afd5f27b007b00fb948162953f1db9c70d2c7e3157d7" + +[[package]] +name = "petgraph" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" +dependencies = [ + "fixedbitset", + "hashbrown 0.15.5", + "indexmap", + "serde", +] + +[[package]] +name = "phf" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e847e2c91a18bfa887dd028ec33f2fe6f25db77db3619024764914affe8b69a6" +dependencies = [ + "aes", + "cbc", + "der", + "pbkdf2", + "scrypt", + "sha2", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "pkcs5", + "rand_core 0.6.4", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "portable-atomic" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] -name = "pin-utils" -version = "0.1.0" +name = "portable-atomic-util" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" +dependencies = [ + "portable-atomic", +] [[package]] name = "potential_utf" @@ -703,6 +4174,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -712,6 +4189,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.117", +] + [[package]] name = "proc-macro2" version = "1.0.101" @@ -721,6 +4208,77 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prost" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-build" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" +dependencies = [ + "heck", + "itertools 0.14.0", + "log", + "multimap", + "petgraph", + "prettyplease", + "prost", + "prost-types", + "regex", + "syn 2.0.117", + "tempfile", +] + +[[package]] +name = "prost-derive" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" +dependencies = [ + "anyhow", + "itertools 0.14.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "prost-types" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" +dependencies = [ + "prost", +] + +[[package]] +name = "quick-xml" +version = "0.37.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "quinn" version = "0.11.9" @@ -750,7 +4308,7 @@ dependencies = [ "bytes", "getrandom 0.3.3", "lru-slab", - "rand", + "rand 0.9.2", "ring", "rustc-hash", "rustls", @@ -778,9 +4336,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -791,14 +4349,47 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -808,7 +4399,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -820,21 +4420,180 @@ dependencies = [ "getrandom 0.3.3", ] +[[package]] +name = "rand_distr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32cb0b9bc82b0a0876c2dd994a7e7a2683d3e7390ca40e6886785ef0c7e3ee31" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "rand_distr" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8615d50dcf34fa31f7ab52692afec947c4dd0ab803cc87cb3b0b4570ff7463" +dependencies = [ + "num-traits", + "rand 0.9.2", +] + +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.3", +] + +[[package]] +name = "random_word" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e47a395bdb55442b883c89062d6bcff25dc90fa5f8369af81e0ac6d49d78cf81" +dependencies = [ + "ahash", + "brotli", + "paste", + "rand 0.9.2", + "unicase", +] + +[[package]] +name = "rangemap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" + +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.16", + "libredox", + "thiserror", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + +[[package]] +name = "regex-syntax" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" + +[[package]] +name = "reqsign" +version = "0.16.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43451dbf3590a7590684c25fb8d12ecdcc90ed3ac123433e500447c7d77ed701" +dependencies = [ + "anyhow", + "async-trait", + "base64", + "chrono", + "form_urlencoded", + "getrandom 0.2.16", + "hex", + "hmac", + "home", + "http 1.3.1", + "jsonwebtoken", + "log", + "percent-encoding", + "quick-xml 0.37.5", + "rand 0.8.5", + "reqwest", + "rsa", + "rust-ini", + "serde", + "serde_json", + "sha1", + "sha2", + "tokio", +] + [[package]] name = "reqwest" -version = "0.12.23" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d429f34c8092b2d42c7c93cec323bb4adeb7c67698f70839adec842ec10c7ceb" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-compression", "base64", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", "http-body-util", "hyper", "hyper-rustls", @@ -864,6 +4623,7 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", + "webpki-roots", ] [[package]] @@ -881,10 +4641,55 @@ dependencies = [ ] [[package]] -name = "rustc-demangle" -version = "0.1.26" +name = "roaring" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba9ce64a8f45d7fc86358410bb1a82e8c987504c0d4900e9141d69a9f26c885" +dependencies = [ + "bytemuck", + "byteorder", +] + +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rust-ini" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "796e8d2b6696392a43bea58116b667fb4c29727dc5abd27d6acf338bb4f688c7" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + +[[package]] +name = "rust-stemmers" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "e46a2036019fdb888131db7a4c847a1063a7493f971ed94ea82c67eada63ca54" +dependencies = [ + "serde", + "serde_derive", +] [[package]] name = "rustc-hash" @@ -892,12 +4697,48 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys 0.12.1", + "windows-sys 0.61.0", +] + [[package]] name = "rustls" version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ + "aws-lc-rs", "once_cell", "ring", "rustls-pki-types", @@ -918,6 +4759,15 @@ dependencies = [ "security-framework", ] +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.12.0" @@ -932,32 +4782,74 @@ dependencies = [ name = "rustls-webpki" version = "0.103.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +checksum = "8572f3c2cb9934231157b45499fc41e1f58c589fdfb81a844ba873265e80f8eb" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", + "windows-sys 0.61.0", ] [[package]] -name = "rustversion" -version = "1.0.22" +name = "scoped-tls" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] -name = "ryu" -version = "1.0.20" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "schannel" -version = "0.1.28" +name = "scrypt" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" dependencies = [ - "windows-sys 0.61.0", + "pbkdf2", + "salsa20", + "sha2", ] [[package]] @@ -983,6 +4875,18 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "seq-macro" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc711410fbe7399f390ca1c3b60ad0f53f80e95c5eb935e52268a0e2cd49acc" + [[package]] name = "serde" version = "1.0.226" @@ -1010,7 +4914,7 @@ checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1034,7 +4938,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1049,12 +4953,96 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "simple_asn1" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror", + "time", +] + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "sketches-ddsketch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.11" @@ -1067,6 +5055,27 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +[[package]] +name = "snafu" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d4bced6a69f90b2056c03dcff2c4737f98d6fb9e0853493996e1d253ca29c6" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54254b8531cafa275c5e096f62d48c81435d1015405a91198ddb11e967301d40" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "socket2" version = "0.6.0" @@ -1077,12 +5086,89 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlparser" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4591acadbcf52f0af60eafbb2c003232b2b4cd8de5f0e9437cb8b1b59046cc0f" +dependencies = [ + "log", + "sqlparser_derive", +] + +[[package]] +name = "sqlparser_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "std_prelude" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" + +[[package]] +name = "stfu8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51f1e89f093f99e7432c491c382b88a6860a5adbe6bf02574bf0a08efff1978" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + [[package]] name = "subtle" version = "2.6.1" @@ -1091,9 +5177,20 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.106" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -1117,7 +5214,178 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + +[[package]] +name = "tantivy" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a966cb0e76e311f09cf18507c9af192f15d34886ee43d7ba7c7e3803660c43" +dependencies = [ + "aho-corasick", + "arc-swap", + "base64", + "bitpacking", + "bon", + "byteorder", + "census", + "crc32fast", + "crossbeam-channel", + "downcast-rs", + "fastdivide", + "fnv", + "fs4", + "htmlescape", + "hyperloglogplus", + "itertools 0.14.0", + "levenshtein_automata", + "log", + "lru", + "lz4_flex 0.11.6", + "measure_time", + "memmap2", + "once_cell", + "oneshot", + "rayon", + "regex", + "rust-stemmers", + "rustc-hash", + "serde", + "serde_json", + "sketches-ddsketch", + "smallvec", + "tantivy-bitpacker", + "tantivy-columnar", + "tantivy-common", + "tantivy-fst", + "tantivy-query-grammar", + "tantivy-stacker", + "tantivy-tokenizer-api", + "tempfile", + "thiserror", + "time", + "uuid", + "winapi", +] + +[[package]] +name = "tantivy-bitpacker" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1adc286a39e089ae9938935cd488d7d34f14502544a36607effd2239ff0e2494" +dependencies = [ + "bitpacking", +] + +[[package]] +name = "tantivy-columnar" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6300428e0c104c4f7db6f95b466a6f5c1b9aece094ec57cdd365337908dc7344" +dependencies = [ + "downcast-rs", + "fastdivide", + "itertools 0.14.0", + "serde", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-sstable", + "tantivy-stacker", +] + +[[package]] +name = "tantivy-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b6ea6090ce03dc72c27d0619e77185d26cc3b20775966c346c6d4f7e99d7f" +dependencies = [ + "async-trait", + "byteorder", + "ownedbytes", + "serde", + "time", +] + +[[package]] +name = "tantivy-fst" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60769b80ad7953d8a7b2c70cdfe722bbcdcac6bccc8ac934c40c034d866fc18" +dependencies = [ + "byteorder", + "regex-syntax", + "utf8-ranges", +] + +[[package]] +name = "tantivy-query-grammar" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e810cdeeebca57fc3f7bfec5f85fdbea9031b2ac9b990eb5ff49b371d52bbe6a" +dependencies = [ + "nom 7.1.3", + "serde", + "serde_json", +] + +[[package]] +name = "tantivy-sstable" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709f22c08a4c90e1b36711c1c6cad5ae21b20b093e535b69b18783dd2cb99416" +dependencies = [ + "futures-util", + "itertools 0.14.0", + "tantivy-bitpacker", + "tantivy-common", + "tantivy-fst", + "zstd", +] + +[[package]] +name = "tantivy-stacker" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bcdebb267671311d1e8891fd9d1301803fdb8ad21ba22e0a30d0cab49ba59c1" +dependencies = [ + "murmurhash32", + "rand_distr 0.4.3", + "tantivy-common", +] + +[[package]] +name = "tantivy-tokenizer-api" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa942fcee81e213e09715bbce8734ae2180070b97b33839a795ba1de201547d" +dependencies = [ + "serde", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "getrandom 0.3.3", + "once_cell", + "rustix 1.1.4", + "windows-sys 0.61.0", ] [[package]] @@ -1133,11 +5401,69 @@ dependencies = [ name = "thiserror-impl" version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "thread-tree" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbd370cb847953a25954d9f63e14824a36113f8c72eecf6eccef5dc4b45d630" +dependencies = [ + "crossbeam-channel", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ - "proc-macro2", - "quote", - "syn", + "crunchy", ] [[package]] @@ -1167,19 +5493,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.1" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", + "parking_lot", "pin-project-lite", - "slab", + "signal-hook-registry", "socket2", - "windows-sys 0.59.0", + "tokio-macros", + "windows-sys 0.61.0", +] + +[[package]] +name = "tokio-macros" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] @@ -1192,6 +5529,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.16" @@ -1222,17 +5570,22 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "async-compression", "bitflags", "bytes", + "futures-core", "futures-util", - "http", - "http-body", + "http 1.3.1", + "http-body 1.0.1", + "http-body-util", "iri-string", "pin-project-lite", + "tokio", + "tokio-util", "tower", "tower-layer", "tower-service", @@ -1252,21 +5605,63 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ + "matchers", + "nu-ansi-term", "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", ] [[package]] @@ -1275,6 +5670,21 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twox-hash" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ea3136b675547379c4bd395ca6b938e5ad3c3d20fad76e7fe85f9e0d011419c" +dependencies = [ + "rand 0.9.2", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + [[package]] name = "unicase" version = "2.8.1" @@ -1287,6 +5697,24 @@ version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" +[[package]] +name = "unicode-segmentation" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + [[package]] name = "untrusted" version = "0.9.0" @@ -1305,12 +5733,64 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "utf8-ranges" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcfc827f90e53a02eaef5e535ee14266c1d569214c6aa70133a624d8a3164ba" + [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" +[[package]] +name = "uuid" +version = "1.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9" +dependencies = [ + "getrandom 0.4.2", + "js-sys", + "serde_core", + "wasm-bindgen", +] + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -1341,7 +5821,16 @@ version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen", + "wit-bindgen 0.46.0", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", ] [[package]] @@ -1367,7 +5856,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -1402,7 +5891,7 @@ checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1416,6 +5905,28 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.2" @@ -1429,6 +5940,18 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "web-sys" version = "0.3.80" @@ -1449,6 +5972,81 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.62.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link 0.2.0", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-link" version = "0.1.3" @@ -1461,6 +6059,24 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +dependencies = [ + "windows-link 0.2.0", +] + +[[package]] +name = "windows-strings" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +dependencies = [ + "windows-link 0.2.0", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -1632,12 +6248,121 @@ version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + [[package]] name = "writeable" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "xxhash-rust" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" + [[package]] name = "yoke" version = "0.8.0" @@ -1658,7 +6383,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -1679,7 +6404,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", ] [[package]] @@ -1699,7 +6424,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", "synstructure", ] @@ -1739,5 +6464,39 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.117", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 1cfb6963..5143d2c2 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,7 @@ [workspace] resolver = "2" -members = ["lance-namespace-reqwest-client"] +members = ["lance-namespace-reqwest-client", "lance-namespace-base"] [workspace.dependencies] -lance-namespace-reqwest-client = { path = "lance-namespace-reqwest-client", version = "0.6.1" } \ No newline at end of file +lance-namespace-reqwest-client = { path = "lance-namespace-reqwest-client", version = "0.6.1" } +lance-namespace-base = { path = "lance-namespace-base", version = "0.1.0" } diff --git a/rust/lance-namespace-base/Cargo.toml b/rust/lance-namespace-base/Cargo.toml new file mode 100644 index 00000000..8cb0304e --- /dev/null +++ b/rust/lance-namespace-base/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "lance-namespace-base" +version = "0.1.0" +edition = "2024" +description = "Base Lance Namespace implementation using the Lance SDK directly" +license = "Apache-2.0" +rust-version = "1.91.0" + +[features] +default = ["aws", "azure", "gcp"] +gcp = ["lance-io/gcp", "lance/gcp"] +aws = ["lance-io/aws", "lance/aws"] +azure = ["lance-io/azure", "lance/azure"] + +[dependencies] +# Lance core crates (path deps to lance repo) +lance-namespace = { path = "../../../lance/rust/lance-namespace" } +lance-core = { path = "../../../lance/rust/lance-core" } +lance = { path = "../../../lance/rust/lance", default-features = false } +lance-index = { path = "../../../lance/rust/lance-index" } +lance-linalg = { path = "../../../lance/rust/lance-linalg" } +lance-io = { path = "../../../lance/rust/lance-io", default-features = false } +lance-table = { path = "../../../lance/rust/lance-table" } + +# Arrow +arrow = { version = "57.0.0", features = ["prettyprint"] } +arrow-ipc = { version = "57.0.0", features = ["zstd"] } +arrow-schema = "57.0.0" + +# Object store +object_store = "0.12" + +# Common +async-trait = "0.1" +bytes = "1.11.1" +snafu = "0.9" +tokio = { version = "1.23", features = ["full"] } +serde_json = "1" +futures = "0.3" +log = "0.4" +chrono = { version = "0.4", default-features = false, features = ["std", "now"] } + +[dev-dependencies] +tempfile = "3" diff --git a/rust/lance-namespace-base/src/base.rs b/rust/lance-namespace-base/src/base.rs new file mode 100644 index 00000000..0f313a65 --- /dev/null +++ b/rust/lance-namespace-base/src/base.rs @@ -0,0 +1,5091 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright The Lance Authors + +//! Base Lance Namespace implementation using the Lance SDK directly. + +use arrow::record_batch::RecordBatchIterator; +use arrow_ipc::reader::StreamReader; +use async_trait::async_trait; +use bytes::Bytes; +use futures::TryStreamExt; +use lance::dataset::builder::DatasetBuilder; +use lance::dataset::transaction::{Operation, Transaction}; +use lance::dataset::{Dataset, WriteMode, WriteParams}; +use lance::index::{DatasetIndexExt, IndexParams, vector::VectorIndexParams}; +use lance::session::Session; +use lance_index::scalar::{BuiltinIndexType, InvertedIndexParams, ScalarIndexParams}; +use lance_index::vector::{ + bq::RQBuildParams, hnsw::builder::HnswBuildParams, ivf::IvfBuildParams, pq::PQBuildParams, + sq::builder::SQBuildParams, +}; +use lance_index::{IndexType, is_system_index}; +use lance_io::object_store::{ObjectStore, ObjectStoreParams, ObjectStoreRegistry}; +use lance_linalg::distance::MetricType; +use lance_table::io::commit::ManifestNamingScheme; +use object_store::path::Path; +use object_store::{Error as ObjectStoreError, ObjectStore as OSObjectStore, PutMode, PutOptions}; +use std::collections::HashMap; +use std::io::Cursor; +use std::sync::Arc; + +use lance_namespace::models::{ + AlterTableAddColumnsRequest, AlterTableAddColumnsResponse, AlterTableAlterColumnsRequest, + AlterTableAlterColumnsResponse, AlterTableDropColumnsRequest, AlterTableDropColumnsResponse, + AlterTransactionRequest, AlterTransactionResponse, AnalyzeTableQueryPlanRequest, + BatchDeleteTableVersionsRequest, BatchDeleteTableVersionsResponse, CountTableRowsRequest, + CreateNamespaceRequest, CreateNamespaceResponse, CreateTableIndexRequest, + CreateTableIndexResponse, CreateTableRequest, CreateTableResponse, + CreateTableScalarIndexResponse, CreateTableTagRequest, CreateTableTagResponse, + CreateTableVersionRequest, CreateTableVersionResponse, DeclareTableRequest, + DeclareTableResponse, DeleteFromTableRequest, DeleteFromTableResponse, DeleteTableTagRequest, + DeleteTableTagResponse, DeregisterTableRequest, DeregisterTableResponse, + DescribeNamespaceRequest, DescribeNamespaceResponse, DescribeTableIndexStatsRequest, + DescribeTableIndexStatsResponse, DescribeTableRequest, DescribeTableResponse, + DescribeTableVersionRequest, DescribeTableVersionResponse, DescribeTransactionRequest, + DescribeTransactionResponse, DropNamespaceRequest, DropNamespaceResponse, + DropTableIndexRequest, DropTableIndexResponse, DropTableRequest, DropTableResponse, + ExplainTableQueryPlanRequest, GetTableStatsRequest, GetTableStatsResponse, + GetTableTagVersionRequest, GetTableTagVersionResponse, IndexContent, + InsertIntoTableRequest, InsertIntoTableResponse, ListNamespacesRequest, + ListNamespacesResponse, ListTableIndicesRequest, ListTableIndicesResponse, + ListTableTagsRequest, ListTableTagsResponse, ListTableVersionsRequest, + ListTableVersionsResponse, ListTablesRequest, ListTablesResponse, + MergeInsertIntoTableRequest, MergeInsertIntoTableResponse, NamespaceExistsRequest, + QueryTableRequest, RegisterTableRequest, RegisterTableResponse, RenameTableRequest, + RenameTableResponse, RestoreTableRequest, RestoreTableResponse, TableExistsRequest, + TableVersion, TagContents, UpdateTableRequest, UpdateTableResponse, + UpdateTableSchemaMetadataRequest, UpdateTableSchemaMetadataResponse, UpdateTableTagRequest, + UpdateTableTagResponse, +}; + +use lance_core::Result; +use lance_namespace::LanceNamespace; +use lance_namespace::error::NamespaceError; +use lance_namespace::schema::arrow_schema_to_json; + +// ── Index param helper types ──────────────────────────────────────────────── + +enum BaseIndexParams { + Scalar { + index_type: IndexType, + params: ScalarIndexParams, + }, + Inverted(InvertedIndexParams), + Vector { + index_type: IndexType, + params: VectorIndexParams, + }, +} + +impl BaseIndexParams { + fn index_type(&self) -> IndexType { + match self { + Self::Scalar { index_type, .. } | Self::Vector { index_type, .. } => *index_type, + Self::Inverted(_) => IndexType::Inverted, + } + } + + fn params(&self) -> &dyn IndexParams { + match self { + Self::Scalar { params, .. } => params, + Self::Inverted(params) => params, + Self::Vector { params, .. } => params, + } + } +} + +// ── Builder ───────────────────────────────────────────────────────────────── + +/// Builder for creating a [`BaseLanceNamespace`]. +#[derive(Clone)] +pub struct BaseLanceNamespaceBuilder { + root: String, + storage_options: Option>, + session: Option>, +} + +impl std::fmt::Debug for BaseLanceNamespaceBuilder { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("BaseLanceNamespaceBuilder") + .field("root", &self.root) + .field("storage_options", &self.storage_options) + .finish() + } +} + +impl BaseLanceNamespaceBuilder { + /// Create a new builder with the specified root path. + pub fn new(root: impl Into) -> Self { + Self { + root: root.into().trim_end_matches('/').to_string(), + storage_options: None, + session: None, + } + } + + /// Add a storage option. + pub fn storage_option(mut self, key: impl Into, value: impl Into) -> Self { + self.storage_options + .get_or_insert_with(HashMap::new) + .insert(key.into(), value.into()); + self + } + + /// Add multiple storage options. + pub fn storage_options(mut self, options: HashMap) -> Self { + self.storage_options + .get_or_insert_with(HashMap::new) + .extend(options); + self + } + + /// Set the Lance session to use. + pub fn session(mut self, session: Arc) -> Self { + self.session = Some(session); + self + } + + /// Create a builder from a properties map. + /// + /// Expects `root` (required) and optional `storage.*` prefixed options. + pub fn from_properties( + properties: HashMap, + session: Option>, + ) -> Result { + let root = properties.get("root").cloned().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Missing required property 'root' for base namespace".to_string(), + }) + })?; + + let storage_options: HashMap = properties + .iter() + .filter_map(|(k, v)| { + k.strip_prefix("storage.") + .map(|key| (key.to_string(), v.clone())) + }) + .collect(); + + let storage_options = if storage_options.is_empty() { + None + } else { + Some(storage_options) + }; + + Ok(Self { + root: root.trim_end_matches('/').to_string(), + storage_options, + session, + }) + } + + /// Build the [`BaseLanceNamespace`]. + pub async fn build(self) -> Result { + let (object_store, base_path) = + Self::initialize_object_store(&self.root, &self.storage_options, &self.session).await?; + + Ok(BaseLanceNamespace { + root: self.root, + storage_options: self.storage_options, + session: self.session, + object_store, + base_path, + }) + } + + async fn initialize_object_store( + root: &str, + storage_options: &Option>, + session: &Option>, + ) -> Result<(Arc, Path)> { + let accessor = storage_options.clone().map(|opts| { + Arc::new(lance_io::object_store::StorageOptionsAccessor::with_static_options(opts)) + }); + let params = ObjectStoreParams { + storage_options_accessor: accessor, + ..Default::default() + }; + + let registry = if let Some(session) = session { + session.store_registry() + } else { + Arc::new(ObjectStoreRegistry::default()) + }; + + let (object_store, base_path) = ObjectStore::from_uri_and_params(registry, root, ¶ms) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create object store: {}", e), + }) + })?; + + Ok((object_store, base_path)) + } +} + +// ── Main struct ───────────────────────────────────────────────────────────── + +/// Base implementation of [`LanceNamespace`] using the Lance SDK directly. +/// +/// Stores namespaces as directories and tables as `{name}.lance` subdirectories. +/// Supports hierarchical namespaces (e.g. `["org","team"]` → `{root}/org/team/`). +pub struct BaseLanceNamespace { + root: String, + storage_options: Option>, + session: Option>, + object_store: Arc, + base_path: Path, +} + +impl std::fmt::Debug for BaseLanceNamespace { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.namespace_id()) + } +} + +// ── Private helpers ───────────────────────────────────────────────────────── + +/// Describes the version ranges to delete for a single table. +struct TableDeleteEntry { + table_id: Option>, + ranges: Vec<(i64, i64)>, +} + +impl BaseLanceNamespace { + // ── Path resolution (hierarchical namespace support) ───────────────── + + /// Resolve a namespace ID to an object_store `Path`. + /// `["a","b"]` → `{base_path}/a/b` + fn resolve_namespace_path(&self, id: &Option>) -> Path { + let mut path = self.base_path.clone(); + if let Some(parts) = id { + for part in parts { + path = path.child(part.as_str()); + } + } + path + } + + /// Resolve a namespace ID to a URI string. + /// `["a","b"]` → `{root}/a/b` + fn resolve_namespace_uri(&self, id: &Option>) -> String { + let mut uri = self.root.clone(); + if let Some(parts) = id { + for part in parts { + uri = format!("{}/{}", uri, part); + } + } + uri + } + + /// Resolve a table ID to a full URI string. + /// `["ns","table"]` → `{root}/ns/table.lance` + fn resolve_table_uri(&self, id: &Option>) -> Result { + let id = id.as_ref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Table ID is required".to_string(), + }) + })?; + if id.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Table ID cannot be empty".to_string(), + } + .into()); + } + let mut uri = self.root.clone(); + for part in id { + uri = format!("{}/{}", uri, part); + } + Ok(format!("{}.lance", uri)) + } + + /// Resolve a table ID to an object_store `Path`. + fn resolve_table_path(&self, id: &Option>) -> Result { + let id = id.as_ref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Table ID is required".to_string(), + }) + })?; + if id.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Table ID cannot be empty".to_string(), + } + .into()); + } + let mut path = self.base_path.clone(); + for (i, part) in id.iter().enumerate() { + if i == id.len() - 1 { + path = path.child(format!("{}.lance", part).as_str()); + } else { + path = path.child(part.as_str()); + } + } + Ok(path) + } + + /// Extract the table name (last element) from a table ID. + fn table_name_from_id(id: &Option>) -> Result { + let id = id.as_ref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Table ID is required".to_string(), + }) + })?; + if id.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Table ID cannot be empty".to_string(), + } + .into()); + } + Ok(id.last().unwrap().clone()) + } + + /// Extract the namespace path (all but last element) from a table ID. + fn namespace_path_from_table_id(id: &Option>) -> Option> { + id.as_ref().and_then(|parts| { + if parts.len() > 1 { + Some(parts[..parts.len() - 1].to_vec()) + } else { + Some(vec![]) + } + }) + } + + /// Ensure a namespace directory exists. + async fn ensure_namespace_exists( + &self, + path: &Path, + id: &Option>, + ) -> Result<()> { + // Root namespace always exists + if id.as_ref().is_none_or(|parts| parts.is_empty()) { + return Ok(()); + } + // Check by looking for the .lance-namespace marker file + let marker_path = path.child(".lance-namespace"); + match self.object_store.inner.head(&marker_path).await { + Ok(_) => Ok(()), + Err(_) => { + let name = id + .as_ref() + .map(|parts| parts.join("/")) + .unwrap_or_else(|| "".to_string()); + Err(NamespaceError::NamespaceNotFound { + message: name, + } + .into()) + } + } + } + + /// Ensure a table's `.lance` directory exists. + async fn ensure_table_exists(&self, id: &Option>) -> Result<()> { + let table_path = self.resolve_table_path(id)?; + match self.object_store.read_dir(table_path).await { + Ok(entries) if !entries.is_empty() => Ok(()), + _ => { + let name = Self::table_name_from_id(id)?; + Err(NamespaceError::TableNotFound { message: name }.into()) + } + } + } + + /// Ensure the parent namespace of a table exists. + async fn ensure_parent_namespace_exists(&self, id: &Option>) -> Result<()> { + let ns_id = Self::namespace_path_from_table_id(id); + if ns_id.as_ref().is_some_and(|parts| !parts.is_empty()) { + let ns_path = self.resolve_namespace_path(&ns_id); + self.ensure_namespace_exists(&ns_path, &ns_id).await?; + } + Ok(()) + } + + // ── Dataset operations ────────────────────────────────────────────── + + async fn load_dataset( + &self, + table_uri: &str, + version: Option, + operation: &str, + ) -> Result { + if let Some(version) = version { + if version < 0 { + return Err(NamespaceError::InvalidInput { + message: format!( + "Table version for {} must be non-negative, got {}", + operation, version + ), + } + .into()); + } + } + + let mut builder = DatasetBuilder::from_uri(table_uri); + if let Some(opts) = &self.storage_options { + builder = builder.with_storage_options(opts.clone()); + } + if let Some(sess) = &self.session { + builder = builder.with_session(sess.clone()); + } + + let dataset = builder.load().await.map_err(|e| { + lance_core::Error::from(NamespaceError::TableNotFound { + message: format!( + "Failed to open table at '{}' for {}: {}", + table_uri, operation, e + ), + }) + })?; + + if let Some(version) = version { + return dataset.checkout_version(version as u64).await.map_err(|e| { + lance_core::Error::from(NamespaceError::TableVersionNotFound { + message: format!( + "Failed to checkout version {} for table at '{}' during {}: {}", + version, table_uri, operation, e + ), + }) + }); + } + + Ok(dataset) + } + + // ── Arrow IPC helpers ─────────────────────────────────────────────── + + fn decode_ipc_stream( + data: &Bytes, + ) -> Result<(Arc, Vec)> { + let cursor = Cursor::new(data.as_ref()); + let stream_reader = StreamReader::try_new(cursor, None).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid Arrow IPC stream: {}", e), + }) + })?; + let schema = stream_reader.schema(); + let mut batches = Vec::new(); + for batch_result in stream_reader { + batches.push(batch_result.map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Failed to read batch from IPC stream: {}", e), + }) + })?); + } + Ok((schema, batches)) + } + + /// Convert a full URI to an `object_store::Path` relative to the bucket/root. + /// + /// For cloud URIs (`s3://`, `gs://`, `az://`) the scheme and bucket name are + /// stripped because the [`ObjectStore`] instance is already bound to a specific + /// bucket. + /// + /// **Limitation:** only the schemes listed below are handled. Other Azure + /// schemes (`wasb://`, `abfss://`) and custom schemes are passed through + /// unchanged and may produce incorrect paths on cloud storage. + fn uri_to_object_store_path(uri: &str) -> Path { + let path_str = if let Some(rest) = uri.strip_prefix("file://") { + rest + } else if let Some(rest) = uri.strip_prefix("s3://") { + rest.split_once('/').map(|(_, p)| p).unwrap_or(rest) + } else if let Some(rest) = uri.strip_prefix("gs://") { + rest.split_once('/').map(|(_, p)| p).unwrap_or(rest) + } else if let Some(rest) = uri.strip_prefix("az://") { + rest.split_once('/').map(|(_, p)| p).unwrap_or(rest) + } else { + uri + }; + Path::from(path_str) + } + + // ── Index building ────────────────────────────────────────────────── + + fn parse_index_type(index_type: &str) -> Result { + match index_type.trim().to_ascii_uppercase().as_str() { + "SCALAR" | "BTREE" => Ok(IndexType::BTree), + "BITMAP" => Ok(IndexType::Bitmap), + "LABEL_LIST" | "LABELLIST" => Ok(IndexType::LabelList), + "INVERTED" | "FTS" => Ok(IndexType::Inverted), + "NGRAM" => Ok(IndexType::NGram), + "ZONEMAP" | "ZONE_MAP" => Ok(IndexType::ZoneMap), + "BLOOMFILTER" | "BLOOM_FILTER" => Ok(IndexType::BloomFilter), + "RTREE" | "R_TREE" => Ok(IndexType::RTree), + "VECTOR" | "IVF_PQ" => Ok(IndexType::IvfPq), + "IVF_FLAT" => Ok(IndexType::IvfFlat), + "IVF_SQ" => Ok(IndexType::IvfSq), + "IVF_RQ" => Ok(IndexType::IvfRq), + "IVF_HNSW_FLAT" => Ok(IndexType::IvfHnswFlat), + "IVF_HNSW_SQ" => Ok(IndexType::IvfHnswSq), + "IVF_HNSW_PQ" => Ok(IndexType::IvfHnswPq), + other => Err(NamespaceError::InvalidInput { + message: format!("Unsupported index_type '{}'", other), + } + .into()), + } + } + + fn parse_metric_type(distance_type: Option<&str>) -> Result { + let distance_type = distance_type.unwrap_or("l2"); + MetricType::try_from(distance_type).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Unsupported distance_type '{}': {}", distance_type, e), + }) + }) + } + + fn build_index_params(request: &CreateTableIndexRequest) -> Result { + let index_type = Self::parse_index_type(&request.index_type)?; + Ok(match index_type { + IndexType::BTree => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::BTree), + }, + IndexType::Bitmap => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::Bitmap), + }, + IndexType::LabelList => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::LabelList), + }, + IndexType::NGram => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::NGram), + }, + IndexType::ZoneMap => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::ZoneMap), + }, + IndexType::BloomFilter => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::BloomFilter), + }, + IndexType::RTree => BaseIndexParams::Scalar { + index_type, + params: ScalarIndexParams::for_builtin(BuiltinIndexType::RTree), + }, + IndexType::Inverted => { + let mut params = InvertedIndexParams::default(); + if let Some(with_position) = request.with_position { + params = params.with_position(with_position); + } + if let Some(base_tokenizer) = &request.base_tokenizer { + params = params.base_tokenizer(base_tokenizer.clone()); + } + if let Some(language) = &request.language { + params = params.language(language)?; + } + if let Some(max_token_length) = request.max_token_length { + if max_token_length < 0 { + return Err(NamespaceError::InvalidInput { + message: format!( + "FTS max_token_length must be non-negative, got {}", + max_token_length + ), + } + .into()); + } + params = params.max_token_length(Some(max_token_length as usize)); + } + if let Some(lower_case) = request.lower_case { + params = params.lower_case(lower_case); + } + if let Some(stem) = request.stem { + params = params.stem(stem); + } + if let Some(remove_stop_words) = request.remove_stop_words { + params = params.remove_stop_words(remove_stop_words); + } + if let Some(ascii_folding) = request.ascii_folding { + params = params.ascii_folding(ascii_folding); + } + BaseIndexParams::Inverted(params) + } + IndexType::IvfFlat => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_flat_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + ), + }, + IndexType::IvfPq => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_pq_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + PQBuildParams::default(), + ), + }, + IndexType::IvfSq => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_sq_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + SQBuildParams::default(), + ), + }, + IndexType::IvfRq => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_rq_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + RQBuildParams::default(), + ), + }, + IndexType::IvfHnswFlat => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::ivf_hnsw( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + HnswBuildParams::default(), + ), + }, + IndexType::IvfHnswSq => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_hnsw_sq_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + HnswBuildParams::default(), + SQBuildParams::default(), + ), + }, + IndexType::IvfHnswPq => BaseIndexParams::Vector { + index_type, + params: VectorIndexParams::with_ivf_hnsw_pq_params( + Self::parse_metric_type(request.distance_type.as_deref())?, + IvfBuildParams::default(), + HnswBuildParams::default(), + PQBuildParams::default(), + ), + }, + other => { + return Err(NamespaceError::InvalidInput { + message: format!("Unsupported index type: {}", other), + } + .into()); + } + }) + } + + // ── Pagination helpers ────────────────────────────────────────────── + + fn apply_pagination( + names: &mut Vec, + page_token: Option, + limit: Option, + ) -> Option { + names.sort(); + + if let Some(start_after) = page_token { + if let Some(index) = names + .iter() + .position(|name| name.as_str() > start_after.as_str()) + { + names.drain(0..index); + } else { + names.clear(); + } + } + + let mut next_page_token = None; + if let Some(limit) = limit { + if limit >= 0 { + let limit = limit as usize; + if limit > 0 && names.len() > limit { + next_page_token = Some(names[limit - 1].clone()); + } + names.truncate(limit); + } + } + + if names.is_empty() { + None + } else { + next_page_token + } + } + + fn paginate_indices( + indices: &mut Vec, + page_token: Option, + limit: Option, + ) -> Option { + indices.sort_by(|a, b| a.index_name.cmp(&b.index_name)); + + if let Some(start_after) = page_token { + if let Some(index) = indices + .iter() + .position(|idx| idx.index_name.as_str() > start_after.as_str()) + { + indices.drain(0..index); + } else { + indices.clear(); + } + } + + let mut next_page_token = None; + if let Some(limit) = limit { + if limit >= 0 { + let limit = limit as usize; + if limit > 0 && indices.len() > limit { + next_page_token = Some(indices[limit - 1].index_name.clone()); + } + indices.truncate(limit); + } + } + if indices.is_empty() { + None + } else { + next_page_token + } + } + + // ── Transaction helpers ───────────────────────────────────────────── + + fn transaction_operation_name(transaction: &Transaction) -> String { + match &transaction.operation { + Operation::CreateIndex { + new_indices, + removed_indices, + } if new_indices.is_empty() && !removed_indices.is_empty() => "DropIndex".to_string(), + _ => transaction.operation.to_string(), + } + } + + fn transaction_response( + version: u64, + transaction: &Transaction, + ) -> DescribeTransactionResponse { + let mut properties = transaction + .transaction_properties + .as_ref() + .map(|properties| (**properties).clone()) + .unwrap_or_default(); + properties.insert("uuid".to_string(), transaction.uuid.clone()); + properties.insert("version".to_string(), version.to_string()); + properties.insert( + "read_version".to_string(), + transaction.read_version.to_string(), + ); + properties.insert( + "operation".to_string(), + Self::transaction_operation_name(transaction), + ); + if let Some(tag) = &transaction.tag { + properties.insert("tag".to_string(), tag.clone()); + } + + DescribeTransactionResponse { + status: "SUCCEEDED".to_string(), + properties: Some(properties), + } + } + + fn describe_table_index_stats_response( + stats: &serde_json::Value, + ) -> DescribeTableIndexStatsResponse { + let get_i64 = |key: &str| { + stats.get(key).and_then(|value| { + value + .as_i64() + .or_else(|| value.as_u64().and_then(|v| i64::try_from(v).ok())) + }) + }; + + DescribeTableIndexStatsResponse { + distance_type: stats + .get("distance_type") + .and_then(|value| value.as_str()) + .map(str::to_string), + index_type: stats + .get("index_type") + .and_then(|value| value.as_str()) + .map(str::to_string), + num_indexed_rows: get_i64("num_indexed_rows"), + num_unindexed_rows: get_i64("num_unindexed_rows"), + num_indices: get_i64("num_indices").and_then(|value| i32::try_from(value).ok()), + } + } + + async fn find_transaction(&self, dataset: &Dataset, id: &str) -> Result<(u64, Transaction)> { + if let Ok(version) = id.parse::() { + let transaction = dataset + .read_transaction_by_version(version) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to read transaction for version {}: {}", + version, e + ), + }) + })? + .ok_or_else(|| { + lance_core::Error::from(NamespaceError::TransactionNotFound { + message: format!("version {}", version), + }) + })?; + return Ok((version, transaction)); + } + + let versions = dataset.versions().await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to list table versions while resolving transaction '{}': {}", + id, e + ), + }) + })?; + + for version in versions.into_iter().rev() { + if let Some(transaction) = dataset + .read_transaction_by_version(version.version) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to read transaction for version {} while resolving '{}': {}", + version.version, id, e + ), + }) + })? + { + if transaction.uuid == id { + return Ok((version.version, transaction)); + } + } + } + + Err(NamespaceError::TransactionNotFound { + message: id.to_string(), + } + .into()) + } + + // ── Version file helpers ──────────────────────────────────────────── + + async fn delete_physical_version_files( + &self, + table_entries: &[TableDeleteEntry], + best_effort: bool, + ) -> Result { + let mut deleted_count = 0i64; + for te in table_entries { + let table_uri = self.resolve_table_uri(&te.table_id)?; + let table_path = Self::uri_to_object_store_path(&table_uri); + let versions_dir_path = table_path.child("_versions"); + + for (start, end) in &te.ranges { + for version in *start..=*end { + let version_path = + versions_dir_path.child(format!("{}.manifest", version as u64)); + match self.object_store.inner.delete(&version_path).await { + Ok(_) => { + deleted_count += 1; + } + Err(object_store::Error::NotFound { .. }) => {} + Err(e) => { + if best_effort { + log::warn!( + "Failed to delete manifest file for version {} of table {:?}: {:?}", + version, te.table_id, e + ); + } else { + return Err(NamespaceError::Internal { + message: format!( + "Failed to delete version {} for table at '{}': {}", + version, table_uri, e + ), + } + .into()); + } + } + } + } + } + } + Ok(deleted_count) + } + + // ── Scanner configuration ────────────────────────────────────────── + + fn configure_scanner( + scanner: &mut lance::dataset::scanner::Scanner, + query: &QueryTableRequest, + ) -> Result<()> { + if let Some(ref filter) = query.filter { + if !filter.is_empty() { + scanner.filter(filter).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid filter expression: {}", e), + }) + })?; + } + } + if let Some(ref columns) = query.columns { + if let Some(ref col_names) = columns.column_names { + let col_refs: Vec<&str> = col_names.iter().map(|s| s.as_str()).collect(); + scanner.project(&col_refs).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid column projection: {}", e), + }) + })?; + } + } + if query.k > 0 { + let _ = scanner.limit(Some(query.k as i64), query.offset.map(|o| o as i64)); + } else if query.offset.is_some() { + let _ = scanner.limit(None, query.offset.map(|o| o as i64)); + } + Ok(()) + } + + // ── Directory helpers ─────────────────────────────────────────────── + + /// List tables in a namespace directory by scanning for `*.lance` subdirectories. + async fn list_directory_tables(&self, ns_path: &Path) -> Result> { + let mut tables = Vec::new(); + let entries = self + .object_store + .read_dir(ns_path.clone()) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to list directory: {}", e), + }) + })?; + + for entry in entries { + let path = entry.trim_end_matches('/'); + if path.ends_with(".lance") { + let table_name = &path[..path.len() - 6]; + tables.push(table_name.to_string()); + } + } + + Ok(tables) + } + + /// Recursively collect all tables from root, with namespace path prefixes. + /// + /// Note: this recurses into **all** non-`.lance` subdirectories, not only + /// those marked with `.lance-namespace`. Stray directories that are not + /// namespaces will be traversed but will not produce false table entries + /// because only entries ending with `.lance` are collected. + async fn collect_tables_recursive( + &self, + dir: &Path, + prefix: &str, + tables: &mut Vec, + ) { + let entries = match self.object_store.read_dir(dir.clone()).await { + Ok(entries) => entries, + Err(_) => return, + }; + + for entry in entries { + let name = entry.trim_end_matches('/'); + let child_path = dir.child(name); + if name.ends_with(".lance") { + let table_name = &name[..name.len() - 6]; + let full_name = if prefix.is_empty() { + table_name.to_string() + } else { + format!("{}/{}", prefix, table_name) + }; + tables.push(full_name); + } else { + let new_prefix = if prefix.is_empty() { + name.to_string() + } else { + format!("{}/{}", prefix, name) + }; + Box::pin(self.collect_tables_recursive(&child_path, &new_prefix, tables)).await; + } + } + } + +} + +// ── LanceNamespace trait implementation ────────────────────────────────────── + +#[async_trait] +impl LanceNamespace for BaseLanceNamespace { + // ── Namespace Operations ──────────────────────────────────────────── + + async fn list_namespaces( + &self, + request: ListNamespacesRequest, + ) -> Result { + let ns_path = self.resolve_namespace_path(&request.id); + self.ensure_namespace_exists(&ns_path, &request.id).await?; + + let entries = self + .object_store + .read_dir(ns_path.clone()) + .await + .unwrap_or_default(); + + let mut namespaces = Vec::new(); + for entry in entries { + let name = entry.trim_end_matches('/').to_string(); + if name.ends_with(".lance") || name == ".lance-namespace" { + continue; + } + // Check if this subdirectory has a .lance-namespace marker + let child_marker = ns_path.child(name.as_str()).child(".lance-namespace"); + if self.object_store.inner.head(&child_marker).await.is_ok() { + namespaces.push(name); + } + } + namespaces.sort(); + + Ok(ListNamespacesResponse::new(namespaces)) + } + + async fn describe_namespace( + &self, + request: DescribeNamespaceRequest, + ) -> Result { + let ns_path = self.resolve_namespace_path(&request.id); + self.ensure_namespace_exists(&ns_path, &request.id).await?; + #[allow(clippy::needless_update)] + Ok(DescribeNamespaceResponse { + properties: Some(HashMap::new()), + ..Default::default() + }) + } + + async fn create_namespace( + &self, + request: CreateNamespaceRequest, + ) -> Result { + let id = &request.id; + if id.is_none() || id.as_ref().unwrap().is_empty() { + return Err(NamespaceError::NamespaceAlreadyExists { + message: "root namespace".to_string(), + } + .into()); + } + + let ns_path = self.resolve_namespace_path(id); + let ns_uri = self.resolve_namespace_uri(id); + + // Check if already exists by looking for marker file + let marker_path = ns_path.child(".lance-namespace"); + if self.object_store.inner.head(&marker_path).await.is_ok() { + return Err(NamespaceError::NamespaceAlreadyExists { + message: id.as_ref().unwrap().join("/"), + } + .into()); + } + + // Create directory by writing a placeholder file and then deleting it, + // since object stores don't have explicit directory creation. + // For local filesystem, we can just create the directory marker. + let marker_path = ns_path.child(".lance-namespace"); + self.object_store + .inner + .put(&marker_path, bytes::Bytes::new().into()) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create namespace at '{}': {}", ns_uri, e), + }) + })?; + + Ok(CreateNamespaceResponse { + properties: Some(HashMap::new()), + ..Default::default() + }) + } + + async fn drop_namespace(&self, request: DropNamespaceRequest) -> Result { + let id = &request.id; + if id.is_none() || id.as_ref().unwrap().is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Root namespace cannot be dropped".to_string(), + } + .into()); + } + + let ns_path = self.resolve_namespace_path(id); + self.ensure_namespace_exists(&ns_path, id).await?; + + // Check if namespace is empty (only .lance-namespace marker allowed) + let entries = self + .object_store + .read_dir(ns_path.clone()) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to check namespace: {}", e), + }) + })?; + + let non_marker_entries: Vec<_> = entries + .iter() + .filter(|e| !e.ends_with(".lance-namespace")) + .collect(); + + if !non_marker_entries.is_empty() { + return Err(NamespaceError::NamespaceNotEmpty { + message: id.as_ref().unwrap().join("/"), + } + .into()); + } + + // Delete the namespace directory + self.object_store + .remove_dir_all(ns_path) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to drop namespace: {}", e), + }) + })?; + + Ok(DropNamespaceResponse { + ..Default::default() + }) + } + + async fn namespace_exists(&self, request: NamespaceExistsRequest) -> Result<()> { + let ns_path = self.resolve_namespace_path(&request.id); + self.ensure_namespace_exists(&ns_path, &request.id).await + } + + // ── Table Operations ──────────────────────────────────────────────── + + async fn list_tables(&self, request: ListTablesRequest) -> Result { + let ns_path = self.resolve_namespace_path(&request.id); + self.ensure_namespace_exists(&ns_path, &request.id).await?; + + let mut tables = self.list_directory_tables(&ns_path).await?; + let page_token = Self::apply_pagination(&mut tables, request.page_token, request.limit); + + Ok(ListTablesResponse { + tables, + page_token, + }) + } + + async fn describe_table( + &self, + request: DescribeTableRequest, + ) -> Result { + self.ensure_table_exists(&request.id).await?; + + let table_name = Self::table_name_from_id(&request.id)?; + let table_uri = self.resolve_table_uri(&request.id)?; + let ns_path = Self::namespace_path_from_table_id(&request.id); + + let load_detailed_metadata = request.load_detailed_metadata.unwrap_or(false); + + if !load_detailed_metadata { + return Ok(DescribeTableResponse { + table: Some(table_name), + namespace: ns_path, + location: Some(table_uri.clone()), + table_uri: Some(table_uri), + ..Default::default() + }); + } + + let mut builder = DatasetBuilder::from_uri(&table_uri); + if let Some(opts) = &self.storage_options { + builder = builder.with_storage_options(opts.clone()); + } + if let Some(sess) = &self.session { + builder = builder.with_session(sess.clone()); + } + match builder.load().await { + Ok(mut dataset) => { + if let Some(requested_version) = request.version { + dataset = dataset.checkout_version(requested_version as u64).await?; + } + + let version_info = dataset.version(); + let lance_schema = dataset.schema(); + let arrow_schema: arrow_schema::Schema = lance_schema.into(); + let json_schema = arrow_schema_to_json(&arrow_schema)?; + + let metadata: HashMap = + version_info.metadata.into_iter().collect(); + + Ok(DescribeTableResponse { + table: Some(table_name), + namespace: ns_path, + version: Some(version_info.version as i64), + location: Some(table_uri.clone()), + table_uri: Some(table_uri), + schema: Some(Box::new(json_schema)), + metadata: Some(metadata), + ..Default::default() + }) + } + Err(err) => Err(NamespaceError::Internal { + message: format!( + "Table directory exists but cannot load dataset {}: {:?}", + table_name, err + ), + } + .into()), + } + } + + async fn table_exists(&self, request: TableExistsRequest) -> Result<()> { + self.ensure_table_exists(&request.id).await + } + + async fn create_table( + &self, + request: CreateTableRequest, + request_data: Bytes, + ) -> Result { + self.ensure_parent_namespace_exists(&request.id).await?; + + let table_uri = self.resolve_table_uri(&request.id)?; + if request_data.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Request data (Arrow IPC stream) is required for create_table".to_string(), + } + .into()); + } + + // Check if table already exists + if self.ensure_table_exists(&request.id).await.is_ok() { + let table_name = Self::table_name_from_id(&request.id)?; + return Err(NamespaceError::TableAlreadyExists { + message: table_name, + } + .into()); + } + + let (arrow_schema, batches) = Self::decode_ipc_stream(&request_data)?; + + let reader = if batches.is_empty() { + let batch = arrow::record_batch::RecordBatch::new_empty(arrow_schema.clone()); + RecordBatchIterator::new(vec![Ok(batch)], arrow_schema.clone()) + } else { + let batch_results: Vec<_> = batches.into_iter().map(Ok).collect(); + RecordBatchIterator::new(batch_results, arrow_schema) + }; + + let store_params = self.storage_options.as_ref().map(|opts| ObjectStoreParams { + storage_options_accessor: Some(Arc::new( + lance_io::object_store::StorageOptionsAccessor::with_static_options(opts.clone()), + )), + ..Default::default() + }); + + let write_params = WriteParams { + mode: WriteMode::Create, + store_params, + ..Default::default() + }; + + Dataset::write(reader, &table_uri, Some(write_params)) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create Lance dataset: {}", e), + }) + })?; + + Ok(CreateTableResponse { + version: Some(1), + location: Some(table_uri), + ..Default::default() + }) + } + + async fn declare_table(&self, request: DeclareTableRequest) -> Result { + self.ensure_parent_namespace_exists(&request.id).await?; + + let table_uri = self.resolve_table_uri(&request.id)?; + let table_name = Self::table_name_from_id(&request.id)?; + + // Check if table already exists + if self.ensure_table_exists(&request.id).await.is_ok() { + return Err(NamespaceError::TableAlreadyExists { + message: table_name, + } + .into()); + } + + // Create a marker file to declare the table + let table_path = self.resolve_table_path(&request.id)?; + let reserved_path = table_path.child(".lance-reserved"); + self.object_store + .inner + .put(&reserved_path, bytes::Bytes::new().into()) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to declare table {}: {}", table_name, e), + }) + })?; + + Ok(DeclareTableResponse { + location: Some(table_uri), + ..Default::default() + }) + } + + async fn register_table( + &self, + _request: RegisterTableRequest, + ) -> Result { + Err(NamespaceError::Unsupported { + message: "register_table is not supported in base namespace".to_string(), + } + .into()) + } + + async fn deregister_table( + &self, + request: DeregisterTableRequest, + ) -> Result { + // In base namespace, deregister = drop (like the Java impl) + let table_uri = self.resolve_table_uri(&request.id)?; + self.ensure_table_exists(&request.id).await?; + + let table_path = self.resolve_table_path(&request.id)?; + self.object_store + .remove_dir_all(table_path) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to deregister table: {}", e), + }) + })?; + + Ok(DeregisterTableResponse { + id: request.id, + location: Some(table_uri), + ..Default::default() + }) + } + + async fn drop_table(&self, request: DropTableRequest) -> Result { + self.ensure_table_exists(&request.id).await?; + + let table_uri = self.resolve_table_uri(&request.id)?; + let table_path = self.resolve_table_path(&request.id)?; + + self.object_store + .remove_dir_all(table_path) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to drop table: {}", e), + }) + })?; + + Ok(DropTableResponse { + id: request.id, + location: Some(table_uri), + ..Default::default() + }) + } + + async fn rename_table(&self, request: RenameTableRequest) -> Result { + self.ensure_table_exists(&request.id).await?; + + let new_name = &request.new_table_name; + if new_name.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "New table name is required".to_string(), + } + .into()); + } + + // Build new table ID (same namespace, different name) + let ns_parts = Self::namespace_path_from_table_id(&request.id); + let mut new_id = ns_parts.unwrap_or_default(); + new_id.push(new_name.to_string()); + let new_id = Some(new_id); + + // Check new table doesn't exist + if self.ensure_table_exists(&new_id).await.is_ok() { + return Err(NamespaceError::TableAlreadyExists { + message: new_name.to_string(), + } + .into()); + } + + let old_path = self.resolve_table_path(&request.id)?; + let new_path = self.resolve_table_path(&new_id)?; + + // Recursively copy all files to the new location, then remove the old directory. + // ObjectStore::rename only handles single objects, which is insufficient for + // Lance table directories on cloud storage. + let entries: Vec = self + .object_store + .inner + .list(Some(&old_path)) + .try_collect() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to list table files for rename: {}", e), + }) + })?; + + let old_prefix = old_path.as_ref(); + let new_prefix = new_path.as_ref(); + + for meta in &entries { + let location_str = meta.location.as_ref(); + let relative = location_str + .strip_prefix(old_prefix) + .unwrap_or(location_str) + .trim_start_matches('/'); + let dest = if relative.is_empty() { + new_path.clone() + } else { + Path::from(format!("{}/{}", new_prefix, relative)) + }; + self.object_store + .inner + .copy(&meta.location, &dest) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to copy file during rename: {}", e), + }) + })?; + } + + self.object_store + .remove_dir_all(old_path) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to remove old table directory during rename: {}", + e + ), + }) + })?; + + Ok(RenameTableResponse { + ..Default::default() + }) + } + + async fn restore_table(&self, request: RestoreTableRequest) -> Result { + self.ensure_table_exists(&request.id).await?; + + let version = request.version; + + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, Some(version), "restore_table") + .await?; + dataset.restore().await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to restore table to version {}: {}", version, e), + }) + })?; + + Ok(RestoreTableResponse { + ..Default::default() + }) + } + + async fn list_all_tables(&self, _request: ListTablesRequest) -> Result { + let mut tables = Vec::new(); + self.collect_tables_recursive(&self.base_path, "", &mut tables) + .await; + tables.sort(); + Ok(ListTablesResponse::new(tables)) + } + + // ── Data Operations ───────────────────────────────────────────────── + + async fn count_table_rows(&self, request: CountTableRowsRequest) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "count_table_rows") + .await?; + + let count = if let Some(ref predicate) = request.predicate { + if predicate.is_empty() { + dataset.count_rows(None).await + } else { + dataset.count_rows(Some(predicate.clone())).await + } + } else { + dataset.count_rows(None).await + } + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to count rows: {}", e), + }) + })?; + + Ok(count as i64) + } + + async fn insert_into_table( + &self, + request: InsertIntoTableRequest, + request_data: Bytes, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + + if request_data.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Request data (Arrow IPC stream) is required for insert_into_table" + .to_string(), + } + .into()); + } + + let (arrow_schema, batches) = Self::decode_ipc_stream(&request_data)?; + let batch_results: Vec<_> = batches.into_iter().map(Ok).collect(); + let reader = RecordBatchIterator::new(batch_results, arrow_schema); + + let store_params = self.storage_options.as_ref().map(|opts| ObjectStoreParams { + storage_options_accessor: Some(Arc::new( + lance_io::object_store::StorageOptionsAccessor::with_static_options(opts.clone()), + )), + ..Default::default() + }); + + let write_params = WriteParams { + mode: WriteMode::Append, + store_params, + ..Default::default() + }; + + Dataset::write(reader, &table_uri, Some(write_params)) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to insert into table: {}", e), + }) + })?; + + Ok(InsertIntoTableResponse { + ..Default::default() + }) + } + + async fn merge_insert_into_table( + &self, + request: MergeInsertIntoTableRequest, + request_data: Bytes, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "merge_insert_into_table") + .await?; + + let on = request.on.as_deref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "'on' column(s) required for merge insert".to_string(), + }) + })?; + + let on_columns: Vec = on.split(',').map(|s| s.trim().to_string()).collect(); + let dataset_arc = Arc::new(dataset); + let mut builder = lance::dataset::MergeInsertBuilder::try_new(dataset_arc, on_columns) + .map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Failed to create merge insert builder: {}", e), + }) + })?; + + if request.when_matched_update_all == Some(true) { + if let Some(ref filt) = request.when_matched_update_all_filt { + builder.when_matched( + lance::dataset::WhenMatched::UpdateIf(filt.clone()), + ); + } else { + builder.when_matched(lance::dataset::WhenMatched::UpdateAll); + } + } + + if request.when_not_matched_insert_all == Some(true) { + builder.when_not_matched(lance::dataset::WhenNotMatched::InsertAll); + } + + if request.when_not_matched_by_source_delete == Some(true) { + builder.when_not_matched_by_source( + lance::dataset::WhenNotMatchedBySource::Delete, + ); + } + + let (arrow_schema, batches) = Self::decode_ipc_stream(&request_data)?; + let batch_results: Vec<_> = batches.into_iter().map(Ok).collect(); + let reader = RecordBatchIterator::new(batch_results, arrow_schema); + + let job = builder.try_build().map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Failed to build merge insert job: {}", e), + }) + })?; + + job.execute_reader(reader).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to merge insert: {}", e), + }) + })?; + + Ok(MergeInsertIntoTableResponse { + ..Default::default() + }) + } + + async fn update_table(&self, request: UpdateTableRequest) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "update_table") + .await?; + + let dataset_arc = Arc::new(dataset); + let mut op = lance::dataset::UpdateBuilder::new(dataset_arc); + + if let Some(ref predicate) = request.predicate { + if !predicate.is_empty() { + op = op.update_where(predicate).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid update predicate: {}", e), + }) + })?; + } + } + + for update_pair in &request.updates { + if update_pair.len() >= 2 { + op = op.set(&update_pair[0], &update_pair[1]).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid update expression: {}", e), + }) + })?; + } + } + + let job = op.build().map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Failed to build update job: {}", e), + }) + })?; + + job.execute().await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to update table: {}", e), + }) + })?; + + Ok(UpdateTableResponse { + ..Default::default() + }) + } + + async fn delete_from_table( + &self, + request: DeleteFromTableRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "delete_from_table") + .await?; + + let predicate = &request.predicate; + if predicate.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "Filter predicate is required for delete".to_string(), + } + .into()); + } + + dataset.delete(predicate).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to delete from table: {}", e), + }) + })?; + + Ok(DeleteFromTableResponse { + ..Default::default() + }) + } + + async fn query_table(&self, request: QueryTableRequest) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, request.version, "query_table") + .await?; + + let mut scanner = dataset.scan(); + Self::configure_scanner(&mut scanner, &request)?; + + let batches: Vec = scanner + .try_into_stream() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create scan stream: {}", e), + }) + })? + .try_collect() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to collect scan results: {}", e), + }) + })?; + + // Serialize to Arrow IPC + let schema = if let Some(first) = batches.first() { + first.schema() + } else { + let lance_schema = dataset.schema(); + Arc::new(lance_schema.into()) + }; + + let mut buffer = Vec::new(); + { + let mut writer = + arrow_ipc::writer::StreamWriter::try_new(&mut buffer, &schema).map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create IPC writer: {}", e), + }) + })?; + for batch in &batches { + writer.write(batch).map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to write IPC batch: {}", e), + }) + })?; + } + writer.finish().map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to finish IPC stream: {}", e), + }) + })?; + } + + Ok(Bytes::from(buffer)) + } + + // ── Index Operations ──────────────────────────────────────────────── + + async fn create_table_index( + &self, + request: CreateTableIndexRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "create_table_index") + .await?; + let index_request = Self::build_index_params(&request)?; + + dataset + .create_index( + &[request.column.as_str()], + index_request.index_type(), + request.name.clone(), + index_request.params(), + false, + ) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create index: {}", e), + }) + })?; + + let transaction_id = dataset + .read_transaction() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to read transaction after index creation: {}", e), + }) + })? + .map(|t| t.uuid); + + Ok(CreateTableIndexResponse { transaction_id }) + } + + async fn create_table_scalar_index( + &self, + request: CreateTableIndexRequest, + ) -> Result { + let index_type = Self::parse_index_type(&request.index_type)?; + if !index_type.is_scalar() { + return Err(NamespaceError::InvalidInput { + message: format!( + "create_table_scalar_index only supports scalar index types, got {}", + request.index_type + ), + } + .into()); + } + + let response = self.create_table_index(request).await?; + Ok(CreateTableScalarIndexResponse { + transaction_id: response.transaction_id, + }) + } + + async fn list_table_indices( + &self, + request: ListTableIndicesRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, request.version, "list_table_indices") + .await?; + + let mut indices = dataset + .describe_indices(None) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to describe table indices: {}", e), + }) + })? + .into_iter() + .filter(|description| { + description + .metadata() + .first() + .map(|metadata| !is_system_index(metadata)) + .unwrap_or(false) + }) + .map(|description| { + let columns = description + .field_ids() + .iter() + .map(|field_id| { + dataset + .schema() + .field_path(i32::try_from(*field_id).map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Field id {} does not fit in i32: {}", field_id, e), + }) + })?) + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to resolve field path for field_id {}: {}", + field_id, e + ), + }) + }) + }) + .collect::>>()?; + + Ok(IndexContent { + index_name: description.name().to_string(), + index_uuid: description.metadata()[0].uuid.to_string(), + columns, + status: "SUCCEEDED".to_string(), + }) + }) + .collect::>>()?; + + let page_token = Self::paginate_indices(&mut indices, request.page_token, request.limit); + Ok(ListTableIndicesResponse { + indexes: indices, + page_token, + }) + } + + async fn describe_table_index_stats( + &self, + request: DescribeTableIndexStatsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, request.version, "describe_table_index_stats") + .await?; + let index_name = request.index_name.as_deref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Index name is required".to_string(), + }) + })?; + + let metadatas = dataset.load_indices_by_name(index_name).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to load index '{}' metadata: {}", index_name, e), + }) + })?; + if metadatas.first().is_some_and(is_system_index) { + return Err(NamespaceError::Unsupported { + message: format!("System index '{}' is not exposed by this API", index_name), + } + .into()); + } + + let stats = + ::index_statistics(&dataset, index_name) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to describe index statistics: {}", e), + }) + })?; + let stats: serde_json::Value = serde_json::from_str(&stats).map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to parse index statistics: {}", e), + }) + })?; + + Ok(Self::describe_table_index_stats_response(&stats)) + } + + async fn drop_table_index( + &self, + request: DropTableIndexRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let index_name = request.index_name.as_deref().ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Index name is required for drop_table_index".to_string(), + }) + })?; + let mut dataset = self + .load_dataset(&table_uri, None, "drop_table_index") + .await?; + + let metadatas = dataset.load_indices_by_name(index_name).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to load index '{}' before dropping: {}", index_name, e), + }) + })?; + if metadatas.first().is_some_and(is_system_index) { + return Err(NamespaceError::Unsupported { + message: format!("System index '{}' cannot be dropped via this API", index_name), + } + .into()); + } + + dataset.drop_index(index_name).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to drop index '{}': {}", index_name, e), + }) + })?; + + let transaction_id = dataset + .read_transaction() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to read transaction after drop index: {}", e), + }) + })? + .map(|t| t.uuid); + + Ok(DropTableIndexResponse { transaction_id }) + } + + // ── Version Operations ────────────────────────────────────────────── + + async fn list_table_versions( + &self, + request: ListTableVersionsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let table_path = Self::uri_to_object_store_path(&table_uri); + let versions_dir = table_path.child("_versions"); + + let manifest_metas: Vec<_> = self + .object_store + .read_dir_all(&versions_dir, None) + .try_collect() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to list manifest files: {}", e), + }) + })?; + + let mut table_versions: Vec = manifest_metas + .into_iter() + .filter_map(|meta| { + let filename = meta.location.filename()?; + let version_str = filename.strip_suffix(".manifest")?; + if version_str.starts_with('d') { + return None; + } + let file_version: u64 = version_str.parse().ok()?; + // Lance V2 naming scheme stores manifests as + // `(u64::MAX - version).manifest` so that lexicographic listing + // returns newest versions first. Detect this by checking + // whether the numeric value exceeds half of u64 range. + let actual_version = if file_version > u64::MAX / 2 { + u64::MAX - file_version + } else { + file_version + }; + + Some(TableVersion { + version: actual_version as i64, + manifest_path: meta.location.to_string(), + manifest_size: Some(meta.size as i64), + e_tag: meta.e_tag, + timestamp_millis: Some(meta.last_modified.timestamp_millis()), + metadata: None, + }) + }) + .collect(); + + let want_descending = request.descending == Some(true); + if want_descending { + table_versions.sort_by(|a, b| b.version.cmp(&a.version)); + } else { + table_versions.sort_by(|a, b| a.version.cmp(&b.version)); + } + + if let Some(limit) = request.limit { + table_versions.truncate(limit as usize); + } + + Ok(ListTableVersionsResponse { + versions: table_versions, + page_token: None, + }) + } + + async fn describe_table_version( + &self, + request: DescribeTableVersionRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + + let mut builder = DatasetBuilder::from_uri(&table_uri); + if let Some(opts) = &self.storage_options { + builder = builder.with_storage_options(opts.clone()); + } + if let Some(sess) = &self.session { + builder = builder.with_session(sess.clone()); + } + let mut dataset = builder.load().await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to open table at '{}': {}", table_uri, e), + }) + })?; + + if let Some(version) = request.version { + dataset = dataset + .checkout_version(version as u64) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::TableVersionNotFound { + message: format!("Failed to checkout version {}: {}", version, e), + }) + })?; + } + + let version_info = dataset.version(); + let manifest_location = dataset.manifest_location(); + let metadata: HashMap = version_info.metadata.into_iter().collect(); + + let table_version = TableVersion { + version: version_info.version as i64, + manifest_path: manifest_location.path.to_string(), + manifest_size: manifest_location.size.map(|s| s as i64), + e_tag: manifest_location.e_tag.clone(), + timestamp_millis: Some(version_info.timestamp.timestamp_millis()), + metadata: if metadata.is_empty() { + None + } else { + Some(metadata) + }, + }; + + Ok(DescribeTableVersionResponse { + version: Box::new(table_version), + }) + } + + async fn create_table_version( + &self, + request: CreateTableVersionRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let staging_manifest_path = &request.manifest_path; + let version = request.version as u64; + // manifest_path and version are required (i64 and String, not Optional) + let table_path = Self::uri_to_object_store_path(&table_uri); + + let naming_scheme = match request.naming_scheme.as_deref() { + Some("V1") => ManifestNamingScheme::V1, + _ => ManifestNamingScheme::V2, + }; + + let final_path = naming_scheme.manifest_path(&table_path, version); + let staging_path = Self::uri_to_object_store_path(staging_manifest_path); + + let manifest_data = self + .object_store + .inner + .get(&staging_path) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to read staging manifest: {}", e), + }) + })? + .bytes() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to read staging manifest bytes: {}", e), + }) + })?; + + let manifest_size = manifest_data.len() as i64; + + let put_result = self + .object_store + .inner + .put_opts( + &final_path, + manifest_data.into(), + PutOptions { + mode: PutMode::Create, + ..Default::default() + }, + ) + .await + .map_err(|e| match e { + ObjectStoreError::AlreadyExists { .. } + | ObjectStoreError::Precondition { .. } => { + lance_core::Error::from(NamespaceError::ConcurrentModification { + message: format!("Version {} already exists", version), + }) + } + _ => lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create version {}: {}", version, e), + }), + })?; + + // Best-effort cleanup of staging manifest + if let Err(e) = self.object_store.inner.delete(&staging_path).await { + log::warn!("Failed to delete staging manifest: {:?}", e); + } + + Ok(CreateTableVersionResponse { + transaction_id: None, + version: Some(Box::new(TableVersion { + version: version as i64, + manifest_path: final_path.to_string(), + manifest_size: Some(manifest_size), + e_tag: put_result.e_tag, + timestamp_millis: None, + metadata: None, + })), + }) + } + + async fn batch_delete_table_versions( + &self, + request: BatchDeleteTableVersionsRequest, + ) -> Result { + let ranges: Vec<(i64, i64)> = request + .ranges + .iter() + .map(|r| { + let start = r.start_version; + let end = if r.end_version > 0 { + r.end_version + } else { + start + }; + (start, end) + }) + .collect(); + + let table_entries = vec![TableDeleteEntry { + table_id: request.id.clone(), + ranges, + }]; + + let total_deleted_count = self + .delete_physical_version_files(&table_entries, false) + .await?; + + Ok(BatchDeleteTableVersionsResponse { + deleted_count: Some(total_deleted_count), + transaction_id: None, + }) + } + + // ── Schema Operations ─────────────────────────────────────────────── + + async fn alter_table_add_columns( + &self, + request: AlterTableAddColumnsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "alter_table_add_columns") + .await?; + + let transforms = &request.new_columns; + + if transforms.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "At least one column transform is required".to_string(), + } + .into()); + } + + let sql_pairs: Vec<(String, String)> = transforms + .iter() + .map(|t| { + ( + t.name.clone(), + t.expression.clone().unwrap_or_default(), + ) + }) + .collect(); + + dataset + .add_columns( + lance::dataset::NewColumnTransform::SqlExpressions(sql_pairs), + None, + None, + ) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to add columns: {}", e), + }) + })?; + + Ok(AlterTableAddColumnsResponse { + ..Default::default() + }) + } + + async fn alter_table_alter_columns( + &self, + request: AlterTableAlterColumnsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "alter_table_alter_columns") + .await?; + + let entries = &request.alterations; + + if entries.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "At least one column alteration is required".to_string(), + } + .into()); + } + + let alterations: Vec = entries + .iter() + .map(|entry| { + let mut alt = lance::dataset::ColumnAlteration::new(entry.path.clone()); + if let Some(ref rename) = entry.rename { + alt = alt.rename(rename.to_string()); + } + if let Some(nullable) = entry.nullable { + alt = alt.set_nullable(nullable); + } + alt + }) + .collect(); + + dataset.alter_columns(&alterations).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to alter columns: {}", e), + }) + })?; + + Ok(AlterTableAlterColumnsResponse { + ..Default::default() + }) + } + + async fn alter_table_drop_columns( + &self, + request: AlterTableDropColumnsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "alter_table_drop_columns") + .await?; + + let columns = &request.columns; + if columns.is_empty() { + return Err(NamespaceError::InvalidInput { + message: "At least one column name is required".to_string(), + } + .into()); + } + + let col_refs: Vec<&str> = columns.iter().map(|s| s.as_str()).collect(); + dataset.drop_columns(&col_refs).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to drop columns: {}", e), + }) + })?; + + Ok(AlterTableDropColumnsResponse { + ..Default::default() + }) + } + + async fn update_table_schema_metadata( + &self, + request: UpdateTableSchemaMetadataRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let mut dataset = self + .load_dataset(&table_uri, None, "update_table_schema_metadata") + .await?; + + let entries: Vec<(&str, &str)> = request + .metadata + .as_ref() + .map(|m| { + m.iter() + .map(|(k, v)| (k.as_str(), v.as_str())) + .collect() + }) + .unwrap_or_default(); + + let updated = dataset + .update_schema_metadata(entries) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to update schema metadata: {}", e), + }) + })?; + + let transaction_id = dataset + .read_transaction() + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!( + "Failed to read transaction after schema metadata update: {}", + e + ), + }) + })? + .map(|t| t.uuid); + + Ok(UpdateTableSchemaMetadataResponse { + metadata: Some(updated), + transaction_id, + }) + } + + async fn get_table_stats( + &self, + request: GetTableStatsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "get_table_stats") + .await?; + + let row_count = dataset.count_rows(None).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to count rows for stats: {}", e), + }) + })?; + + let fragments = dataset.get_fragments(); + let mut fragment_lengths = Vec::with_capacity(fragments.len()); + for f in &fragments { + let count = f.count_rows(None).await.unwrap_or(0) as i64; + fragment_lengths.push(count); + } + let num_fragments = fragment_lengths.len() as i64; + let num_small_fragments = fragment_lengths.iter().filter(|&&l| l < 1024).count() as i64; + + let (min, max, mean, p25, p50, p75, p99) = if fragment_lengths.is_empty() { + (0, 0, 0, 0, 0, 0, 0) + } else { + let mut sorted = fragment_lengths.clone(); + sorted.sort(); + let len = sorted.len(); + let sum: i64 = sorted.iter().sum(); + let percentile = |p: usize| sorted[(len - 1) * p / 100]; + ( + sorted[0], + sorted[len - 1], + sum / len as i64, + percentile(25), + percentile(50), + percentile(75), + percentile(99), + ) + }; + + let num_indices = dataset + .describe_indices(None) + .await + .map(|v| v.len() as i64) + .unwrap_or(0); + + Ok(GetTableStatsResponse::new( + 0, // total_bytes — not easily available without scanning all files + row_count as i64, + num_indices, + lance_namespace::models::FragmentStats::new( + num_fragments, + num_small_fragments, + lance_namespace::models::FragmentSummary::new(min, max, mean, p25, p50, p75, p99), + ), + )) + } + + // ── Transaction Operations ────────────────────────────────────────── + + async fn describe_transaction( + &self, + request: DescribeTransactionRequest, + ) -> Result { + let mut request_id = request.id.ok_or_else(|| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: "Transaction id must include table id and transaction identifier" + .to_string(), + }) + })?; + if request_id.len() < 2 { + return Err(NamespaceError::InvalidInput { + message: format!( + "Transaction request id must include table id and transaction identifier, got {:?}", + request_id + ), + } + .into()); + } + + let id = request_id.pop().expect("request_id len checked above"); + let table_id = Some(request_id); + let table_uri = self.resolve_table_uri(&table_id)?; + let dataset = self + .load_dataset(&table_uri, None, "describe_transaction") + .await?; + let (version, transaction) = self.find_transaction(&dataset, &id).await?; + + Ok(Self::transaction_response(version, &transaction)) + } + + async fn alter_transaction( + &self, + _request: AlterTransactionRequest, + ) -> Result { + Err(NamespaceError::Unsupported { + message: "alter_transaction is not supported in base namespace".to_string(), + } + .into()) + } + + // ── Query Plan Operations ─────────────────────────────────────────── + + async fn explain_table_query_plan( + &self, + request: ExplainTableQueryPlanRequest, + ) -> Result { + let query = &request.query; + let table_uri = self.resolve_table_uri(&query.id)?; + let dataset = self + .load_dataset(&table_uri, query.version, "explain_table_query_plan") + .await?; + + let mut scanner = dataset.scan(); + Self::configure_scanner(&mut scanner, query)?; + + let verbose = request.verbose.unwrap_or(false); + scanner.explain_plan(verbose).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to explain query plan: {}", e), + }) + }) + } + + async fn analyze_table_query_plan( + &self, + request: AnalyzeTableQueryPlanRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, request.version, "analyze_table_query_plan") + .await?; + + let mut scanner = dataset.scan(); + if let Some(ref filter) = request.filter { + if !filter.is_empty() { + scanner.filter(filter).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid filter expression: {}", e), + }) + })?; + } + } + if let Some(ref columns) = request.columns { + if let Some(ref col_names) = columns.column_names { + let col_refs: Vec<&str> = col_names.iter().map(|s| s.as_str()).collect(); + scanner.project(&col_refs).map_err(|e| { + lance_core::Error::from(NamespaceError::InvalidInput { + message: format!("Invalid column projection: {}", e), + }) + })?; + } + } + if request.k > 0 { + let _ = scanner.limit(Some(request.k as i64), request.offset.map(|o| o as i64)); + } + + // analyze = explain with verbose + scanner.explain_plan(true).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to analyze query plan: {}", e), + }) + }) + } + + // ── Tag Operations ────────────────────────────────────────────────── + + async fn create_table_tag( + &self, + request: CreateTableTagRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "create_table_tag") + .await?; + + dataset + .tags() + .create(&request.tag, request.version as u64) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to create tag '{}': {}", request.tag, e), + }) + })?; + + Ok(CreateTableTagResponse { + transaction_id: None, + }) + } + + async fn delete_table_tag( + &self, + request: DeleteTableTagRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "delete_table_tag") + .await?; + + dataset.tags().delete(&request.tag).await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to delete tag '{}': {}", request.tag, e), + }) + })?; + + Ok(DeleteTableTagResponse { + transaction_id: None, + }) + } + + async fn update_table_tag( + &self, + request: UpdateTableTagRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "update_table_tag") + .await?; + + dataset + .tags() + .update(&request.tag, request.version as u64) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to update tag '{}': {}", request.tag, e), + }) + })?; + + Ok(UpdateTableTagResponse { + transaction_id: None, + }) + } + + async fn list_table_tags( + &self, + request: ListTableTagsRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "list_table_tags") + .await?; + + let sdk_tags = dataset.tags().list().await.map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to list tags: {}", e), + }) + })?; + + let mut tags: HashMap = sdk_tags + .into_iter() + .map(|(name, contents)| { + ( + name, + TagContents { + branch: contents.branch, + version: contents.version as i64, + manifest_size: contents.manifest_size as i64, + }, + ) + }) + .collect(); + + // Apply pagination + let mut tag_names: Vec = tags.keys().cloned().collect(); + tag_names.sort(); + + if let Some(ref start_after) = request.page_token { + tag_names.retain(|name| name.as_str() > start_after.as_str()); + } + + let mut page_token = None; + if let Some(limit) = request.limit { + let limit = limit as usize; + if limit > 0 && tag_names.len() > limit { + page_token = Some(tag_names[limit - 1].clone()); + tag_names.truncate(limit); + } + } + + let filtered_tags: HashMap = tag_names + .into_iter() + .filter_map(|name| tags.remove(&name).map(|contents| (name, contents))) + .collect(); + + Ok(ListTableTagsResponse { + tags: filtered_tags, + page_token, + }) + } + + async fn get_table_tag_version( + &self, + request: GetTableTagVersionRequest, + ) -> Result { + let table_uri = self.resolve_table_uri(&request.id)?; + let dataset = self + .load_dataset(&table_uri, None, "get_table_tag_version") + .await?; + + let version = dataset + .tags() + .get_version(&request.tag) + .await + .map_err(|e| { + lance_core::Error::from(NamespaceError::Internal { + message: format!("Failed to get version for tag '{}': {}", request.tag, e), + }) + })?; + + Ok(GetTableTagVersionResponse { + version: version as i64, + }) + } + + // ── Utility ───────────────────────────────────────────────────────── + + fn namespace_id(&self) -> String { + format!("BaseLanceNamespace{{root={}}}", self.root) + } +} + +// ── Tests ─────────────────────────────────────────────────────────────────── + +#[cfg(test)] +mod tests { + use super::*; + use arrow::array::{Int32Array, StringArray}; + use arrow::datatypes::{DataType, Field, Schema as ArrowSchema}; + use arrow_ipc::reader::StreamReader; + use std::io::Cursor; + + fn create_ipc_data_from_batches( + schema: Arc, + batches: Vec, + ) -> Vec { + let mut buffer = Vec::new(); + { + let mut writer = + arrow_ipc::writer::StreamWriter::try_new(&mut buffer, &schema).unwrap(); + for batch in &batches { + writer.write(batch).unwrap(); + } + writer.finish().unwrap(); + } + buffer + } + + fn create_test_table_data() -> Vec { + let schema = Arc::new(ArrowSchema::new(vec![ + Field::new("id", DataType::Int32, false), + Field::new("name", DataType::Utf8, true), + Field::new("age", DataType::Int32, true), + ])); + let batch = arrow::record_batch::RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(Int32Array::from(vec![1, 2, 3])), + Arc::new(StringArray::from(vec!["Alice", "Bob", "Charlie"])), + Arc::new(Int32Array::from(vec![30, 25, 35])), + ], + ) + .unwrap(); + create_ipc_data_from_batches(schema, vec![batch]) + } + + fn create_additional_data() -> Vec { + let schema = Arc::new(ArrowSchema::new(vec![ + Field::new("id", DataType::Int32, false), + Field::new("name", DataType::Utf8, true), + Field::new("age", DataType::Int32, true), + ])); + let batch = arrow::record_batch::RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(Int32Array::from(vec![4, 5])), + Arc::new(StringArray::from(vec!["Dave", "Eve"])), + Arc::new(Int32Array::from(vec![40, 28])), + ], + ) + .unwrap(); + create_ipc_data_from_batches(schema, vec![batch]) + } + + async fn create_test_namespace() -> (BaseLanceNamespace, tempfile::TempDir) { + let temp_dir = tempfile::TempDir::new().unwrap(); + let namespace = BaseLanceNamespaceBuilder::new(temp_dir.path().to_str().unwrap()) + .build() + .await + .unwrap(); + (namespace, temp_dir) + } + + async fn create_namespace(ns: &BaseLanceNamespace, parts: &[&str]) { + ns.create_namespace(CreateNamespaceRequest { + id: Some(parts.iter().map(|s| s.to_string()).collect()), + ..Default::default() + }) + .await + .unwrap(); + } + + async fn create_test_table(ns: &BaseLanceNamespace, id_parts: &[&str]) { + let data = create_test_table_data(); + ns.create_table( + CreateTableRequest { + id: Some(id_parts.iter().map(|s| s.to_string()).collect()), + ..Default::default() + }, + Bytes::from(data), + ) + .await + .unwrap(); + } + + fn count_rows_in_ipc(data: &[u8]) -> usize { + let cursor = Cursor::new(data); + let reader = StreamReader::try_new(cursor, None).unwrap(); + let mut total = 0; + for batch in reader { + total += batch.unwrap().num_rows(); + } + total + } + + fn table_id(parts: &[&str]) -> Option> { + Some(parts.iter().map(|s| s.to_string()).collect()) + } + + // ── Namespace Operations ──────────────────────────────────────────── + + #[tokio::test] + async fn test_namespace_id() { + let (ns, _dir) = create_test_namespace().await; + assert!(ns.namespace_id().contains("BaseLanceNamespace")); + } + + #[tokio::test] + async fn test_create_and_list_namespaces() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let resp = ns + .list_namespaces(ListNamespacesRequest { + id: None, + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.namespaces.contains(&"workspace".to_string())); + } + + #[tokio::test] + async fn test_create_namespace_already_exists() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let result = ns + .create_namespace(CreateNamespaceRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("already exists")); + } + + #[tokio::test] + async fn test_describe_namespace() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let resp = ns + .describe_namespace(DescribeNamespaceRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.properties.is_some()); + } + + #[tokio::test] + async fn test_namespace_exists() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + assert!(ns + .namespace_exists(NamespaceExistsRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await + .is_ok()); + + assert!(ns + .namespace_exists(NamespaceExistsRequest { + id: table_id(&["nonexistent"]), + ..Default::default() + }) + .await + .is_err()); + } + + #[tokio::test] + async fn test_drop_namespace() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + ns.drop_namespace(DropNamespaceRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await + .unwrap(); + + assert!(ns + .namespace_exists(NamespaceExistsRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await + .is_err()); + } + + #[tokio::test] + async fn test_drop_namespace_not_empty() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .drop_namespace(DropNamespaceRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("not empty")); + } + + #[tokio::test] + async fn test_nested_namespaces() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["org"]).await; + create_namespace(&ns, &["org", "team"]).await; + + let resp = ns + .list_namespaces(ListNamespacesRequest { + id: table_id(&["org"]), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.namespaces.contains(&"team".to_string())); + } + + // ── Table Operations ──────────────────────────────────────────────── + + #[tokio::test] + async fn test_create_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let data = create_test_table_data(); + let resp = ns + .create_table( + CreateTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }, + Bytes::from(data), + ) + .await + .unwrap(); + + assert!(resp.location.unwrap().contains("test_table")); + assert_eq!(resp.version, Some(1)); + } + + #[tokio::test] + async fn test_create_table_already_exists() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let data = create_test_table_data(); + let result = ns + .create_table( + CreateTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }, + Bytes::from(data), + ) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("already exists")); + } + + #[tokio::test] + async fn test_list_tables() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "table1"]).await; + create_test_table(&ns, &["workspace", "table2"]).await; + + let resp = ns + .list_tables(ListTablesRequest { + id: table_id(&["workspace"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.tables.len(), 2); + assert!(resp.tables.contains(&"table1".to_string())); + assert!(resp.tables.contains(&"table2".to_string())); + } + + #[tokio::test] + async fn test_describe_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let resp = ns + .describe_table(DescribeTableRequest { + id: table_id(&["workspace", "test_table"]), + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + + assert!(resp.location.unwrap().contains("test_table")); + assert_eq!(resp.version, Some(1)); + assert!(resp.schema.is_some()); + assert_eq!(resp.schema.unwrap().fields.len(), 3); + } + + #[tokio::test] + async fn test_table_exists() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .is_ok()); + + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "nonexistent"]), + ..Default::default() + }) + .await + .is_err()); + } + + #[tokio::test] + async fn test_drop_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + ns.drop_table(DropTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .is_err()); + } + + #[tokio::test] + async fn test_count_table_rows() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + #[tokio::test] + async fn test_table_at_root_level() { + let (ns, _dir) = create_test_namespace().await; + + let data = create_test_table_data(); + let resp = ns + .create_table( + CreateTableRequest { + id: table_id(&["root_table"]), + ..Default::default() + }, + Bytes::from(data), + ) + .await + .unwrap(); + assert!(resp.location.is_some()); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["root_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + // ── Data Operations ───────────────────────────────────────────────── + + #[tokio::test] + async fn test_insert_into_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let additional = create_additional_data(); + ns.insert_into_table( + InsertIntoTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }, + Bytes::from(additional), + ) + .await + .unwrap(); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 5); + } + + #[tokio::test] + async fn test_query_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .query_table(QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 3); + } + + #[tokio::test] + async fn test_query_table_with_filter() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .query_table(QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + filter: Some("age > 28".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 2); // Alice (30) and Charlie (35) + } + + #[tokio::test] + async fn test_query_table_with_projection() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let mut columns = lance_namespace::models::QueryTableRequestColumns::new(); + columns.column_names = Some(vec!["id".to_string(), "name".to_string()]); + + let result = ns + .query_table(QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + columns: Some(Box::new(columns)), + ..Default::default() + }) + .await + .unwrap(); + + let cursor = Cursor::new(&result[..]); + let reader = StreamReader::try_new(cursor, None).unwrap(); + let schema = reader.schema(); + assert_eq!(schema.fields().len(), 2); + assert_eq!(schema.field(0).name(), "id"); + assert_eq!(schema.field(1).name(), "name"); + } + + #[tokio::test] + async fn test_delete_from_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + ns.delete_from_table(DeleteFromTableRequest { + id: table_id(&["workspace", "test_table"]), + predicate: "id = 2".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 2); + } + + #[tokio::test] + async fn test_merge_insert_into_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + // Merge data: update id=1, insert id=4 + let schema = Arc::new(ArrowSchema::new(vec![ + Field::new("id", DataType::Int32, false), + Field::new("name", DataType::Utf8, true), + Field::new("age", DataType::Int32, true), + ])); + let batch = arrow::record_batch::RecordBatch::try_new( + schema.clone(), + vec![ + Arc::new(Int32Array::from(vec![1, 4])), + Arc::new(StringArray::from(vec!["Alice Updated", "Dave"])), + Arc::new(Int32Array::from(vec![31, 40])), + ], + ) + .unwrap(); + let merge_data = create_ipc_data_from_batches(schema, vec![batch]); + + ns.merge_insert_into_table( + MergeInsertIntoTableRequest { + id: table_id(&["workspace", "test_table"]), + on: Some("id".to_string()), + when_matched_update_all: Some(true), + when_not_matched_insert_all: Some(true), + ..Default::default() + }, + Bytes::from(merge_data), + ) + .await + .unwrap(); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 4); // Alice updated, Bob, Charlie, Dave + } + + #[tokio::test] + async fn test_insert_query_delete_roundtrip() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Verify initial + let result = ns + .query_table(QueryTableRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 3); + + // Insert more + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + let result = ns + .query_table(QueryTableRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 5); + + // Delete + ns.delete_from_table(DeleteFromTableRequest { + id: tid.clone(), + predicate: "id >= 4".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + let result = ns + .query_table(QueryTableRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 3); + } + + // ── Index Operations ──────────────────────────────────────────────── + + #[tokio::test] + async fn test_create_and_list_scalar_index() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_scalar_index(CreateTableIndexRequest { + id: tid.clone(), + column: "id".to_string(), + index_type: "btree".to_string(), + name: Some("id_idx".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .list_table_indices(ListTableIndicesRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.indexes.len(), 1); + assert!(resp.indexes[0].columns.contains(&"id".to_string())); + } + + #[tokio::test] + async fn test_drop_table_index() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_scalar_index(CreateTableIndexRequest { + id: tid.clone(), + column: "id".to_string(), + index_type: "btree".to_string(), + name: Some("id_idx".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .list_table_indices(ListTableIndicesRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + let index_name = resp.indexes[0].index_name.clone(); + + ns.drop_table_index(DropTableIndexRequest { + id: tid.clone(), + index_name: Some(index_name), + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .list_table_indices(ListTableIndicesRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.indexes.len(), 0); + } + + // ── Schema Operations ─────────────────────────────────────────────── + + #[tokio::test] + async fn test_alter_table_add_columns() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + let mut transform = lance_namespace::models::NewColumnTransform::new( + "score".to_string(), + ); + transform.expression = Some("0".to_string()); + + ns.alter_table_add_columns(AlterTableAddColumnsRequest { + id: tid.clone(), + new_columns: vec![transform], + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .describe_table(DescribeTableRequest { + id: tid, + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + let schema = resp.schema.unwrap(); + assert_eq!(schema.fields.len(), 4); + assert!(schema.fields.iter().any(|f| f.name == "score")); + } + + #[tokio::test] + async fn test_alter_table_drop_columns() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.alter_table_drop_columns(AlterTableDropColumnsRequest { + id: tid.clone(), + columns: vec!["age".to_string()], + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .describe_table(DescribeTableRequest { + id: tid, + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + let schema = resp.schema.unwrap(); + assert!(!schema.fields.iter().any(|f| f.name == "age")); + } + + #[tokio::test] + async fn test_alter_table_alter_columns() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + let mut entry = lance_namespace::models::AlterColumnsEntry::new( + "name".to_string(), + serde_json::Value::Null, + ); + entry.rename = Some("full_name".to_string()); + + ns.alter_table_alter_columns(AlterTableAlterColumnsRequest { + id: tid.clone(), + alterations: vec![entry], + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .describe_table(DescribeTableRequest { + id: tid, + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + let schema = resp.schema.unwrap(); + assert!(schema.fields.iter().any(|f| f.name == "full_name")); + assert!(!schema.fields.iter().any(|f| f.name == "name")); + } + + #[tokio::test] + async fn test_get_table_stats() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let resp = ns + .get_table_stats(GetTableStatsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.num_rows, 3); + } + + // ── Version Operations ────────────────────────────────────────────── + + #[tokio::test] + async fn test_list_table_versions() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + let resp = ns + .list_table_versions(ListTableVersionsRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.versions.len() >= 2); + } + + #[tokio::test] + async fn test_restore_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create version 2 (5 rows total) + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 5); + + // Restore to version 1 + ns.restore_table(RestoreTableRequest { + id: tid.clone(), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + // ── Advanced ──────────────────────────────────────────────────────── + + #[tokio::test] + async fn test_table_in_child_namespace() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["org"]).await; + create_namespace(&ns, &["org", "team"]).await; + create_test_table(&ns, &["org", "team", "dataset"]).await; + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["org", "team", "dataset"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + #[tokio::test] + async fn test_rename_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + ns.rename_table(RenameTableRequest { + id: table_id(&["workspace", "test_table"]), + new_table_name: "renamed_table".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + // Old name should not exist + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .is_err()); + + // New name should exist + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "renamed_table"]), + ..Default::default() + }) + .await + .is_ok()); + } + + #[tokio::test] + async fn test_list_all_tables() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["ns1"]).await; + create_namespace(&ns, &["ns2"]).await; + create_test_table(&ns, &["ns1", "table_a"]).await; + create_test_table(&ns, &["ns2", "table_b"]).await; + + let resp = ns + .list_all_tables(ListTablesRequest { + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.tables.len(), 2); + } + + #[tokio::test] + async fn test_deregister_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + ns.deregister_table(DeregisterTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .unwrap(); + + // Table should be gone + assert!(ns + .table_exists(TableExistsRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await + .is_err()); + } + + // ── Additional coverage ──────────────────────────────────────────── + + #[tokio::test] + async fn test_update_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.update_table(UpdateTableRequest { + id: tid.clone(), + updates: vec![vec!["age".to_string(), "age + 1".to_string()]], + predicate: Some("id = 1".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + let result = ns + .query_table(QueryTableRequest { + id: tid, + filter: Some("id = 1".to_string()), + ..Default::default() + }) + .await + .unwrap(); + let cursor = Cursor::new(&result[..]); + let reader = StreamReader::try_new(cursor, None).unwrap(); + for batch in reader { + let batch = batch.unwrap(); + let ages = batch + .column_by_name("age") + .unwrap() + .as_any() + .downcast_ref::() + .unwrap(); + assert_eq!(ages.value(0), 31); // was 30, now 31 + } + } + + #[tokio::test] + async fn test_declare_table() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let tid = table_id(&["workspace", "reserved_table"]); + + let resp = ns + .declare_table(DeclareTableRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.location.is_some()); + + // Table directory should exist (has .lance-reserved marker) + assert!(ns + .table_exists(TableExistsRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .is_ok()); + + // Declaring the same table again should fail + let result = ns + .declare_table(DeclareTableRequest { + id: tid, + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_describe_table_version() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + let resp = ns + .describe_table_version(DescribeTableVersionRequest { + id: tid, + version: Some(1), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.version.version, 1); + } + + #[tokio::test] + async fn test_count_table_rows_with_predicate() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + predicate: Some("age > 28".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 2); // Alice (30) and Charlie (35) + } + + #[tokio::test] + async fn test_rename_table_preserves_data() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + ns.rename_table(RenameTableRequest { + id: table_id(&["workspace", "test_table"]), + new_table_name: "renamed_table".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + // Verify data is preserved after rename + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "renamed_table"]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + #[tokio::test] + async fn test_list_all_tables_includes_namespace_prefix() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["ns1"]).await; + create_namespace(&ns, &["ns2"]).await; + create_test_table(&ns, &["ns1", "table_a"]).await; + create_test_table(&ns, &["ns2", "table_b"]).await; + + let resp = ns + .list_all_tables(ListTablesRequest { + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.tables.contains(&"ns1/table_a".to_string())); + assert!(resp.tables.contains(&"ns2/table_b".to_string())); + } + + #[tokio::test] + async fn test_list_tables_pagination() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "alpha"]).await; + create_test_table(&ns, &["workspace", "beta"]).await; + create_test_table(&ns, &["workspace", "gamma"]).await; + + // Page 1: limit 2 + let resp = ns + .list_tables(ListTablesRequest { + id: table_id(&["workspace"]), + limit: Some(2), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.tables.len(), 2); + assert_eq!(resp.tables[0], "alpha"); + assert_eq!(resp.tables[1], "beta"); + assert!(resp.page_token.is_some()); + + // Page 2: use page_token + let resp2 = ns + .list_tables(ListTablesRequest { + id: table_id(&["workspace"]), + page_token: resp.page_token, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp2.tables.len(), 1); + assert_eq!(resp2.tables[0], "gamma"); + } + + // ── Error cases ──────────────────────────────────────────────────── + + #[tokio::test] + async fn test_create_table_empty_data() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + + let result = ns + .create_table( + CreateTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }, + Bytes::new(), + ) + .await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("required for create_table")); + } + + #[tokio::test] + async fn test_insert_into_table_empty_data() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .insert_into_table( + InsertIntoTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }, + Bytes::new(), + ) + .await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("required for insert_into_table")); + } + + #[tokio::test] + async fn test_delete_from_table_empty_predicate() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .delete_from_table(DeleteFromTableRequest { + id: table_id(&["workspace", "test_table"]), + predicate: "".to_string(), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("predicate is required")); + } + + #[tokio::test] + async fn test_register_table_unsupported() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .register_table(RegisterTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("not supported")); + } + + #[tokio::test] + async fn test_drop_root_namespace_fails() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .drop_namespace(DropNamespaceRequest { + id: Some(vec![]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_create_root_namespace_fails() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .create_namespace(CreateNamespaceRequest { + id: Some(vec![]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("already exists")); + } + + // ── Builder ──────────────────────────────────────────────────────── + + #[tokio::test] + async fn test_from_properties_builder() { + let temp_dir = tempfile::TempDir::new().unwrap(); + let root = temp_dir.path().to_str().unwrap().to_string(); + + let mut properties = HashMap::new(); + properties.insert("root".to_string(), root); + properties.insert("storage.key1".to_string(), "value1".to_string()); + + let ns = BaseLanceNamespaceBuilder::from_properties(properties, None) + .unwrap() + .build() + .await + .unwrap(); + assert!(ns.namespace_id().contains("BaseLanceNamespace")); + } + + #[tokio::test] + async fn test_from_properties_missing_root() { + let properties = HashMap::new(); + let result = BaseLanceNamespaceBuilder::from_properties(properties, None); + assert!(result.is_err()); + } + + // ── Unsupported operations ───────────────────────────────────────── + + #[tokio::test] + async fn test_alter_transaction_unsupported() { + let (ns, _dir) = create_test_namespace().await; + let result = ns + .alter_transaction(AlterTransactionRequest { + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("not supported")); + } + + // ── Tag operations ──────────────────────────────────────────────── + + #[tokio::test] + async fn test_create_and_get_table_tag() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: "v1.0".to_string(), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .get_table_tag_version(GetTableTagVersionRequest { + id: tid, + tag: "v1.0".to_string(), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.version, 1); + } + + #[tokio::test] + async fn test_list_table_tags() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: "v1.0".to_string(), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + + // Insert to create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: "v2.0".to_string(), + version: 2, + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .list_table_tags(ListTableTagsRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.tags.len(), 2); + assert!(resp.tags.contains_key("v1.0")); + assert!(resp.tags.contains_key("v2.0")); + assert_eq!(resp.tags["v1.0"].version, 1); + assert_eq!(resp.tags["v2.0"].version, 2); + } + + #[tokio::test] + async fn test_update_table_tag() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: "latest".to_string(), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + + // Insert to create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + ns.update_table_tag(UpdateTableTagRequest { + id: tid.clone(), + tag: "latest".to_string(), + version: 2, + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .get_table_tag_version(GetTableTagVersionRequest { + id: tid, + tag: "latest".to_string(), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.version, 2); + } + + #[tokio::test] + async fn test_delete_table_tag() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: "to-delete".to_string(), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + + ns.delete_table_tag(DeleteTableTagRequest { + id: tid.clone(), + tag: "to-delete".to_string(), + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .list_table_tags(ListTableTagsRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.tags.is_empty()); + } + + #[tokio::test] + async fn test_list_table_tags_pagination() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + for i in 1..=3 { + ns.create_table_tag(CreateTableTagRequest { + id: tid.clone(), + tag: format!("tag-{}", i), + version: 1, + ..Default::default() + }) + .await + .unwrap(); + } + + let resp = ns + .list_table_tags(ListTableTagsRequest { + id: tid.clone(), + limit: Some(2), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.tags.len(), 2); + assert!(resp.page_token.is_some()); + } + + // ── Query plan operations ────────────────────────────────────────── + + #[tokio::test] + async fn test_explain_table_query_plan() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let query = QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + filter: Some("age > 25".to_string()), + ..Default::default() + }; + + let plan = ns + .explain_table_query_plan(ExplainTableQueryPlanRequest { + id: table_id(&["workspace", "test_table"]), + query: Box::new(query), + verbose: Some(false), + ..Default::default() + }) + .await + .unwrap(); + assert!(!plan.is_empty()); + } + + #[tokio::test] + async fn test_explain_table_query_plan_verbose() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let query = QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + ..Default::default() + }; + + let plan = ns + .explain_table_query_plan(ExplainTableQueryPlanRequest { + id: table_id(&["workspace", "test_table"]), + query: Box::new(query), + verbose: Some(true), + ..Default::default() + }) + .await + .unwrap(); + assert!(!plan.is_empty()); + } + + #[tokio::test] + async fn test_analyze_table_query_plan() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let plan = ns + .analyze_table_query_plan(AnalyzeTableQueryPlanRequest { + id: table_id(&["workspace", "test_table"]), + filter: Some("age > 25".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert!(!plan.is_empty()); + } + + // ── Update table schema metadata ────────────────────────────────── + + #[tokio::test] + async fn test_update_table_schema_metadata() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + let mut metadata = HashMap::new(); + metadata.insert("author".to_string(), "test".to_string()); + metadata.insert("version_label".to_string(), "initial".to_string()); + + let resp = ns + .update_table_schema_metadata(UpdateTableSchemaMetadataRequest { + id: tid.clone(), + metadata: Some(metadata), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.metadata.is_some()); + let updated = resp.metadata.unwrap(); + assert_eq!(updated.get("author").unwrap(), "test"); + assert_eq!(updated.get("version_label").unwrap(), "initial"); + } + + #[tokio::test] + async fn test_update_table_schema_metadata_empty() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Empty metadata should succeed (no-op merge) + let resp = ns + .update_table_schema_metadata(UpdateTableSchemaMetadataRequest { + id: tid, + metadata: None, + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.metadata.is_some()); + } + + // ── Describe transaction ─────────────────────────────────────────── + + #[tokio::test] + async fn test_describe_transaction() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create a transaction at version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + // Describe by version number + let resp = ns + .describe_transaction(DescribeTransactionRequest { + id: Some(vec![ + "workspace".to_string(), + "test_table".to_string(), + "2".to_string(), + ]), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.status, "SUCCEEDED"); + assert!(resp.properties.is_some()); + let props = resp.properties.unwrap(); + assert_eq!(props.get("version").unwrap(), "2"); + } + + #[tokio::test] + async fn test_describe_transaction_not_found() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .describe_transaction(DescribeTransactionRequest { + id: Some(vec![ + "workspace".to_string(), + "test_table".to_string(), + "nonexistent-uuid".to_string(), + ]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_describe_transaction_missing_id() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .describe_transaction(DescribeTransactionRequest { + id: None, + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_describe_transaction_short_id() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .describe_transaction(DescribeTransactionRequest { + id: Some(vec!["only_one_part".to_string()]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + // ── Describe table index stats ───────────────────────────────────── + + #[tokio::test] + async fn test_describe_table_index_stats() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + ns.create_table_scalar_index(CreateTableIndexRequest { + id: tid.clone(), + column: "id".to_string(), + index_type: "btree".to_string(), + name: Some("id_stats_idx".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + let resp = ns + .describe_table_index_stats(DescribeTableIndexStatsRequest { + id: tid, + index_name: Some("id_stats_idx".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.num_indexed_rows.is_some()); + } + + #[tokio::test] + async fn test_describe_table_index_stats_missing_name() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .describe_table_index_stats(DescribeTableIndexStatsRequest { + id: table_id(&["workspace", "test_table"]), + index_name: None, + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + // ── Query table with limit and offset ────────────────────────────── + + #[tokio::test] + async fn test_query_table_with_limit() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .query_table(QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + k: 2, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 2); + } + + #[tokio::test] + async fn test_query_table_with_offset() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .query_table(QueryTableRequest { + id: table_id(&["workspace", "test_table"]), + k: 10, + offset: Some(1), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result), 2); // 3 total, skip 1 + } + + // ── List table versions descending / limit ───────────────────────── + + #[tokio::test] + async fn test_list_table_versions_descending() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + let resp = ns + .list_table_versions(ListTableVersionsRequest { + id: tid.clone(), + descending: Some(true), + ..Default::default() + }) + .await + .unwrap(); + + assert!(resp.versions.len() >= 2); + assert!(resp.versions[0].version >= resp.versions[1].version); + } + + #[tokio::test] + async fn test_list_table_versions_with_limit() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + let resp = ns + .list_table_versions(ListTableVersionsRequest { + id: tid, + limit: Some(1), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.versions.len(), 1); + } + + // ── Create table in nonexistent namespace ────────────────────────── + + #[tokio::test] + async fn test_create_table_in_nonexistent_namespace() { + let (ns, _dir) = create_test_namespace().await; + + let data = create_test_table_data(); + let result = ns + .create_table( + CreateTableRequest { + id: table_id(&["nonexistent_ns", "test_table"]), + ..Default::default() + }, + Bytes::from(data), + ) + .await; + assert!(result.is_err()); + } + + // ── Count rows with empty predicate ──────────────────────────────── + + #[tokio::test] + async fn test_count_table_rows_empty_predicate() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + // Empty string predicate should count all rows (treated as no filter) + let count = ns + .count_table_rows(CountTableRowsRequest { + id: table_id(&["workspace", "test_table"]), + predicate: Some("".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count, 3); + } + + // ── Table ID edge cases ──────────────────────────────────────────── + + #[tokio::test] + async fn test_table_operations_with_none_id() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .table_exists(TableExistsRequest { + id: None, + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_table_operations_with_empty_id() { + let (ns, _dir) = create_test_namespace().await; + + let result = ns + .table_exists(TableExistsRequest { + id: Some(vec![]), + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + // ── Describe table without detailed metadata ─────────────────────── + + #[tokio::test] + async fn test_describe_table_without_detailed_metadata() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let resp = ns + .describe_table(DescribeTableRequest { + id: table_id(&["workspace", "test_table"]), + load_detailed_metadata: Some(false), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.location.is_some()); + assert!(resp.schema.is_none()); // No schema when detailed=false + assert!(resp.version.is_none()); // No version when detailed=false + } + + // ── Rename table edge cases ──────────────────────────────────────── + + #[tokio::test] + async fn test_rename_table_empty_name() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .rename_table(RenameTableRequest { + id: table_id(&["workspace", "test_table"]), + new_table_name: "".to_string(), + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + #[tokio::test] + async fn test_rename_table_target_exists() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "table_a"]).await; + create_test_table(&ns, &["workspace", "table_b"]).await; + + let result = ns + .rename_table(RenameTableRequest { + id: table_id(&["workspace", "table_a"]), + new_table_name: "table_b".to_string(), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("already exists")); + } + + // ── Scalar index type validation ─────────────────────────────────── + + #[tokio::test] + async fn test_create_scalar_index_rejects_vector_type() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .create_table_scalar_index(CreateTableIndexRequest { + id: table_id(&["workspace", "test_table"]), + column: "id".to_string(), + index_type: "IVF_PQ".to_string(), + name: Some("bad_idx".to_string()), + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result + .unwrap_err() + .to_string() + .contains("scalar index types")); + } + + // ── Drop index missing name ──────────────────────────────────────── + + #[tokio::test] + async fn test_drop_table_index_missing_name() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .drop_table_index(DropTableIndexRequest { + id: table_id(&["workspace", "test_table"]), + index_name: None, + ..Default::default() + }) + .await; + assert!(result.is_err()); + } + + // ── Alter columns edge cases ─────────────────────────────────────── + + #[tokio::test] + async fn test_alter_table_add_columns_empty() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .alter_table_add_columns(AlterTableAddColumnsRequest { + id: table_id(&["workspace", "test_table"]), + new_columns: vec![], + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("At least one")); + } + + #[tokio::test] + async fn test_alter_table_drop_columns_empty() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .alter_table_drop_columns(AlterTableDropColumnsRequest { + id: table_id(&["workspace", "test_table"]), + columns: vec![], + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("At least one")); + } + + #[tokio::test] + async fn test_alter_table_alter_columns_empty() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let result = ns + .alter_table_alter_columns(AlterTableAlterColumnsRequest { + id: table_id(&["workspace", "test_table"]), + alterations: vec![], + ..Default::default() + }) + .await; + assert!(result.is_err()); + assert!(result.unwrap_err().to_string().contains("At least one")); + } + + // ── Batch delete table versions ─────────────────────────────────── + + #[tokio::test] + async fn test_batch_delete_table_versions() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Create version 2 and 3 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + // Verify we have at least 3 versions + let versions_before = ns + .list_table_versions(ListTableVersionsRequest { + id: tid.clone(), + ..Default::default() + }) + .await + .unwrap(); + assert!(versions_before.versions.len() >= 3); + + // Delete version 1 only + let resp = ns + .batch_delete_table_versions(BatchDeleteTableVersionsRequest { + id: tid.clone(), + ranges: vec![lance_namespace::models::VersionRange::new(1, 1)], + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.deleted_count.is_some()); + } + + // ── Create table version ────────────────────────────────────────── + + #[tokio::test] + async fn test_create_table_version() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Get the current manifest for version 1 to use as staging data + let version_resp = ns + .describe_table_version(DescribeTableVersionRequest { + id: tid.clone(), + version: Some(1), + ..Default::default() + }) + .await + .unwrap(); + let manifest_path = version_resp.version.manifest_path.clone(); + + // Create version 2 by copying manifest 1 as staging + let resp = ns + .create_table_version(CreateTableVersionRequest { + id: tid.clone(), + version: 2, + manifest_path, + naming_scheme: Some("V2".to_string()), + ..Default::default() + }) + .await + .unwrap(); + assert!(resp.version.is_some()); + let created = resp.version.unwrap(); + assert_eq!(created.version, 2); + assert!(created.manifest_size.is_some()); + } + + // ── FTS / Inverted index creation ───────────────────────────────── + + #[tokio::test] + async fn test_create_inverted_index() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + let resp = ns + .create_table_index(CreateTableIndexRequest { + id: tid.clone(), + column: "name".to_string(), + index_type: "INVERTED".to_string(), + name: Some("name_fts_idx".to_string()), + ..Default::default() + }) + .await + .unwrap(); + // Should have a transaction id from the index creation + assert!(resp.transaction_id.is_some()); + + // Verify the index appears in the list + let indices = ns + .list_table_indices(ListTableIndicesRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert!(indices.indexes.iter().any(|i| i.columns.contains(&"name".to_string()))); + } + + // ── Describe table with specific version ────────────────────────── + + #[tokio::test] + async fn test_describe_table_at_specific_version() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create version 2 with 5 rows + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + // Describe at version 1 + let resp_v1 = ns + .describe_table(DescribeTableRequest { + id: tid.clone(), + version: Some(1), + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp_v1.version, Some(1)); + + // Describe at latest (version 2) + let resp_v2 = ns + .describe_table(DescribeTableRequest { + id: tid, + load_detailed_metadata: Some(true), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp_v2.version, Some(2)); + } + + // ── Query table at specific version ─────────────────────────────── + + #[tokio::test] + async fn test_query_table_at_specific_version() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + // Query at version 1 — should return 3 rows + let result_v1 = ns + .query_table(QueryTableRequest { + id: tid.clone(), + version: Some(1), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result_v1), 3); + + // Query at latest (version 2) — should return 5 rows + let result_v2 = ns + .query_table(QueryTableRequest { + id: tid, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(count_rows_in_ipc(&result_v2), 5); + } + + // ── List table indices pagination ───────────────────────────────── + + #[tokio::test] + async fn test_list_table_indices_pagination() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Create two scalar indices + ns.create_table_scalar_index(CreateTableIndexRequest { + id: tid.clone(), + column: "id".to_string(), + index_type: "btree".to_string(), + name: Some("idx_id".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + ns.create_table_scalar_index(CreateTableIndexRequest { + id: tid.clone(), + column: "name".to_string(), + index_type: "btree".to_string(), + name: Some("idx_name".to_string()), + ..Default::default() + }) + .await + .unwrap(); + + // Page 1: limit 1 + let resp = ns + .list_table_indices(ListTableIndicesRequest { + id: tid.clone(), + limit: Some(1), + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.indexes.len(), 1); + assert!(resp.page_token.is_some()); + + // Page 2: use page token + let resp2 = ns + .list_table_indices(ListTableIndicesRequest { + id: tid, + page_token: resp.page_token, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp2.indexes.len(), 1); + } + + // ── Describe table version without explicit version (latest) ────── + + #[tokio::test] + async fn test_describe_table_version_latest() { + let (ns, _dir) = create_test_namespace().await; + create_namespace(&ns, &["workspace"]).await; + create_test_table(&ns, &["workspace", "test_table"]).await; + + let tid = table_id(&["workspace", "test_table"]); + + // Insert to create version 2 + ns.insert_into_table( + InsertIntoTableRequest { + id: tid.clone(), + ..Default::default() + }, + Bytes::from(create_additional_data()), + ) + .await + .unwrap(); + + // Describe without specifying version — should return latest (2) + let resp = ns + .describe_table_version(DescribeTableVersionRequest { + id: tid, + version: None, + ..Default::default() + }) + .await + .unwrap(); + assert_eq!(resp.version.version, 2); + } +} diff --git a/rust/lance-namespace-base/src/lib.rs b/rust/lance-namespace-base/src/lib.rs new file mode 100644 index 00000000..9f1e49c3 --- /dev/null +++ b/rust/lance-namespace-base/src/lib.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright The Lance Authors + +//! Base Lance Namespace implementation using the Lance SDK directly. +//! +//! This crate provides a filesystem-directory-based implementation of the +//! [`LanceNamespace`] trait that delegates all operations to the Lance Rust SDK +//! (`Dataset`, `Scanner`, index APIs, etc.). +//! +//! ## Features +//! +//! - Hierarchical namespaces mapped to filesystem directories +//! - Tables stored as `{namespace_path}/{table_name}.lance` +//! - No manifest table, credential vending, or context providers +//! - Supports local filesystem and cloud storage via Lance's object store +//! +//! ## Usage +//! +//! ```no_run +//! # use lance_namespace_base::BaseLanceNamespaceBuilder; +//! # async fn example() -> Result<(), Box> { +//! let namespace = BaseLanceNamespaceBuilder::new("/path/to/data") +//! .build() +//! .await?; +//! # Ok(()) +//! # } +//! ``` + +pub mod base; + +pub use base::{BaseLanceNamespace, BaseLanceNamespaceBuilder};