diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d0bc9f146..e4566547c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -16,3 +16,7 @@ updates: directory: "/packages/duckdb-server" schedule: interval: monthly + - package-ecosystem: cargo + directory: "/packages/duckdb-server-rust" + schedule: + interval: monthly diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8d61c13e3..42ab2e38b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -34,7 +34,7 @@ jobs: - run: npm run test python: - name: Test on Python + name: Test in Python runs-on: ubuntu-latest @@ -64,3 +64,36 @@ jobs: hatch build hatch fmt --check hatch run test:cov + + rust: + name: Test in Rust + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rust-src, rustfmt + + - name: Check formatting + run: | + cd packages/duckdb-server-rust + cargo fmt -- --check + - name: Check + run: | + cd packages/duckdb-server-rust + cargo check + - name: Clippy + run: | + cd packages/duckdb-server-rust + cargo clippy --all -- -D warnings + - name: Build + run: | + cd packages/duckdb-server-rust + cargo build --verbose + - name: Test + run: | + cd packages/duckdb-server-rust + cargo test --verbose diff --git a/dev/bundle.html b/dev/bundle.html index 1bd8dd35f..ee947c43a 100644 --- a/dev/bundle.html +++ b/dev/bundle.html @@ -17,6 +17,7 @@ @@ -47,28 +48,31 @@ async function create() { try { - await coordinator().createBundle('test', queries); - output.innerText = "Created bundle" + await coordinator.createBundle('test', queries); + output.innerText = "Created bundle"; } catch(err) { - output.innerText = `Error: ${err}` + output.innerText = `Error: ${err}`; + console.log(err.stack); } } async function load() { try { - await coordinator().loadBundle('test'); - output.innerText = "Loaded bundle" + await coordinator.loadBundle('test'); + output.innerText = "Loaded bundle"; } catch(err) { - output.innerText = `Error: ${err}` + output.innerText = `Error: ${err}`; + console.log(err.stack); } } async function query() { try { - const result = await coordinator().query(queries[1], {cache: false}); - output.innerText = `Result = ${result}` + const result = await coordinator.query(queries[1], {cache: false}); + output.innerText = `Result = ${result}`; } catch(err) { - output.innerText = `Error: ${err}` + output.innerText = `Error: ${err}`; + console.log(err.stack); } } diff --git a/dev/index.html b/dev/index.html index 8e52c152b..f9ba18789 100644 --- a/dev/index.html +++ b/dev/index.html @@ -65,6 +65,7 @@ + diff --git a/dev/setup.js b/dev/setup.js index 863821600..86cfc5702 100644 --- a/dev/setup.js +++ b/dev/setup.js @@ -16,17 +16,20 @@ export function clear() { let wasm; -export async function setDatabaseConnector(type, options) { +export async function setDatabaseConnector(type) { let connector; switch (type) { case 'socket': - connector = socketConnector(options); + connector = socketConnector(); break; case 'rest': - connector = restConnector(options); + connector = restConnector(); + break; + case 'rest_https': + connector = restConnector('https://localhost:3000/'); break; case 'wasm': - connector = wasm || (wasm = wasmConnector(options)); + connector = wasm || (wasm = wasmConnector()); break; default: throw new Error(`Unrecognized connector type: ${type}`); diff --git a/package.json b/package.json index b28052056..a0bb0fb3a 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "lint": "lerna run lint", "test": "lerna run test", "server": "cd packages/duckdb-server && hatch run serve", + "server:rust": "cd packages/duckdb-server-rust && cargo run", "server:node": "nodemon packages/duckdb/bin/run-server.js", "dev": "vite", "release": "npm run test && npm run lint && lerna publish && npm run release:python", diff --git a/packages/core/src/Coordinator.js b/packages/core/src/Coordinator.js index 191258273..68cd1b840 100644 --- a/packages/core/src/Coordinator.js +++ b/packages/core/src/Coordinator.js @@ -44,6 +44,7 @@ export class Coordinator { consolidate = true, indexes = {} } = {}) { + /** @type {QueryManager} */ this.manager = manager; this.manager.cache(cache); this.manager.consolidate(consolidate); @@ -152,11 +153,25 @@ export class Coordinator { return this.query(query, { ...options, cache: true, priority: Priority.Low }); } + /** + * Create a bundle of queries that can be loaded into the cache. + * + * @param {string} name The name of the bundle. + * @param {[string | {sql: string}, {alias: string}]} queries The queries to save into the bundle. + * @param {number} priority Request priority. + * @returns + */ createBundle(name, queries, priority = Priority.Low) { - const options = { name, queries }; + const options = { name, queries: queries.map(q => typeof q == 'string' ? {sql: q} : q) }; return this.manager.request({ type: 'create-bundle', options }, priority); } + /** + * Load a bundle into the cache. + * @param {string} name The name of the bundle. + * @param {number} priority Request priority. + * @returns + */ loadBundle(name, priority = Priority.High) { const options = { name }; return this.manager.request({ type: 'load-bundle', options }, priority); diff --git a/packages/core/src/QueryManager.js b/packages/core/src/QueryManager.js index 9badd816b..c91f35502 100644 --- a/packages/core/src/QueryManager.js +++ b/packages/core/src/QueryManager.js @@ -1,13 +1,13 @@ import { consolidator } from './QueryConsolidator.js'; import { lruCache, voidCache } from './util/cache.js'; -import { priorityQueue } from './util/priority-queue.js'; +import { PriorityQueue } from './util/priority-queue.js'; import { QueryResult } from './util/query-result.js'; export const Priority = { High: 0, Normal: 1, Low: 2 }; export class QueryManager { constructor() { - this.queue = priorityQueue(3); + this.queue = new PriorityQueue(3); this.db = null; this.clientCache = null; this._logger = null; diff --git a/packages/core/src/connectors/rest.js b/packages/core/src/connectors/rest.js index 00c788698..388b0889d 100644 --- a/packages/core/src/connectors/rest.js +++ b/packages/core/src/connectors/rest.js @@ -5,7 +5,7 @@ export function restConnector(uri = 'http://localhost:3000/') { /** * Query the DuckDB server. * @param {object} query - * @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'. + * @param {'exec' | 'arrow' | 'json' | 'create-bundle' | 'load-bundle'} [query.type] The query type. * @param {string} query.sql A SQL query string. * @returns the query result */ @@ -19,9 +19,9 @@ export function restConnector(uri = 'http://localhost:3000/') { body: JSON.stringify(query) }); - return query.type === 'exec' ? req + return query.type === 'json' ? (await req).json() : query.type === 'arrow' ? tableFromIPC(req) - : (await req).json(); + : req; } }; } diff --git a/packages/core/src/connectors/socket.js b/packages/core/src/connectors/socket.js index 95f070545..1e4af0fd5 100644 --- a/packages/core/src/connectors/socket.js +++ b/packages/core/src/connectors/socket.js @@ -84,7 +84,7 @@ export function socketConnector(uri = 'ws://localhost:3000/') { /** * Query the DuckDB server. * @param {object} query - * @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'. + * @param {'exec' | 'arrow' | 'json' | 'create-bundle' | 'load-bundle'} [query.type] The query type. * @param {string} query.sql A SQL query string. * @returns the query result */ diff --git a/packages/core/src/connectors/wasm.js b/packages/core/src/connectors/wasm.js index 3f20640ca..eafee4091 100644 --- a/packages/core/src/connectors/wasm.js +++ b/packages/core/src/connectors/wasm.js @@ -45,7 +45,7 @@ export function wasmConnector(options = {}) { /** * Query the DuckDB-WASM instance. * @param {object} query - * @param {'exec' | 'arrow' | 'json'} [query.type] The query type: 'exec', 'arrow', or 'json'. + * @param {'exec' | 'arrow' | 'json' | 'create-bundle' | 'load-bundle'} [query.type] The query type. * @param {string} query.sql A SQL query string. * @returns the query result */ @@ -53,9 +53,9 @@ export function wasmConnector(options = {}) { const { type, sql } = query; const con = await getConnection(); const result = await con.query(sql); - return type === 'exec' ? undefined + return type === 'json' ? result.toArray() : type === 'arrow' ? result - : result.toArray(); + : undefined; } }; } diff --git a/packages/core/src/util/priority-queue.js b/packages/core/src/util/priority-queue.js index 85f997498..5b2b5bc7b 100644 --- a/packages/core/src/util/priority-queue.js +++ b/packages/core/src/util/priority-queue.js @@ -1,85 +1,84 @@ -/** - * Create a new priority queue instance. - * @param {number} ranks An integer number of rank-order priority levels. - * @returns A priority queue instance. - */ -export function priorityQueue(ranks) { - // one list for each integer priority level - const queue = Array.from( +export class PriorityQueue { + /** + * Create a new priority queue instance. + * @param {number} ranks An integer number of rank-order priority levels. + */ + constructor(ranks) { + // one list for each integer priority level + this.queue = Array.from( { length: ranks }, () => ({ head: null, tail: null }) ); + } - return { - /** - * Indicate if the queue is empty. - * @returns {boolean} true if empty, false otherwise. - */ - isEmpty() { - return queue.every(list => !list.head); - }, + /** + * Indicate if the queue is empty. + * @returns {boolean} true if empty, false otherwise. + */ + isEmpty() { + return this.queue.every(list => !list.head); + } - /** - * Insert an item into the queue with a given priority rank. - * @param {*} item The item to add. - * @param {number} rank The integer priority rank. - * Priority ranks are integers starting at zero. - * Lower ranks indicate higher priority. - */ - insert(item, rank) { - const list = queue[rank]; - if (!list) { - throw new Error(`Invalid queue priority rank: ${rank}`); - } + /** + * Insert an item into the queue with a given priority rank. + * @param {*} item The item to add. + * @param {number} rank The integer priority rank. + * Priority ranks are integers starting at zero. + * Lower ranks indicate higher priority. + */ + insert(item, rank) { + const list = this.queue[rank]; + if (!list) { + throw new Error(`Invalid queue priority rank: ${rank}`); + } - const node = { item, next: null }; - if (list.head === null) { - list.head = list.tail = node; - } else { - list.tail = (list.tail.next = node); - } - }, + const node = { item, next: null }; + if (list.head === null) { + list.head = list.tail = node; + } else { + list.tail = list.tail.next = node; + } + } - /** - * Remove a set of items from the queue, regardless of priority rank. - * If a provided item is not in the queue it will be ignored. - * @param {(item: *) => boolean} test A predicate function to test - * if an item should be removed (true to drop, false to keep). - */ - remove(test) { - for (const list of queue) { - let { head, tail } = list; - for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) { - if (test(curr.item)) { - if (curr === head) { - head = curr.next; - } else { - prev.next = curr.next; - } - if (curr === tail) tail = prev || head; - } - } - list.head = head; - list.tail = tail; - } - }, + /** + * Remove a set of items from the queue, regardless of priority rank. + * If a provided item is not in the queue it will be ignored. + * @param {(item: *) => boolean} test A predicate function to test + * if an item should be removed (true to drop, false to keep). + */ + remove(test) { + for (const list of this.queue) { + let { head, tail } = list; + for (let prev = null, curr = head; curr; prev = curr, curr = curr.next) { + if (test(curr.item)) { + if (curr === head) { + head = curr.next; + } else { + prev.next = curr.next; + } + if (curr === tail) tail = prev || head; + } + } + list.head = head; + list.tail = tail; + } + } - /** - * Remove and return the next highest priority item. - * @returns {*} The next item in the queue, - * or undefined if this queue is empty. - */ - next() { - for (const list of queue) { - const { head } = list; - if (head !== null) { - list.head = head.next; - if (list.tail === head) { - list.tail = null; - } - return head.item; - } - } - } - }; + /** + * Remove and return the next highest priority item. + * @returns {*} The next item in the queue, + * or undefined if this queue is empty. + */ + next() { + for (const list of this.queue) { + const { head } = list; + if (head !== null) { + list.head = head.next; + if (list.tail === head) { + list.tail = null; + } + return head.item; + } + } + } } diff --git a/packages/duckdb-server-rust/.gitignore b/packages/duckdb-server-rust/.gitignore new file mode 100644 index 000000000..2a02fa38b --- /dev/null +++ b/packages/duckdb-server-rust/.gitignore @@ -0,0 +1,3 @@ +target/ +localhost.pem +localhost-key.pem diff --git a/packages/duckdb-server-rust/.vscode/launch.json b/packages/duckdb-server-rust/.vscode/launch.json new file mode 100644 index 000000000..a501cc629 --- /dev/null +++ b/packages/duckdb-server-rust/.vscode/launch.json @@ -0,0 +1,45 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'duckdb-server-rust'", + "cargo": { + "args": [ + "build", + "--bin=duckdb-server-rust", + "--package=duckdb-server-rust" + ], + "filter": { + "name": "duckdb-server-rust", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, + { + "type": "lldb", + "request": "launch", + "name": "Debug unit tests in executable 'duckdb-server-rust'", + "cargo": { + "args": [ + "test", + "--no-run", + "--bin=duckdb-server-rust", + "--package=duckdb-server-rust" + ], + "filter": { + "name": "duckdb-server-rust", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} \ No newline at end of file diff --git a/packages/duckdb-server-rust/Cargo.lock b/packages/duckdb-server-rust/Cargo.lock new file mode 100644 index 000000000..47337069b --- /dev/null +++ b/packages/duckdb-server-rust/Cargo.lock @@ -0,0 +1,3425 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "const-random", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "arrow" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05048a8932648b63f21c37d88b552ccc8a65afb6dfe9fc9f30ce79174c2e7a85" +dependencies = [ + "arrow-arith", + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-csv", + "arrow-data", + "arrow-ipc", + "arrow-json", + "arrow-ord", + "arrow-row", + "arrow-schema", + "arrow-select", + "arrow-string", +] + +[[package]] +name = "arrow-arith" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d8a57966e43bfe9a3277984a14c24ec617ad874e4c0e1d2a1b083a39cfbf22c" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "num", +] + +[[package]] +name = "arrow-array" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f4a9468c882dc66862cef4e1fd8423d47e67972377d85d80e022786427768c" +dependencies = [ + "ahash 0.8.11", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "hashbrown 0.14.5", + "num", +] + +[[package]] +name = "arrow-buffer" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c975484888fc95ec4a632cdc98be39c085b1bb518531b0c80c5d462063e5daa1" +dependencies = [ + "bytes", + "half", + "num", +] + +[[package]] +name = "arrow-cast" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da26719e76b81d8bc3faad1d4dbdc1bcc10d14704e63dc17fc9f3e7e1e567c8e" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "atoi", + "base64 0.22.1", + "chrono", + "comfy-table", + "half", + "lexical-core", + "num", + "ryu", +] + +[[package]] +name = "arrow-csv" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c13c36dc5ddf8c128df19bab27898eea64bf9da2b555ec1cd17a8ff57fba9ec2" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "csv", + "csv-core", + "lazy_static", + "lexical-core", + "regex", +] + +[[package]] +name = "arrow-data" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd9d6f18c65ef7a2573ab498c374d8ae364b4a4edf67105357491c031f716ca5" +dependencies = [ + "arrow-buffer", + "arrow-schema", + "half", + "num", +] + +[[package]] +name = "arrow-ipc" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e786e1cdd952205d9a8afc69397b317cfbb6e0095e445c69cda7e8da5c1eeb0f" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "flatbuffers", +] + +[[package]] +name = "arrow-json" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb22284c5a2a01d73cebfd88a33511a3234ab45d66086b2ca2d1228c3498e445" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-cast", + "arrow-data", + "arrow-schema", + "chrono", + "half", + "indexmap", + "lexical-core", + "num", + "serde", + "serde_json", +] + +[[package]] +name = "arrow-ord" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42745f86b1ab99ef96d1c0bcf49180848a64fe2c7a7a0d945bc64fa2b21ba9bc" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "half", + "num", +] + +[[package]] +name = "arrow-row" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd09a518c602a55bd406bcc291a967b284cfa7a63edfbf8b897ea4748aad23c" +dependencies = [ + "ahash 0.8.11", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "half", +] + +[[package]] +name = "arrow-schema" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e972cd1ff4a4ccd22f86d3e53e835c2ed92e0eea6a3e8eadb72b4f1ac802cf8" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "arrow-select" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "600bae05d43483d216fb3494f8c32fdbefd8aa4e1de237e790dbb3d9f44690a3" +dependencies = [ + "ahash 0.8.11", + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "num", +] + +[[package]] +name = "arrow-string" +version = "52.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dc1985b67cb45f6606a248ac2b4a288849f196bab8c657ea5589f47cdd55e6" +dependencies = [ + "arrow-array", + "arrow-buffer", + "arrow-data", + "arrow-schema", + "arrow-select", + "memchr", + "num", + "regex", + "regex-syntax 0.8.4", +] + +[[package]] +name = "async-compression" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", + "zstd", + "zstd-safe", +] + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "aws-lc-rs" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae74d9bd0a7530e8afd1770739ad34b36838829d6ad61818f9230f683f5ad77" +dependencies = [ + "aws-lc-sys", + "mirai-annotations", + "paste", + "zeroize", +] + +[[package]] +name = "aws-lc-sys" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0e249228c6ad2d240c2dc94b714d711629d52bad946075d8e9b2f5391f0703" +dependencies = [ + "bindgen", + "cc", + "cmake", + "dunce", + "fs_extra", + "libc", + "paste", +] + +[[package]] +name = "axum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +dependencies = [ + "async-trait", + "axum-core", + "axum-macros", + "base64 0.21.7", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.1", + "tokio", + "tokio-tungstenite", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "axum-server" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56bac90848f6a9393ac03c63c640925c4b7c8ca21654de40d53f55964667c7d8" +dependencies = [ + "arc-swap", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower 0.4.13", + "tower-service", +] + +[[package]] +name = "axum-server-dual-protocol" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2164551db024e87f20316d164eab9f5ad342d8188b08051ceb15ca92a60ea7b7" +dependencies = [ + "axum-server", + "bytes", + "http", + "http-body-util", + "pin-project", + "rustls", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-streams" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e2eb21ea12eb351da044b8d9ea9d1f622c7f05e9a4ad0a441ed253026b4b4cd" +dependencies = [ + "arrow", + "axum", + "bytes", + "cargo-husky", + "futures", + "http", + "http-body", + "mime", + "tokio", + "tokio-stream", + "tokio-util", +] + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.74", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.74", + "syn_derive", +] + +[[package]] +name = "brotli" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" + +[[package]] +name = "cargo-husky" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b02b629252fe8ef6460461409564e2c21d0c8e77e0944f3d189ff06c4e932ad" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets", +] + +[[package]] +name = "ciborium" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" + +[[package]] +name = "ciborium-ll" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d8838454fda655dafd3accb2b6e2bea645b9e4078abe84a22ceb947235c5cc" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "cmake" +version = "0.1.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +dependencies = [ + "cc", +] + +[[package]] +name = "comfy-table" +version = "7.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b34115915337defe99b2aff5c2ce6771e5fbc4079f4b506301f5cf394c8452f7" +dependencies = [ + "strum 0.26.3", + "strum_macros 0.26.4", + "unicode-width", +] + +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom", + "once_cell", + "tiny-keccak", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "futures", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "deadpool" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-r2d2" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8976b03b05529a3ea46dba37aaa51e6990bf85a075f8d8e1b150d50d816f71a" +dependencies = [ + "deadpool", + "deadpool-sync", + "r2d2", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" +dependencies = [ + "tokio", +] + +[[package]] +name = "deadpool-sync" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524bc3df0d57e98ecd022e21ba31166c2625e7d3e5bcc4510efaeeab4abcab04" +dependencies = [ + "deadpool-runtime", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "duckdb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "626373a331b49f94b24edc4e53a59b0b354f085ac3b339d43d31da7a9b145004" +dependencies = [ + "arrow", + "cast", + "csv", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libduckdb-sys", + "memchr", + "num-integer", + "r2d2", + "rust_decimal", + "smallvec", + "strum 0.25.0", + "url", +] + +[[package]] +name = "duckdb-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "arrow", + "async-stream", + "async-trait", + "axum", + "axum-server", + "axum-server-dual-protocol", + "axum-streams", + "criterion", + "deadpool", + "deadpool-r2d2", + "duckdb", + "futures", + "http-body-util", + "listenfd", + "lru", + "r2d2", + "regex", + "serde", + "serde_json", + "sha2", + "temp_testdir", + "tokio", + "tokio-stream", + "tower 0.5.0", + "tower-http", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "filetime" +version = "0.2.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf401df4a4e3872c4fe8151134cf483738e74b67fc934d6532c882b3d24a4550" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flatbuffers" +version = "24.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8add37afff2d4ffa83bc748a70b4b1370984f6980768554182424ef71447c35f" +dependencies = [ + "bitflags 1.3.2", + "rustc_version", +] + +[[package]] +name = "flate2" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", + "num-traits", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "is-terminal" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lexical-core" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cde5de06e8d4c2faabc400238f9ae1c74d5412d03a7bd067645ccbc47070e46" +dependencies = [ + "lexical-parse-float", + "lexical-parse-integer", + "lexical-util", + "lexical-write-float", + "lexical-write-integer", +] + +[[package]] +name = "lexical-parse-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683b3a5ebd0130b8fb52ba0bdc718cc56815b6a097e28ae5a6997d0ad17dc05f" +dependencies = [ + "lexical-parse-integer", + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-parse-integer" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d0994485ed0c312f6d965766754ea177d07f9c00c9b82a5ee62ed5b47945ee9" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "lexical-util" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5255b9ff16ff898710eb9eb63cb39248ea8a5bb036bea8085b1a767ff6c4e3fc" +dependencies = [ + "static_assertions", +] + +[[package]] +name = "lexical-write-float" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accabaa1c4581f05a3923d1b4cfd124c329352288b7b9da09e766b0668116862" +dependencies = [ + "lexical-util", + "lexical-write-integer", + "static_assertions", +] + +[[package]] +name = "lexical-write-integer" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b6f3d1f4422866b68192d62f77bc5c700bee84f3069f2469d7bc8c77852446" +dependencies = [ + "lexical-util", + "static_assertions", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libduckdb-sys" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa48143af4679c674db9ad7951ff1d3ce67b8b55578e523d96af54152df6c13b" +dependencies = [ + "autocfg", + "cc", + "flate2", + "pkg-config", + "serde", + "serde_json", + "tar", + "vcpkg", +] + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "listenfd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0500463acd96259d219abb05dc57e5a076ef04b2db9a2112846929b5f174c96" +dependencies = [ + "libc", + "uuid", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "mirai-annotations" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9be0862c1b3f26a88803c4a49de6889c10e608b3ee9344e6ef5b45fb37ad3d1" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.36.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b64972346851a39438c60b341ebc01bba47464ae329e55cf343eb93964efd9" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" +dependencies = [ + "proc-macro2", + "syn 2.0.74", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r2d2" +version = "0.8.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" +dependencies = [ + "log", + "parking_lot", + "scheduled-thread-pool", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1790d1c4c0ca81211399e0e0af16333276f375209e71a37b67698a373db5b47a" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.23.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c58f8c84392efc0a126acce10fa59ff7b3d2ac06ab451a33f2741989b806b044" +dependencies = [ + "aws-lc-rs", + "once_cell", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + +[[package]] +name = "rustls-webpki" +version = "0.102.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +dependencies = [ + "aws-lc-rs", + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scheduled-thread-pool" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.207" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5665e14a49a4ea1b91029ba7d3bca9f299e1f7cfa194388ccc20f14743e784f2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.207" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aea2634c86b0e8ef2cfdc0c340baede54ec27b1e46febd7f80dffb2aa44a00e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "serde_json" +version = "1.0.124" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66ad62847a56b3dba58cc891acd13884b9c61138d330c0d7b6181713d4fce38d" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros 0.25.3", +] + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.74", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.74", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "temp_testdir" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "921f1e9c427802414907a48b21a6504ff6b3a15a1a3cf37e699590949ad9befc" + +[[package]] +name = "thiserror" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.39.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36b837f86b25d7c0d7988f00a54e74739be6477f2aac6201b8f429a7569991b7" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5" +dependencies = [ + "async-compression", + "bitflags 2.6.0", + "bytes", + "futures-core", + "http", + "http-body", + "http-body-util", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand", + "sha1", + "thiserror", + "url", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.74", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/packages/duckdb-server-rust/Cargo.toml b/packages/duckdb-server-rust/Cargo.toml new file mode 100644 index 000000000..89da32ec3 --- /dev/null +++ b/packages/duckdb-server-rust/Cargo.toml @@ -0,0 +1,52 @@ +[package] +name = "duckdb-server" +version = "0.1.0" +edition = "2021" +repository = "https://github.com/uwdata/mosaic" +description = "DuckDB Server for Mosaic." +license = "BSD-3-Clause" +exclude = [ + "data/*", + ".vscode/*", +] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +arrow = "52.1" +async-trait = "0.1.80" +axum = { version = "0.7", features = ["http1", "http2", "ws", "json", "tokio", "tracing", "macros"] } +axum-server = { version = "0.7", features = ["tls-rustls"] } +axum-server-dual-protocol = "0.7" +duckdb = { version = "1", features = ["bundled", "csv", "json", "parquet", "url", "r2d2"] } +futures = "0.3" +listenfd = "1.0" +lru = "0.12" +r2d2 = "0.8" +regex = "1.5" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +sha2 = "0.10" +tokio = { version = "1", features = ["full"] } +tower-http = { version = "0.5.0", features = ["cors", "compression-full", "trace"] } +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } +axum-streams = { version = "0.18", features=["arrow"] } +async-stream = "0.3" +deadpool = { version = "0.12", features = ["managed"] } +deadpool-r2d2 = {version = "0.4.1"} +tokio-stream = "0.1" + +[dev-dependencies] +criterion = {version = "0.5", features=["async_futures", "html_reports"]} +http-body-util = "0.1.0" +temp_testdir = "0.2" +tower = { version = "0.5", features = ["util"] } + +[[bench]] +name = "benchmark" +harness = false + +[profile.release] +codegen-units = 1 diff --git a/packages/duckdb-server-rust/Readme.md b/packages/duckdb-server-rust/Readme.md new file mode 100644 index 000000000..6b87e2db1 --- /dev/null +++ b/packages/duckdb-server-rust/Readme.md @@ -0,0 +1,121 @@ +# DuckDB Server + +[![Crates.io](https://img.shields.io/crates/v/duckdb-server.svg)](https://crates.io/crates/duckdb-server) + +A Rust-based server that runs a local DuckDB instance and support queries over Web Sockets or HTTP/HTTPS, returning data in either [Apache Arrow](https://arrow.apache.org/) or JSON format. + +_Note:_ This package provides a local DuckDB server. To instead use DuckDB-WASM in the browser, use the `wasmConnector` in the [`mosaic-core`](https://github.com/uwdata/mosaic/tree/main/packages/mosaic-core) package. + +## Usage + +Install the server with Cargo or [Cargo B(inary)Install](https://github.com/cargo-bins/cargo-binstall). + +```sh +cargo install duckdb-server +# or +cargo binstall duckdb-server +``` + +Then run the server with + +```sh +duckdb-server +``` + +You can disable or customize logging with the `RUST_LOG` environment variable. + +```sh +env RUST_LOG="" duckdb-server +``` + +The server can reuse existing sockets with `listenfd`. + +```sh +systemfd --no-pid -s http::3000 -- duckdb-server +``` + +To use HTTPS and HTTP/2, you need `localhost.pem` and `localhost-key.pem` in the current directory or at the env variable `CARGO_MANIFEST_DIR`. + +Create certificates for localhost with [mkcert](https://github.com/FiloSottile/mkcert) + +```sh +mkcert localhost +``` + +## API + +The server supports queries via HTTP GET and POST, and WebSockets. The GET endpoint is useful for debugging. For example, you can query it with [this url](). + +Each endpoint takes a JSON object with a command in the `type`. The server supports the following commands. + +### `exec` + +Executes the SQL query in the `sql` field. + +### `arrow` + +Executes the SQL query in the `sql` field and returns the result in Apache Arrow format. + +### `json` + +Executes the SQL query in the `sql` field and returns the result in JSON format. + +### `create-bundle` + +Caches the results of the SQL queries in the `queries` field and the required datasets. + +### `load-bundle` + +Loads the bundled results. + +## Developers + +### Build + +Build the release binary with + +```sh +cargo build --release +``` + +### Develop + +To run the server and restart it when the code changes, install `cargo-watch` and `systemfd` with + +```sh +cargo install cargo-watch systemfd +``` + +Then run the server with + +```sh +systemfd --no-pid -s https::3000 -- cargo watch -x run +``` + +Or just use (but this won't restart when the code changes) + +```sh +cargo run +``` + +Before sending a pull request, run the tests with + +```sh +cargo test +cargo clippy +cargo fmt +``` + +Run the benchmarks with + +```sh +cargo bench +``` + +### Update dependencies + +Update the lockfile with `cargo update` and look for outdated dependencies with [cargo-outdated](https://github.com/kbknapp/cargo-outdated) `cargo outdated -d 1`. + +### Release + +Bump the version in `Cargo.toml` and then run `cargo publish`. diff --git a/packages/duckdb-server-rust/benches/benchmark.rs b/packages/duckdb-server-rust/benches/benchmark.rs new file mode 100644 index 000000000..79769d180 --- /dev/null +++ b/packages/duckdb-server-rust/benches/benchmark.rs @@ -0,0 +1,43 @@ +use criterion::async_executor::FuturesExecutor; +use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; +use serde_json::to_value; +use std::sync::Arc; +use tokio::sync::Mutex; + +use duckdb_server::{get_key, handle, AppState, Command, ConnectionPool, QueryParams}; + +pub fn benchmark(c: &mut Criterion) { + let db = ConnectionPool::new(":memory:", 10).unwrap(); + let cache = lru::LruCache::new(10.try_into().unwrap()); + + let state = Arc::new(AppState { + db: Box::new(db), + cache: Mutex::new(cache), + }); + + let mut group = c.benchmark_group("handle"); + for command in [Command::Arrow, Command::Json].iter() { + group.bench_with_input( + BenchmarkId::from_parameter(to_value(command).unwrap().to_string()), + command, + |b, command| { + b.to_async(FuturesExecutor).iter(|| { + let params = QueryParams { + query_type: Some(command.clone()), + sql: Some("SELECT 1 AS foo".to_string()), + ..QueryParams::default() + }; + handle(&state, params) + }) + }, + ); + } + group.finish(); + + c.bench_function("get key", |b| { + b.iter(|| get_key("SELECT 1", &Command::Arrow)) + }); +} + +criterion_group!(benches, benchmark); +criterion_main!(benches); diff --git a/packages/duckdb-server-rust/data b/packages/duckdb-server-rust/data new file mode 120000 index 000000000..e67b45590 --- /dev/null +++ b/packages/duckdb-server-rust/data @@ -0,0 +1 @@ +../../data \ No newline at end of file diff --git a/packages/duckdb-server-rust/src/app.rs b/packages/duckdb-server-rust/src/app.rs new file mode 100644 index 000000000..6ed4e3ec7 --- /dev/null +++ b/packages/duckdb-server-rust/src/app.rs @@ -0,0 +1,67 @@ +use anyhow::Result; +use axum::{ + extract::{Query, State, WebSocketUpgrade}, + http::Method, + response::Json, + routing::get, + Router, +}; +use std::sync::Arc; +use std::time::Duration; +use tokio::sync::Mutex; +use tower_http::cors::{Any, CorsLayer}; +use tower_http::{compression::CompressionLayer, trace::TraceLayer}; + +use crate::db::ConnectionPool; +use crate::interfaces::{AppError, AppState, QueryParams, QueryResponse}; +use crate::query; +use crate::websocket; + +async fn handle_get( + State(state): State>, + ws: Option, + Query(params): Query, +) -> Result { + if let Some(ws) = ws { + // WebSocket upgrade + Ok(QueryResponse::Response( + ws.on_upgrade(|socket| websocket::handle(socket, state)), + )) + } else { + // HTTP request + query::handle(&state, params).await + } +} + +async fn handle_post( + State(state): State>, + Json(params): Json, +) -> Result { + query::handle(&state, params).await +} + +pub fn app() -> Result { + // Database and state setup + let db = ConnectionPool::new(":memory:", 16)?; + let cache = lru::LruCache::new(1000.try_into()?); + + let state = Arc::new(AppState { + db: Box::new(db), + cache: Mutex::new(cache), + }); + + // CORS setup + let cors = CorsLayer::new() + .allow_origin(Any) + .allow_methods([Method::OPTIONS, Method::POST, Method::GET]) + .allow_headers(Any) + .max_age(Duration::from_secs(60) * 60 * 24); + + // Router setup + Ok(Router::new() + .route("/", get(handle_get).post(handle_post)) + .with_state(state) + .layer(cors) + .layer(CompressionLayer::new()) + .layer(TraceLayer::new_for_http())) +} diff --git a/packages/duckdb-server-rust/src/bundle.rs b/packages/duckdb-server-rust/src/bundle.rs new file mode 100644 index 000000000..ae0a80641 --- /dev/null +++ b/packages/duckdb-server-rust/src/bundle.rs @@ -0,0 +1,132 @@ +use crate::cache::{get_key, retrieve}; +use crate::db::Database; +use crate::interfaces::Command; +use anyhow::{Context, Result}; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::fs; +use std::path::Path; +use tokio::sync::Mutex; + +#[derive(Serialize, Deserialize)] +pub struct Manifest { + tables: Vec, + queries: Vec, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct Query { + pub sql: String, + pub alias: Option, +} + +pub async fn create( + db: &dyn Database, + cache: &Mutex>>, + queries: Vec, + bundle_dir: &Path, +) -> Result { + let describe_re = Regex::new(r"^DESCRIBE ")?; + let pragma_re = Regex::new(r"^PRAGMA ")?; + let view_re = Regex::new(r"^CREATE( TEMP| TEMPORARY)? VIEW")?; + let table_re = Regex::new(r"^CREATE( TEMP| TEMPORARY)? TABLE( IF NOT EXISTS)? ([^\s]+)")?; + + let mut manifest = Manifest { + tables: Vec::new(), + queries: Vec::new(), + }; + + fs::create_dir_all(bundle_dir).context("Failed to create bundle directory")?; + + for query in queries { + let sql = query.sql; + + if let Some(alias) = &query.alias { + let file = bundle_dir.join(format!("{alias}.parquet")); + db.execute(format!( + "COPY ({}) TO '{}' (FORMAT PARQUET)", + sql, + file.display() + )) + .await?; + manifest.tables.push(alias.clone()); + } else if sql.starts_with("CREATE ") { + if view_re.is_match(&sql) { + continue; // Ignore views + } + + if let Some(captures) = table_re.captures(&sql) { + let table = captures.get(3).unwrap().as_str(); + let file = bundle_dir.join(format!("{table}.parquet")); + db.execute(sql.clone()).await?; + db.execute(format!( + "COPY {} TO '{}' (FORMAT PARQUET)", + table, + file.display() + )) + .await?; + manifest.tables.push(table.to_string()); + } + } else if !pragma_re.is_match(&sql) { + let command = if describe_re.is_match(&sql) { + Command::Json + } else { + Command::Arrow + }; + let key = get_key(&sql, &command); + let result = retrieve(cache, sql, &command, true, |sql| { + if let Command::Arrow = command { + db.get_arrow(sql) + } else { + db.get_json(sql) + } + }) + .await?; + fs::write(bundle_dir.join(&key), &result) + .context("Failed to write query result to file")?; + manifest.queries.push(key); + } + } + + let manifest_file = bundle_dir.join("bundle.json"); + let manifest_json = + serde_json::to_string_pretty(&manifest).context("Failed to serialize manifest")?; + fs::write(manifest_file, manifest_json).context("Failed to write manifest to file")?; + + Ok(manifest) +} + +pub async fn load( + db: &dyn Database, + cache: &Mutex>>, + bundle_dir: &Path, +) -> Result<()> { + let manifest_file = bundle_dir.join("bundle.json"); + let manifest_json = + fs::read_to_string(&manifest_file).context("Failed to read manifest file")?; + let manifest: Manifest = + serde_json::from_str(&manifest_json).context("Failed to deserialize manifest")?; + + // Load precomputed query results into the cache + let mut cache_lock = cache.lock().await; + for key in &manifest.queries { + tracing::debug!("Load from bundle into cache: {}", key); + let file = bundle_dir.join(key); + let data = fs::read(&file).context("Failed to read query result file")?; + cache_lock.put(key.clone(), data); + } + drop(cache_lock); + + // Load precomputed temp tables into the database + for table in &manifest.tables { + let file = bundle_dir.join(format!("{table}.parquet")); + db.execute(format!( + "CREATE TEMP TABLE IF NOT EXISTS {} AS SELECT * FROM '{}'", + table, + file.display() + )) + .await?; + } + + Ok(()) +} diff --git a/packages/duckdb-server-rust/src/cache.rs b/packages/duckdb-server-rust/src/cache.rs new file mode 100644 index 000000000..b59430e71 --- /dev/null +++ b/packages/duckdb-server-rust/src/cache.rs @@ -0,0 +1,44 @@ +use anyhow::Result; +use serde_json::to_value; +use tokio::sync::Mutex; + +use crate::interfaces::Command; + +#[must_use] +pub fn get_key(sql: &str, command: &Command) -> String { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + hasher.update(sql); + format!( + "{:x}.{}", + hasher.finalize(), + to_value(command).unwrap().as_str().unwrap() + ) +} + +pub async fn retrieve( + cache: &Mutex>>, + sql: String, + command: &Command, + persist: bool, + f: F, +) -> Result> +where + F: FnOnce(String) -> Fut, + Fut: std::future::Future>>, +{ + let key = get_key(&sql, command); + + if let Some(cached) = cache.lock().await.get(&key) { + tracing::debug!("Cache hit {}!", key); + return Ok(cached.clone()); + } + + let result = f(sql).await?; + + if persist { + cache.lock().await.put(key, result.clone()); + } + + Ok(result) +} diff --git a/packages/duckdb-server-rust/src/db.rs b/packages/duckdb-server-rust/src/db.rs new file mode 100644 index 000000000..3a861f0f9 --- /dev/null +++ b/packages/duckdb-server-rust/src/db.rs @@ -0,0 +1,132 @@ +use anyhow::{Error, Result}; +use arrow::record_batch::RecordBatch; +use async_trait::async_trait; +use deadpool_r2d2::Runtime; +use duckdb::DuckdbConnectionManager; +use futures::stream::Stream; + +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReceiverStream; + +use crate::interfaces::adapt_anyhow_error; + +#[async_trait] +pub trait Database: Send + Sync { + async fn execute(&self, sql: String) -> Result<()>; + async fn get_json(&self, sql: String) -> Result>; + async fn get_arrow(&self, sql: String) -> Result>; + async fn stream_record_batch( + &self, + sql: String, + ) -> Result>, Error>; +} + +type DuckDBManager = deadpool_r2d2::Manager; +type DuckDBPool = deadpool_r2d2::Pool; + +pub struct ConnectionPool { + pool: DuckDBPool, +} + +impl ConnectionPool { + pub fn new(db_path: &str, pool_size: usize) -> Result { + let r2d2_manager = DuckdbConnectionManager::file(db_path)?; + let manager: deadpool_r2d2::Manager = + DuckDBManager::new(r2d2_manager, Runtime::Tokio1); + let pool = DuckDBPool::builder(manager).max_size(pool_size).build()?; + Ok(Self { pool }) + } +} + +#[async_trait] +impl Database for ConnectionPool { + async fn execute(&self, sql: String) -> Result<()> { + let manager = self.pool.get().await?; + let _ = manager + .interact(move |conn| conn.execute_batch(&sql)) + .await + .map_err(adapt_anyhow_error)?; + Ok(()) + } + + async fn get_json(&self, sql: String) -> Result> { + let manager = self.pool.get().await?; + let json_data = manager + .interact(move |conn| { + let mut stmt = conn.prepare(&sql)?; + let arrow = stmt.query_arrow([])?; + + let buf = Vec::new(); + let mut writer = arrow::json::ArrayWriter::new(buf); + for batch in arrow { + writer.write(&batch)?; + } + writer.finish()?; + Ok::, Error>(writer.into_inner()) + }) + .await + .map_err(adapt_anyhow_error)??; + + Ok(json_data) + } + + async fn get_arrow(&self, sql: String) -> Result> { + let manager = self.pool.get().await?; + let buffer = manager + .interact(move |conn| { + let mut stmt = conn.prepare(&sql)?; + let arrow = stmt.query_arrow([])?; + let schema = arrow.get_schema(); + + let mut buffer: Vec = Vec::new(); + { + let schema_ref = schema.as_ref(); + let mut writer = + arrow::ipc::writer::FileWriter::try_new(&mut buffer, schema_ref)?; + + for batch in arrow { + writer.write(&batch)?; + } + + writer.finish()?; + } + + Ok::, Error>(buffer) + }) + .await + .map_err(adapt_anyhow_error)??; + + Ok(buffer) + } + + async fn stream_record_batch( + &self, + sql: String, + ) -> Result>, Error> { + let conn = self.pool.get().await?; + let (tx, rx) = mpsc::channel(100); + + tokio::spawn(async move { + let result = conn + .interact(move |conn| { + let mut stmt = conn.prepare(&sql)?; + let arrow = stmt.query_arrow([])?; + + for batch in arrow { + if let Err(e) = tx.blocking_send(batch) { + tracing::error!("Error processing batch: {:?}", e); + break; + } + } + Ok::<_, Error>(()) + }) + .await; + + if let Err(e) = result { + tracing::error!("Error in database interaction: {:?}", e); + } + }); + + Ok(Box::new(ReceiverStream::new(rx))) + } +} diff --git a/packages/duckdb-server-rust/src/interfaces.rs b/packages/duckdb-server-rust/src/interfaces.rs new file mode 100644 index 000000000..e4d16497a --- /dev/null +++ b/packages/duckdb-server-rust/src/interfaces.rs @@ -0,0 +1,112 @@ +use anyhow::anyhow; +use axum::Json; +use axum::{ + body::Bytes, + http::StatusCode, + response::{IntoResponse, Response}, +}; +use deadpool_r2d2::InteractError; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tokio::sync::Mutex; + +use crate::bundle::Query as BundleQuery; +use crate::db::Database; + +pub struct AppState { + pub db: Box, + pub cache: Mutex>>, +} + +#[derive(Deserialize, Serialize, Debug, Clone)] +#[serde(rename_all = "kebab-case")] +pub enum Command { + Arrow, + Exec, + Json, + CreateBundle, + LoadBundle, +} + +#[derive(Deserialize, Serialize, Debug, Default)] +pub struct QueryParams { + #[serde(rename = "type")] + pub query_type: Option, + pub persist: Option, + pub sql: Option, + pub name: Option, + pub queries: Option>, +} + +pub enum QueryResponse { + Arrow(Vec), + Json(String), + Response(Response), + Empty, +} + +impl IntoResponse for QueryResponse { + fn into_response(self) -> Response { + match self { + QueryResponse::Arrow(bytes) => ( + StatusCode::OK, + [("Content-Type", "application/vnd.apache.arrow.stream")], + Bytes::from(bytes), + ) + .into_response(), + QueryResponse::Json(value) => ( + StatusCode::OK, + [("Content-Type", "application/json")], + value, + ) + .into_response(), + QueryResponse::Response(response) => response, + QueryResponse::Empty => StatusCode::OK.into_response(), + } + } +} + +#[derive(Debug)] +pub enum AppError { + Error(anyhow::Error), + BadRequest, +} + +impl IntoResponse for AppError { + fn into_response(self) -> Response { + let (status, err_msg) = match self { + AppError::Error(error) => { + tracing::error!("Error: {:?}", error); + ( + StatusCode::INTERNAL_SERVER_ERROR, + format!("Something went wrong: {error}"), + ) + } + AppError::BadRequest => (StatusCode::BAD_REQUEST, "Bad request".to_string()), + }; + (status, Json(json!({ "message": err_msg }))).into_response() + } +} + +impl From for AppError +where + E: Into, +{ + fn from(err: E) -> Self { + AppError::Error(err.into()) + } +} + +pub fn adapt_anyhow_error(error: T) -> anyhow::Error { + error.as_anyhow_error() +} + +pub trait Error { + fn as_anyhow_error(&self) -> anyhow::Error; +} + +impl Error for InteractError { + fn as_anyhow_error(&self) -> anyhow::Error { + anyhow!("Interact Error {:?}", self) + } +} diff --git a/packages/duckdb-server-rust/src/lib.rs b/packages/duckdb-server-rust/src/lib.rs new file mode 100644 index 000000000..077b9d92d --- /dev/null +++ b/packages/duckdb-server-rust/src/lib.rs @@ -0,0 +1,13 @@ +mod app; +mod bundle; +mod cache; +mod db; +mod interfaces; +mod query; +mod websocket; + +pub use app::app; +pub use cache::{get_key, retrieve}; +pub use db::{ConnectionPool, Database}; +pub use interfaces::{AppError, AppState, Command, QueryParams, QueryResponse}; +pub use query::handle; diff --git a/packages/duckdb-server-rust/src/main.rs b/packages/duckdb-server-rust/src/main.rs new file mode 100644 index 000000000..87fdfe219 --- /dev/null +++ b/packages/duckdb-server-rust/src/main.rs @@ -0,0 +1,82 @@ +use anyhow::Result; +use axum_server::tls_rustls::RustlsConfig; +use listenfd::ListenFd; +use std::net::TcpListener; +use std::{net::Ipv4Addr, net::SocketAddr, path::PathBuf}; +use tokio::net; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; + +mod app; +mod bundle; +mod cache; +mod db; +mod interfaces; +mod query; +mod websocket; + +#[tokio::main] +async fn main() -> Result<(), Box> { + // Tracing setup + tracing_subscriber::registry() + .with( + tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| { + "duckdb_server=debug,tower_http=debug,axum::rejection=trace".into() + }), + ) + .with(tracing_subscriber::fmt::layer()) + .init(); + + // App setup + let app = app::app()?; + + // TLS configuration + let mut config = RustlsConfig::from_pem_file( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("localhost.pem"), + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("localhost-key.pem"), + ) + .await; + + if config.is_err() { + // try current directory for HTTPS keys if env didn't work + config = RustlsConfig::from_pem_file("./localhost.pem", "./localhost-key.pem").await; + } + + // Listenfd setup + let addr = SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 3000); + let mut listenfd = ListenFd::from_env(); + let listener = match listenfd.take_tcp_listener(0)? { + // if we are given a tcp listener on listen fd 0, we use that one + Some(listener) => { + listener.set_nonblocking(true)?; + listener + } + // otherwise fall back to local listening + None => TcpListener::bind(addr)?, + }; + + // Run the server + match config { + Err(_) => { + tracing::warn!("No keys for HTTPS found."); + tracing::info!( + "DuckDB Server listening on http://{0} and ws://{0}.", + listener.local_addr()? + ); + + let listener = net::TcpListener::from_std(listener)?; + axum::serve(listener, app).await?; + } + Ok(config) => { + tracing::info!( + "DuckDB Server listening on http(s)://{0} and ws://{0}", + listener.local_addr()? + ); + + axum_server_dual_protocol::from_tcp_dual_protocol(listener, config) + .serve(app.into_make_service()) + .await?; + } + } + + Ok(()) +} diff --git a/packages/duckdb-server-rust/src/query.rs b/packages/duckdb-server-rust/src/query.rs new file mode 100644 index 000000000..0ea15cc7a --- /dev/null +++ b/packages/duckdb-server-rust/src/query.rs @@ -0,0 +1,70 @@ +use anyhow::Result; +use std::path::{Path, PathBuf}; + +use crate::bundle::{create, load}; +use crate::cache::retrieve; +use crate::interfaces::{AppError, AppState, Command, QueryParams, QueryResponse}; + +fn create_bundle_path(bundle_name: &str) -> PathBuf { + Path::new(".mosaic").join("bundle").join(bundle_name) +} + +pub async fn handle(state: &AppState, params: QueryParams) -> Result { + let command = ¶ms.query_type; + tracing::info!("Command: '{:?}', Params: '{:?}'", command, params); + match command { + Some(Command::Arrow) => { + if let Some(sql) = params.sql { + let persist = params.persist.unwrap_or(true); + let buffer = retrieve(&state.cache, sql, &Command::Arrow, persist, |sql| { + state.db.get_arrow(sql) + }) + .await?; + Ok(QueryResponse::Arrow(buffer)) + } else { + Err(AppError::BadRequest) + } + } + Some(Command::Exec) => { + if let Some(sql) = params.sql { + state.db.execute(sql).await?; + Ok(QueryResponse::Empty) + } else { + Err(AppError::BadRequest) + } + } + Some(Command::Json) => { + if let Some(sql) = params.sql { + let persist = params.persist.unwrap_or(true); + let json: Vec = retrieve(&state.cache, sql, &Command::Json, persist, |sql| { + state.db.get_json(sql) + }) + .await?; + let string = String::from_utf8(json)?; + Ok(QueryResponse::Json(string)) + } else { + Err(AppError::BadRequest) + } + } + Some(Command::CreateBundle) => { + if let Some(queries) = params.queries { + let bundle_name = params.name.unwrap_or_else(|| "default".to_string()); + let bundle_path = create_bundle_path(&bundle_name); + create(state.db.as_ref(), &state.cache, queries, &bundle_path).await?; + Ok(QueryResponse::Empty) + } else { + Err(AppError::BadRequest) + } + } + Some(Command::LoadBundle) => { + if let Some(bundle_name) = params.name { + let bundle_path = create_bundle_path(&bundle_name); + load(state.db.as_ref(), &state.cache, &bundle_path).await?; + Ok(QueryResponse::Empty) + } else { + Err(AppError::BadRequest) + } + } + None => Err(AppError::BadRequest), + } +} diff --git a/packages/duckdb-server-rust/src/test.rs b/packages/duckdb-server-rust/src/test.rs new file mode 100644 index 000000000..4cbbb891d --- /dev/null +++ b/packages/duckdb-server-rust/src/test.rs @@ -0,0 +1,195 @@ +use anyhow::Result; +use arrow::{ + array::{Int32Array, RecordBatch}, + datatypes::{DataType, Field, Schema}, + ipc::reader::FileReader, +}; +use axum::{ + body::Body, + http::{self, Request, StatusCode}, +}; +use http_body_util::BodyExt; +use serde_json::json; +use std::sync::Arc; +use temp_testdir::TempDir; +use tokio::sync::Mutex; +use tower::ServiceExt; + +use crate::bundle::{create, load, Query}; +use crate::cache::get_key; +use crate::db::ConnectionPool; +use crate::interfaces::QueryParams; +use crate::interfaces::QueryResponse; +use crate::interfaces::{AppState, Command}; +use crate::{app, query::handle}; + +#[test] +fn key() { + let key = get_key("SELECT 1", &Command::Arrow); + assert_eq!( + key, + "e004ebd5b5532a4b85984a62f8ad48a81aa3460c1ca07701f386135d72cdecf5.arrow" + ); +} + +#[tokio::test] +async fn get_json() -> Result<()> { + let db = ConnectionPool::new(":memory:", 1)?; + let cache = lru::LruCache::new(10.try_into()?); + + let state = Arc::new(AppState { + db: Box::new(db), + cache: Mutex::new(cache), + }); + + let params = QueryParams { + query_type: Some(Command::Json), + sql: Some("SELECT 1 AS foo".to_string()), + ..QueryParams::default() + }; + + let json = handle(&state, params).await.unwrap(); + + if let QueryResponse::Json(json) = json { + assert_eq!(json, "[{\"foo\":1}]"); + } + + Ok(()) +} + +#[tokio::test] +async fn get_arrow() -> Result<()> { + let db = ConnectionPool::new(":memory:", 1)?; + let cache = lru::LruCache::new(10.try_into()?); + + let state = Arc::new(AppState { + db: Box::new(db), + cache: Mutex::new(cache), + }); + + let params = QueryParams { + query_type: Some(Command::Arrow), + sql: Some("SELECT 1 AS foo".to_string()), + ..QueryParams::default() + }; + + let arrow = handle(&state, params).await.unwrap(); + + if let QueryResponse::Arrow(arrow) = arrow { + let mut reader = FileReader::try_new(std::io::Cursor::new(arrow), None)?; + let actual_batch = reader.next().unwrap(); + let actual_batch = actual_batch?; + + let schema = Arc::new(Schema::new(vec![Field::new("foo", DataType::Int32, true)])); + let foo_values = Int32Array::from(vec![1]); + let batch = RecordBatch::try_new(schema.clone(), vec![Arc::new(foo_values)])?; + + assert_eq!(actual_batch, batch); + } + + Ok(()) +} + +#[tokio::test] +async fn select_1_get() -> Result<()> { + let app = app::app()?; + + let response = app + .oneshot( + Request::builder() + .uri("/?type=json&sql=SELECT%201%20as%20foo") + .body(Body::empty())?, + ) + .await?; + + assert_eq!(response.status(), StatusCode::OK); + + let body = response.into_body().collect().await?.to_bytes(); + assert_eq!(&body[..], b"[{\"foo\":1}]"); + + Ok(()) +} + +#[tokio::test] +async fn select_1_post() -> Result<()> { + let app = app::app()?; + + let response = app + .oneshot( + Request::builder() + .method(http::Method::POST) + .uri("/") + .header(http::header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec( + &json!({"type": "json", "sql": "select 1 as foo"}), + )?))?, + ) + .await?; + + assert_eq!(response.status(), StatusCode::OK); + + let body = response.into_body().collect().await?.to_bytes(); + assert_eq!(&body[..], b"[{\"foo\":1}]"); + + Ok(()) +} + +#[tokio::test] +async fn query_arrow() -> Result<()> { + let app = app::app()?; + + let response = app + .oneshot( + Request::builder() + .method(http::Method::POST) + .uri("/") + .header(http::header::CONTENT_TYPE, "application/json") + .body(Body::from(serde_json::to_vec( + &json!({"type": "arrow", "sql": "select 1 as foo"}), + )?))?, + ) + .await?; + + assert_eq!(response.status(), StatusCode::OK); + + let body = response.into_body().collect().await?; + + let mut reader = FileReader::try_new(std::io::Cursor::new(body.to_bytes()), None)?; + let actual_batch = reader.next().unwrap(); + let actual_batch = actual_batch?; + + let schema = Arc::new(Schema::new(vec![Field::new("foo", DataType::Int32, true)])); + let foo_values = Int32Array::from(vec![1]); + let batch = RecordBatch::try_new(schema.clone(), vec![Arc::new(foo_values)])?; + + assert_eq!(actual_batch, batch); + + Ok(()) +} + +#[tokio::test] +async fn create_and_load_bundle() -> Result<()> { + let temp = TempDir::default(); + + let db = ConnectionPool::new(":memory:", 1)?; + let cache = &Mutex::new(lru::LruCache::new(10.try_into()?)); + + let queries = vec![ + Query {sql: r#"CREATE TEMP TABLE IF NOT EXISTS flights AS SELECT * FROM read_parquet("data/flights-200k.parquet")"#.to_string(), alias: None}, + Query {sql: r#"SELECT count(*) FROM "flights""#.to_string(), alias: None}, + ]; + + assert_eq!(cache.lock().await.len(), 0); + + create(&db, cache, queries, &temp).await?; + + assert_eq!(cache.lock().await.len(), 1); + cache.lock().await.clear(); + + load(&db, cache, &temp).await?; + + let cache = cache; + assert_eq!(cache.lock().await.len(), 1); + + Ok(()) +} diff --git a/packages/duckdb-server-rust/src/websocket.rs b/packages/duckdb-server-rust/src/websocket.rs new file mode 100644 index 000000000..ec1306c00 --- /dev/null +++ b/packages/duckdb-server-rust/src/websocket.rs @@ -0,0 +1,65 @@ +use axum::extract::ws::{Message, WebSocket}; +use serde_json::json; +use std::sync::Arc; + +use crate::interfaces::{AppError, AppState, QueryResponse}; +use crate::query; + +async fn handle_message(message: String, state: &AppState) -> Result { + let params = serde_json::from_str(&message)?; + query::handle(state, params).await +} + +pub async fn handle(mut socket: WebSocket, state: Arc) { + while let Some(msg) = socket.recv().await { + if let Ok(msg) = msg { + match msg { + Message::Text(text) => { + let response = handle_message(text, &state).await; + if match response { + Err(error) => match error { + AppError::BadRequest => { + socket + .send(Message::Text( + json!({"error": "Bad request"}).to_string(), + )) + .await + } + AppError::Error(error) => { + socket + .send(Message::Text( + json!({"error": format!("{}", error)}).to_string(), + )) + .await + } + }, + Ok(result) => match result { + QueryResponse::Arrow(arrow) => { + socket.send(Message::Binary(arrow)).await + } + QueryResponse::Json(json) => socket.send(Message::Text(json)).await, + QueryResponse::Empty => { + socket.send(Message::Text("{}".to_string())).await + } + QueryResponse::Response(_) => { + socket + .send(Message::Text( + json!({"error": "Unknown response Type"}).to_string(), + )) + .await + } + }, + } + .is_err() + { + break; + } + } + Message::Close(_) => break, + _ => {} + } + } else { + break; + } + } +} diff --git a/packages/duckdb-server/pkg/server.py b/packages/duckdb-server/pkg/server.py index 92c3757f4..f0339615e 100644 --- a/packages/duckdb-server/pkg/server.py +++ b/packages/duckdb-server/pkg/server.py @@ -94,10 +94,10 @@ def handle_query(handler: Handler, con, cache, query): json = retrieve(cache, query, partial(get_json, con)) handler.json(json) elif command == "create-bundle": - create_bundle(con, cache, query.get("queries"), BUNDLE_DIR) + create_bundle(con, cache, query.get("queries"), BUNDLE_DIR / query.get("name")) handler.done() elif command == "load-bundle": - load_bundle(con, cache, BUNDLE_DIR) + load_bundle(con, cache, BUNDLE_DIR / query.get("name")) handler.done() else: raise ValueError(f"Unknown command {command}") diff --git a/packages/duckdb-server/pkg/tests/test_bundle.py b/packages/duckdb-server/pkg/tests/test_bundle.py index ad43f2014..5b7622218 100644 --- a/packages/duckdb-server/pkg/tests/test_bundle.py +++ b/packages/duckdb-server/pkg/tests/test_bundle.py @@ -21,8 +21,12 @@ def test_bundle(bundle_dir): cache = {} + assert len(cache) == 0 + create_bundle(con, cache, queries, directory=bundle_dir) + assert len(cache) == 0 + load_bundle(con, cache, directory=bundle_dir) assert len(cache) == 1 diff --git a/packages/duckdb/src/data-server.js b/packages/duckdb/src/data-server.js index 2f2e81ac2..184c24002 100644 --- a/packages/duckdb/src/data-server.js +++ b/packages/duckdb/src/data-server.js @@ -103,7 +103,7 @@ export function queryHandler(db, queryCache) { try { const { sql, type = 'json' } = query; - console.log(`> ${type.toUpperCase()}${sql ? ' ' + sql : ''}`); + console.log(`> ${type.toUpperCase()}${sql ? ` ${sql}` : ''}`); // process query and return result switch (type) { diff --git a/packages/plot/src/marks/ConnectedMark.js b/packages/plot/src/marks/ConnectedMark.js index 44247688c..b9cb427ff 100644 --- a/packages/plot/src/marks/ConnectedMark.js +++ b/packages/plot/src/marks/ConnectedMark.js @@ -45,7 +45,7 @@ export class ConnectedMark extends Mark { /** * M4 is an optimization for value-preserving time-series aggregation - * (http://www.vldb.org/pvldb/vol7/p797-jugel.pdf). This implementation uses + * (https://www.vldb.org/pvldb/vol7/p797-jugel.pdf). This implementation uses * an efficient version with a single scan and the aggregate function * argmin and argmax, following https://arxiv.org/pdf/2306.03714.pdf. */ diff --git a/packages/plot/src/marks/util/stats.js b/packages/plot/src/marks/util/stats.js index 9b70e7076..7970947cc 100644 --- a/packages/plot/src/marks/util/stats.js +++ b/packages/plot/src/marks/util/stats.js @@ -172,7 +172,7 @@ export function qt(p, dof) { export function erfinv(x) { // Implementation from "Approximating the erfinv function" by Mike Giles, // GPU Computing Gems, volume 2, 2010. - // Ported from Apache Commons Math, http://www.apache.org/licenses/LICENSE-2.0 + // Ported from Apache Commons Math, https://www.apache.org/licenses/LICENSE-2.0 // beware that the logarithm argument must be // computed as (1.0 - x) * (1.0 + x),