diff --git a/Cargo.lock b/Cargo.lock index 96863853db1..96603f9c24c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -46,9 +46,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -115,22 +115,22 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.11" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -159,12 +159,9 @@ dependencies = [ [[package]] name = "arc-swap" -version = "1.8.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" -dependencies = [ - "rustversion", -] +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] name = "arcref" @@ -651,9 +648,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.36" +version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" +checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" dependencies = [ "compression-codecs", "compression-core", @@ -753,7 +750,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -793,7 +790,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -810,7 +807,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -854,9 +851,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-config" -version = "1.8.12" +version = "1.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96571e6996817bf3d58f6b569e4b9fd2e9d2fcf9f7424eed07b2ce9bb87535e5" +checksum = "37cf2b6af2a95a20e266782b4f76f1a5e12bf412a9db2de9c1e9123b9d8c0ad8" dependencies = [ "aws-credential-types", "aws-runtime", @@ -884,9 +881,9 @@ dependencies = [ [[package]] name = "aws-credential-types" -version = "1.2.11" +version = "1.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cd362783681b15d136480ad555a099e82ecd8e2d10a841e14dfd0078d67fee3" +checksum = "faf26925f4a5b59eb76722b63c2892b1d70d06fa053c72e4a100ec308c1d47bc" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -896,9 +893,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.15.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88aab2464f1f25453baa7a07c84c5b7684e274054ba06817f382357f77a288" +checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786" dependencies = [ "aws-lc-sys", "zeroize", @@ -906,10 +903,11 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.35.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45afffdee1e7c9126814751f88dddc747f41d91da16c9551a0f1e8a11e788a1" +checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd" dependencies = [ + "bindgen", "cc", "cmake", "dunce", @@ -918,9 +916,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.5.17" +version = "1.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81b5b2898f6798ad58f484856768bca817e3cd9de0974c24ae0f1113fe88f1b" +checksum = "bfa006bb32360ed90ac51203feafb9d02e3d21046e1fd3a450a404b90ea73e5d" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -942,9 +940,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.91.0" +version = "1.86.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee6402a36f27b52fe67661c6732d684b2635152b676aa2babbfb5204f99115d" +checksum = "4a0abbfab841446cce6e87af853a3ba2cc1bc9afcd3f3550dd556c43d434c86d" dependencies = [ "aws-credential-types", "aws-runtime", @@ -964,9 +962,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.93.0" +version = "1.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45a7f750bbd170ee3677671ad782d90b894548f4e4ae168302c57ec9de5cb3e" +checksum = "9a68d675582afea0e94d38b6ca9c5aaae4ca14f1d36faa6edb19b42e687e70d7" dependencies = [ "aws-credential-types", "aws-runtime", @@ -986,9 +984,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.95.0" +version = "1.88.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55542378e419558e6b1f398ca70adb0b2088077e79ad9f14eb09441f2f7b2164" +checksum = "d30990923f4f675523c51eb1c0dec9b752fb267b36a61e83cbc219c9d86da715" dependencies = [ "aws-credential-types", "aws-runtime", @@ -1009,9 +1007,9 @@ dependencies = [ [[package]] name = "aws-sigv4" -version = "1.3.7" +version = "1.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e523e1c4e8e7e8ff219d732988e22bfeae8a1cafdbe6d9eca1546fa080be7c" +checksum = "bffc03068fbb9c8dd5ce1c6fb240678a5cffb86fb2b7b1985c999c4b83c8df68" dependencies = [ "aws-credential-types", "aws-smithy-http", @@ -1031,9 +1029,9 @@ dependencies = [ [[package]] name = "aws-smithy-async" -version = "1.2.7" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee19095c7c4dda59f1697d028ce704c24b2d33c6718790c7f1d5a3015b4107c" +checksum = "127fcfad33b7dfc531141fda7e1c402ac65f88aca5511a4d31e2e3d2cd01ce9c" dependencies = [ "futures-util", "pin-project-lite", @@ -1042,16 +1040,15 @@ dependencies = [ [[package]] name = "aws-smithy-http" -version = "0.62.6" +version = "0.62.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" +checksum = "3feafd437c763db26aa04e0cc7591185d0961e64c61885bece0fb9d50ceac671" dependencies = [ "aws-smithy-runtime-api", "aws-smithy-types", "bytes", "bytes-utils", "futures-core", - "futures-util", "http 0.2.12", "http 1.3.1", "http-body 0.4.6", @@ -1063,9 +1060,9 @@ dependencies = [ [[package]] name = "aws-smithy-http-client" -version = "1.1.5" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59e62db736db19c488966c8d787f52e6270be565727236fd5579eaa301e7bc4a" +checksum = "1053b5e587e6fa40ce5a79ea27957b04ba660baa02b28b7436f64850152234f1" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api", @@ -1087,27 +1084,27 @@ dependencies = [ [[package]] name = "aws-smithy-json" -version = "0.61.9" +version = "0.61.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" +checksum = "cff418fc8ec5cadf8173b10125f05c2e7e1d46771406187b2c878557d4503390" dependencies = [ "aws-smithy-types", ] [[package]] name = "aws-smithy-observability" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17f616c3f2260612fe44cede278bafa18e73e6479c4e393e2c4518cf2a9a228a" +checksum = "2d1881b1ea6d313f9890710d65c158bdab6fb08c91ea825f74c1c8c357baf4cc" dependencies = [ "aws-smithy-runtime-api", ] [[package]] name = "aws-smithy-query" -version = "0.60.9" +version = "0.60.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae5d689cf437eae90460e944a58b5668530d433b4ff85789e69d2f2a556e057d" +checksum = "d28a63441360c477465f80c7abac3b9c4d075ca638f982e605b7dc2a2c7156c9" dependencies = [ "aws-smithy-types", "urlencoding", @@ -1115,9 +1112,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime" -version = "1.9.5" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a392db6c583ea4a912538afb86b7be7c5d8887d91604f50eb55c262ee1b4a5f5" +checksum = "40ab99739082da5347660c556689256438defae3bcefd66c52b095905730e404" dependencies = [ "aws-smithy-async", "aws-smithy-http", @@ -1139,9 +1136,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.9.3" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0d43d899f9e508300e587bf582ba54c27a452dd0a9ea294690669138ae14a2" +checksum = "3683c5b152d2ad753607179ed71988e8cfd52964443b4f74fd8e552d0bbfeb46" dependencies = [ "aws-smithy-async", "aws-smithy-types", @@ -1156,9 +1153,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.3.5" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905cb13a9895626d49cf2ced759b062d913834c7482c38e49557eac4e6193f01" +checksum = "9f5b3a7486f6690ba25952cabf1e7d75e34d69eaff5081904a47bc79074d6457" dependencies = [ "base64-simd", "bytes", @@ -1179,18 +1176,18 @@ dependencies = [ [[package]] name = "aws-smithy-xml" -version = "0.60.13" +version = "0.60.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11b2f670422ff42bf7065031e72b45bc52a3508bd089f743ea90731ca2b6ea57" +checksum = "e9c34127e8c624bc2999f3b657e749c1393bedc9cd97b92a804db8ced4d2e163" dependencies = [ "xmlparser", ] [[package]] name = "aws-types" -version = "1.3.11" +version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d980627d2dd7bfc32a3c025685a033eeab8d365cc840c631ef59d1b8f428164" +checksum = "e2fd329bf0e901ff3f60425691410c69094dc2a1f34b331f37bfc4e9ac1565a1" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1202,9 +1199,9 @@ dependencies = [ [[package]] name = "backon" -version = "1.6.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" +checksum = "592277618714fbcecda9a02ba7a8781f319d26532a88553bbacc77ba5d2b3a8d" dependencies = [ "fastrand", "gloo-timers", @@ -1229,21 +1226,21 @@ dependencies = [ [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" [[package]] name = "better_io" -version = "0.2.0" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef0a3155e943e341e557863e69a708999c94ede624e37865c8e2a91b94efa78f" +checksum = "92fde17f91e7ba10b2a07f8dff29530b77144894bc6ae850fbc66e1276af0d28" [[package]] name = "bigdecimal" -version = "0.4.10" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6867f1565b3aad85681f1015055b087fcfd840d6aeee6eee7f2da317603695" +checksum = "1a22f228ab7a1b23027ccc6c350b72868017af7ea8356fbdf19f8d991c690013" dependencies = [ "autocfg", "libm", @@ -1269,7 +1266,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -1401,7 +1398,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -1424,7 +1421,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -1450,9 +1447,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4" dependencies = [ "memchr", "regex-automata", @@ -1580,16 +1577,16 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.110", + "syn 2.0.114", "tempfile", "toml", ] [[package]] name = "cc" -version = "1.2.51" +version = "1.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a" dependencies = [ "find-msvc-tools", "jobserver", @@ -1677,9 +1674,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.54" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6e6ff9dcd79cff5cd969a17a545d79e84ab086e444102a591e288a8aa3ce394" +checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" dependencies = [ "clap_builder", "clap_derive", @@ -1687,9 +1684,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.54" +version = "4.5.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa42cf4d2b7a41bc8f663a7cab4031ebafa1bf3875705bfaf8466dc60ab52c00" +checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" dependencies = [ "anstream", "anstyle", @@ -1707,20 +1704,20 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cmake" -version = "0.1.57" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" dependencies = [ "cc", ] @@ -1738,9 +1735,9 @@ dependencies = [ [[package]] name = "codspeed" -version = "4.2.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0d98d97fd75ca4489a1a0997820a6521531085e7c8a98941bd0e1264d567dd" +checksum = "c3b847e05a34be5c38f3f2a5052178a3bd32e6b5702f3ea775efde95c483a539" dependencies = [ "anyhow", "cc", @@ -1756,9 +1753,9 @@ dependencies = [ [[package]] name = "codspeed-divan-compat" -version = "4.2.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4179ec5518e79efcd02ed50aa483ff807902e43c85146e87fff58b9cffc06078" +checksum = "f0f0e9fe5eaa39995ec35e46407f7154346cc25bd1300c64c21636f3d00cb2cc" dependencies = [ "clap", "codspeed", @@ -1769,23 +1766,23 @@ dependencies = [ [[package]] name = "codspeed-divan-compat-macros" -version = "4.2.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15eaee97aa5bceb32cc683fe25cd6373b7fc48baee5c12471996b58b6ddf0d7c" +checksum = "88c8babf2a40fd2206a2e030cf020d0d58144cd56e1dc408bfba02cdefb08b4f" dependencies = [ "divan-macros", "itertools 0.14.0", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "codspeed-divan-compat-walltime" -version = "4.2.1" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c38671153aa73be075d6019cab5ab1e6b31d36644067c1ac4cef73bf9723ce33" +checksum = "7f26092328e12a36704ffc552f379c6405dd94d3149970b79b22d371717c2aae" dependencies = [ "cfg-if", "clap", @@ -1861,7 +1858,7 @@ dependencies = [ "indicatif", "itertools 0.14.0", "lance-bench", - "parquet 57.0.0", + "parquet 57.1.0", "regex", "serde", "tokio", @@ -1872,9 +1869,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.35" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" +checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" dependencies = [ "compression-core", "flate2", @@ -1883,9 +1880,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.31" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" +checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" [[package]] name = "concurrent-queue" @@ -2031,9 +2028,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.4.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -2140,9 +2137,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -2160,30 +2157,30 @@ dependencies = [ [[package]] name = "csv" -version = "1.4.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52cd9d68cf7efc6ddfaaee42e7288d3a99d613d4b50f76ce9827ae0c6e14f938" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" dependencies = [ "csv-core", "itoa", "ryu", - "serde_core", + "serde", ] [[package]] name = "csv-core" -version = "0.1.13" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704a3c26996a80471189265814dbc2c257598b96b8a7feae2d31ace646bb9782" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" dependencies = [ "memchr", ] [[package]] name = "cudarc" -version = "0.18.2" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aa12038120eb13347a6ae2ffab1d34efe78150125108627fd85044dd4d6ff1e" +checksum = "ef0cfc5e22a6b6f7d04ee45b0151232ca236ede8ca3534210fd4072bdead0d60" dependencies = [ "half", "libloading 0.8.9", @@ -2191,9 +2188,9 @@ dependencies = [ [[package]] name = "cxx" -version = "1.0.192" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbda285ba6e5866529faf76352bdf73801d9b44a6308d7cd58ca2379f378e994" +checksum = "a7620f6cfc4dcca21f2b085b7a890e16c60fd66f560cd69ee60594908dc72ab1" dependencies = [ "cc", "cxx-build", @@ -2206,9 +2203,9 @@ dependencies = [ [[package]] name = "cxx-build" -version = "1.0.192" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9efde466c5d532d57efd92f861da3bdb7f61e369128ce8b4c3fe0c9de4fa4d" +checksum = "7a9bc1a22964ff6a355fbec24cf68266a0ed28f8b84c0864c386474ea3d0e479" dependencies = [ "cc", "codespan-reporting", @@ -2216,39 +2213,39 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "cxxbridge-cmd" -version = "1.0.192" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3efb93799095bccd4f763ca07997dc39a69e5e61ab52d2c407d4988d21ce144d" +checksum = "b1f29a879d35f7906e3c9b77d7a1005a6a0787d330c09dfe4ffb5f617728cb44" dependencies = [ "clap", "codespan-reporting", "indexmap", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "cxxbridge-flags" -version = "1.0.192" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3092010228026e143b32a4463ed9fa8f86dca266af4bf5f3b2a26e113dbe4e45" +checksum = "d67109015f93f683e364085aa6489a5b2118b4a40058482101d699936a7836d6" [[package]] name = "cxxbridge-macro" -version = "1.0.192" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31d72ebfcd351ae404fb00ff378dfc9571827a00722c9e735c9181aec320ba0a" +checksum = "d187e019e7b05a1f3e69a8396b70800ee867aa9fc2ab972761173ccee03742df" dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -2282,7 +2279,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -2296,7 +2293,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -2307,7 +2304,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -2318,7 +2315,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -2425,7 +2422,7 @@ dependencies = [ "log", "object_store", "parking_lot", - "parquet 57.0.0", + "parquet 57.1.0", "rand 0.9.2", "regex", "rstest", @@ -2596,7 +2593,7 @@ dependencies = [ "libc", "log", "object_store", - "parquet 57.0.0", + "parquet 57.1.0", "paste", "sqlparser 0.59.0", "tokio", @@ -2828,7 +2825,7 @@ dependencies = [ "log", "object_store", "parking_lot", - "parquet 57.0.0", + "parquet 57.1.0", "tokio", ] @@ -3217,7 +3214,7 @@ checksum = "ec6f637bce95efac05cdfb9b6c19579ed4aa5f6b94d951cfa5bb054b7bb4f730" dependencies = [ "datafusion-expr 50.3.0", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3228,7 +3225,7 @@ checksum = "1063ad4c9e094b3f798acee16d9a47bd7372d9699be2de21b05c3bd3f34ab848" dependencies = [ "datafusion-doc 51.0.0", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3622,9 +3619,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", "serde_core", @@ -3638,7 +3635,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3659,7 +3656,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3703,7 +3700,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3714,7 +3711,7 @@ checksum = "8dc51d98e636f5e3b0759a39257458b22619cac7e96d932da6eeb052891bb67c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -3728,9 +3725,9 @@ dependencies = [ [[package]] name = "document-features" -version = "0.2.12" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ "litrs", ] @@ -3813,14 +3810,14 @@ checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "env_filter" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ "log", "regex", @@ -3899,9 +3896,9 @@ dependencies = [ [[package]] name = "exponential-decay-histogram" -version = "0.1.14" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7962d7e9baab6ea05af175491fa6a8441f3bf461558037622142573d98dd6d6" +checksum = "988360e80225a42d5e2f78fcb90ef7d54d1e4394d335476b5465d34942426776" dependencies = [ "ordered-float 5.1.0", "rand 0.9.2", @@ -3990,9 +3987,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "finl_unicode" @@ -4037,9 +4034,9 @@ dependencies = [ [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "libz-rs-sys", @@ -4204,7 +4201,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -4254,24 +4251,23 @@ dependencies = [ [[package]] name = "generator" -version = "0.8.8" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" dependencies = [ "cc", "cfg-if", "libc", "log", "rustversion", - "windows-link 0.2.1", - "windows-result 0.3.4", + "windows", ] [[package]] name = "generic-array" -version = "0.14.7" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +checksum = "1dc8f7d2ded5f9209535e4b3fd4d39c002f30902ff5ce9f64e2c33d549576500" dependencies = [ "typenum", "version_check", @@ -4348,9 +4344,9 @@ checksum = "f9e2d4c0a8296178d8802098410ca05d86b17a10bb5ab559b3fb404c1f948220" [[package]] name = "h2" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" +checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" dependencies = [ "atomic-waker", "bytes", @@ -4455,11 +4451,11 @@ dependencies = [ [[package]] name = "home" -version = "0.5.12" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -4547,9 +4543,9 @@ checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "1.8.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" dependencies = [ "atomic-waker", "bytes", @@ -4603,9 +4599,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" dependencies = [ "base64", "bytes", @@ -4619,7 +4615,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2 0.6.0", "system-configuration", "tokio", "tower-service", @@ -4662,9 +4658,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", "potential_utf", @@ -4675,9 +4671,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -4688,10 +4684,11 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ + "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -4702,38 +4699,42 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +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.1.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "2.1.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", "icu_locale_core", + "stable_deref_trait", + "tinystr", "writeable", "yoke", "zerofrom", @@ -4785,14 +4786,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -4814,12 +4815,9 @@ dependencies = [ [[package]] name = "indoc" -version = "2.0.7" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" [[package]] name = "inout" @@ -4833,14 +4831,13 @@ dependencies = [ [[package]] name = "insta" -version = "1.46.0" +version = "1.44.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b66886d14d18d420ab5052cbff544fc5d34d0b2cdd35eb5976aaa10a4a472e5" +checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698" dependencies = [ "console 0.15.11", "once_cell", "similar", - "tempfile", ] [[package]] @@ -4853,7 +4850,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -4879,9 +4876,9 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.10" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" dependencies = [ "memchr", "serde", @@ -4889,9 +4886,9 @@ dependencies = [ [[package]] name = "is_terminal_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" @@ -4937,9 +4934,9 @@ dependencies = [ [[package]] name = "jiff" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a87d9b8105c23642f50cbbae03d1f75d8422c5cb98ce7ee9271f7ff7505be6b8" +checksum = "49cce2b81f2098e7e3efc35bc2e0a6b7abec9d34128283d7a26fa8f32a6dbb35" dependencies = [ "jiff-static", "jiff-tzdb-platform", @@ -4952,13 +4949,13 @@ dependencies = [ [[package]] name = "jiff-static" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b787bebb543f8969132630c51fd0afab173a86c6abae56ff3b9e5e3e3f9f6e58" +checksum = "980af8b43c3ad5d8d349ace167ec8170839f753a42d233ba19e08afe1850fa69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -5012,9 +5009,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" dependencies = [ "once_cell", "wasm-bindgen", @@ -5022,9 +5019,9 @@ dependencies = [ [[package]] name = "jsonb" -version = "0.5.5" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a901f06163d352fbe41c3c2ff5e08b75330a003cc941e988fb501022f5421e6" +checksum = "a452366d21e8d3cbca680c41388e01d6a88739afef7877961946a6da409f9ccd" dependencies = [ "byteorder", "ethnum", @@ -5704,9 +5701,9 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.12" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ "bitflags 2.10.0", "libc", @@ -5753,15 +5750,15 @@ checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "litrs" -version = "1.0.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" [[package]] name = "lock_api" @@ -5774,9 +5771,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.29" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "loom" @@ -6002,14 +5999,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.61.2", + "windows-sys 0.59.0", ] [[package]] @@ -6020,9 +6017,9 @@ checksum = "dce6dd36094cac388f119d2e9dc82dc730ef91c32a6222170d630e5414b956e6" [[package]] name = "moka" -version = "0.12.12" +version = "0.12.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3dec6bd31b08944e08b58fd99373893a6c17054d6f3ea5006cc894f4f4eee2a" +checksum = "8261cd88c312e0004c1d51baad2980c66528dfdb2bee62003e643a4d8f86b077" dependencies = [ "async-lock", "crossbeam-channel", @@ -6033,6 +6030,7 @@ dependencies = [ "futures-util", "parking_lot", "portable-atomic", + "rustc_version", "smallvec", "tagptr", "uuid", @@ -6062,7 +6060,7 @@ checksum = "b093064383341eb3271f42e381cb8f10a01459478446953953c75d24bd339fc0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", "target-features", ] @@ -6081,7 +6079,7 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe 0.1.6", + "openssl-probe", "openssl-sys", "schannel", "security-framework 2.11.1", @@ -6246,9 +6244,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.4.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ "winapi", ] @@ -6288,10 +6286,11 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.6" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" dependencies = [ + "byteorder", "lazy_static", "libm", "num-integer", @@ -6325,7 +6324,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -6397,7 +6396,7 @@ checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -6449,7 +6448,7 @@ dependencies = [ "md-5", "parking_lot", "percent-encoding", - "quick-xml 0.38.4", + "quick-xml 0.38.3", "rand 0.9.2", "reqwest", "ring", @@ -6468,9 +6467,9 @@ dependencies = [ [[package]] name = "object_store_opendal" -version = "0.54.1" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b88fc0e0c4890c1d99e2b8c519c5db40f7d9b69a0f562ff1ad4967a4c8bbc6" +checksum = "5ce697ee723fdc3eaf6c457abf4059034be15167022b18b619993802cd1443d5" dependencies = [ "async-trait", "bytes", @@ -6492,9 +6491,9 @@ dependencies = [ [[package]] name = "once_cell_polyfill" -version = "1.70.2" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "oneshot" @@ -6504,9 +6503,9 @@ checksum = "b4ce411919553d3f9fa53a0880544cda985a112117a0444d5ff1e870a893d6ea" [[package]] name = "opendal" -version = "0.54.1" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42afda58fa2cf50914402d132cc1caacff116a85d10c72ab2082bb7c50021754" +checksum = "ffb9838d0575c6dbaf3fcec7255af8d5771996d4af900bbb6fa9a314dec00a1a" dependencies = [ "anyhow", "backon", @@ -6521,7 +6520,7 @@ dependencies = [ "log", "md-5", "percent-encoding", - "quick-xml 0.38.4", + "quick-xml 0.37.5", "reqsign", "reqwest", "serde", @@ -6554,7 +6553,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -6563,12 +6562,6 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" -[[package]] -name = "openssl-probe" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" - [[package]] name = "openssl-sys" version = "0.9.111" @@ -6747,7 +6740,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -6814,9 +6807,9 @@ dependencies = [ [[package]] name = "parquet" -version = "57.0.0" +version = "57.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a0f31027ef1af7549f7cec603a9a21dce706d3f8d7c2060a68f43c1773be95a" +checksum = "be3e4f6d320dd92bfa7d612e265d7d08bba0a240bab86af3425e1d255a511d89" dependencies = [ "ahash 0.8.12", "arrow-array 57.1.0", @@ -6834,7 +6827,7 @@ dependencies = [ "futures", "half", "hashbrown 0.16.1", - "lz4_flex 0.11.5", + "lz4_flex 0.12.0", "num-bigint", "num-integer", "num-traits", @@ -6879,9 +6872,9 @@ dependencies = [ [[package]] name = "pco" -version = "0.4.9" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42382de9fb564e2d10cb4d5ca97cc06d928f0f9667bbef456b57e60827b6548b" +checksum = "daea1197f2969fab4d5c6620eade5d46c98a8e9b04ad2bc3725fc5dfc4eb8a49" dependencies = [ "better_io", "dtype_dispatch", @@ -6950,7 +6943,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7034,7 +7027,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7072,7 +7065,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7190,9 +7183,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "84df19adbe5b5a0782edcab45899906947ab039ccf4573713735ee7de1e6b08a" dependencies = [ "zerovec", ] @@ -7205,9 +7198,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppmd-rust" -version = "1.3.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d558c559f0450f16f2a27a1f017ef38468c1090c9ce63c8e51366232d53717b4" +checksum = "c834641d8ad1b348c9ee86dec3b9840d805acd5f24daa5f90c788951a52ff59b" [[package]] name = "ppv-lite86" @@ -7225,7 +7218,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7267,14 +7260,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -7325,7 +7318,7 @@ dependencies = [ "prost 0.13.5", "prost-types 0.13.5", "regex", - "syn 2.0.110", + "syn 2.0.114", "tempfile", ] @@ -7345,7 +7338,7 @@ dependencies = [ "prost 0.14.1", "prost-types 0.14.1", "regex", - "syn 2.0.110", + "syn 2.0.114", "tempfile", ] @@ -7359,7 +7352,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7372,7 +7365,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7385,7 +7378,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7492,7 +7485,7 @@ dependencies = [ "proc-macro2", "pyo3-macros-backend", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7505,7 +7498,7 @@ dependencies = [ "proc-macro2", "pyo3-build-config", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7520,9 +7513,9 @@ dependencies = [ [[package]] name = "quick-xml" -version = "0.38.4" +version = "0.38.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" dependencies = [ "memchr", "serde", @@ -7541,7 +7534,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls", - "socket2 0.6.1", + "socket2 0.6.0", "thiserror 2.0.17", "tokio", "tracing", @@ -7578,16 +7571,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.0", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -7729,9 +7722,9 @@ dependencies = [ [[package]] name = "rangemap" -version = "1.7.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68" +checksum = "f93e7e49bb0bf967717f7bd674458b3d6b0c5f48ec7e3038166026a69fc22223" [[package]] name = "ratatui" @@ -7881,7 +7874,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -7898,9 +7891,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", @@ -7915,9 +7908,9 @@ checksum = "8d942b98df5e658f56f20d592c7f868833fe38115e65c33003d8cd224b0155da" [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "c3160422bbd54dd5ecfdca71e5fd59b7b8fe2b1697ab2baf64f6d05dcc66d298" [[package]] name = "relative-path" @@ -7968,10 +7961,11 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.28" +version = "0.12.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", @@ -8071,9 +8065,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.11.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba9ce64a8f45d7fc86358410bb1a82e8c987504c0d4900e9141d69a9f26c885" +checksum = "f08d6a905edb32d74a5d5737a0c9d7e950c312f3c46cb0ca0a2ca09ea11878a0" dependencies = [ "bytemuck", "byteorder", @@ -8081,9 +8075,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.10" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" dependencies = [ "const-oid", "digest", @@ -8125,7 +8119,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.110", + "syn 2.0.114", "unicode-ident", ] @@ -8137,7 +8131,7 @@ checksum = "b3a8fb4672e840a587a66fc577a5491375df51ddb88f2a2c2a792598c326fe14" dependencies = [ "quote", "rand 0.8.5", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -8225,9 +8219,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.36" +version = "0.23.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" +checksum = "cd3c25631629d034ce7cd9940adc9d45762d46de2b0f57193c4443b92c6d4d40" dependencies = [ "aws-lc-rs", "once_cell", @@ -8240,11 +8234,11 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" dependencies = [ - "openssl-probe 0.2.0", + "openssl-probe", "rustls-pki-types", "schannel", "security-framework 3.5.1", @@ -8261,9 +8255,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" dependencies = [ "web-time", "zeroize", @@ -8271,9 +8265,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "e10b3f4191e8a80e6b43eebabfac91e5dcecebb27a71f04e820c47ec41d314bf" dependencies = [ "aws-lc-rs", "ring", @@ -8452,20 +8446,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.148" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", + "ryu", "serde", "serde_core", - "zmij", ] [[package]] @@ -8476,14 +8470,14 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -8567,9 +8561,9 @@ dependencies = [ [[package]] name = "signal-hook-mio" -version = "0.2.5" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" dependencies = [ "libc", "mio", @@ -8578,9 +8572,9 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" dependencies = [ "libc", ] @@ -8710,7 +8704,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -8731,12 +8725,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.59.0", ] [[package]] @@ -8783,7 +8777,7 @@ checksum = "da5fc6819faabb412da764b99d3b713bb55083c11e7e0c00144d386cd6a1939c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -8854,7 +8848,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -8866,7 +8860,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -8888,9 +8882,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.110" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -8914,7 +8908,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -9160,9 +9154,9 @@ checksum = "c1bbb9f3c5c463a01705937a24fdabc5047929ac764b2d5b9cf681c1f5041ed5" [[package]] name = "target-lexicon" -version = "0.13.4" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1dd07eb858a2067e2f3c7155d54e929265c264e6f37efe3ee7a8d1b5a1dd0ba" +checksum = "df7f62577c25e07834649fc3b39fafdc597c0a3527dc1c60129201ccfcbaa50c" [[package]] name = "tempfile" @@ -9280,7 +9274,7 @@ dependencies = [ "quote", "regex", "reqwest", - "syn 2.0.110", + "syn 2.0.114", "sysinfo 0.35.2", "uzers", "which", @@ -9321,7 +9315,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -9332,7 +9326,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -9418,9 +9412,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -9453,7 +9447,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.0", "tokio-macros", "windows-sys 0.61.2", ] @@ -9466,7 +9460,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -9491,9 +9485,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.18" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -9502,9 +9496,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.18" +version = "0.7.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" dependencies = [ "bytes", "futures-core", @@ -9560,9 +9554,9 @@ dependencies = [ [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" [[package]] name = "tonic" @@ -9613,22 +9607,17 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.8" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" dependencies = [ - "async-compression", "bitflags 2.10.0", "bytes", - "futures-core", "futures-util", "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", @@ -9664,9 +9653,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -9682,14 +9671,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.36" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -9782,15 +9771,15 @@ dependencies = [ [[package]] name = "unicase" -version = "2.9.0" +version = "2.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-segmentation" @@ -9829,9 +9818,9 @@ checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3" [[package]] name = "unit-prefix" -version = "0.5.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" +checksum = "323402cff2dd658f39ca17c789b502021b3f18707c91cdf22e3838e1b4023817" [[package]] name = "untrusted" @@ -9932,7 +9921,7 @@ dependencies = [ "fastlanes", "itertools 0.14.0", "mimalloc", - "parquet 57.0.0", + "parquet 57.1.0", "rand 0.9.2", "serde_json", "tokio", @@ -10074,7 +10063,7 @@ dependencies = [ "noodles-bgzf", "noodles-vcf", "parking_lot", - "parquet 57.0.0", + "parquet 57.1.0", "rand 0.9.2", "regex", "reqwest", @@ -10712,7 +10701,7 @@ dependencies = [ "futures", "itertools 0.14.0", "parking_lot", - "roaring 0.11.3", + "roaring 0.11.2", "sketches-ddsketch", "tracing", "vortex-array", @@ -10779,8 +10768,11 @@ name = "vortex-tui" version = "0.1.0" dependencies = [ "anyhow", + "arrow-array 57.1.0", + "arrow-schema 57.1.0", "clap", "crossterm", + "datafusion 51.0.0", "env_logger", "flatbuffers", "futures", @@ -10788,11 +10780,14 @@ dependencies = [ "humansize", "indicatif", "itertools 0.14.0", - "parquet 57.0.0", + "parquet 57.1.0", "ratatui", + "serde", + "serde_json", "taffy", "tokio", "vortex", + "vortex-datafusion", ] [[package]] @@ -10901,9 +10896,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" dependencies = [ "cfg-if", "once_cell", @@ -10914,9 +10909,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" dependencies = [ "cfg-if", "js-sys", @@ -10927,9 +10922,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10937,22 +10932,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" dependencies = [ "unicode-ident", ] @@ -10972,9 +10967,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.83" +version = "0.3.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -10992,9 +10987,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.5" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" +checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" dependencies = [ "rustls-pki-types", ] @@ -11144,8 +11139,8 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", + "windows-result", + "windows-strings", ] [[package]] @@ -11167,7 +11162,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -11178,7 +11173,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -11205,13 +11200,13 @@ dependencies = [ [[package]] name = "windows-registry" -version = "0.6.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" +checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", + "windows-link 0.1.3", + "windows-result", + "windows-strings", ] [[package]] @@ -11223,15 +11218,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link 0.2.1", -] - [[package]] name = "windows-strings" version = "0.4.2" @@ -11241,15 +11227,6 @@ dependencies = [ "windows-link 0.1.3", ] -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link 0.2.1", -] - [[package]] name = "windows-sys" version = "0.45.0" @@ -11526,9 +11503,9 @@ dependencies = [ [[package]] name = "writeable" -version = "0.6.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "wyz" @@ -11584,10 +11561,11 @@ checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" [[package]] name = "yoke" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ + "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -11595,34 +11573,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.28" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.28" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -11642,7 +11620,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", "synstructure", ] @@ -11657,20 +11635,20 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] name = "zerotrie" -version = "0.2.3" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" dependencies = [ "displaydoc", "yoke", @@ -11679,9 +11657,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.5" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -11690,13 +11668,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.114", ] [[package]] @@ -11741,17 +11719,11 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f06ae92f42f5e5c42443fd094f245eb656abf56dd7cce9b8b263236565e00f2" -[[package]] -name = "zmij" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e0d8dffbae3d840f64bda38e28391faef673a7b5a6017840f2a106c8145868" - [[package]] name = "zopfli" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" +checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" dependencies = [ "bumpalo", "crc32fast", diff --git a/vortex-tui/Cargo.toml b/vortex-tui/Cargo.toml index 30cc3f974b4..919298afff6 100644 --- a/vortex-tui/Cargo.toml +++ b/vortex-tui/Cargo.toml @@ -15,8 +15,11 @@ version = { workspace = true } [dependencies] anyhow = { workspace = true } +arrow-array = { workspace = true } +arrow-schema = { workspace = true } clap = { workspace = true, features = ["derive"] } crossterm = { workspace = true } +datafusion = { workspace = true } env_logger = { version = "0.11" } flatbuffers = { workspace = true } futures = { workspace = true, features = ["executor"] } @@ -26,9 +29,12 @@ indicatif = { workspace = true, features = ["futures"] } itertools = { workspace = true } parquet = { workspace = true, features = ["arrow", "async"] } ratatui = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } taffy = { workspace = true } tokio = { workspace = true, features = ["rt-multi-thread"] } vortex = { workspace = true, features = ["tokio"] } +vortex-datafusion = { workspace = true } [lints] workspace = true diff --git a/vortex-tui/src/browse/app.rs b/vortex-tui/src/browse/app.rs index c9e079b91a9..869c89d33ff 100644 --- a/vortex-tui/src/browse/app.rs +++ b/vortex-tui/src/browse/app.rs @@ -25,6 +25,7 @@ use vortex::layout::segments::SegmentId; use vortex::layout::segments::SegmentSource; use vortex::session::VortexSession; +use super::ui::QueryState; use super::ui::SegmentGridState; /// The currently active tab in the TUI browser. @@ -41,6 +42,9 @@ pub enum Tab { /// /// Displays a visual representation of how segments are laid out in the file. Segments, + + /// SQL query interface powered by DataFusion. + Query, } /// A navigable pointer into the layout hierarchy of a Vortex file. @@ -254,6 +258,12 @@ pub struct AppState<'a> { /// Vertical scroll offset for the encoding tree display in flat layout view. pub tree_scroll_offset: u16, + + /// State for the Query tab + pub query_state: QueryState, + + /// File path for use in query execution + pub file_path: String, } impl<'a> AppState<'a> { @@ -270,6 +280,12 @@ impl<'a> AppState<'a> { let cursor = LayoutCursor::new(vxf.footer().clone(), vxf.segment_source()); + let file_path = path + .as_ref() + .to_str() + .map(|s| s.to_string()) + .unwrap_or_default(); + Ok(AppState { session, vxf, @@ -282,6 +298,8 @@ impl<'a> AppState<'a> { segment_grid_state: SegmentGridState::default(), frame_size: Size::new(0, 0), tree_scroll_offset: 0, + query_state: QueryState::default(), + file_path, }) } diff --git a/vortex-tui/src/browse/mod.rs b/vortex-tui/src/browse/mod.rs index 63299af6b3e..adeb0bb4da0 100644 --- a/vortex-tui/src/browse/mod.rs +++ b/vortex-tui/src/browse/mod.rs @@ -14,6 +14,8 @@ use crossterm::event::KeyCode; use crossterm::event::KeyEventKind; use crossterm::event::KeyModifiers; use ratatui::DefaultTerminal; +use ui::QueryFocus; +use ui::SortDirection; use ui::render_app; use vortex::error::VortexExpect; use vortex::error::VortexResult; @@ -81,10 +83,62 @@ fn navigate_layout_down(app: &mut AppState, amount: usize) { } } +#[allow(clippy::cognitive_complexity)] fn handle_normal_mode(app: &mut AppState, event: Event) -> HandleResult { if let Event::Key(key) = event && key.kind == KeyEventKind::Press { + // Check if we're in Query tab with SQL input focus - handle text input first + let in_sql_input = + app.current_tab == Tab::Query && app.query_state.focus == QueryFocus::SqlInput; + + // Handle SQL input mode - most keys should type into the input + if in_sql_input { + match (key.code, key.modifiers) { + // These keys exit/switch even in SQL input mode + (KeyCode::Tab, _) => { + app.current_tab = Tab::Layout; + } + (KeyCode::Esc, _) => { + app.query_state.toggle_focus(); + } + (KeyCode::Enter, _) => { + // Execute the SQL query with COUNT(*) for pagination + app.query_state.sort_column = None; + app.query_state.sort_direction = SortDirection::None; + let file_path = app.file_path.clone(); + app.query_state + .execute_initial_query(app.session, &file_path); + // Switch focus to results table after executing + app.query_state.focus = QueryFocus::ResultsTable; + } + // Navigation keys + (KeyCode::Left, _) => app.query_state.move_cursor_left(), + (KeyCode::Right, _) => app.query_state.move_cursor_right(), + (KeyCode::Home, _) => app.query_state.move_cursor_start(), + (KeyCode::End, _) => app.query_state.move_cursor_end(), + // Control key shortcuts + (KeyCode::Char('a'), KeyModifiers::CONTROL) => app.query_state.move_cursor_start(), + (KeyCode::Char('e'), KeyModifiers::CONTROL) => app.query_state.move_cursor_end(), + (KeyCode::Char('u'), KeyModifiers::CONTROL) => app.query_state.clear_input(), + (KeyCode::Char('b'), KeyModifiers::CONTROL) => app.query_state.move_cursor_left(), + (KeyCode::Char('f'), KeyModifiers::CONTROL) => app.query_state.move_cursor_right(), + (KeyCode::Char('d'), KeyModifiers::CONTROL) => { + app.query_state.delete_char_forward() + } + // Delete keys + (KeyCode::Backspace, _) => app.query_state.delete_char(), + (KeyCode::Delete, _) => app.query_state.delete_char_forward(), + // All other characters get typed into the input + (KeyCode::Char(c), KeyModifiers::NONE | KeyModifiers::SHIFT) => { + app.query_state.insert_char(c); + } + _ => {} + } + return HandleResult::Continue; + } + + // Normal mode handling for all other cases match (key.code, key.modifiers) { (KeyCode::Char('q'), _) => { return HandleResult::Exit; @@ -92,30 +146,62 @@ fn handle_normal_mode(app: &mut AppState, event: Event) -> HandleResult { (KeyCode::Tab, _) => { app.current_tab = match app.current_tab { Tab::Layout => Tab::Segments, - Tab::Segments => Tab::Layout, + Tab::Segments => Tab::Query, + Tab::Query => Tab::Layout, }; } + + // Query tab: '[' for previous page + (KeyCode::Char('['), KeyModifiers::NONE) => { + if app.current_tab == Tab::Query { + app.query_state + .prev_page(app.session, &app.file_path.clone()); + } + } + + // Query tab: ']' for next page + (KeyCode::Char(']'), KeyModifiers::NONE) => { + if app.current_tab == Tab::Query { + app.query_state + .next_page(app.session, &app.file_path.clone()); + } + } + (KeyCode::Up | KeyCode::Char('k'), _) | (KeyCode::Char('p'), KeyModifiers::CONTROL) => { match app.current_tab { Tab::Layout => navigate_layout_up(app, SCROLL_LINE), Tab::Segments => app.segment_grid_state.scroll_up(SEGMENT_SCROLL_LINE), + Tab::Query => { + app.query_state.table_state.select_previous(); + } } } (KeyCode::Down | KeyCode::Char('j'), _) | (KeyCode::Char('n'), KeyModifiers::CONTROL) => match app.current_tab { Tab::Layout => navigate_layout_down(app, SCROLL_LINE), Tab::Segments => app.segment_grid_state.scroll_down(SEGMENT_SCROLL_LINE), + Tab::Query => { + app.query_state.table_state.select_next(); + } }, (KeyCode::PageUp, _) | (KeyCode::Char('v'), KeyModifiers::ALT) => { match app.current_tab { Tab::Layout => navigate_layout_up(app, SCROLL_PAGE), Tab::Segments => app.segment_grid_state.scroll_up(SEGMENT_SCROLL_PAGE), + Tab::Query => { + app.query_state + .prev_page(app.session, &app.file_path.clone()); + } } } (KeyCode::PageDown, _) | (KeyCode::Char('v'), KeyModifiers::CONTROL) => { match app.current_tab { Tab::Layout => navigate_layout_down(app, SCROLL_PAGE), Tab::Segments => app.segment_grid_state.scroll_down(SEGMENT_SCROLL_PAGE), + Tab::Query => { + app.query_state + .next_page(app.session, &app.file_path.clone()); + } } } (KeyCode::Home, _) | (KeyCode::Char('<'), KeyModifiers::ALT) => match app.current_tab { @@ -123,12 +209,18 @@ fn handle_normal_mode(app: &mut AppState, event: Event) -> HandleResult { Tab::Segments => app .segment_grid_state .scroll_left(SEGMENT_SCROLL_HORIZONTAL_JUMP), + Tab::Query => { + app.query_state.table_state.select_first(); + } }, (KeyCode::End, _) | (KeyCode::Char('>'), KeyModifiers::ALT) => match app.current_tab { Tab::Layout => app.layouts_list_state.select_last(), Tab::Segments => app .segment_grid_state .scroll_right(SEGMENT_SCROLL_HORIZONTAL_JUMP), + Tab::Query => { + app.query_state.table_state.select_last(); + } }, (KeyCode::Enter, _) => { if app.current_tab == Tab::Layout && app.cursor.layout().nchildren() > 0 { @@ -147,6 +239,10 @@ fn handle_normal_mode(app: &mut AppState, event: Event) -> HandleResult { Tab::Segments => app .segment_grid_state .scroll_left(SEGMENT_SCROLL_HORIZONTAL_STEP), + Tab::Query => { + app.query_state.horizontal_scroll = + app.query_state.horizontal_scroll.saturating_sub(1); + } }, (KeyCode::Right | KeyCode::Char('l'), _) | (KeyCode::Char('b'), KeyModifiers::ALT) => { match app.current_tab { @@ -154,11 +250,34 @@ fn handle_normal_mode(app: &mut AppState, event: Event) -> HandleResult { Tab::Segments => app .segment_grid_state .scroll_right(SEGMENT_SCROLL_HORIZONTAL_STEP), + Tab::Query => { + let max_col = app.query_state.column_count().saturating_sub(1); + if app.query_state.horizontal_scroll < max_col { + app.query_state.horizontal_scroll += 1; + } + } } } (KeyCode::Char('/'), _) | (KeyCode::Char('s'), KeyModifiers::CONTROL) => { - app.key_mode = KeyMode::Search; + if app.current_tab != Tab::Query { + app.key_mode = KeyMode::Search; + } + } + + (KeyCode::Char('s'), KeyModifiers::NONE) => { + if app.current_tab == Tab::Query { + // Sort by selected column - modifies the SQL query + let col = app.query_state.selected_column(); + app.query_state.apply_sort(app.session, col, &app.file_path); + } + } + + (KeyCode::Esc, _) => { + if app.current_tab == Tab::Query { + // Toggle focus in Query tab + app.query_state.toggle_focus(); + } } _ => {} diff --git a/vortex-tui/src/browse/ui/mod.rs b/vortex-tui/src/browse/ui/mod.rs index e639a756b66..6080d3940c5 100644 --- a/vortex-tui/src/browse/ui/mod.rs +++ b/vortex-tui/src/browse/ui/mod.rs @@ -4,9 +4,14 @@ //! UI rendering components for the TUI browser. mod layouts; +mod query; mod segments; use layouts::render_layouts; +pub use query::QueryFocus; +pub use query::QueryState; +pub use query::SortDirection; +use query::render_query; use ratatui::prelude::*; use ratatui::widgets::Block; use ratatui::widgets::BorderType; @@ -65,17 +70,13 @@ pub fn render_app(app: &mut AppState<'_>, frame: &mut Frame<'_>) { let selected_tab = match app.current_tab { Tab::Layout => 0, Tab::Segments => 1, + Tab::Query => 2, }; - let tabs = Tabs::new([ - "File Layout", - "Segments", - // TODO(aduffy): add SQL query interface - // "Query", - ]) - .style(Style::default().bold().white()) - .highlight_style(Style::default().bold().black().on_white()) - .select(Some(selected_tab)); + let tabs = Tabs::new(["File Layout", "Segments", "Query"]) + .style(Style::default().bold().white()) + .highlight_style(Style::default().bold().black().on_white()) + .select(Some(selected_tab)); frame.render_widget(tabs, tab_view); @@ -85,5 +86,6 @@ pub fn render_app(app: &mut AppState<'_>, frame: &mut Frame<'_>) { render_layouts(app, app_view, frame.buffer_mut()); } Tab::Segments => segments_ui(app, app_view, frame.buffer_mut()), + Tab::Query => render_query(app, app_view, frame.buffer_mut()), } } diff --git a/vortex-tui/src/browse/ui/query.rs b/vortex-tui/src/browse/ui/query.rs new file mode 100644 index 00000000000..692edd74423 --- /dev/null +++ b/vortex-tui/src/browse/ui/query.rs @@ -0,0 +1,667 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +use arrow_array::RecordBatch; +use ratatui::buffer::Buffer; +use ratatui::layout::Constraint; +use ratatui::layout::Layout; +use ratatui::layout::Rect; +use ratatui::style::Color; +use ratatui::style::Style; +use ratatui::text::Line; +use ratatui::text::Span; +use ratatui::widgets::Block; +use ratatui::widgets::BorderType; +use ratatui::widgets::Borders; +use ratatui::widgets::Cell; +use ratatui::widgets::Paragraph; +use ratatui::widgets::Row; +use ratatui::widgets::Scrollbar; +use ratatui::widgets::ScrollbarOrientation; +use ratatui::widgets::ScrollbarState; +use ratatui::widgets::StatefulWidget; +use ratatui::widgets::Table; +use ratatui::widgets::TableState; +use ratatui::widgets::Widget; +use tokio::runtime::Handle; +use tokio::task::block_in_place; + +use crate::browse::app::AppState; +use crate::datafusion_helper::arrow_value_to_json; +use crate::datafusion_helper::execute_vortex_query; +use crate::datafusion_helper::json_value_to_display; + +/// Sort direction for table columns. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub enum SortDirection { + /// No sorting applied. + #[default] + None, + /// Sort in ascending order. + Ascending, + /// Sort in descending order. + Descending, +} + +impl SortDirection { + /// Cycle to the next sort direction: None -> Ascending -> Descending -> None. + pub fn cycle(self) -> Self { + match self { + SortDirection::None => SortDirection::Ascending, + SortDirection::Ascending => SortDirection::Descending, + SortDirection::Descending => SortDirection::None, + } + } + + /// Get the sort direction indicator character for display. + pub fn indicator(self) -> &'static str { + match self { + SortDirection::None => "", + SortDirection::Ascending => " ▲", + SortDirection::Descending => " ▼", + } + } +} + +/// Focus state within the Query tab. +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)] +pub enum QueryFocus { + /// Focus is on the SQL input field. + #[default] + SqlInput, + /// Focus is on the results table. + ResultsTable, +} + +/// State for the SQL query interface. +pub struct QueryState { + /// The SQL query input text. + pub sql_input: String, + /// Cursor position in the SQL input. + pub cursor_position: usize, + /// Current focus within the Query tab. + pub focus: QueryFocus, + /// Query results as RecordBatches. + pub results: Option, + /// Error message if query failed. + pub error: Option, + /// Whether a query is currently running. + pub running: bool, + /// Table state for the results view. + pub table_state: TableState, + /// Horizontal scroll offset for the results table. + pub horizontal_scroll: usize, + /// Column being sorted (if any). + pub sort_column: Option, + /// Sort direction. + pub sort_direction: SortDirection, + /// Current page (0-indexed). + pub current_page: usize, + /// Rows per page (parsed from LIMIT clause). + pub page_size: usize, + /// Total row count from COUNT(*) query. + pub total_row_count: Option, + /// Base SQL query (without LIMIT/OFFSET) for pagination. + pub base_query: String, + /// ORDER BY clause if any. + pub order_clause: Option, +} + +impl Default for QueryState { + fn default() -> Self { + let default_sql = "SELECT * FROM data LIMIT 20"; + Self { + sql_input: default_sql.to_string(), + cursor_position: default_sql.len(), + focus: QueryFocus::default(), + results: None, + error: None, + running: false, + table_state: TableState::default(), + horizontal_scroll: 0, + sort_column: None, + sort_direction: SortDirection::default(), + current_page: 0, + page_size: 20, + total_row_count: None, + base_query: "SELECT * FROM data".to_string(), + order_clause: None, + } + } +} + +impl QueryState { + /// Insert a character at the cursor position. + pub fn insert_char(&mut self, c: char) { + self.sql_input.insert(self.cursor_position, c); + self.cursor_position += 1; + } + + /// Delete the character before the cursor. + pub fn delete_char(&mut self) { + if self.cursor_position > 0 { + self.cursor_position -= 1; + self.sql_input.remove(self.cursor_position); + } + } + + /// Delete the character at the cursor. + pub fn delete_char_forward(&mut self) { + if self.cursor_position < self.sql_input.len() { + self.sql_input.remove(self.cursor_position); + } + } + + /// Move cursor left. + pub fn move_cursor_left(&mut self) { + self.cursor_position = self.cursor_position.saturating_sub(1); + } + + /// Move cursor right. + pub fn move_cursor_right(&mut self) { + if self.cursor_position < self.sql_input.len() { + self.cursor_position += 1; + } + } + + /// Move cursor to start. + pub fn move_cursor_start(&mut self) { + self.cursor_position = 0; + } + + /// Move cursor to end. + pub fn move_cursor_end(&mut self) { + self.cursor_position = self.sql_input.len(); + } + + /// Clear the SQL input. + pub fn clear_input(&mut self) { + self.sql_input.clear(); + self.cursor_position = 0; + } + + /// Toggle focus between SQL input and results table. + pub fn toggle_focus(&mut self) { + self.focus = match self.focus { + QueryFocus::SqlInput => QueryFocus::ResultsTable, + QueryFocus::ResultsTable => QueryFocus::SqlInput, + }; + } + + /// Execute initial query - parses SQL, gets total count, fetches first page. + pub fn execute_initial_query( + &mut self, + session: &vortex::session::VortexSession, + file_path: &str, + ) { + self.running = true; + self.error = None; + + // Parse the SQL to extract base query, order clause, and page size + let (base_sql, order_clause, limit) = self.parse_sql_parts(); + self.base_query = base_sql; + self.order_clause = order_clause; + self.page_size = limit.unwrap_or(20); + self.current_page = 0; + + // Get total row count + self.total_row_count = get_row_count(session, file_path, &self.base_query).ok(); + + // Build and execute the query + self.rebuild_and_execute(session, file_path); + } + + /// Navigate to next page. + pub fn next_page(&mut self, session: &vortex::session::VortexSession, file_path: &str) { + let total_pages = self.total_pages(); + if self.current_page + 1 < total_pages { + self.current_page += 1; + self.rebuild_and_execute(session, file_path); + } + } + + /// Navigate to previous page. + pub fn prev_page(&mut self, session: &vortex::session::VortexSession, file_path: &str) { + if self.current_page > 0 { + self.current_page -= 1; + self.rebuild_and_execute(session, file_path); + } + } + + /// Get total number of pages. + pub fn total_pages(&self) -> usize { + match self.total_row_count { + Some(total) if total > 0 => total.div_ceil(self.page_size), + _ => 1, + } + } + + /// Build SQL query from current state and execute it. + fn rebuild_and_execute(&mut self, session: &vortex::session::VortexSession, file_path: &str) { + let offset = self.current_page * self.page_size; + + let new_sql = match &self.order_clause { + Some(order) => { + format!( + "{} {} LIMIT {} OFFSET {}", + self.base_query, order, self.page_size, offset + ) + } + None => { + format!( + "{} LIMIT {} OFFSET {}", + self.base_query, self.page_size, offset + ) + } + }; + + self.sql_input = new_sql; + self.cursor_position = self.sql_input.len(); + + self.running = true; + self.error = None; + + match execute_query(session, file_path, &self.sql_input) { + Ok(results) => { + self.results = Some(results); + self.table_state.select(Some(0)); + } + Err(e) => { + self.error = Some(e); + } + } + self.running = false; + } + + /// Parse SQL to extract base query, ORDER BY clause, and LIMIT value. + fn parse_sql_parts(&self) -> (String, Option, Option) { + let sql = &self.sql_input; + let sql_upper = sql.to_uppercase(); + + // Find positions of clauses + let order_idx = sql_upper.find(" ORDER BY "); + let limit_idx = sql_upper.find(" LIMIT "); + let offset_idx = sql_upper.find(" OFFSET "); + + // Extract limit value if present + let limit_value = if let Some(li) = limit_idx { + let after_limit = &sql[li + 7..]; // Skip " LIMIT " + let end_idx = after_limit + .find(|c: char| !c.is_ascii_digit() && c != ' ') + .unwrap_or(after_limit.len()); + after_limit[..end_idx].trim().parse::().ok() + } else { + None + }; + + // Find the earliest of LIMIT or OFFSET to know where to cut + let cut_idx = match (limit_idx, offset_idx) { + (Some(li), Some(oi)) => Some(li.min(oi)), + (Some(li), None) => Some(li), + (None, Some(oi)) => Some(oi), + (None, None) => None, + }; + + match (order_idx, cut_idx) { + (Some(oi), Some(ci)) if oi < ci => { + // ORDER BY comes before LIMIT/OFFSET + let base = sql[..oi].trim().to_string(); + let order = sql[oi..ci].trim().to_string(); + (base, Some(order), limit_value) + } + (Some(oi), None) => { + // Only ORDER BY, no LIMIT/OFFSET + let base = sql[..oi].trim().to_string(); + let order = sql[oi..].trim().to_string(); + (base, Some(order), limit_value) + } + (None, Some(ci)) => { + // No ORDER BY, just LIMIT/OFFSET + let base = sql[..ci].trim().to_string(); + (base, None, limit_value) + } + (Some(_oi), Some(ci)) => { + // ORDER BY comes after LIMIT (unusual) - just cut at LIMIT + let base = sql[..ci].trim().to_string(); + (base, None, limit_value) + } + (None, None) => { + // No ORDER BY or LIMIT/OFFSET + (sql.clone(), None, limit_value) + } + } + } + + /// Get the currently selected column index. + pub fn selected_column(&self) -> usize { + self.horizontal_scroll + } + + /// Total number of columns in results. + pub fn column_count(&self) -> usize { + self.results + .as_ref() + .and_then(|r| r.batches.first()) + .map(|b| b.num_columns()) + .unwrap_or(0) + } + + /// Apply sort on a column by modifying the ORDER BY clause and re-executing. + pub fn apply_sort( + &mut self, + session: &vortex::session::VortexSession, + column: usize, + file_path: &str, + ) { + // Get the column name from results + let column_name = match &self.results { + Some(results) if column < results.column_names.len() => { + results.column_names[column].clone() + } + _ => return, + }; + + // Cycle sort direction + if self.sort_column == Some(column) { + self.sort_direction = self.sort_direction.cycle(); + if self.sort_direction == SortDirection::None { + self.sort_column = None; + } + } else { + self.sort_column = Some(column); + self.sort_direction = SortDirection::Ascending; + } + + // Update the ORDER BY clause + self.order_clause = if self.sort_direction == SortDirection::None { + None + } else { + let direction = match self.sort_direction { + SortDirection::Ascending => "ASC", + SortDirection::Descending => "DESC", + SortDirection::None => unreachable!(), + }; + Some(format!("ORDER BY \"{column_name}\" {direction}")) + }; + + // Reset to first page and re-execute + self.current_page = 0; + self.rebuild_and_execute(session, file_path); + } +} + +/// Holds query results for display. +pub struct QueryResults { + pub batches: Vec, + pub total_rows: usize, + pub column_names: Vec, +} + +/// Execute a SQL query against the Vortex file. +pub fn execute_query( + session: &vortex::session::VortexSession, + file_path: &str, + sql: &str, +) -> Result { + block_in_place(|| { + Handle::current().block_on(async { + let batches = execute_vortex_query(session, file_path, sql).await?; + + let total_rows: usize = batches.iter().map(|b| b.num_rows()).sum(); + + let column_names = if let Some(batch) = batches.first() { + let schema = batch.schema(); + schema.fields().iter().map(|f| f.name().clone()).collect() + } else { + vec![] + }; + + Ok(QueryResults { + batches, + total_rows, + column_names, + }) + }) + }) +} + +/// Get total row count for a base query using COUNT(*). +pub fn get_row_count( + session: &vortex::session::VortexSession, + file_path: &str, + base_query: &str, +) -> Result { + block_in_place(|| { + Handle::current().block_on(async { + let count_sql = format!("SELECT COUNT(*) as count FROM ({base_query}) AS subquery"); + + let batches = execute_vortex_query(session, file_path, &count_sql).await?; + + // Extract count from result + if let Some(batch) = batches.first() + && batch.num_rows() > 0 + && batch.num_columns() > 0 + { + use arrow_array::Int64Array; + if let Some(arr) = batch.column(0).as_any().downcast_ref::() { + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] + return Ok(arr.value(0) as usize); + } + } + + Ok(0) + }) + }) +} + +/// Render the Query tab UI. +pub fn render_query(app: &mut AppState<'_>, area: Rect, buf: &mut Buffer) { + let [input_area, results_area] = + Layout::vertical([Constraint::Length(5), Constraint::Min(10)]).areas(area); + + render_sql_input(app, input_area, buf); + render_results_table(app, results_area, buf); +} + +fn render_sql_input(app: &mut AppState<'_>, area: Rect, buf: &mut Buffer) { + let is_focused = app.query_state.focus == QueryFocus::SqlInput; + + let border_color = if is_focused { + Color::Cyan + } else { + Color::DarkGray + }; + + let block = Block::default() + .title("SQL Query (Enter to execute, Esc to switch focus)") + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .border_style(Style::default().fg(border_color)); + + let inner = block.inner(area); + block.render(area, buf); + + // Create the input text with cursor + let sql = &app.query_state.sql_input; + let cursor_pos = app.query_state.cursor_position; + + let (before_cursor, after_cursor) = sql.split_at(cursor_pos.min(sql.len())); + + let first_char = after_cursor.chars().next(); + let cursor_char = if is_focused { + match first_char { + None => Span::styled(" ", Style::default().bg(Color::White).fg(Color::Black)), + Some(c) => Span::styled( + c.to_string(), + Style::default().bg(Color::White).fg(Color::Black), + ), + } + } else { + match first_char { + None => Span::raw(""), + Some(c) => Span::raw(c.to_string()), + } + }; + + let rest = match first_char { + Some(c) if after_cursor.len() > c.len_utf8() => &after_cursor[c.len_utf8()..], + _ => "", + }; + + let line = Line::from(vec![Span::raw(before_cursor), cursor_char, Span::raw(rest)]); + + let paragraph = Paragraph::new(line).style(Style::default().fg(Color::White)); + + paragraph.render(inner, buf); +} + +fn render_results_table(app: &mut AppState<'_>, area: Rect, buf: &mut Buffer) { + let is_focused = app.query_state.focus == QueryFocus::ResultsTable; + + let border_color = if is_focused { + Color::Cyan + } else { + Color::DarkGray + }; + + // Show status in title + let title = if app.query_state.running { + "Results (running...)".to_string() + } else if let Some(ref error) = app.query_state.error { + format!("Results (error: {})", truncate_str(error, 50)) + } else if let Some(ref _results) = app.query_state.results { + let total_rows = app.query_state.total_row_count.unwrap_or(0); + let total_pages = app.query_state.total_pages(); + format!( + "Results ({} rows, page {}/{}) [hjkl navigate, [/] pages, s sort]", + total_rows, + app.query_state.current_page + 1, + total_pages, + ) + } else { + "Results (press Enter to execute query)".to_string() + }; + + let block = Block::default() + .title(title) + .borders(Borders::ALL) + .border_type(BorderType::Rounded) + .border_style(Style::default().fg(border_color)); + + let inner = block.inner(area); + block.render(area, buf); + + if let Some(ref error) = app.query_state.error { + let error_text = Paragraph::new(error.as_str()) + .style(Style::default().fg(Color::Red)) + .wrap(ratatui::widgets::Wrap { trim: true }); + error_text.render(inner, buf); + return; + } + + let Some(ref results) = app.query_state.results else { + let help = Paragraph::new("Enter a SQL query above and press Enter to execute.\nThe table is available as 'data'.\n\nExample: SELECT * FROM data WHERE column > 10 LIMIT 100") + .style(Style::default().fg(Color::Gray)); + help.render(inner, buf); + return; + }; + + if results.batches.is_empty() || results.total_rows == 0 { + let empty = + Paragraph::new("Query returned no results.").style(Style::default().fg(Color::Yellow)); + empty.render(inner, buf); + return; + } + + // Build header row with sort indicators + let header_cells: Vec = results + .column_names + .iter() + .enumerate() + .map(|(i, name)| { + let indicator = if app.query_state.sort_column == Some(i) { + app.query_state.sort_direction.indicator() + } else { + "" + }; + + let style = if is_focused && i == app.query_state.horizontal_scroll { + Style::default().fg(Color::Black).bg(Color::Cyan).bold() + } else { + Style::default().fg(Color::Green).bold() + }; + + Cell::from(format!("{name}{indicator}")).style(style) + }) + .collect(); + + let header = Row::new(header_cells).height(1); + + // Since we use LIMIT/OFFSET in SQL, batches contain only the current page's data + // Display all rows from the batches + let rows = get_all_rows(results, &app.query_state); + + // Calculate column widths + #[allow(clippy::cast_possible_truncation)] + let widths: Vec = results + .column_names + .iter() + .map(|name| Constraint::Min((name.len() + 3).max(10) as u16)) + .collect(); + + let table = Table::new(rows, widths) + .header(header) + .row_highlight_style(Style::default().bg(Color::DarkGray)); + + // Split area for table and scrollbar + let [table_area, scrollbar_area] = + Layout::horizontal([Constraint::Min(0), Constraint::Length(1)]).areas(inner); + + StatefulWidget::render(table, table_area, buf, &mut app.query_state.table_state); + + // Render vertical scrollbar + let total_pages = app.query_state.total_pages(); + if total_pages > 1 { + let mut scrollbar_state = ScrollbarState::new(total_pages) + .position(app.query_state.current_page) + .viewport_content_length(1); + + Scrollbar::new(ScrollbarOrientation::VerticalRight) + .begin_symbol(Some("▲")) + .end_symbol(Some("▼")) + .render(scrollbar_area, buf, &mut scrollbar_state); + } +} + +/// Get all rows from batches (pagination is handled via SQL LIMIT/OFFSET). +fn get_all_rows<'a>(results: &'a QueryResults, query_state: &QueryState) -> Vec> { + let mut rows = Vec::new(); + + for batch in &results.batches { + for row_idx in 0..batch.num_rows() { + let cells: Vec = (0..batch.num_columns()) + .map(|col_idx| { + let json_value = arrow_value_to_json(batch.column(col_idx).as_ref(), row_idx); + let value = json_value_to_display(json_value); + let style = if query_state.sort_column == Some(col_idx) { + Style::default().fg(Color::Cyan) + } else { + Style::default() + }; + Cell::from(truncate_str(&value, 30).to_string()).style(style) + }) + .collect(); + rows.push(Row::new(cells)); + } + } + + rows +} + +fn truncate_str(s: &str, max_len: usize) -> &str { + if s.len() <= max_len { + s + } else { + &s[..max_len.saturating_sub(3)] + } +} diff --git a/vortex-tui/src/browse/ui/segments.rs b/vortex-tui/src/browse/ui/segments.rs index d73f2291a02..b8d20dbc2b1 100644 --- a/vortex-tui/src/browse/ui/segments.rs +++ b/vortex-tui/src/browse/ui/segments.rs @@ -1,8 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: Copyright the Vortex contributors -use std::sync::Arc; - use humansize::DECIMAL; use ratatui::buffer::Buffer; use ratatui::layout::Rect; @@ -30,14 +28,12 @@ use taffy::TaffyTree; use taffy::TraversePartialTree; use vortex::dtype::FieldName; use vortex::error::VortexExpect; -use vortex::error::VortexResult; use vortex::error::vortex_err; -use vortex::file::SegmentSpec; -use vortex::layout::Layout; -use vortex::layout::LayoutChildType; use vortex::utils::aliases::hash_map::HashMap; use crate::browse::app::AppState; +use crate::segment_tree::SegmentTree; +use crate::segment_tree::collect_segment_tree; /// State for the segment grid visualization. /// @@ -111,13 +107,6 @@ pub struct NodeContents<'a> { contents: Vec>, } -pub struct SegmentDisplay { - name: FieldName, - spec: SegmentSpec, - row_offset: u64, - row_count: u64, -} - #[expect( clippy::cast_possible_truncation, reason = "UI coordinates are small enough" @@ -404,108 +393,3 @@ fn to_display_segment_tree<'a>( )?; Ok((tree, root, node_contents)) } - -fn collect_segment_tree(root_layout: &dyn Layout, segments: &Arc<[SegmentSpec]>) -> SegmentTree { - let mut tree = SegmentTree { - segments: HashMap::new(), - segment_ordering: Vec::new(), - }; - segments_by_name_impl(root_layout, None, None, Some(0), segments, &mut tree) - .vortex_expect("operation should succeed in TUI"); - - tree -} - -struct SegmentTree { - segments: HashMap>, - segment_ordering: Vec, -} - -fn segments_by_name_impl( - root: &dyn Layout, - group_name: Option, - name: Option, - row_offset: Option, - segments: &Arc<[SegmentSpec]>, - segment_tree: &mut SegmentTree, -) -> VortexResult<()> { - // Recurse into children - for (child, child_type) in root.children()?.into_iter().zip(root.child_types()) { - match child_type { - LayoutChildType::Transparent(sub_name) => segments_by_name_impl( - child.as_ref(), - group_name.clone(), - Some( - name.as_ref() - .map(|n| format!("{n}.{sub_name}").into()) - .unwrap_or_else(|| sub_name.into()), - ), - row_offset, - segments, - segment_tree, - )?, - LayoutChildType::Auxiliary(aux_name) => segments_by_name_impl( - child.as_ref(), - group_name.clone(), - Some( - name.as_ref() - .map(|n| format!("{n}.{aux_name}").into()) - .unwrap_or_else(|| aux_name.into()), - ), - Some(0), - segments, - segment_tree, - )?, - LayoutChildType::Chunk((idx, chunk_row_offset)) => { - segments_by_name_impl( - child.as_ref(), - group_name.clone(), - Some( - name.as_ref() - .map(|n| format!("{n}.[{idx}]")) - .unwrap_or_else(|| format!("[{idx}]")) - .into(), - ), - // Compute absolute row offset. - Some(chunk_row_offset + row_offset.unwrap_or(0)), - segments, - segment_tree, - )? - } - LayoutChildType::Field(field_name) => { - // Step into a new group name - let group_name = group_name - .as_ref() - .map(|n| format!("{n}.{field_name}").into()) - .unwrap_or_else(|| field_name); - segment_tree.segment_ordering.push(group_name.clone()); - - segments_by_name_impl( - child.as_ref(), - Some(group_name), - None, - row_offset, - segments, - segment_tree, - )? - } - } - } - - let current_segments = segment_tree - .segments - .entry(group_name.unwrap_or_else(|| FieldName::from("root"))) - .or_default(); - - for segment_id in root.segment_ids() { - let segment_spec = segments[*segment_id as usize].clone(); - current_segments.push(SegmentDisplay { - name: name.clone().unwrap_or_else(|| "".into()), - spec: segment_spec, - row_count: root.row_count(), - row_offset: row_offset.unwrap_or(0), - }) - } - - Ok(()) -} diff --git a/vortex-tui/src/datafusion_helper.rs b/vortex-tui/src/datafusion_helper.rs new file mode 100644 index 00000000000..9205ca0bede --- /dev/null +++ b/vortex-tui/src/datafusion_helper.rs @@ -0,0 +1,237 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Shared DataFusion query execution utilities for both CLI and TUI. + +use std::sync::Arc; + +use arrow_array::Array as ArrowArray; +use arrow_array::RecordBatch; +use datafusion::datasource::listing::ListingOptions; +use datafusion::datasource::listing::ListingTable; +use datafusion::datasource::listing::ListingTableConfig; +use datafusion::datasource::listing::ListingTableUrl; +use datafusion::prelude::SessionContext; +use vortex::session::VortexSession; +use vortex_datafusion::VortexFormat; + +/// Execute a SQL query against a Vortex file. +/// +/// The file is registered as a table named "data". +/// Returns the result as a vector of RecordBatches. +/// +/// # Errors +/// +/// Returns an error if the query fails to parse or execute. +pub async fn execute_vortex_query( + session: &VortexSession, + file_path: &str, + sql: &str, +) -> Result, String> { + let ctx = create_vortex_context(session, file_path).await?; + + let df = ctx.sql(sql).await.map_err(|e| format!("SQL error: {e}"))?; + + df.collect() + .await + .map_err(|e| format!("Query execution error: {e}")) +} + +/// Create a DataFusion SessionContext with a Vortex file registered as "data". +/// +/// # Errors +/// +/// Returns an error if the context cannot be created. +pub async fn create_vortex_context( + session: &VortexSession, + file_path: &str, +) -> Result { + let ctx = SessionContext::new(); + let format = Arc::new(VortexFormat::new(session.clone())); + + let table_url = + ListingTableUrl::parse(file_path).map_err(|e| format!("Failed to parse file path: {e}"))?; + + let config = ListingTableConfig::new(table_url) + .with_listing_options( + ListingOptions::new(format).with_session_config_options(ctx.state().config()), + ) + .infer_schema(&ctx.state()) + .await + .map_err(|e| format!("Failed to infer schema: {e}"))?; + + let listing_table = Arc::new( + ListingTable::try_new(config).map_err(|e| format!("Failed to create table: {e}"))?, + ); + + ctx.register_table("data", listing_table) + .map_err(|e| format!("Failed to register table: {e}"))?; + + Ok(ctx) +} + +/// Convert an Arrow array value at a given index to a JSON value. +/// +/// # Panics +/// +/// Panics if the array type doesn't match the expected Arrow array type during downcast. +/// This should not happen for well-formed Arrow arrays. +#[allow(clippy::unwrap_used)] +pub fn arrow_value_to_json(array: &dyn ArrowArray, idx: usize) -> serde_json::Value { + use arrow_array::*; + use arrow_schema::DataType; + + if array.is_null(idx) { + return serde_json::Value::Null; + } + + match array.data_type() { + DataType::Null => serde_json::Value::Null, + DataType::Boolean => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::Bool(arr.value(idx)) + } + DataType::Int8 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Int16 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Int32 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Int64 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::UInt8 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::UInt16 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::UInt32 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::UInt64 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Float16 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx).to_f32()) + } + DataType::Float32 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Float64 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Utf8 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::String(arr.value(idx).to_string()) + } + DataType::LargeUtf8 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::String(arr.value(idx).to_string()) + } + DataType::Utf8View => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::String(arr.value(idx).to_string()) + } + DataType::Binary => { + let arr = array.as_any().downcast_ref::().unwrap(); + let hex: String = arr.value(idx).iter().map(|b| format!("{b:02x}")).collect(); + serde_json::Value::String(hex) + } + DataType::LargeBinary => { + let arr = array.as_any().downcast_ref::().unwrap(); + let hex: String = arr.value(idx).iter().map(|b| format!("{b:02x}")).collect(); + serde_json::Value::String(hex) + } + DataType::BinaryView => { + let arr = array.as_any().downcast_ref::().unwrap(); + let hex: String = arr.value(idx).iter().map(|b| format!("{b:02x}")).collect(); + serde_json::Value::String(hex) + } + DataType::Date32 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Date64 => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::json!(arr.value(idx)) + } + DataType::Timestamp(..) => { + if let Some(arr) = array.as_any().downcast_ref::() { + serde_json::json!(arr.value(idx)) + } else if let Some(arr) = array.as_any().downcast_ref::() { + serde_json::json!(arr.value(idx)) + } else if let Some(arr) = array.as_any().downcast_ref::() { + serde_json::json!(arr.value(idx)) + } else if let Some(arr) = array.as_any().downcast_ref::() { + serde_json::json!(arr.value(idx)) + } else { + serde_json::Value::String("".to_string()) + } + } + DataType::Decimal128(..) => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::String(arr.value_as_string(idx)) + } + DataType::Decimal256(..) => { + let arr = array.as_any().downcast_ref::().unwrap(); + serde_json::Value::String(arr.value_as_string(idx)) + } + DataType::List(_) => { + let arr = array.as_any().downcast_ref::().unwrap(); + let value_arr = arr.value(idx); + let elements: Vec = (0..value_arr.len()) + .map(|i| arrow_value_to_json(value_arr.as_ref(), i)) + .collect(); + serde_json::Value::Array(elements) + } + DataType::LargeList(_) => { + let arr = array.as_any().downcast_ref::().unwrap(); + let value_arr = arr.value(idx); + let elements: Vec = (0..value_arr.len()) + .map(|i| arrow_value_to_json(value_arr.as_ref(), i)) + .collect(); + serde_json::Value::Array(elements) + } + DataType::Struct(_) => { + let arr = array.as_any().downcast_ref::().unwrap(); + let mut obj = serde_json::Map::new(); + for (i, field) in arr.fields().iter().enumerate() { + let col = arr.column(i); + obj.insert(field.name().clone(), arrow_value_to_json(col.as_ref(), idx)); + } + serde_json::Value::Object(obj) + } + _ => { + // Fallback for unsupported types + serde_json::Value::String(format!("<{}>", array.data_type())) + } + } +} + +/// Format a JSON value for display in the TUI. +/// +/// - Null becomes "NULL" +/// - Strings are displayed without quotes +/// - Other values use their JSON string representation +pub fn json_value_to_display(value: serde_json::Value) -> String { + match value { + serde_json::Value::Null => "NULL".to_string(), + serde_json::Value::String(s) => s, + other => other.to_string(), + } +} diff --git a/vortex-tui/src/inspect.rs b/vortex-tui/src/inspect.rs index fc8cedfec34..65ad6da1105 100644 --- a/vortex-tui/src/inspect.rs +++ b/vortex-tui/src/inspect.rs @@ -8,11 +8,13 @@ use std::fs::File; use std::io::Read; use std::io::Seek; use std::io::SeekFrom; +use std::path::Path; use std::path::PathBuf; use std::sync::Arc; use flatbuffers::root; use itertools::Itertools; +use serde::Serialize; use vortex::buffer::Alignment; use vortex::buffer::ByteBuffer; use vortex::error::VortexExpect; @@ -38,6 +40,10 @@ pub struct InspectArgs { /// Path to the Vortex file to inspect. pub file: PathBuf, + + /// Output as JSON + #[arg(long, global = true)] + pub json: bool, } /// What component of the Vortex file to inspect. @@ -53,6 +59,90 @@ pub enum InspectMode { Footer, } +/// JSON output structure for inspect command. +#[derive(Serialize)] +pub struct InspectOutput { + /// Path to the inspected file. + pub file_path: String, + /// Size of the file in bytes. + pub file_size: u64, + /// EOF marker information. + pub eof: EofInfoJson, + /// Postscript information (if available). + #[serde(skip_serializing_if = "Option::is_none")] + pub postscript: Option, + /// Footer information (if available). + #[serde(skip_serializing_if = "Option::is_none")] + pub footer: Option, +} + +/// EOF marker information for JSON output. +#[derive(Serialize)] +pub struct EofInfoJson { + /// File format version. + pub version: u16, + /// Current supported version. + pub current_version: u16, + /// Postscript size in bytes. + pub postscript_size: u16, + /// Magic bytes as string. + pub magic_bytes: String, + /// Whether magic bytes are valid. + pub valid_magic: bool, +} + +/// Segment information for JSON output. +#[derive(Serialize)] +pub struct SegmentInfoJson { + /// Offset in file. + pub offset: u64, + /// Length in bytes. + pub length: u32, + /// Alignment requirement. + pub alignment: usize, +} + +/// Postscript information for JSON output. +#[derive(Serialize)] +pub struct PostscriptInfoJson { + /// DType segment info. + pub dtype: Option, + /// Layout segment info. + pub layout: SegmentInfoJson, + /// Statistics segment info. + pub statistics: Option, + /// Footer segment info. + pub footer: SegmentInfoJson, +} + +/// Footer information for JSON output. +#[derive(Serialize)] +pub struct FooterInfoJson { + /// Total number of segments. + pub total_segments: usize, + /// Total data size in bytes. + pub total_data_size: u64, + /// Individual segment details. + pub segments: Vec, +} + +/// Footer segment information for JSON output. +#[derive(Serialize)] +pub struct FooterSegmentJson { + /// Segment index. + pub index: usize, + /// Start offset in file. + pub offset: u64, + /// End offset in file. + pub end_offset: u64, + /// Length in bytes. + pub length: u32, + /// Alignment requirement. + pub alignment: usize, + /// Path in layout tree. + pub path: Option, +} + /// Inspect Vortex file footer and metadata. /// /// # Errors @@ -61,12 +151,134 @@ pub enum InspectMode { pub async fn exec_inspect(session: &VortexSession, args: InspectArgs) -> anyhow::Result<()> { let mut inspector = VortexInspector::new(session, args.file.clone())?; - println!("File: {}", args.file.display()); + let mode = args.mode.unwrap_or(InspectMode::Footer); + + if args.json { + exec_inspect_json(&mut inspector, &args.file, mode).await + } else { + exec_inspect_text(&mut inspector, &args.file, mode).await + } +} + +async fn exec_inspect_json( + inspector: &mut VortexInspector<'_>, + file_path: &Path, + mode: InspectMode, +) -> anyhow::Result<()> { + let eof = inspector.read_eof()?; + let eof_json = EofInfoJson { + version: eof.version, + current_version: VERSION, + postscript_size: eof.postscript_size, + magic_bytes: std::str::from_utf8(&eof.magic_bytes) + .unwrap_or("") + .to_string(), + valid_magic: eof.valid_magic, + }; + + let postscript_json = + if matches!(mode, InspectMode::Postscript | InspectMode::Footer) && eof.valid_magic { + inspector + .read_postscript(eof.postscript_size) + .ok() + .map(|ps| PostscriptInfoJson { + dtype: ps.dtype.map(|s| SegmentInfoJson { + offset: s.offset, + length: s.length, + alignment: *s.alignment, + }), + layout: SegmentInfoJson { + offset: ps.layout.offset, + length: ps.layout.length, + alignment: *ps.layout.alignment, + }, + statistics: ps.statistics.map(|s| SegmentInfoJson { + offset: s.offset, + length: s.length, + alignment: *s.alignment, + }), + footer: SegmentInfoJson { + offset: ps.footer.offset, + length: ps.footer.length, + alignment: *ps.footer.alignment, + }, + }) + } else { + None + }; + + let footer_json = + if matches!(mode, InspectMode::Footer) && eof.valid_magic && postscript_json.is_some() { + inspector.read_footer().await.ok().map(|footer| { + let segment_map = footer.segment_map().clone(); + let root_layout = footer.layout().clone(); + + let mut segment_paths: Vec>>> = vec![None; segment_map.len()]; + let mut queue = + VecDeque::<(Vec>, LayoutRef)>::from_iter([(Vec::new(), root_layout)]); + while !queue.is_empty() { + let (path, layout) = queue.pop_front().vortex_expect("queue is not empty"); + for segment in layout.segment_ids() { + segment_paths[*segment as usize] = Some(path.clone()); + } + if let Ok(children) = layout.children() { + for (child_layout, child_name) in + children.into_iter().zip(layout.child_names()) + { + let child_path = path.iter().cloned().chain([child_name]).collect(); + queue.push_back((child_path, child_layout)); + } + } + } + + let segments: Vec = segment_map + .iter() + .enumerate() + .map(|(i, segment)| FooterSegmentJson { + index: i, + offset: segment.offset, + end_offset: segment.offset + segment.length as u64, + length: segment.length, + alignment: *segment.alignment, + path: segment_paths[i] + .as_ref() + .map(|p| p.iter().map(|s| s.as_ref()).collect::>().join(".")), + }) + .collect(); + + FooterInfoJson { + total_segments: segment_map.len(), + total_data_size: segment_map.iter().map(|s| s.length as u64).sum(), + segments, + } + }) + } else { + None + }; + + let output = InspectOutput { + file_path: file_path.display().to_string(), + file_size: inspector.file_size, + eof: eof_json, + postscript: postscript_json, + footer: footer_json, + }; + + let json_output = serde_json::to_string_pretty(&output)?; + println!("{json_output}"); + + Ok(()) +} + +async fn exec_inspect_text( + inspector: &mut VortexInspector<'_>, + file_path: &Path, + mode: InspectMode, +) -> anyhow::Result<()> { + println!("File: {}", file_path.display()); println!("Size: {} bytes", inspector.file_size); println!(); - let mode = args.mode.unwrap_or(InspectMode::Footer); - match mode { InspectMode::Eof => { let eof = inspector.read_eof()?; diff --git a/vortex-tui/src/lib.rs b/vortex-tui/src/lib.rs index 1cb303b67b5..78a63895410 100644 --- a/vortex-tui/src/lib.rs +++ b/vortex-tui/src/lib.rs @@ -31,7 +31,11 @@ use vortex::session::VortexSession; pub mod browse; pub mod convert; +pub mod datafusion_helper; pub mod inspect; +pub mod query; +pub mod segment_tree; +pub mod segments; pub mod tree; #[derive(clap::Parser)] @@ -51,18 +55,24 @@ enum Commands { Browse { file: PathBuf }, /// Inspect Vortex file footer and metadata Inspect(inspect::InspectArgs), + /// Execute a SQL query against a Vortex file using DataFusion + Query(query::QueryArgs), + /// Display segment information for a Vortex file + Segments(segments::SegmentsArgs), } impl Commands { fn file_path(&self) -> &PathBuf { match self { Commands::Tree(args) => match &args.mode { - tree::TreeMode::Array { file } => file, + tree::TreeMode::Array { file, .. } => file, tree::TreeMode::Layout { file, .. } => file, }, Commands::Browse { file } => file, Commands::Convert(flags) => &flags.file, Commands::Inspect(args) => &args.file, + Commands::Query(args) => &args.file, + Commands::Segments(args) => &args.file, } } } @@ -95,6 +105,8 @@ pub async fn launch(session: &VortexSession) -> anyhow::Result<()> { Commands::Convert(flags) => convert::exec_convert(session, flags).await?, Commands::Browse { file } => browse::exec_tui(session, file).await?, Commands::Inspect(args) => inspect::exec_inspect(session, args).await?, + Commands::Query(args) => query::exec_query(session, args).await?, + Commands::Segments(args) => segments::exec_segments(session, args).await?, }; Ok(()) diff --git a/vortex-tui/src/query.rs b/vortex-tui/src/query.rs new file mode 100644 index 00000000000..fa789bef4dc --- /dev/null +++ b/vortex-tui/src/query.rs @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Execute SQL queries against Vortex files using DataFusion. + +use std::path::PathBuf; + +use arrow_array::RecordBatch; +use serde::Serialize; +use vortex::error::VortexResult; +use vortex::error::vortex_err; +use vortex::session::VortexSession; + +use crate::datafusion_helper::arrow_value_to_json; +use crate::datafusion_helper::execute_vortex_query; + +/// Command-line arguments for the query command. +#[derive(Debug, clap::Parser)] +pub struct QueryArgs { + /// Path to the Vortex file + pub file: PathBuf, + + /// SQL query to execute. The table is available as 'data'. + /// Example: "SELECT * FROM data WHERE col > 10 LIMIT 100" + #[arg(long, short)] + pub sql: String, +} + +#[derive(Serialize)] +struct QueryOutput { + schema: SchemaInfo, + total_rows: u64, + rows: Vec, +} + +#[derive(Serialize)] +struct SchemaInfo { + fields: Vec, +} + +#[derive(Serialize)] +struct FieldInfo { + name: String, + dtype: String, + nullable: bool, +} + +/// Execute a SQL query against a Vortex file. +/// +/// # Errors +/// +/// Returns an error if the file cannot be opened or the query fails. +pub async fn exec_query(session: &VortexSession, args: QueryArgs) -> VortexResult<()> { + let file_path = args + .file + .to_str() + .ok_or_else(|| vortex_err!("Path is not valid UTF-8"))?; + + let batches: Vec = execute_vortex_query(session, file_path, &args.sql) + .await + .map_err(|e| vortex_err!("{e}"))?; + + // Build schema info from the result + let schema = if let Some(batch) = batches.first() { + build_schema_from_arrow(batch.schema().as_ref()) + } else { + SchemaInfo { fields: vec![] } + }; + + // Convert batches to JSON rows + let mut rows = Vec::new(); + for batch in &batches { + batch_to_json_rows(batch, &mut rows)?; + } + + let total_rows = rows.len() as u64; + + let output = QueryOutput { + schema, + total_rows, + rows, + }; + + let json_output = serde_json::to_string_pretty(&output) + .map_err(|e| vortex_err!("Failed to serialize JSON: {e}"))?; + println!("{json_output}"); + + Ok(()) +} + +fn build_schema_from_arrow(schema: &arrow_schema::Schema) -> SchemaInfo { + let fields = schema + .fields() + .iter() + .map(|f| FieldInfo { + name: f.name().clone(), + dtype: f.data_type().to_string(), + nullable: f.is_nullable(), + }) + .collect(); + + SchemaInfo { fields } +} + +fn batch_to_json_rows(batch: &RecordBatch, rows: &mut Vec) -> VortexResult<()> { + let schema = batch.schema(); + + for row_idx in 0..batch.num_rows() { + let mut obj = serde_json::Map::new(); + + for (col_idx, field) in schema.fields().iter().enumerate() { + let column = batch.column(col_idx); + let value = arrow_value_to_json(column.as_ref(), row_idx); + obj.insert(field.name().clone(), value); + } + + rows.push(serde_json::Value::Object(obj)); + } + + Ok(()) +} diff --git a/vortex-tui/src/segment_tree.rs b/vortex-tui/src/segment_tree.rs new file mode 100644 index 00000000000..79dd419722d --- /dev/null +++ b/vortex-tui/src/segment_tree.rs @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Shared segment tree collection logic used by both the TUI browse view and the CLI segments command. + +use std::sync::Arc; + +use vortex::dtype::FieldName; +use vortex::error::VortexResult; +use vortex::file::SegmentSpec; +use vortex::layout::Layout; +use vortex::layout::LayoutChildType; +use vortex::utils::aliases::hash_map::HashMap; + +/// Information about a single segment for display purposes. +pub struct SegmentDisplay { + /// Name of the segment (e.g., "data", "[0]", "zones") + pub name: FieldName, + /// The underlying segment specification + pub spec: SegmentSpec, + /// Row offset within the file + pub row_offset: u64, + /// Number of rows in this segment + pub row_count: u64, +} + +/// A tree of segments organized by field name. +pub struct SegmentTree { + /// Map from field name to list of segments for that field + pub segments: HashMap>, + /// Ordered list of field names (columns) in display order + pub segment_ordering: Vec, +} + +/// Collect segment tree from a layout and segment map. +pub fn collect_segment_tree( + root_layout: &dyn Layout, + segments: &Arc<[SegmentSpec]>, +) -> SegmentTree { + let mut tree = SegmentTree { + segments: HashMap::new(), + segment_ordering: Vec::new(), + }; + // Ignore errors during traversal - we want to collect as much as possible + drop(segments_by_name_impl( + root_layout, + None, + None, + Some(0), + segments, + &mut tree, + )); + tree +} + +fn segments_by_name_impl( + root: &dyn Layout, + group_name: Option, + name: Option, + row_offset: Option, + segments: &Arc<[SegmentSpec]>, + segment_tree: &mut SegmentTree, +) -> VortexResult<()> { + // Recurse into children + for (child, child_type) in root.children()?.into_iter().zip(root.child_types()) { + match child_type { + LayoutChildType::Transparent(sub_name) => segments_by_name_impl( + child.as_ref(), + group_name.clone(), + Some( + name.as_ref() + .map(|n| format!("{n}.{sub_name}").into()) + .unwrap_or_else(|| sub_name.into()), + ), + row_offset, + segments, + segment_tree, + )?, + LayoutChildType::Auxiliary(aux_name) => segments_by_name_impl( + child.as_ref(), + group_name.clone(), + Some( + name.as_ref() + .map(|n| format!("{n}.{aux_name}").into()) + .unwrap_or_else(|| aux_name.into()), + ), + Some(0), + segments, + segment_tree, + )?, + LayoutChildType::Chunk((idx, chunk_row_offset)) => segments_by_name_impl( + child.as_ref(), + group_name.clone(), + Some( + name.as_ref() + .map(|n| format!("{n}.[{idx}]")) + .unwrap_or_else(|| format!("[{idx}]")) + .into(), + ), + // Compute absolute row offset. + Some(chunk_row_offset + row_offset.unwrap_or(0)), + segments, + segment_tree, + )?, + LayoutChildType::Field(field_name) => { + // Step into a new group name + let new_group_name = group_name + .as_ref() + .map(|n| format!("{n}.{field_name}").into()) + .unwrap_or_else(|| field_name); + segment_tree.segment_ordering.push(new_group_name.clone()); + + segments_by_name_impl( + child.as_ref(), + Some(new_group_name), + None, + row_offset, + segments, + segment_tree, + )? + } + } + } + + let current_segments = segment_tree + .segments + .entry(group_name.unwrap_or_else(|| FieldName::from("root"))) + .or_default(); + + for segment_id in root.segment_ids() { + let segment_spec = segments[*segment_id as usize].clone(); + current_segments.push(SegmentDisplay { + name: name.clone().unwrap_or_else(|| "".into()), + spec: segment_spec, + row_count: root.row_count(), + row_offset: row_offset.unwrap_or(0), + }) + } + + Ok(()) +} diff --git a/vortex-tui/src/segments.rs b/vortex-tui/src/segments.rs new file mode 100644 index 00000000000..2a4bbc9ca1b --- /dev/null +++ b/vortex-tui/src/segments.rs @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: Copyright the Vortex contributors + +//! Display segment information for Vortex files. + +use std::path::PathBuf; + +use serde::Serialize; +use vortex::error::VortexResult; +use vortex::file::OpenOptionsSessionExt; +use vortex::session::VortexSession; + +use crate::segment_tree::collect_segment_tree; + +/// Command-line arguments for the segments command. +#[derive(Debug, clap::Parser)] +pub struct SegmentsArgs { + /// Path to the Vortex file + pub file: PathBuf, +} + +#[derive(Serialize)] +struct SegmentsOutput { + /// Columns in display order + columns: Vec, +} + +#[derive(Serialize)] +struct ColumnInfo { + /// Field name (column header) + name: String, + /// Segments within this column + segments: Vec, +} + +#[derive(Serialize)] +struct SegmentInfo { + /// Segment name (e.g., "[0]", "data", etc.) + name: String, + /// Row range start + row_offset: u64, + /// Number of rows + row_count: u64, + /// Byte offset in file + byte_offset: u64, + /// Length in bytes + byte_length: u32, + /// Alignment requirement + alignment: usize, + /// Gap from previous segment end + byte_gap: u64, +} + +/// Display segment information for a Vortex file. +/// +/// # Errors +/// +/// Returns an error if the file cannot be opened or read. +pub async fn exec_segments(session: &VortexSession, args: SegmentsArgs) -> VortexResult<()> { + let vxf = session.open_options().open(args.file).await?; + + let footer = vxf.footer(); + let mut segment_tree = collect_segment_tree(footer.layout().as_ref(), footer.segment_map()); + + // Convert to output format + let columns: Vec = segment_tree + .segment_ordering + .iter() + .filter_map(|name| { + let mut segments = segment_tree.segments.remove(name)?; + + // Sort by byte offset + segments.sort_by(|a, b| a.spec.offset.cmp(&b.spec.offset)); + + // Convert to output format, computing byte gaps + let mut current_offset = 0u64; + let segment_infos: Vec = segments + .into_iter() + .map(|seg| { + let byte_gap = if current_offset == 0 { + 0 + } else { + seg.spec.offset.saturating_sub(current_offset) + }; + current_offset = seg.spec.offset + seg.spec.length as u64; + + SegmentInfo { + name: seg.name.to_string(), + row_offset: seg.row_offset, + row_count: seg.row_count, + byte_offset: seg.spec.offset, + byte_length: seg.spec.length, + alignment: *seg.spec.alignment, + byte_gap, + } + }) + .collect(); + + Some(ColumnInfo { + name: name.to_string(), + segments: segment_infos, + }) + }) + .collect(); + + let output = SegmentsOutput { columns }; + + let json_output = serde_json::to_string_pretty(&output) + .map_err(|e| vortex::error::vortex_err!("Failed to serialize JSON: {e}"))?; + println!("{json_output}"); + + Ok(()) +} diff --git a/vortex-tui/src/tree.rs b/vortex-tui/src/tree.rs index 8ba63383db0..32ef339d6b4 100644 --- a/vortex-tui/src/tree.rs +++ b/vortex-tui/src/tree.rs @@ -6,9 +6,11 @@ use std::path::Path; use std::path::PathBuf; +use serde::Serialize; use vortex::array::stream::ArrayStreamExt; use vortex::error::VortexResult; use vortex::file::OpenOptionsSessionExt; +use vortex::layout::LayoutRef; use vortex::session::VortexSession; /// Command-line arguments for the tree command. @@ -26,6 +28,9 @@ pub enum TreeMode { Array { /// Path to the Vortex file file: PathBuf, + /// Output as JSON + #[arg(long)] + json: bool, }, /// Display the layout tree structure (metadata only, no array loading) Layout { @@ -34,9 +39,39 @@ pub enum TreeMode { /// Show additional metadata information including buffer sizes (requires fetching segments) #[arg(short, long)] verbose: bool, + /// Output as JSON + #[arg(long)] + json: bool, }, } +/// Layout tree node for JSON output. +#[derive(Serialize)] +pub struct LayoutTreeNode { + /// Encoding name. + pub encoding: String, + /// Data type. + pub dtype: String, + /// Number of rows. + pub row_count: u64, + /// Metadata size in bytes. + pub metadata_bytes: usize, + /// Segment IDs referenced by this layout. + pub segment_ids: Vec, + /// Child layouts. + pub children: Vec, +} + +/// Layout tree node with name for JSON output. +#[derive(Serialize)] +pub struct LayoutTreeNodeWithName { + /// Child name. + pub name: String, + /// Child node data. + #[serde(flatten)] + pub node: LayoutTreeNode, +} + /// Print tree views of a Vortex file (layout tree or array tree). /// /// # Errors @@ -44,14 +79,18 @@ pub enum TreeMode { /// Returns an error if the file cannot be opened or read. pub async fn exec_tree(session: &VortexSession, args: TreeArgs) -> VortexResult<()> { match args.mode { - TreeMode::Array { file } => exec_array_tree(session, &file).await?, - TreeMode::Layout { file, verbose } => exec_layout_tree(session, &file, verbose).await?, + TreeMode::Array { file, json } => exec_array_tree(session, &file, json).await?, + TreeMode::Layout { + file, + verbose, + json, + } => exec_layout_tree(session, &file, verbose, json).await?, } Ok(()) } -async fn exec_array_tree(session: &VortexSession, file: &Path) -> VortexResult<()> { +async fn exec_array_tree(session: &VortexSession, file: &Path, _json: bool) -> VortexResult<()> { let full = session .open_options() .open(file) @@ -66,21 +105,57 @@ async fn exec_array_tree(session: &VortexSession, file: &Path) -> VortexResult<( Ok(()) } -async fn exec_layout_tree(session: &VortexSession, file: &Path, verbose: bool) -> VortexResult<()> { +async fn exec_layout_tree( + session: &VortexSession, + file: &Path, + verbose: bool, + json: bool, +) -> VortexResult<()> { let vxf = session.open_options().open(file).await?; + let footer = vxf.footer(); - if verbose { + if json { + let tree = layout_to_json(footer.layout().clone())?; + let json_output = serde_json::to_string_pretty(&tree) + .map_err(|e| vortex::error::vortex_err!("Failed to serialize JSON: {e}"))?; + println!("{json_output}"); + } else if verbose { // In verbose mode, fetch segments to display buffer sizes. - let output = vxf - .footer() + let output = footer .layout() .display_tree_with_segments(vxf.segment_source()) .await?; - println!("{}", output); + println!("{output}"); } else { // In non-verbose mode, just display layout tree without fetching segments. - println!("{}", vxf.footer().layout().display_tree()); + println!("{}", footer.layout().display_tree()); } Ok(()) } + +fn layout_to_json(layout: LayoutRef) -> VortexResult { + let children = layout.children()?; + let child_names: Vec<_> = layout.child_names().collect(); + + let children_json: Vec = children + .into_iter() + .zip(child_names.into_iter()) + .map(|(child, name)| { + let node = layout_to_json(child)?; + Ok(LayoutTreeNodeWithName { + name: name.to_string(), + node, + }) + }) + .collect::>>()?; + + Ok(LayoutTreeNode { + encoding: layout.encoding().to_string(), + dtype: layout.dtype().to_string(), + row_count: layout.row_count(), + metadata_bytes: layout.metadata().len(), + segment_ids: layout.segment_ids().iter().map(|s| **s).collect(), + children: children_json, + }) +}