Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ Names the refactors removed — `externalIdPrefix`, `metadataKey`/`metadataValue

Related resources are one field, not two: both `Event` and `EventFilter` carry `relatedResources`, an array of the backend's `IdCollection` (`[{"id": "34"}, {"externalId": "sensor_abc"}]`, modelled by `IdAndExtId`). An entry may name a resource by id, external id, or both; the backend resolves the missing side and returns both. `dataSetId` on the filter uses the same shape. There are no aliases for the retired flat `relatedResourceIds` / `relatedResourceExternalIds` arrays.

`EventFilterForm` + `AdvancedEventFilter` remain the richer style for events; some advanced-filter endpoints are not yet wired up server-side and are tested only via serde round-trips.
`EventFilterForm` additionally carries `advancedFilter`, a **string** holding a boolean expression in the api's PostgreSQL-flavoured filter language — `type NOT LIKE 'pump' AND (subType = 'water' OR subType = 'gas')`. It replaced a nested and/or/not `Filter` tree in 0.4.0. Three of that tree's nine variants (`range`, `containsAny`, `containsAll`) never had a server-side binding and returned 500, which is part of why it went. The expression is parsed and validated by the api, not here, so an invalid one comes back as a 400 carrying an offset and often a corrected expression.

#### Sorting and paging

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "intellistream-datahub-sdk"
version = "0.3.0"
version = "0.4.0"
edition = "2021"
rust-version = "1.85"
description = "Async Rust SDK for the IntelliStream DataHub REST API: time series and datapoints, events, resources and relationship edges, files, datasets, labels and subscriptions."
Expand Down
2 changes: 1 addition & 1 deletion datahub_python_bindings/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "datahub_python_bindings"
version = "0.3.0"
version = "0.4.0"
edition = "2024"
rust-version = "1.85"
description = "PyO3 bindings for the IntelliStream DataHub SDK, published to PyPI as intellistream-datahub-sdk."
Expand Down
2 changes: 1 addition & 1 deletion datahub_python_bindings/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ exclude = ["**/__pycache__/**"]
[project]
name = "intellistream-datahub-sdk"

version = "0.3.0"
version = "0.4.0"
description = "Python bindings for the IntelliStream DataHub SDK: time series and datapoints, events, resources and relationship edges, files, datasets, labels and subscriptions."
readme = "README.md"
authors = [{ name = "IntelliStream AS", email = "support@intellistream.ai" }]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,7 @@ class EventsServiceSync:
sort_by: SortBy | None = None,
sort_order: str | None = None,
cursor: str | None = None,
advanced_filter: str | None = None,
) -> Page:
"""Pass either ``filter=`` or the individual criteria keywords; passing both is a
``TypeError``. Paging is always given here rather than on the filter, so one filter can be
Expand Down Expand Up @@ -954,6 +955,7 @@ class EventsServiceAsync:
sort_by: SortBy | None = None,
sort_order: str | None = None,
cursor: str | None = None,
advanced_filter: str | None = None,
) -> Page:
"""Pass either ``filter=`` or the individual criteria keywords; passing both is a
``TypeError``. Paging is always given here rather than on the filter, so one filter can be
Expand Down
6 changes: 4 additions & 2 deletions datahub_python_bindings/src/events/async_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ impl PyEventsServiceAsync {
#[pyo3(signature = (filter=None, external_id=None, source=None, r#type=None, sub_type=None,
status=None, data_set_id=None, event_time=None, metadata=None,
related_resources=None, created_time=None, last_updated_time=None,
limit=None, sort_by=None, sort_order=None, cursor=None))]
limit=None, sort_by=None, sort_order=None, cursor=None,
advanced_filter=None))]
#[allow(clippy::too_many_arguments)]
fn filter<'py>(
&self,
Expand All @@ -145,11 +146,12 @@ impl PyEventsServiceAsync {
sort_by: Option<crate::StringOrList>,
sort_order: Option<String>,
cursor: Option<String>,
advanced_filter: Option<String>,
) -> PyResult<Bound<'py, PyAny>> {
let form = crate::events::event_filter_form(
filter, external_id, source, r#type, sub_type, status, data_set_id, event_time,
metadata, related_resources, created_time, last_updated_time, limit, sort_by,
sort_order, cursor,
sort_order, cursor, advanced_filter,
)?;
let service = self.api_service.clone();

Expand Down
8 changes: 8 additions & 0 deletions datahub_python_bindings/src/events/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub fn event_filter_form(
sort_by: Option<StringOrList>,
sort_order: Option<String>,
cursor: Option<String>,
advanced_filter: Option<String>,
) -> PyResult<EventFilterForm> {
let any_keyword = external_id.is_some()
|| source.is_some()
Expand Down Expand Up @@ -131,6 +132,13 @@ pub fn event_filter_form(
if let Some(cursor) = cursor {
form.set_cursor(cursor);
}
// A boolean expression in the api's filter language, e.g.
// type NOT LIKE 'pump' AND (subType = 'water' OR subType = 'gas')
// Parsed and validated by the api, so an invalid one comes back as a 400 that carries an
// offset and usually a corrected expression.
if let Some(advanced_filter) = advanced_filter {
form.set_advanced_filter(advanced_filter);
}
Ok(form.build())
}

Expand Down
6 changes: 4 additions & 2 deletions datahub_python_bindings/src/events/sync_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,8 @@ impl PyEventsServiceSync {
#[pyo3(signature = (filter=None, external_id=None, source=None, r#type=None, sub_type=None,
status=None, data_set_id=None, event_time=None, metadata=None,
related_resources=None, created_time=None, last_updated_time=None,
limit=None, sort_by=None, sort_order=None, cursor=None))]
limit=None, sort_by=None, sort_order=None, cursor=None,
advanced_filter=None))]
#[allow(clippy::too_many_arguments)]
fn filter<'py>(
&self,
Expand All @@ -129,11 +130,12 @@ impl PyEventsServiceSync {
sort_by: Option<crate::StringOrList>,
sort_order: Option<String>,
cursor: Option<String>,
advanced_filter: Option<String>,
) -> PyResult<crate::PyPage> {
let form = crate::events::event_filter_form(
filter, external_id, source, r#type, sub_type, status, data_set_id, event_time,
metadata, related_resources, created_time, last_updated_time, limit, sort_by,
sort_order, cursor,
sort_order, cursor, advanced_filter,
)?;
let service = self.api_service.clone();

Expand Down
8 changes: 5 additions & 3 deletions docs/api-coverage.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ vocabularies). All take a `limit` param, default 1000, capped at 10000.
Covered: `byids`, `search`, `fetch-related`, `create`, `update`, `delete`.

Missing: `GET /resources/{id}` (single fetch by numeric id), `POST /resources/filter` (structured
filtering — note the SDK ships `AdvancedFilter` machinery in `src/filters.rs` with no resource
endpoint wired to it), `POST /resources/fetch-nearest`.
filtering), `POST /resources/fetch-nearest`. Note that events' `advancedFilter` is now a plain
expression string and carries no reusable type, so a resource equivalent would start from the
api's filter language rather than from anything in `src/filters.rs`.

### `/timeseries` — 11 of 12

Expand Down Expand Up @@ -149,7 +150,8 @@ knowing, found while testing against a live backend:
3. ~~`GET /files/download/{id}`~~ — **done**, along with the rest of `/files`.
4. **`/edges` service** — needed for any relationship management that isn't a resource-create side
effect, and for discovering relationship types.
5. **`/resources/filter`** — the `AdvancedFilter` types already exist; only the call is missing.
5. **`/resources/filter`** — needs both the call and whatever filter shape the api settles on for
resources; the events filter language is a string, with no Rust-side types to reuse.
6. **`/policies` and `/governance`** — newer surfaces; wire up when the platform needs them.
7. Lower value: events vocabulary enumeration, `/stats`, `/tenant/features`,
`recommend-value-type`, the live datapoint WebSocket.
Expand Down
Loading
Loading