diff --git a/Cargo.lock b/Cargo.lock index db6fe1c..5cf712e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,7 +190,7 @@ dependencies = [ "arrow-schema", "arrow-select", "atoi", - "base64 0.22.1", + "base64", "chrono", "comfy-table", "half", @@ -357,9 +357,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.84" +version = "0.1.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1244b10dcd56c92219da4e14caa97e312079e185f04ba3eea25061561dc0a0" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" dependencies = [ "proc-macro2", "quote", @@ -402,12 +402,6 @@ dependencies = [ "windows-targets", ] -[[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" @@ -449,15 +443,15 @@ dependencies = [ [[package]] name = "boon" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9672cb0edeadf721484e298c0ed4dd70b0eaa3acaed5b4fd0bd73ca32e51d814" +checksum = "baa187da765010b70370368c49f08244b1ae5cae1d5d33072f76c8cb7112fe3e" dependencies = [ "ahash 0.8.11", "appendlist", - "base64 0.21.7", + "base64", "fluent-uri", - "idna 0.5.0", + "idna", "once_cell", "percent-encoding", "regex", @@ -467,6 +461,12 @@ dependencies = [ "url", ] +[[package]] +name = "borrow-or-share" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eeab4423108c5d7c744f4d234de88d18d636100093ae04caf4825134b9c3a32" + [[package]] name = "borsh" version = "1.5.3" @@ -924,11 +924,12 @@ checksum = "8bf7cc16383c4b8d58b9905a8509f02926ce3058053c056376248d958c9df1e8" [[package]] name = "fluent-uri" -version = "0.1.4" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +checksum = "1918b65d96df47d3591bed19c5cca17e3fa5d0707318e4b5ef2eae01764df7e5" dependencies = [ - "bitflags 1.3.2", + "borrow-or-share", + "ref-cast", ] [[package]] @@ -1579,16 +1580,6 @@ dependencies = [ "syn 2.0.95", ] -[[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 = "idna" version = "1.0.3" @@ -2059,7 +2050,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cfccb68961a56facde1163f9319e0d15743352344e7808a11795fb99698dcaf" dependencies = [ "async-trait", - "base64 0.22.1", + "base64", "bytes", "chrono", "futures", @@ -2142,7 +2133,7 @@ dependencies = [ "arrow-ipc", "arrow-schema", "arrow-select", - "base64 0.22.1", + "base64", "brotli", "bytes", "chrono", @@ -2238,9 +2229,9 @@ dependencies = [ [[package]] name = "phf" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros", "phf_shared", @@ -2248,9 +2239,9 @@ dependencies = [ [[package]] name = "phf_codegen" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d39688d359e6b34654d328e262234662d16cc0f60ec8dcbe5e718709342a5a" +checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" dependencies = [ "phf_generator", "phf_shared", @@ -2258,9 +2249,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" dependencies = [ "phf_shared", "rand", @@ -2268,9 +2259,9 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" dependencies = [ "phf_generator", "phf_shared", @@ -2281,9 +2272,9 @@ dependencies = [ [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" dependencies = [ "siphasher", ] @@ -2585,6 +2576,26 @@ dependencies = [ "bitflags 2.6.0", ] +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.95", +] + [[package]] name = "regex" version = "1.11.1" @@ -2629,7 +2640,7 @@ version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-core", "futures-util", @@ -2886,9 +2897,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" dependencies = [ "bitflags 2.6.0", "core-foundation", @@ -2899,9 +2910,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.13.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -2941,9 +2952,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.134" +version = "1.0.135" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" dependencies = [ "indexmap", "itoa", @@ -2999,9 +3010,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "siphasher" -version = "0.3.11" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "slab" @@ -3082,7 +3093,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stac" version = "0.11.1" -source = "git+https://github.com/stac-utils/stac-rs#37743d9d616f24e9306508877c74d8f02b0244a1" +source = "git+https://github.com/stac-utils/stac-rs#0476743b841c6e413b77a5281a1515172fbcd804" dependencies = [ "arrow-array", "arrow-cast", @@ -3090,6 +3101,7 @@ dependencies = [ "arrow-schema", "bytes", "chrono", + "geo", "geo-types", "geoarrow", "geojson", @@ -3109,7 +3121,7 @@ dependencies = [ [[package]] name = "stac-api" version = "0.7.0" -source = "git+https://github.com/stac-utils/stac-rs#37743d9d616f24e9306508877c74d8f02b0244a1" +source = "git+https://github.com/stac-utils/stac-rs#0476743b841c6e413b77a5281a1515172fbcd804" dependencies = [ "async-stream", "chrono", @@ -3134,7 +3146,7 @@ dependencies = [ [[package]] name = "stac-derive" version = "0.2.0" -source = "git+https://github.com/stac-utils/stac-rs#37743d9d616f24e9306508877c74d8f02b0244a1" +source = "git+https://github.com/stac-utils/stac-rs#0476743b841c6e413b77a5281a1515172fbcd804" dependencies = [ "quote", "syn 2.0.95", @@ -3143,12 +3155,16 @@ dependencies = [ [[package]] name = "stac-duckdb" version = "0.1.0" -source = "git+https://github.com/stac-utils/stac-rs#37743d9d616f24e9306508877c74d8f02b0244a1" +source = "git+https://github.com/stac-utils/stac-rs#0476743b841c6e413b77a5281a1515172fbcd804" dependencies = [ "arrow", + "chrono", "duckdb", + "geo", "geoarrow", + "geojson", "log", + "serde_json", "stac", "stac-api", "thiserror 2.0.9", @@ -3546,27 +3562,12 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "unicode-bidi" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" - [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" -[[package]] -name = "unicode-normalization" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-width" version = "0.2.0" @@ -3592,7 +3593,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", - "idna 1.0.3", + "idna", "percent-encoding", "serde", ] diff --git a/scripts/test b/scripts/test index 8d69715..97e737d 100755 --- a/scripts/test +++ b/scripts/test @@ -2,4 +2,4 @@ set -e -uv run maturin dev --uv && uv run pytest "$@" +maturin dev --uv && pytest "$@" diff --git a/src/duckdb.rs b/src/duckdb.rs index 76d654b..005140d 100644 --- a/src/duckdb.rs +++ b/src/duckdb.rs @@ -1,5 +1,9 @@ use crate::{Error, Result}; -use pyo3::{exceptions::PyException, prelude::*, types::PyDict}; +use pyo3::{ + exceptions::PyException, + prelude::*, + types::{PyDict, PyList}, +}; use stac_api::python::{StringOrDict, StringOrList}; use stac_duckdb::Client; use std::sync::Mutex; @@ -57,4 +61,13 @@ impl DuckdbClient { let dict = pythonize::pythonize(py, &item_collection)?; dict.extract() } + + fn get_collections<'py>(&self, py: Python<'py>, href: String) -> PyResult> { + let client = self + .0 + .lock() + .map_err(|err| PyException::new_err(err.to_string()))?; + let collections = client.collections(&href).map_err(Error::from)?; + pythonize::pythonize(py, &collections)?.extract() + } } diff --git a/stacrs.pyi b/stacrs.pyi index e411358..1990982 100644 --- a/stacrs.pyi +++ b/stacrs.pyi @@ -7,10 +7,9 @@ class DuckdbClient: self, href: str, *, - intersects: Optional[str | dict[str, Any]] = None, ids: Optional[str | list[str]] = None, collections: Optional[str | list[str]] = None, - max_items: Optional[int] = None, + intersects: Optional[str | dict[str, Any]] = None, limit: Optional[int] = None, bbox: Optional[list[float]] = None, datetime: Optional[str] = None, @@ -21,7 +20,52 @@ class DuckdbClient: query: Optional[dict[str, Any]] = None, **kwargs: str, ) -> dict[str, Any]: - """Search a stac-geoparquet file with duckdb, returning an item collection""" + """Search a stac-geoparquet file with duckdb, returning an item collection. + + Args: + href: The stac-geoparquet file. + ids: Array of Item ids to return. + collections: Array of one or more Collection IDs that each matching + Item must be in. + intersects: Searches items by performing intersection between their + geometry and provided GeoJSON geometry. + limit: The page size returned from the server. Use `max_items` to + actually limit the number of items returned from this function. + bbox: Requested bounding box. + datetime: Single date+time, or a range (`/` separator), formatted to + RFC 3339, section 5.6. Use double dots .. for open date ranges. + include: fields to include in the response (see [the extension + docs](https://github.com/stac-api-extensions/fields?tab=readme-ov-file#includeexclude-semantics)) + for more on the semantics). + exclude: fields to exclude from the response (see [the extension + docs](https://github.com/stac-api-extensions/fields?tab=readme-ov-file#includeexclude-semantics)) + for more on the semantics). + sortby: Fields by which to sort results (use `-field` to sort descending). + filter: CQL2 filter expression. Strings will be interpreted as + cql2-text, dictionaries as cql2-json. + query: Additional filtering based on properties. It is recommended + to use filter instead, if possible. + kwargs: Additional parameters to pass in to the search. + + Returns: + dict[str, Any]: A feature collection of STAC items. + """ + + def get_collections(self, href: str) -> list[dict[str, Any]]: + """Returns all collections in this stac-geoparquet file. + + These collections will be auto-generated from the STAC items, one + collection per id in the `collections` column. + + Eventually, these collections might be stored in the stac-geoparquet + metadata and retrieved from there, but that's not the case yet. + + Args: + href: The stac-geoparquet file to build the collections from. + + Returns: + A list of STAC Collections + """ def migrate_href(href: str, version: Optional[str] = None) -> dict[str, Any]: """ diff --git a/tests/test_duckdb.py b/tests/test_duckdb.py index 2ede109..3173e8e 100644 --- a/tests/test_duckdb.py +++ b/tests/test_duckdb.py @@ -28,3 +28,8 @@ def test_search_offset(client: DuckdbClient) -> None: item_collection["features"][0]["id"] == "S2A_MSIL2A_20241201T175721_R141_T13TDE_20241201T213150" ) + + +def test_get_collections(client: DuckdbClient) -> None: + collections = client.get_collections("data/100-sentinel-2-items.parquet") + assert len(collections) == 1