diff --git a/docs/advanced/asset-health-score.mdx b/docs/advanced/asset-health-score.mdx index bad073a..4cef18a 100644 --- a/docs/advanced/asset-health-score.mdx +++ b/docs/advanced/asset-health-score.mdx @@ -81,10 +81,10 @@ double bearingTemp = Double.parseDouble(pts.get(pts.size() - 1).getValue()); // The latest datapoint, per signal; the scoring arithmetic below is shown in Python. use intellistream_datahub_sdk::generic::{DataWrapper, IdAndExtId}; -let latest = api.time_series +let page = api.time_series .retrieve_latest_datapoint(&DataWrapper::from(vec![ - IdAndExtId::from_external_id("pump_07_bearing_temp_c")])).await? - .get_items().remove(0); + IdAndExtId::from_external_id("pump_07_bearing_temp_c")])).await?; +let latest = &page.get_items()[0]; let bearing_temp = latest.datapoints.last().and_then(|p| p.value).unwrap_or(f64::NAN); ``` diff --git a/docs/advanced/demand-forecasting.mdx b/docs/advanced/demand-forecasting.mdx index 3ff85c8..c52d7a2 100644 --- a/docs/advanced/demand-forecasting.mdx +++ b/docs/advanced/demand-forecasting.mdx @@ -88,9 +88,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let history = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let history = &page.get_items()[0]; ``` diff --git a/docs/advanced/kmeans-clustering.mdx b/docs/advanced/kmeans-clustering.mdx index c86fdef..3c3f314 100644 --- a/docs/advanced/kmeans-clustering.mdx +++ b/docs/advanced/kmeans-clustering.mdx @@ -97,9 +97,9 @@ let filter = RetrieveFilter { granularity: Some("30d".into()), ..Default::default() }; -let sig = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let sig = &page.get_items()[0]; ``` @@ -120,8 +120,7 @@ for asset, d in zip(assets, dist): event_time=pd.Timestamp.now(tz="UTC"), metadata={"asset": asset, "cohort": str(int(km.labels_[assets.index(asset)]))})]) -outliers = list(client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="peer_outlier"), limit=100))) +outliers = list(client.events.filter(type="peer_outlier", limit=100)) print(f"{len(outliers)} peer outlier(s) on record") ``` diff --git a/docs/advanced/lstm-anomaly-detection.mdx b/docs/advanced/lstm-anomaly-detection.mdx index 6485ad4..3e61858 100644 --- a/docs/advanced/lstm-anomaly-detection.mdx +++ b/docs/advanced/lstm-anomaly-detection.mdx @@ -91,9 +91,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; ``` diff --git a/docs/advanced/lstm-forecasting.mdx b/docs/advanced/lstm-forecasting.mdx index 4cf5555..4fd4726 100644 --- a/docs/advanced/lstm-forecasting.mdx +++ b/docs/advanced/lstm-forecasting.mdx @@ -94,9 +94,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; ``` diff --git a/docs/advanced/pca-process-monitoring.mdx b/docs/advanced/pca-process-monitoring.mdx index 067744c..5830b98 100644 --- a/docs/advanced/pca-process-monitoring.mdx +++ b/docs/advanced/pca-process-monitoring.mdx @@ -100,9 +100,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let pts = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let pts = &page.get_items()[0]; ``` @@ -154,8 +154,7 @@ if t2(znew)[-1] > T2_LIMIT or spe(znew)[-1] > SPE_LIMIT: "top_contributor": culprit})]) # the seeded fault sits in the last ten hours, so the deviation must be on record -found = list(client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="process_deviation"), limit=10))) +found = list(client.events.filter(type="process_deviation", limit=10)) assert found, "the seeded fault should have raised a process_deviation event" print(f"{len(found)} process deviation(s) on record, latest names {found[-1].metadata['top_contributor']}") ``` diff --git a/docs/advanced/predictive-maintenance.mdx b/docs/advanced/predictive-maintenance.mdx index 288b594..990fbd2 100644 --- a/docs/advanced/predictive-maintenance.mdx +++ b/docs/advanced/predictive-maintenance.mdx @@ -91,9 +91,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; ``` diff --git a/docs/advanced/random-forest-soft-sensor.mdx b/docs/advanced/random-forest-soft-sensor.mdx index 4a8cb9c..91f8301 100644 --- a/docs/advanced/random-forest-soft-sensor.mdx +++ b/docs/advanced/random-forest-soft-sensor.mdx @@ -94,9 +94,9 @@ let filter = RetrieveFilter { limit: Some(100_000), ..Default::default() }; -let pts = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let pts = &page.get_items()[0]; ``` diff --git a/docs/advanced/sustained-alarm-window.mdx b/docs/advanced/sustained-alarm-window.mdx index dc8f3dc..054d7a1 100644 --- a/docs/advanced/sustained-alarm-window.mdx +++ b/docs/advanced/sustained-alarm-window.mdx @@ -163,6 +163,7 @@ class SustainedHigh: use chrono::{DateTime, Duration, Utc}; use intellistream_datahub_sdk::events::Event; use std::collections::VecDeque; +use intellistream_datahub_sdk::ApiService; const LIMIT: f64 = 4.5; const CLEAR_BELOW: f64 = 4.2; @@ -213,10 +214,10 @@ impl SustainedHigh { let peak = self.recent.iter().map(|(_, v)| *v).fold(f64::MIN, f64::max); let mut event = Event::new( - format!("sustained_high_{}_{}", self.series_id, at.timestamp())); - event.r#type = Some("sustained_high".into()); + format!("sustained_high_{}_{}", self.series_id, at.timestamp()), + "sustained_high".into(), + at); event.status = Some("open".into()); - event.set_event_time(at); event.add_metadata("series".into(), self.series_id.clone()); event.add_metadata("limit".into(), LIMIT.to_string()); event.add_metadata("window_minutes".into(), "20".into()); @@ -315,17 +316,15 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; let mut detector = SustainedHigh::new(SERIES); let (mut raised, mut crossings, mut previous) = (0, 0, 0.0_f64); for p in &series.datapoints { - let millis = p.timestamp.parse::()?; - let at = Utc.timestamp_millis_opt(millis).single().expect("valid time"); - let value = p.value.as_deref() - .and_then(|v| v.parse::().ok()).unwrap_or(0.0); + let at = p.timestamp; + let value = p.value.unwrap_or(0.0); if previous <= LIMIT && value > LIMIT { crossings += 1; } previous = value; if detector.push(&api, at, value).await.is_some() { raised += 1; } @@ -371,8 +370,7 @@ if (found.getItems().size() != 1) { ```python -found = list(client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="sustained_high"), limit=100))) +found = list(client.events.filter(type="sustained_high", limit=100)) for e in found: print(e.external_id, e.metadata) @@ -386,10 +384,10 @@ assert len(found) == 1, f"expected one finding, found {len(found)}" ```rust -use intellistream_datahub_sdk::filters::{BasicEventFilter, EventFilter}; +use intellistream_datahub_sdk::filters::{EventFilter, EventFilterForm}; -let filter = EventFilter::default() - .set_filter(BasicEventFilter { +let filter = EventFilterForm::default() + .set_filter(EventFilter { r#type: Some(vec!["sustained_high".into()]), ..Default::default() }) .set_limit(100) .build(); diff --git a/docs/advanced/xgboost-failure-prediction.mdx b/docs/advanced/xgboost-failure-prediction.mdx index 109e98a..aad6e6a 100644 --- a/docs/advanced/xgboost-failure-prediction.mdx +++ b/docs/advanced/xgboost-failure-prediction.mdx @@ -95,9 +95,9 @@ let filter = RetrieveFilter { granularity: Some("7d".into()), ..Default::default() }; -let agg = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let agg = &page.get_items()[0]; ``` @@ -112,8 +112,7 @@ events and label each `(pump, day)` accordingly. # failures: DataFrame of (pump, failed_on), pulled from /events (type = esp_failure) failures = pd.DataFrame([ {"pump": e.metadata.get("pump"), "failed_on": pd.to_datetime(e.event_time, utc=True)} - for e in client.events.filter(intellistream_datahub_sdk.EventFilter( - intellistream_datahub_sdk.BasicEventFilter(type="esp_failure"), limit=1000))]) + for e in client.events.filter(type="esp_failure", limit=1000)]) # one feature row per pump per day across the history you have training_grid = [(p, d) for p in ["pump_esp_a12"] diff --git a/docs/guides/attach-files.mdx b/docs/guides/attach-files.mdx index d6695cf..1a7216c 100644 --- a/docs/guides/attach-files.mdx +++ b/docs/guides/attach-files.mdx @@ -37,7 +37,7 @@ var uploaded = client.files().upload( .description("ESP A-12 calibration certificate") .build()); -System.out.println("stored as id " + uploaded.getItems().iterator().next().getId()); +System.out.println("stored as id " + uploaded.getItems().get(0).getId()); ``` @@ -63,7 +63,7 @@ use intellistream_datahub_sdk::files::FileUpload; // MIME type is inferred from the file content let mut upload = FileUpload::new_with_destination_path( - "calibration_a12.pdf", "/certificates/2026/"); + "calibration_a12.pdf", "/certificates/2026/")?; upload.set_external_id("calibration_pump_esp_a12".into()); upload.set_file_name("calibration_a12.pdf".into()); upload.set_data_set_id(42); @@ -139,7 +139,7 @@ string (the endpoint also accepts an external id in that position). ```java -long id = uploaded.getItems().iterator().next().getId(); +long id = uploaded.getItems().get(0).getId(); byte[] bytes = client.files().download(String.valueOf(id)); Files.write(Path.of("calibration_a12.pdf"), bytes); ``` diff --git a/docs/guides/correlate-alarms.mdx b/docs/guides/correlate-alarms.mdx index 8aeec73..99f9b00 100644 --- a/docs/guides/correlate-alarms.mdx +++ b/docs/guides/correlate-alarms.mdx @@ -96,10 +96,10 @@ subsystem both alarms belong to, the likely common cause. ```java Set aNodes = na.nodes().stream() - .map(Resource::getExternalId).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).collect(Collectors.toSet()); Set shared = nb.nodes().stream() - .map(Resource::getExternalId) + .map(NodeModel::getExternalId) .filter(aNodes::contains) .collect(Collectors.toSet()); shared.remove("sensor_a"); diff --git a/docs/guides/model-assets-graph.mdx b/docs/guides/model-assets-graph.mdx index b40c695..f0e2f49 100644 --- a/docs/guides/model-assets-graph.mdx +++ b/docs/guides/model-assets-graph.mdx @@ -26,17 +26,17 @@ well in code, not because the server requires it. ```java -ResourceForm plant = new ResourceForm(); +Resource plant = new Resource(); plant.setExternalId("plant_oslo"); plant.setName("Oslo Plant"); plant.setLabels(List.of("Plant")); // at least one label is required -ResourceForm line = new ResourceForm(); +Resource line = new Resource(); line.setExternalId("line_a"); line.setName("Assembly line A"); line.setLabels(List.of("Line")); -ResourceForm press = new ResourceForm(); +Resource press = new Resource(); press.setExternalId("press_07"); press.setName("Hydraulic press 07"); press.setLabels(List.of("Machine")); @@ -126,9 +126,9 @@ it with a relationship (`press_07` → `PRODUCES` → `press_07_oil_temp`), then ```java -Timeseries oilTemp = new Timeseries() - .setExternalId("press_07_oil_temp") - .setName("Press 07 oil temperature"); +Timeseries oilTemp = new Timeseries(); +oilTemp.setExternalId("press_07_oil_temp"); +oilTemp.setName("Press 07 oil temperature"); oilTemp.setUnit("celsius"); oilTemp.setUnitExternalId("temperature_deg_c"); client.timeseries().create(List.of(oilTemp)); diff --git a/docs/guides/work-with-units.mdx b/docs/guides/work-with-units.mdx index efe48d1..cfc49b9 100644 --- a/docs/guides/work-with-units.mdx +++ b/docs/guides/work-with-units.mdx @@ -54,7 +54,9 @@ and Rust examples set `float`); it describes what the numbers mean. ```java -var series = Timeseries.of("wellhead_pressure_bar").name("Wellhead pressure"); +var series = new Timeseries(); +series.setExternalId("wellhead_pressure_bar"); +series.setName("Wellhead pressure"); series.setUnit("bar"); series.setUnitExternalId("pressure_bar"); client.timeseries().create(series); @@ -101,9 +103,9 @@ Resolve a unit you already know, by external id, or by numeric id. ```java UnitModel celsius = client.units().byIds(List.of( - IdCollection.createFromExternalId("temperature_deg_c"))).getItems().iterator().next(); + IdCollection.createFromExternalId("temperature_deg_c"))).getItems().get(0); UnitModel byId = client.units().byIds(List.of( - IdCollection.createFromId(7))).getItems().iterator().next(); + IdCollection.createFromId(7))).getItems().get(0); ``` @@ -112,7 +114,7 @@ UnitModel byId = client.units().byIds(List.of( ```python import intellistream_datahub_sdk -celsius = client.units.by_external_ids("temperature_deg_c") +celsius = client.units.by_external_id("temperature_deg_c") by_id = client.units.by_ids([intellistream_datahub_sdk.IdCollection(id=7)]) ``` diff --git a/docs/industries/agriculture-food/precision-farming.mdx b/docs/industries/agriculture-food/precision-farming.mdx index f887911..3de85e0 100644 --- a/docs/industries/agriculture-food/precision-farming.mdx +++ b/docs/industries/agriculture-food/precision-farming.mdx @@ -42,9 +42,13 @@ A farm *contains* fields; each field's sensors are series. ```java -var moisture = Timeseries.of("field_north_40_soil_moisture").name("North 40 soil moisture"); +var moisture = new Timeseries(); +moisture.setExternalId("field_north_40_soil_moisture"); +moisture.setName("North 40 soil moisture"); moisture.setUnit("pct"); -var soilTemp = Timeseries.of("field_north_40_soil_temp_c").name("North 40 soil temperature"); +var soilTemp = new Timeseries(); +soilTemp.setExternalId("field_north_40_soil_temp_c"); +soilTemp.setName("North 40 soil temperature"); soilTemp.setUnit("deg_c"); client.timeseries().create(moisture, soilTemp); @@ -130,7 +134,7 @@ client.files.upload_file(intellistream_datahub_sdk.FileUpload( use intellistream_datahub_sdk::files::FileUpload; let mut upload = FileUpload::new_with_destination_path( - "north_40_2026_06_28.tif", "/fields/north_40/scans/"); + "north_40_2026_06_28.tif", "/fields/north_40/scans/")?; upload.external_id = "scan_north_40_2026_06_28".into(); upload.name = "2026_06_28.tif".into(); api.files.upload_file(upload).await?; diff --git a/docs/industries/agriculture-food/salmon-farming.mdx b/docs/industries/agriculture-food/salmon-farming.mdx index e27e997..220b532 100644 --- a/docs/industries/agriculture-food/salmon-farming.mdx +++ b/docs/industries/agriculture-food/salmon-farming.mdx @@ -92,12 +92,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["farm_hardanger_pens"]).await?; while let Some(Ok(msg)) = listener.next().await { if oxygen_below(&msg.payload, 6.0) { // mg/L — danger approaching - let mut alarm = Event::new(format!("low_oxygen_h07_{}", Utc::now().timestamp())); - alarm.r#type = Some("low_oxygen".into()); + let mut alarm = Event::new( + format!("low_oxygen_h07_{}", Utc::now().timestamp()), + "low_oxygen".into(), + Utc::now()); alarm.status = Some("critical".into()); alarm.add_metadata("pen".into(), "pen_h_07".into()); alarm.add_metadata("do_mg_l".into(), "5.6".into()); - alarm.set_event_time(Utc::now()); api.events.create(&vec![alarm]).await?; // triggers aeration } listener.ack(&[msg.message_id.as_str()]).await?; @@ -117,9 +118,13 @@ See [Query & aggregate](/guides/query-and-aggregate). ```java -var feed = Timeseries.of("pen_h_07_feed_kg").name("Pen H-07 feed"); +var feed = new Timeseries(); +feed.setExternalId("pen_h_07_feed_kg"); +feed.setName("Pen H-07 feed"); feed.setUnit("kg"); -var biomass = Timeseries.of("pen_h_07_biomass_kg").name("Pen H-07 biomass"); +var biomass = new Timeseries(); +biomass.setExternalId("pen_h_07_biomass_kg"); +biomass.setName("Pen H-07 biomass"); biomass.setUnit("kg"); client.timeseries().create(feed, biomass); diff --git a/docs/industries/built-environment/construction.mdx b/docs/industries/built-environment/construction.mdx index 3b0a18b..ca2edf0 100644 --- a/docs/industries/built-environment/construction.mdx +++ b/docs/industries/built-environment/construction.mdx @@ -45,12 +45,12 @@ a crew can find the current revision instantly. See [Attach files](/guides/attac ```java -ResourceForm site = new ResourceForm(); +Resource site = new Resource(); site.setExternalId("site_harbour_tower"); site.setName("Harbour Tower"); site.setLabels(List.of("Site")); -ResourceForm zone = new ResourceForm(); +Resource zone = new Resource(); zone.setExternalId("zone_level_12"); zone.setName("Level 12"); zone.setLabels(List.of("Zone")); @@ -113,7 +113,7 @@ api.resources.create( vec![RelForm::by_external_ids("site_harbour_tower", "zone_level_12", "contains")]).await?; let mut upload = FileUpload::new_with_destination_path( - "level_12_rev_c.pdf", "/harbour_tower/level_12/drawings/"); + "level_12_rev_c.pdf", "/harbour_tower/level_12/drawings/")?; upload.external_id = "drawing_level_12_structural_rev_c".into(); upload.name = "structural_rev_c.pdf".into(); api.files.upload_file(upload).await?; @@ -159,13 +159,14 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut incident = Event::new(format!("safety_incident_l12_{}", Utc::now().timestamp())); -incident.r#type = Some("safety_incident".into()); +let mut incident = Event::new( + format!("safety_incident_l12_{}", Utc::now().timestamp()), + "safety_incident".into(), + Utc::now()); incident.sub_type = Some("near_miss".into()); incident.status = Some("open".into()); incident.add_metadata("zone".into(), "zone_level_12".into()); incident.add_metadata("category".into(), "dropped_object".into()); -incident.set_event_time(Utc::now()); api.events.create(&vec![incident]).await?; ``` diff --git a/docs/industries/built-environment/smart-buildings.mdx b/docs/industries/built-environment/smart-buildings.mdx index 73027d6..79c8750 100644 --- a/docs/industries/built-environment/smart-buildings.mdx +++ b/docs/industries/built-environment/smart-buildings.mdx @@ -92,12 +92,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["tower_a_comfort"]).await?; while let Some(Ok(msg)) = listener.next().await { if outside_comfort(&msg.payload) { // temp or CO2 out of band - let mut alert = Event::new(format!("comfort_alert_l8_{}", Utc::now().timestamp())); - alert.r#type = Some("comfort_alert".into()); + let mut alert = Event::new( + format!("comfort_alert_l8_{}", Utc::now().timestamp()), + "comfort_alert".into(), + Utc::now()); alert.status = Some("open".into()); alert.add_metadata("zone".into(), "zone_l8_open_plan".into()); alert.add_metadata("co2_ppm".into(), "1180".into()); - alert.set_event_time(Utc::now()); api.events.create(&vec![alert]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; @@ -162,9 +163,9 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { chart_daily_kwh(&p.timestamp, p.sum); } ``` diff --git a/docs/industries/energy-utilities/air-quality.mdx b/docs/industries/energy-utilities/air-quality.mdx index 43acd37..546c04b 100644 --- a/docs/industries/energy-utilities/air-quality.mdx +++ b/docs/industries/energy-utilities/air-quality.mdx @@ -55,7 +55,7 @@ client.units().list().getItems().forEach(u -> for u in client.units.list(): print(u.external_id, u.name, u.symbol) -ugm3 = client.units.by_external_ids("ug_m3") # confirm the one you'll use +ugm3 = client.units.by_external_id("ug_m3") # confirm the one you'll use ``` @@ -80,11 +80,17 @@ every value is self-describing and a chart can label its axis correctly. ```java -var pm25 = Timeseries.of("station_kirkeveien_pm25").name("Kirkeveien PM2.5"); +var pm25 = new Timeseries(); +pm25.setExternalId("station_kirkeveien_pm25"); +pm25.setName("Kirkeveien PM2.5"); pm25.setUnit("ug_m3"); -var no2 = Timeseries.of("station_kirkeveien_no2").name("Kirkeveien NO2"); +var no2 = new Timeseries(); +no2.setExternalId("station_kirkeveien_no2"); +no2.setName("Kirkeveien NO2"); no2.setUnit("ppb"); -var co = Timeseries.of("station_kirkeveien_co").name("Kirkeveien CO"); +var co = new Timeseries(); +co.setExternalId("station_kirkeveien_co"); +co.setName("Kirkeveien CO"); co.setUnit("ppm"); client.timeseries().create(pm25, no2, co); ``` diff --git a/docs/industries/energy-utilities/ev-charging.mdx b/docs/industries/energy-utilities/ev-charging.mdx index c21d84d..858e1ae 100644 --- a/docs/industries/energy-utilities/ev-charging.mdx +++ b/docs/industries/energy-utilities/ev-charging.mdx @@ -87,12 +87,13 @@ use intellistream_datahub_sdk::events::Event; let mut listener = api.subscriptions.listen(&["network_status"]).await?; while let Some(Ok(msg)) = listener.next().await { if faulted(&msg.payload) { - let mut down = Event::new(format!("charger_down_oslo_14_{}", Utc::now().timestamp())); - down.r#type = Some("charger_down".into()); + let mut down = Event::new( + format!("charger_down_oslo_14_{}", Utc::now().timestamp()), + "charger_down".into(), + Utc::now()); down.status = Some("open".into()); down.add_metadata("charger".into(), "charger_oslo_14".into()); down.add_metadata("connector".into(), "2".into()); - down.set_event_time(Utc::now()); api.events.create(&vec![down]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; @@ -114,8 +115,7 @@ close it runs to its grid limit — the input to load-balancing. See The faulted reading in the demo trips the loop, and a `charger_down` event lands: ```python -for e in client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="charger_down"), limit=5)): +for e in client.events.filter(type="charger_down", limit=5): print(e.external_id, e.metadata) # charger_down_oslo_14_… {'charger': 'charger_oslo_14', 'connector': '2'} ``` diff --git a/docs/industries/energy-utilities/grid.mdx b/docs/industries/energy-utilities/grid.mdx index 3bddbf9..fa07a9f 100644 --- a/docs/industries/energy-utilities/grid.mdx +++ b/docs/industries/energy-utilities/grid.mdx @@ -43,12 +43,12 @@ A region *contains* substations, a substation *contains* transformers, a transfo ```java -ResourceForm region = new ResourceForm(); +Resource region = new Resource(); region.setExternalId("grid_region_east"); region.setName("Eastern region"); region.setLabels(List.of("Region")); -ResourceForm substation = new ResourceForm(); +Resource substation = new Resource(); substation.setExternalId("substation_oslo_1"); substation.setName("Oslo substation 1"); substation.setLabels(List.of("Substation")); @@ -145,6 +145,7 @@ for dp in client.timeseries.retrieve_datapoints(rf)[0].get_datapoints(): ```rust use chrono::Utc; +use intellistream_datahub_sdk::generic::{DataWrapper, RetrieveFilter}; let filter = RetrieveFilter { external_id: Some("feeder_f12_load_mw".into()), @@ -154,9 +155,9 @@ let filter = RetrieveFilter { granularity: Some("1h".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { chart(&p.timestamp, p.average, p.max); } ``` @@ -197,14 +198,16 @@ client.events.create([intellistream_datahub_sdk.Event( ```rust use chrono::Utc; +use intellistream_datahub_sdk::events::Event; -let mut event = Event::new(format!("feeder_overload_f12_{}", Utc::now().timestamp())); -event.r#type = Some("feeder_overload".into()); +let mut event = Event::new( + format!("feeder_overload_f12_{}", Utc::now().timestamp()), + "feeder_overload".into(), + Utc::now()); event.status = Some("open".into()); event.add_metadata("feeder".into(), "feeder_f12".into()); event.add_metadata("peak_mw".into(), "14.8".into()); event.add_metadata("rating_mw".into(), "12.0".into()); -event.set_event_time(Utc::now()); api.events.create(&vec![event]).await?; ``` diff --git a/docs/industries/energy-utilities/waste.mdx b/docs/industries/energy-utilities/waste.mdx index 336f4d6..db1af23 100644 --- a/docs/industries/energy-utilities/waste.mdx +++ b/docs/industries/energy-utilities/waste.mdx @@ -76,16 +76,17 @@ if fill >= 80.0: use chrono::Utc; use intellistream_datahub_sdk::events::Event; -let points = api.time_series.retrieve_datapoints(&last_reading("bin_grunerlokka_114_fill_pct")).await? - .get_items().remove(0); -let fill: f64 = points.datapoints[0].value.as_deref().unwrap_or("0").parse().unwrap_or(0.0); +let page = api.time_series.retrieve_datapoints(&last_reading("bin_grunerlokka_114_fill_pct")).await?; +let points = &page.get_items()[0]; +let fill: f64 = points.datapoints[0].value.unwrap_or(0.0); if fill >= 80.0 { - let mut due = Event::new(format!("collection_due_114_{}", Utc::now().timestamp())); - due.r#type = Some("collection_due".into()); + let mut due = Event::new( + format!("collection_due_114_{}", Utc::now().timestamp()), + "collection_due".into(), + points.datapoints[0].timestamp); due.status = Some("open".into()); due.add_metadata("bin".into(), "bin_grunerlokka_114".into()); due.add_metadata("fill_pct".into(), fill.to_string()); - due.set_event_time(points.datapoints[0].timestamp); api.events.create(&vec![due]).await?; } ``` diff --git a/docs/industries/energy-utilities/water.mdx b/docs/industries/energy-utilities/water.mdx index e434f1d..148bce2 100644 --- a/docs/industries/energy-utilities/water.mdx +++ b/docs/industries/energy-utilities/water.mdx @@ -101,9 +101,9 @@ ResourceNetwork west = client.resources().fetchRelated("zone_west_12", 20); ResourceNetwork east = client.resources().fetchRelated("zone_east_07", 20); Set westUpstream = west.nodes().stream() - .map(Resource::getExternalId).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).collect(Collectors.toSet()); Set common = east.nodes().stream() - .map(Resource::getExternalId).filter(westUpstream::contains).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).filter(westUpstream::contains).collect(Collectors.toSet()); // common holds main_trunk_north (and source_lake_a) → isolate there ``` @@ -131,9 +131,9 @@ let west = api.resources.fetch_related( let east = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("zone_east_07").with_depth(20)).await?; -let w: HashSet<&str> = west.nodes().iter().map(|n| n.external_id.as_str()).collect(); +let w: HashSet<&str> = west.nodes().iter().map(|n| n.external_id()).collect(); let common: Vec<&str> = east.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| w.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| w.contains(id)).collect(); // common holds "main_trunk_north" → isolate there ``` diff --git a/docs/industries/energy-utilities/wind.mdx b/docs/industries/energy-utilities/wind.mdx index 80f6350..d00623a 100644 --- a/docs/industries/energy-utilities/wind.mdx +++ b/docs/industries/energy-utilities/wind.mdx @@ -43,9 +43,13 @@ Each turbine reports power and wind speed continuously. Hand the readings off in ```java -var power = Timeseries.of("turbine_t14_power_kw").name("Turbine T14 power"); +var power = new Timeseries(); +power.setExternalId("turbine_t14_power_kw"); +power.setName("Turbine T14 power"); power.setUnit("kw"); -var wind = Timeseries.of("turbine_t14_wind_ms").name("Turbine T14 wind speed"); +var wind = new Timeseries(); +wind.setExternalId("turbine_t14_wind_ms"); +wind.setName("Turbine T14 wind speed"); wind.setUnit("m_s"); client.timeseries().create(power, wind); @@ -161,9 +165,9 @@ let filter = RetrieveFilter { granularity: Some("1h".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; let rated = 3500.0; for p in &series.datapoints { if let Some(avg) = p.average { record_capacity_factor(&p.timestamp, avg / rated); } diff --git a/docs/industries/financial-services/aml.mdx b/docs/industries/financial-services/aml.mdx index ea4f92a..0c77454 100644 --- a/docs/industries/financial-services/aml.mdx +++ b/docs/industries/financial-services/aml.mdx @@ -97,7 +97,7 @@ through. Other flagged accounts in the same cluster are the ring. ResourceNetwork ring = client.resources().fetchRelated("account_77310", 5); ring.nodes().stream() - .map(Resource::getExternalId) + .map(NodeModel::getExternalId) .filter(id -> id.startsWith("account_")) .forEach(a -> System.out.println("linked account: " + a)); ``` @@ -122,8 +122,8 @@ let ring = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("account_77310").with_depth(5)).await?; for node in ring.nodes() { - if node.external_id.starts_with("account_") { - println!("linked account: {}", node.external_id); + if node.external_id().starts_with("account_") { + println!("linked account: {}", node.external_id()); } } ``` diff --git a/docs/industries/financial-services/insurance-fraud.mdx b/docs/industries/financial-services/insurance-fraud.mdx index 1f4b4ce..81a4622 100644 --- a/docs/industries/financial-services/insurance-fraud.mdx +++ b/docs/industries/financial-services/insurance-fraud.mdx @@ -103,7 +103,7 @@ ResourceNetwork ring = client.resources().fetchRelated("claim_88421", 4); // other claims reachable through shared parties/phones/shops ring.nodes().stream() - .map(Resource::getExternalId) + .map(NodeModel::getExternalId) .filter(id -> id.startsWith("claim_") && !id.equals("claim_88421")) .forEach(c -> System.out.println("linked claim: " + c)); ``` @@ -129,8 +129,8 @@ let ring = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("claim_88421").with_depth(4)).await?; for node in ring.nodes() { - if node.external_id.starts_with("claim_") && node.external_id != "claim_88421" { - println!("linked claim: {}", node.external_id); + if node.external_id().starts_with("claim_") && node.external_id() != "claim_88421" { + println!("linked claim: {}", node.external_id()); } } ``` diff --git a/docs/industries/financial-services/portfolio-risk.mdx b/docs/industries/financial-services/portfolio-risk.mdx index 7a25d20..21b6706 100644 --- a/docs/industries/financial-services/portfolio-risk.mdx +++ b/docs/industries/financial-services/portfolio-risk.mdx @@ -46,7 +46,7 @@ DataSetModel desk = new DataSetModel(); desk.setExternalId("desk_equities"); desk.setName("Equities desk"); var created = client.datasets().create(List.of(desk)); -long deskId = created.getItems().iterator().next().getId(); +long deskId = created.getItems().get(0).getId(); ``` @@ -85,10 +85,11 @@ so currency amounts store faithfully. ```java -var mtm = Timeseries.of("portfolio_growth_mtm_usd") - .name("Growth portfolio — mark-to-market (USD)") - .setValueType("numeric") - .setDataSetId(deskId); +var mtm = new Timeseries(); +mtm.setExternalId("portfolio_growth_mtm_usd"); +mtm.setName("Growth portfolio — mark-to-market (USD)"); +mtm.setValueType("numeric"); +mtm.setDataSetId(deskId); mtm.setUnit("usd"); client.timeseries().create(mtm); @@ -120,7 +121,7 @@ use chrono::Utc; let mut ts = TimeSeries::new("portfolio_growth_mtm_usd", "Growth portfolio — mark-to-market (USD)"); ts.unit = Some("usd".into()); -ts.value_type = "numeric".into(); +ts.value_type = Some("numeric".into()); ts.data_set_id = desk_id; // desk_id is already Option api.time_series.create_one(&ts).await?; @@ -173,14 +174,15 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut breach = Event::new(format!("var_limit_breach_growth_{}", Utc::now().timestamp())); -breach.r#type = Some("var_limit_breach".into()); +let mut breach = Event::new( + format!("var_limit_breach_growth_{}", Utc::now().timestamp()), + "var_limit_breach".into(), + Utc::now()); breach.status = Some("open".into()); breach.data_set_id = desk_id; breach.add_metadata("portfolio".into(), "portfolio_growth".into()); breach.add_metadata("var_1d_usd".into(), "512340".into()); breach.add_metadata("limit_usd".into(), "500000".into()); -breach.set_event_time(Utc::now()); api.events.create(&vec![breach]).await?; ``` diff --git a/docs/industries/healthcare/cold-chain.mdx b/docs/industries/healthcare/cold-chain.mdx index 5b729c3..52f7b07 100644 --- a/docs/industries/healthcare/cold-chain.mdx +++ b/docs/industries/healthcare/cold-chain.mdx @@ -88,12 +88,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["pharmacy_fridges"]).await?; while let Some(Ok(msg)) = listener.next().await { if out_of_band(&msg.payload, 2.0, 8.0) { // °C — vaccine fridge band - let mut excursion = Event::new(format!("cold_chain_excursion_f12_{}", Utc::now().timestamp())); - excursion.r#type = Some("cold_chain_excursion".into()); + let mut excursion = Event::new( + format!("cold_chain_excursion_f12_{}", Utc::now().timestamp()), + "cold_chain_excursion".into(), + Utc::now()); excursion.status = Some("critical".into()); excursion.add_metadata("fridge".into(), "fridge_pharmacy_12".into()); excursion.add_metadata("temp_c".into(), "9.3".into()); - excursion.set_event_time(Utc::now()); api.events.create(&vec![excursion]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/healthcare/hospital-operations.mdx b/docs/industries/healthcare/hospital-operations.mdx index af7071a..03bfa79 100644 --- a/docs/industries/healthcare/hospital-operations.mdx +++ b/docs/industries/healthcare/hospital-operations.mdx @@ -45,12 +45,12 @@ for any physical estate, which lets a ward-level alert roll up to the whole site ```java -ResourceForm hospital = new ResourceForm(); +Resource hospital = new Resource(); hospital.setExternalId("hospital_central"); hospital.setName("Central Hospital"); hospital.setLabels(List.of("Hospital")); -ResourceForm ward = new ResourceForm(); +Resource ward = new Resource(); ward.setExternalId("ward_icu"); ward.setName("Intensive care"); ward.setLabels(List.of("Ward")); @@ -161,12 +161,13 @@ let mut listener = api.subscriptions.listen(&["bed_capacity"]).await?; while let Some(Ok(msg)) = listener.next().await { update_wallboard(&msg.payload); if over_threshold(&msg.payload) { // e.g. occupancy > 95% - let mut warning = Event::new(format!("capacity_warning_icu_{}", Utc::now().timestamp())); - warning.r#type = Some("capacity_warning".into()); + let mut warning = Event::new( + format!("capacity_warning_icu_{}", Utc::now().timestamp()), + "capacity_warning".into(), + Utc::now()); warning.status = Some("open".into()); warning.add_metadata("ward".into(), "ward_icu".into()); warning.add_metadata("occupancy_pct".into(), "96".into()); - warning.set_event_time(Utc::now()); api.events.create(&vec![warning]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/healthcare/medical-devices.mdx b/docs/industries/healthcare/medical-devices.mdx index 306d0dc..20b55bd 100644 --- a/docs/industries/healthcare/medical-devices.mdx +++ b/docs/industries/healthcare/medical-devices.mdx @@ -45,7 +45,7 @@ event for biomedical engineering. ```java -ResourceForm pump = new ResourceForm(); +Resource pump = new Resource(); pump.setExternalId("pump_icu_3391"); pump.setName("Infusion pump 3391"); pump.setLabels(List.of("Pump")); @@ -138,8 +138,8 @@ let affected = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("model_acme_x200").with_depth(3)).await?; for node in affected.nodes() { - if node.external_id.starts_with("pump_") { - println!("pull from service: {}", node.external_id); + if node.external_id().starts_with("pump_") { + println!("pull from service: {}", node.external_id()); } } ``` diff --git a/docs/industries/healthcare/patient-flow.mdx b/docs/industries/healthcare/patient-flow.mdx index 83e1351..1be56f9 100644 --- a/docs/industries/healthcare/patient-flow.mdx +++ b/docs/industries/healthcare/patient-flow.mdx @@ -87,9 +87,9 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { track_stage("time_to_bed", &p.timestamp, p.average); } ``` @@ -133,12 +133,13 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut breach = Event::new(format!("flow_breach_ed_{}", Utc::now().timestamp())); -breach.r#type = Some("flow_breach".into()); +let mut breach = Event::new( + format!("flow_breach_ed_{}", Utc::now().timestamp()), + "flow_breach".into(), + Utc::now()); breach.status = Some("open".into()); breach.add_metadata("stage".into(), "emergency_department".into()); breach.add_metadata("breach_rate_pct".into(), "22".into()); -breach.set_event_time(Utc::now()); api.events.create(&vec![breach]).await?; ``` diff --git a/docs/industries/manufacturing-process/discrete.mdx b/docs/industries/manufacturing-process/discrete.mdx index e924eea..0f25708 100644 --- a/docs/industries/manufacturing-process/discrete.mdx +++ b/docs/industries/manufacturing-process/discrete.mdx @@ -42,9 +42,13 @@ series: `station_07_cycle_time_s`, `station_07_units`, `station_07_scrap`. ```java -var cycleTime = Timeseries.of("station_07_cycle_time_s").name("Station 07 cycle time"); +var cycleTime = new Timeseries(); +cycleTime.setExternalId("station_07_cycle_time_s"); +cycleTime.setName("Station 07 cycle time"); cycleTime.setUnit("s"); -var scrap = Timeseries.of("station_07_scrap").name("Station 07 scrap count"); +var scrap = new Timeseries(); +scrap.setExternalId("station_07_scrap"); +scrap.setName("Station 07 scrap count"); scrap.setUnit("count"); client.timeseries().create(cycleTime, scrap); @@ -148,9 +152,9 @@ let filter = RetrieveFilter { granularity: Some("1h".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { record_hourly_performance(&p.timestamp, p.average); } ``` @@ -193,13 +197,14 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut excursion = Event::new(format!("scrap_excursion_st07_{}", Utc::now().timestamp())); -excursion.r#type = Some("scrap_excursion".into()); +let mut excursion = Event::new( + format!("scrap_excursion_st07_{}", Utc::now().timestamp()), + "scrap_excursion".into(), + Utc::now()); excursion.status = Some("open".into()); excursion.add_metadata("station".into(), "station_07".into()); excursion.add_metadata("scrap_rate_pct".into(), "4.8".into()); excursion.add_metadata("limit_pct".into(), "2.0".into()); -excursion.set_event_time(Utc::now()); api.events.create(&vec![excursion]).await?; ``` diff --git a/docs/industries/manufacturing-process/pharma.mdx b/docs/industries/manufacturing-process/pharma.mdx index 253f984..89d05d8 100644 --- a/docs/industries/manufacturing-process/pharma.mdx +++ b/docs/industries/manufacturing-process/pharma.mdx @@ -46,9 +46,10 @@ A bioreactor's pH, temperature and dissolved oxygen are the batch record. Use th ```java -var ph = Timeseries.of("batch_22f_ph") - .name("Batch 22F — pH") - .setValueType("numeric"); +var ph = new Timeseries(); +ph.setExternalId("batch_22f_ph"); +ph.setName("Batch 22F — pH"); +ph.setValueType("numeric"); ph.setUnit("ph"); client.timeseries().create(ph); @@ -78,7 +79,7 @@ use chrono::Utc; let mut ph = TimeSeries::new("batch_22f_ph", "Batch 22F — pH"); ph.unit = Some("ph".into()); -ph.value_type = "numeric".into(); +ph.value_type = Some("numeric".into()); api.time_series.create_one(&ph).await?; api.time_series @@ -139,8 +140,8 @@ let lineage = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("lot_22f_final").with_depth(10)).await?; for node in lineage.nodes() { - if node.external_id.starts_with("lot_raw_") { - println!("raw material: {}", node.external_id); + if node.external_id().starts_with("lot_raw_") { + println!("raw material: {}", node.external_id()); } } ``` diff --git a/docs/industries/manufacturing-process/semiconductor.mdx b/docs/industries/manufacturing-process/semiconductor.mdx index efc3f92..e607afe 100644 --- a/docs/industries/manufacturing-process/semiconductor.mdx +++ b/docs/industries/manufacturing-process/semiconductor.mdx @@ -47,9 +47,10 @@ exact — use the `NUMERIC` value type so values store without floating-point dr ```java -var pressure = Timeseries.of("tool_etch_07_chamber_pressure_mtorr") - .name("Etch-07 chamber pressure") - .setValueType("numeric"); +var pressure = new Timeseries(); +pressure.setExternalId("tool_etch_07_chamber_pressure_mtorr"); +pressure.setName("Etch-07 chamber pressure"); +pressure.setValueType("numeric"); pressure.setUnit("mtorr"); client.timeseries().create(pressure); @@ -81,7 +82,7 @@ use chrono::Utc; let mut p = TimeSeries::new("tool_etch_07_chamber_pressure_mtorr", "Etch-07 chamber pressure"); p.unit = Some("mtorr".into()); -p.value_type = "numeric".into(); +p.value_type = Some("numeric".into()); api.time_series.create_one(&p).await?; api.time_series @@ -107,9 +108,9 @@ ResourceNetwork lotA = client.resources().fetchRelated("lot_22841", 6); ResourceNetwork lotB = client.resources().fetchRelated("lot_22863", 6); Set toolsA = lotA.nodes().stream() - .map(Resource::getExternalId).filter(id -> id.startsWith("tool_")).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).filter(id -> id.startsWith("tool_")).collect(Collectors.toSet()); Set suspect = lotB.nodes().stream() - .map(Resource::getExternalId).filter(toolsA::contains).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).filter(toolsA::contains).collect(Collectors.toSet()); // suspect contains "tool_etch_07" → the chamber to pull and check ``` @@ -139,9 +140,9 @@ let lot_b = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("lot_22863").with_depth(6)).await?; let tools_a: HashSet<&str> = lot_a.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| id.starts_with("tool_")).collect(); + .map(|n| n.external_id()).filter(|id| id.starts_with("tool_")).collect(); let suspect: Vec<&str> = lot_b.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| tools_a.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| tools_a.contains(id)).collect(); // suspect contains "tool_etch_07" ``` diff --git a/docs/industries/mining-metals/operations.mdx b/docs/industries/mining-metals/operations.mdx index 5e6e02d..5259f78 100644 --- a/docs/industries/mining-metals/operations.mdx +++ b/docs/industries/mining-metals/operations.mdx @@ -80,17 +80,18 @@ if any(float(dp.value) < 250.0 for dp in points.get_datapoints()): use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let points = api.time_series.retrieve_datapoints(&last_hour("truck_785_oil_pressure_kpa")).await? - .get_items().remove(0); +let page = api.time_series.retrieve_datapoints(&last_hour("truck_785_oil_pressure_kpa")).await?; +let points = &page.get_items()[0]; let low = points.datapoints.iter() - .any(|p| p.value.as_deref().and_then(|v| v.parse::().ok()).unwrap_or(999.0) < 250.0); + .any(|p| p.value.unwrap_or(999.0) < 250.0); if low { - let mut warning = Event::new(format!("equipment_warning_785_{}", Utc::now().timestamp())); - warning.r#type = Some("equipment_warning".into()); + let mut warning = Event::new( + format!("equipment_warning_785_{}", Utc::now().timestamp()), + "equipment_warning".into(), + Utc::now()); warning.status = Some("open".into()); warning.add_metadata("unit".into(), "truck_785".into()); warning.add_metadata("signal".into(), "oil_pressure".into()); - warning.set_event_time(Utc::now()); api.events.create(&vec![warning]).await?; } ``` @@ -153,9 +154,9 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { compare_to_plan(&p.timestamp, p.average); } ``` diff --git a/docs/industries/mining-metals/processing-plant.mdx b/docs/industries/mining-metals/processing-plant.mdx index 175c5e0..3fd2840 100644 --- a/docs/industries/mining-metals/processing-plant.mdx +++ b/docs/industries/mining-metals/processing-plant.mdx @@ -88,9 +88,9 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { compare_to_target(&p.timestamp, p.average); } ``` @@ -134,13 +134,14 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut loss = Event::new(format!("recovery_loss_mill1_{}", Utc::now().timestamp())); -loss.r#type = Some("recovery_loss".into()); +let mut loss = Event::new( + format!("recovery_loss_mill1_{}", Utc::now().timestamp()), + "recovery_loss".into(), + Utc::now()); loss.status = Some("open".into()); loss.add_metadata("mill".into(), "mill_1".into()); loss.add_metadata("recovery_pct".into(), "88.4".into()); loss.add_metadata("target_pct".into(), "91.0".into()); -loss.set_event_time(Utc::now()); api.events.create(&vec![loss]).await?; ``` diff --git a/docs/industries/mining-metals/tailings-safety.mdx b/docs/industries/mining-metals/tailings-safety.mdx index eeb349b..2f1cdaa 100644 --- a/docs/industries/mining-metals/tailings-safety.mdx +++ b/docs/industries/mining-metals/tailings-safety.mdx @@ -95,13 +95,14 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["tsf_instruments"]).await?; while let Some(Ok(msg)) = listener.next().await { if let Some(level) = trigger_level(&msg.payload) { // "amber" | "red" - let mut alarm = Event::new(format!("tailings_alarm_p14_{}", Utc::now().timestamp())); - alarm.r#type = Some("tailings_alarm".into()); + let mut alarm = Event::new( + format!("tailings_alarm_p14_{}", Utc::now().timestamp()), + "tailings_alarm".into(), + Utc::now()); alarm.status = Some(if level == "red" { "critical" } else { "warning" }.into()); alarm.add_metadata("instrument".into(), "piezometer_p14".into()); alarm.add_metadata("level".into(), level.into()); alarm.add_metadata("pore_pressure_kpa".into(), "186".into()); - alarm.set_event_time(Utc::now()); api.events.create(&vec![alarm]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/oil-and-gas/drilling.mdx b/docs/industries/oil-and-gas/drilling.mdx index 2a17094..045f45f 100644 --- a/docs/industries/oil-and-gas/drilling.mdx +++ b/docs/industries/oil-and-gas/drilling.mdx @@ -100,13 +100,14 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["rig_deepwater_1"]).await?; while let Some(Ok(msg)) = listener.next().await { if influx_detected(&msg.payload) { // flow_out > flow_in & pit rising - let mut kick = Event::new(format!("kick_detected_a12_{}", Utc::now().timestamp())); - kick.r#type = Some("kick_detected".into()); + let mut kick = Event::new( + format!("kick_detected_a12_{}", Utc::now().timestamp()), + "kick_detected".into(), + Utc::now()); kick.status = Some("critical".into()); kick.add_metadata("well".into(), "well_a12".into()); kick.add_metadata("rig".into(), "rig_deepwater_1".into()); kick.add_metadata("flow_delta_gpm".into(), "18".into()); - kick.set_event_time(Utc::now()); api.events.create(&vec![kick]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; @@ -137,8 +138,7 @@ Run the setup, then the loop above. The demo kick (flow-out climbing past flow-i the detector and a `kick_detected` event lands — confirm it: ```python -hits = client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="kick_detected"), limit=5)) +hits = client.events.filter(type="kick_detected", limit=5) for e in hits: print(e.external_id, "→", e.status) # kick_detected_a12_1751… → critical diff --git a/docs/industries/oil-and-gas/emissions.mdx b/docs/industries/oil-and-gas/emissions.mdx index f0ae01e..820f5be 100644 --- a/docs/industries/oil-and-gas/emissions.mdx +++ b/docs/industries/oil-and-gas/emissions.mdx @@ -88,9 +88,9 @@ let filter = RetrieveFilter { granularity: Some("1d".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; let monthly: f64 = series.datapoints.iter() .filter_map(|p| p.sum).sum(); ``` @@ -135,13 +135,14 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut exceedance = Event::new(format!("flaring_exceedance_north_{}", Utc::now().timestamp())); -exceedance.r#type = Some("flaring_exceedance".into()); +let mut exceedance = Event::new( + format!("flaring_exceedance_north_{}", Utc::now().timestamp()), + "flaring_exceedance".into(), + Utc::now()); exceedance.status = Some("open".into()); exceedance.add_metadata("site".into(), "platform_north".into()); exceedance.add_metadata("flared_m3".into(), "142000".into()); exceedance.add_metadata("permit_m3".into(), "120000".into()); -exceedance.set_event_time(Utc::now()); api.events.create(&vec![exceedance]).await?; ``` diff --git a/docs/industries/oil-and-gas/pipeline.mdx b/docs/industries/oil-and-gas/pipeline.mdx index bef91cf..bbb946d 100644 --- a/docs/industries/oil-and-gas/pipeline.mdx +++ b/docs/industries/oil-and-gas/pipeline.mdx @@ -92,16 +92,17 @@ if inflow - outflow > tolerance(inflow): use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let inflow = latest("segment_pn_07_flow_in_m3h").await?; -let outflow = latest("segment_pn_07_flow_out_m3h").await?; +let inflow: f64 = latest("segment_pn_07_flow_in_m3h").await?; +let outflow: f64 = latest("segment_pn_07_flow_out_m3h").await?; if inflow - outflow > tolerance(inflow) { - let mut leak = Event::new(format!("leak_suspected_pn07_{}", Utc::now().timestamp())); - leak.r#type = Some("leak_suspected".into()); + let mut leak = Event::new( + format!("leak_suspected_pn07_{}", Utc::now().timestamp()), + "leak_suspected".into(), + Utc::now()); leak.status = Some("critical".into()); leak.add_metadata("segment".into(), "segment_pn_07".into()); leak.add_metadata("imbalance_m3h".into(), (inflow - outflow).to_string()); - leak.set_event_time(Utc::now()); api.events.create(&vec![leak]).await?; } ``` @@ -155,8 +156,8 @@ let around = api.resources.fetch_related( .with_relationship_types(vec!["connects_to".into(), "isolated_by".into()])).await?; for node in around.nodes() { - if node.external_id.starts_with("valve_") { - println!("close: {}", node.external_id); + if node.external_id().starts_with("valve_") { + println!("close: {}", node.external_id()); } } ``` diff --git a/docs/industries/oil-and-gas/production.mdx b/docs/industries/oil-and-gas/production.mdx index 503a91d..228f451 100644 --- a/docs/industries/oil-and-gas/production.mdx +++ b/docs/industries/oil-and-gas/production.mdx @@ -58,17 +58,17 @@ Modeling it as a graph lets you walk from a field down to any individual sensor. ```java -ResourceForm field = new ResourceForm(); +Resource field = new Resource(); field.setExternalId("field_north_sea"); field.setName("North Sea field"); field.setLabels(List.of("Field")); -ResourceForm well = new ResourceForm(); +Resource well = new Resource(); well.setExternalId("well_a12"); well.setName("Well A-12"); well.setLabels(List.of("Well")); -ResourceForm pump = new ResourceForm(); +Resource pump = new Resource(); pump.setExternalId("pump_esp_a12"); pump.setName("ESP — Well A-12"); pump.setLabels(List.of("Pump")); @@ -230,18 +230,20 @@ if any(float(dp.value) < 80.0 for dp in points.get_datapoints()): ```rust use chrono::Utc; +use intellistream_datahub_sdk::events::Event; -let points = api.time_series.retrieve_datapoints(&last_hour("pump_intake_pressure_bar")).await? - .get_items().remove(0); +let page = api.time_series.retrieve_datapoints(&last_hour("pump_intake_pressure_bar")).await?; +let points = &page.get_items()[0]; let low = points.datapoints.iter() - .any(|p| p.value.as_deref().and_then(|v| v.parse::().ok()).unwrap_or(99.0) < 80.0); + .any(|p| p.value.unwrap_or(99.0) < 80.0); if low { - let mut event = Event::new(format!("esp_anomaly_a12_{}", Utc::now().timestamp())); - event.r#type = Some("esp_anomaly".into()); + let mut event = Event::new( + format!("esp_anomaly_a12_{}", Utc::now().timestamp()), + "esp_anomaly".into(), + Utc::now()); event.status = Some("open".into()); event.add_metadata("well".into(), "well_a12".into()); event.add_metadata("pump".into(), "pump_esp_a12".into()); - event.set_event_time(Utc::now()); api.events.create(&vec![event]).await?; } ``` @@ -265,9 +267,9 @@ ResourceNetwork na = client.resources().fetchRelated("wellhead_temp_a12", 5); ResourceNetwork nb = client.resources().fetchRelated("pump_temp_a12", 5); Set aNodes = na.nodes().stream() - .map(Resource::getExternalId).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).collect(Collectors.toSet()); Set shared = nb.nodes().stream() - .map(Resource::getExternalId).filter(aNodes::contains).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).filter(aNodes::contains).collect(Collectors.toSet()); // shared contains "cooling_system" → one root cause, not two ``` @@ -295,9 +297,9 @@ let na = api.resources.fetch_related( let nb = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("pump_temp_a12").with_depth(5)).await?; -let a: HashSet<&str> = na.nodes().iter().map(|n| n.external_id.as_str()).collect(); +let a: HashSet<&str> = na.nodes().iter().map(|n| n.external_id()).collect(); let shared: Vec<&str> = nb.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| a.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| a.contains(id)).collect(); // shared contains "cooling_system" → one root cause, not two ``` diff --git a/docs/industries/oil-and-gas/refining.mdx b/docs/industries/oil-and-gas/refining.mdx index 01065a4..83a6390 100644 --- a/docs/industries/oil-and-gas/refining.mdx +++ b/docs/industries/oil-and-gas/refining.mdx @@ -88,9 +88,9 @@ let filter = RetrieveFilter { granularity: Some("1h".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { record_energy_intensity(&p.timestamp, p.sum); } ``` @@ -134,13 +134,14 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut upset = Event::new(format!("process_upset_cdu1_{}", Utc::now().timestamp())); -upset.r#type = Some("process_upset".into()); +let mut upset = Event::new( + format!("process_upset_cdu1_{}", Utc::now().timestamp()), + "process_upset".into(), + Utc::now()); upset.status = Some("open".into()); upset.add_metadata("unit".into(), "crude_unit_1".into()); upset.add_metadata("tag".into(), "column_top_temp".into()); upset.add_metadata("value_c".into(), "168".into()); -upset.set_event_time(Utc::now()); api.events.create(&vec![upset]).await?; ``` diff --git a/docs/industries/oil-and-gas/storage.mdx b/docs/industries/oil-and-gas/storage.mdx index f54f2ac..cb80727 100644 --- a/docs/industries/oil-and-gas/storage.mdx +++ b/docs/industries/oil-and-gas/storage.mdx @@ -96,19 +96,20 @@ if abs(unexplained) > tolerance(closing): use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let measured_change = latest("tank_t_12_volume_bbl").await? +let measured_change: f64 = latest("tank_t_12_volume_bbl").await? - first_value("tank_t_12_volume_bbl", shift_start).await?; -let metered = sum_over("tank_t_12_receipts_bbl", shift_start).await? +let metered: f64 = sum_over("tank_t_12_receipts_bbl", shift_start).await? - sum_over("tank_t_12_deliveries_bbl", shift_start).await?; let unexplained = measured_change - metered; if unexplained.abs() > tolerance(latest("tank_t_12_volume_bbl").await?) { - let mut loss = Event::new(format!("inventory_discrepancy_t12_{}", Utc::now().timestamp())); - loss.r#type = Some("inventory_discrepancy".into()); + let mut loss = Event::new( + format!("inventory_discrepancy_t12_{}", Utc::now().timestamp()), + "inventory_discrepancy".into(), + shift_start); loss.status = Some("open".into()); loss.add_metadata("tank".into(), "tank_t_12".into()); loss.add_metadata("unexplained_bbl".into(), format!("{:.1}", unexplained)); - loss.set_event_time(shift_start); api.events.create(&vec![loss]).await?; } ``` diff --git a/docs/industries/technology-operations/data-centers.mdx b/docs/industries/technology-operations/data-centers.mdx index 25a2b69..392338c 100644 --- a/docs/industries/technology-operations/data-centers.mdx +++ b/docs/industries/technology-operations/data-centers.mdx @@ -94,12 +94,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["hall_2_thermal"]).await?; while let Some(Ok(msg)) = listener.next().await { if inlet_above(&msg.payload, 27.0) { // °C — above ASHRAE band - let mut warning = Event::new(format!("thermal_warning_r14_{}", Utc::now().timestamp())); - warning.r#type = Some("thermal_warning".into()); + let mut warning = Event::new( + format!("thermal_warning_r14_{}", Utc::now().timestamp()), + "thermal_warning".into(), + Utc::now()); warning.status = Some("open".into()); warning.add_metadata("rack".into(), "rack_r14".into()); warning.add_metadata("inlet_c".into(), "29.4".into()); - warning.set_event_time(Utc::now()); api.events.create(&vec![warning]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; @@ -129,8 +130,8 @@ rack to the unit they share — the exact ResourceNetwork a = client.resources().fetchRelated("rack_r14", 3); ResourceNetwork b = client.resources().fetchRelated("rack_r15", 3); -Set aNodes = a.nodes().stream().map(Resource::getExternalId).collect(Collectors.toSet()); -Set shared = b.nodes().stream().map(Resource::getExternalId) +Set aNodes = a.nodes().stream().map(NodeModel::getExternalId).collect(Collectors.toSet()); +Set shared = b.nodes().stream().map(NodeModel::getExternalId) .filter(aNodes::contains).collect(Collectors.toSet()); // shared contains "crac_unit_2" → one failing unit, not two hot racks ``` @@ -156,9 +157,9 @@ let a = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("rack_r14").with_depth(3)).await?; let b = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("rack_r15").with_depth(3)).await?; -let an: HashSet<&str> = a.nodes().iter().map(|n| n.external_id.as_str()).collect(); +let an: HashSet<&str> = a.nodes().iter().map(|n| n.external_id()).collect(); let shared: Vec<&str> = b.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| an.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| an.contains(id)).collect(); // shared contains "crac_unit_2" ``` diff --git a/docs/industries/technology-operations/network.mdx b/docs/industries/technology-operations/network.mdx index 3c1fe0a..c9d923a 100644 --- a/docs/industries/technology-operations/network.mdx +++ b/docs/industries/technology-operations/network.mdx @@ -98,9 +98,9 @@ let filter = RetrieveFilter { end: Some(Utc::now()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { flag_if_saturated(&p.timestamp, p.max); } ``` @@ -122,8 +122,8 @@ field team at the one link to fix instead of a dozen cells to chase. ResourceNetwork c1 = client.resources().fetchRelated("cell_oslo_4412", 4); ResourceNetwork c2 = client.resources().fetchRelated("cell_oslo_4418", 4); -Set n1 = c1.nodes().stream().map(Resource::getExternalId).collect(Collectors.toSet()); -Set shared = c2.nodes().stream().map(Resource::getExternalId) +Set n1 = c1.nodes().stream().map(NodeModel::getExternalId).collect(Collectors.toSet()); +Set shared = c2.nodes().stream().map(NodeModel::getExternalId) .filter(n1::contains).collect(Collectors.toSet()); // shared contains "backhaul_link_88" → fix the link, not the cells ``` @@ -149,9 +149,9 @@ let c1 = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("cell_oslo_4412").with_depth(4)).await?; let c2 = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("cell_oslo_4418").with_depth(4)).await?; -let n1: HashSet<&str> = c1.nodes().iter().map(|n| n.external_id.as_str()).collect(); +let n1: HashSet<&str> = c1.nodes().iter().map(|n| n.external_id()).collect(); let shared: Vec<&str> = c2.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| n1.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| n1.contains(id)).collect(); // shared contains "backhaul_link_88" ``` diff --git a/docs/industries/technology-operations/observability.mdx b/docs/industries/technology-operations/observability.mdx index 43b2552..c8203f7 100644 --- a/docs/industries/technology-operations/observability.mdx +++ b/docs/industries/technology-operations/observability.mdx @@ -51,12 +51,12 @@ on a host fan out to the services it affects. ```java -ResourceForm service = new ResourceForm(); +Resource service = new Resource(); service.setExternalId("service_checkout"); service.setName("Checkout service"); service.setLabels(List.of("Service")); -ResourceForm host = new ResourceForm(); +Resource host = new Resource(); host.setExternalId("host_web_01"); host.setName("web-01"); host.setLabels(List.of("Host")); @@ -164,12 +164,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["checkout_slo"]).await?; while let Some(Ok(msg)) = listener.next().await { if breaches_slo(&msg.payload) { // e.g. p99 latency > 300 ms - let mut event = Event::new(format!("slo_breach_checkout_{}", Utc::now().timestamp())); - event.r#type = Some("slo_breach".into()); + let mut event = Event::new( + format!("slo_breach_checkout_{}", Utc::now().timestamp()), + "slo_breach".into(), + Utc::now()); event.status = Some("firing".into()); event.add_metadata("service".into(), "service_checkout".into()); event.add_metadata("slo".into(), "latency_p99".into()); - event.set_event_time(Utc::now()); api.events.create(&vec![event]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; @@ -198,21 +199,20 @@ DataWrapper breaches = client.events().filter(retriever); ```python -breaches = client.events.filter(intellistream_datahub_sdk.EventFilter( - basic_filter=intellistream_datahub_sdk.BasicEventFilter(type="slo_breach"), limit=200)) +breaches = client.events.filter(type="slo_breach", limit=200) ``` ```rust -use intellistream_datahub_sdk::filters::{BasicEventFilter, EventFilter}; +use intellistream_datahub_sdk::filters::{EventFilter, EventFilterForm}; -let mut basic = BasicEventFilter::default(); -basic.set_type(&["slo_breach"]); -let mut filter = EventFilter::default(); -filter.set_filter(basic); -filter.set_limit(200); +let filter = EventFilterForm::default() + .set_filter(EventFilter { + r#type: Some(vec!["slo_breach".into()]), ..Default::default() }) + .set_limit(200) + .build(); let breaches = api.events.filter(&filter).await?; ``` @@ -235,9 +235,9 @@ ResourceNetwork checkout = client.resources().fetchRelated("service_checkout", 4 ResourceNetwork payments = client.resources().fetchRelated("service_payments", 4); Set checkoutDeps = checkout.nodes().stream() - .map(Resource::getExternalId).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).collect(Collectors.toSet()); Set shared = payments.nodes().stream() - .map(Resource::getExternalId).filter(checkoutDeps::contains).collect(Collectors.toSet()); + .map(NodeModel::getExternalId).filter(checkoutDeps::contains).collect(Collectors.toSet()); // shared contains "order_db" → one failing dependency, not two outages ``` @@ -266,9 +266,9 @@ let checkout = api.resources.fetch_related( let payments = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("service_payments").with_depth(4)).await?; -let deps: HashSet<&str> = checkout.nodes().iter().map(|n| n.external_id.as_str()).collect(); +let deps: HashSet<&str> = checkout.nodes().iter().map(|n| n.external_id()).collect(); let shared: Vec<&str> = payments.nodes().iter() - .map(|n| n.external_id.as_str()).filter(|id| deps.contains(id)).collect(); + .map(|n| n.external_id()).filter(|id| deps.contains(id)).collect(); // shared contains "order_db" → one failing dependency, not two outages ``` diff --git a/docs/industries/transport-logistics/aerospace.mdx b/docs/industries/transport-logistics/aerospace.mdx index 9853d9f..75276ec 100644 --- a/docs/industries/transport-logistics/aerospace.mdx +++ b/docs/industries/transport-logistics/aerospace.mdx @@ -47,12 +47,12 @@ that shared node is what makes fleet-wide correlation possible. ```java -ResourceForm aircraft = new ResourceForm(); +Resource aircraft = new Resource(); aircraft.setExternalId("aircraft_ln_312"); aircraft.setName("Aircraft LN-312"); aircraft.setLabels(List.of("aircraft_ln_312")); -ResourceForm pump = new ResourceForm(); +Resource pump = new Resource(); pump.setExternalId("hyd_pump_ln_312_1"); pump.setName("Hydraulic pump #1"); pump.setLabels(List.of("hyd_pump_ln_312_1")); @@ -156,8 +156,8 @@ let affected = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("part_type_hp_47").with_depth(3)).await?; for node in affected.nodes() { - if node.external_id.starts_with("aircraft_") { - println!("inspect: {}", node.external_id); + if node.external_id().starts_with("aircraft_") { + println!("inspect: {}", node.external_id()); } } ``` diff --git a/docs/industries/transport-logistics/airports.mdx b/docs/industries/transport-logistics/airports.mdx index 113ad48..8cbd0ca 100644 --- a/docs/industries/transport-logistics/airports.mdx +++ b/docs/industries/transport-logistics/airports.mdx @@ -86,13 +86,14 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["stand_b12_turnaround"]).await?; while let Some(Ok(msg)) = listener.next().await { if leg_overrunning(&msg.payload) { // e.g. fuelling past plan - let mut risk = Event::new(format!("turnaround_risk_su204_{}", Utc::now().timestamp())); - risk.r#type = Some("turnaround_risk".into()); + let mut risk = Event::new( + format!("turnaround_risk_su204_{}", Utc::now().timestamp()), + "turnaround_risk".into(), + Utc::now()); risk.status = Some("open".into()); risk.add_metadata("flight".into(), "flight_su204".into()); risk.add_metadata("leg".into(), "fuelling".into()); risk.add_metadata("stand".into(), "stand_b12".into()); - risk.set_event_time(Utc::now()); api.events.create(&vec![risk]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/transport-logistics/last-mile.mdx b/docs/industries/transport-logistics/last-mile.mdx index f130837..b3df15a 100644 --- a/docs/industries/transport-logistics/last-mile.mdx +++ b/docs/industries/transport-logistics/last-mile.mdx @@ -84,13 +84,14 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["fleet_eta"]).await?; while let Some(Ok(msg)) = listener.next().await { if eta_past_window(&msg.payload) { - let mut risk = Event::new(format!("delivery_at_risk_v22_{}", Utc::now().timestamp())); - risk.r#type = Some("delivery_at_risk".into()); + let mut risk = Event::new( + format!("delivery_at_risk_v22_{}", Utc::now().timestamp()), + "delivery_at_risk".into(), + Utc::now()); risk.status = Some("open".into()); risk.add_metadata("van".into(), "van_22".into()); risk.add_metadata("route".into(), "route_oslo_e".into()); risk.add_metadata("stops_left".into(), "9".into()); - risk.set_event_time(Utc::now()); api.events.create(&vec![risk]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/transport-logistics/maritime.mdx b/docs/industries/transport-logistics/maritime.mdx index 6fd9d2c..8f677d9 100644 --- a/docs/industries/transport-logistics/maritime.mdx +++ b/docs/industries/transport-logistics/maritime.mdx @@ -134,12 +134,13 @@ use chrono::Utc; let mut listener = api.subscriptions.listen(&["reefer_fleet"]).await?; while let Some(Ok(msg)) = listener.next().await { if out_of_band(&msg.payload) { // |supply - setpoint| > tolerance - let mut excursion = Event::new(format!("reefer_excursion_1182_{}", Utc::now().timestamp())); - excursion.r#type = Some("reefer_excursion".into()); + let mut excursion = Event::new( + format!("reefer_excursion_1182_{}", Utc::now().timestamp()), + "reefer_excursion".into(), + Utc::now()); excursion.status = Some("open".into()); excursion.add_metadata("reefer".into(), "reefer_msc_1182".into()); excursion.add_metadata("vessel".into(), "vessel_nordic_star".into()); - excursion.set_event_time(Utc::now()); api.events.create(&vec![excursion]).await?; } listener.ack(&[msg.message_id.as_str()]).await?; diff --git a/docs/industries/transport-logistics/ports.mdx b/docs/industries/transport-logistics/ports.mdx index 9c01bfd..dcfe99b 100644 --- a/docs/industries/transport-logistics/ports.mdx +++ b/docs/industries/transport-logistics/ports.mdx @@ -87,9 +87,9 @@ let filter = RetrieveFilter { granularity: Some("1h".into()), ..Default::default() }; -let series = api.time_series - .retrieve_datapoints(&DataWrapper::from(vec![filter])).await? - .get_items().remove(0); +let page = api.time_series + .retrieve_datapoints(&DataWrapper::from(vec![filter])).await?; +let series = &page.get_items()[0]; for p in &series.datapoints { compare_to_target(&p.timestamp, p.sum); } ``` @@ -133,12 +133,13 @@ client.events.create([intellistream_datahub_sdk.Event( use intellistream_datahub_sdk::events::Event; use chrono::Utc; -let mut congestion = Event::new(format!("yard_congestion_b07_{}", Utc::now().timestamp())); -congestion.r#type = Some("yard_congestion".into()); +let mut congestion = Event::new( + format!("yard_congestion_b07_{}", Utc::now().timestamp()), + "yard_congestion".into(), + Utc::now()); congestion.status = Some("open".into()); congestion.add_metadata("block".into(), "yard_block_b07".into()); congestion.add_metadata("occupancy_pct".into(), "94".into()); -congestion.set_event_time(Utc::now()); api.events.create(&vec![congestion]).await?; ``` diff --git a/docs/industries/transport-logistics/rail.mdx b/docs/industries/transport-logistics/rail.mdx index 61cfd82..fbb9cde 100644 --- a/docs/industries/transport-logistics/rail.mdx +++ b/docs/industries/transport-logistics/rail.mdx @@ -127,7 +127,7 @@ let reachable = api.resources.fetch_related( .with_relationship_types(vec!["connects_to".into()])).await?; let still_connected = reachable.nodes().iter() - .any(|n| n.external_id == "station_bergen_n"); + .any(|n| n.external_id() == "station_bergen_n"); println!("{}", if still_connected { "route open" } else { "SEVERED — reroute required" }); ``` diff --git a/docs/industries/transport-logistics/retail.mdx b/docs/industries/transport-logistics/retail.mdx index dbde095..20ae55b 100644 --- a/docs/industries/transport-logistics/retail.mdx +++ b/docs/industries/transport-logistics/retail.mdx @@ -46,11 +46,12 @@ DataSetModel region = new DataSetModel(); region.setExternalId("region_nordics"); region.setName("Nordics region"); long regionId = client.datasets().create(List.of(region)) - .getItems().iterator().next().getId(); + .getItems().get(0).getId(); -var salesSeries = Timeseries.of("store_oslo_01_sku_4471_sales") - .name("Oslo 01 — SKU 4471 units sold") - .setDataSetId(regionId); +var salesSeries = new Timeseries(); +salesSeries.setExternalId("store_oslo_01_sku_4471_sales"); +salesSeries.setName("Oslo 01 — SKU 4471 units sold"); +salesSeries.setDataSetId(regionId); salesSeries.setUnit("units"); client.timeseries().create(salesSeries); ``` @@ -101,9 +102,11 @@ replenishment. See [Datasets reference](/reference/datasets) and ```java -DataSetRetreiver retriever = new DataSetRetreiver(); -retriever.getFilter().setExternalIdPrefix("region_nordics"); // scope to the region's dataset -DataWrapper regional = client.datasets().filter(retriever); +import ai.intellistream.datahub.models.IdCollection; + +// scope to the region's dataset +DataWrapper regional = client.datasets().byIds( + List.of(IdCollection.createFromExternalId("region_nordics"))); ``` diff --git a/docs/industries/transport-logistics/supply-chain.mdx b/docs/industries/transport-logistics/supply-chain.mdx index 354564a..2f83a62 100644 --- a/docs/industries/transport-logistics/supply-chain.mdx +++ b/docs/industries/transport-logistics/supply-chain.mdx @@ -137,11 +137,11 @@ let impacted = api.resources.fetch_related( &RelatedResourcesForm::from_external_id("lot_acme_8842").with_depth(10)).await?; for node in impacted.nodes() { - if node.external_id.starts_with("shipment_") { - println!("recall shipment: {}", node.external_id); + if node.external_id().starts_with("shipment_") { + println!("recall shipment: {}", node.external_id()); } - if node.external_id.starts_with("product_") { - println!("affected product: {}", node.external_id); + if node.external_id().starts_with("product_") { + println!("affected product: {}", node.external_id()); } } ``` diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx index a8918f0..015d500 100644 --- a/docs/quickstart.mdx +++ b/docs/quickstart.mdx @@ -102,7 +102,9 @@ TOKEN=eyJhbGciOi... # or CLIENT_ID / CLIENT_SECRET / TOKEN_URI ```java var client = DatahubClient.fromEnv(); -var series = Timeseries.of("engine_temperature").name("Engine temperature"); +var series = new Timeseries(); +series.setExternalId("engine_temperature"); +series.setName("Engine temperature"); series.setUnit("celsius"); series.setValueType("float"); client.timeseries().create(series); diff --git a/docs/reference/client.md b/docs/reference/client.md index 1aff1df..c9fe9dc 100644 --- a/docs/reference/client.md +++ b/docs/reference/client.md @@ -423,7 +423,8 @@ response surfaces as an exception/error carrying the HTTP status, the raw body, -Methods return `DataWrapper`: `getItems()` holds the results. Non-2xx throws +Methods return `DataWrapper`: `getItems()` holds the results, as a `List` in the order the +API returned them, so a single result is `getItems().get(0)`. Non-2xx throws `DatahubApiException`: ```java diff --git a/docs/reference/edges.md b/docs/reference/edges.md index 82eda1b..f9d6c8e 100644 --- a/docs/reference/edges.md +++ b/docs/reference/edges.md @@ -70,7 +70,7 @@ contains.setToExternalId("pump_1"); contains.setRelationshipType("CONTAINS"); DataWrapper created = client.edges().create(List.of(contains)); -System.out.println(created.getItems().iterator().next().getId()); +System.out.println(created.getItems().get(0).getId()); ``` `setName("Flows To")` is the alternative to `setRelationshipType`: it normalises the name to diff --git a/docs/reference/files.md b/docs/reference/files.md index 2170da9..0532fcd 100644 --- a/docs/reference/files.md +++ b/docs/reference/files.md @@ -89,7 +89,7 @@ uploaded = client.files.upload_file(upload) # -> list[INode] use intellistream_datahub_sdk::files::FileUpload; // mime type is inferred from the file content -let mut upload = FileUpload::new_with_destination_path("report.csv", "/reports/2026/"); +let mut upload = FileUpload::new_with_destination_path("report.csv", "/reports/2026/")?; upload.set_external_id("report_2026_q2".into()); upload.set_file_name("q2.csv".into()); upload.set_data_set_id(42); diff --git a/docs/reference/resources.md b/docs/reference/resources.md index 68546cd..62794ba 100644 --- a/docs/reference/resources.md +++ b/docs/reference/resources.md @@ -168,7 +168,7 @@ compare the returned items against what you asked for when a miss matters. ```java import ai.intellistream.datahub.models.IdCollection; -NodeModel pump = client.resources().getById(5677892).getItems().iterator().next(); +NodeModel pump = client.resources().getById(5677892).getItems().get(0); DataWrapper some = client.resources().byIds(List.of( IdCollection.createFromExternalId("pump_1"), @@ -266,12 +266,12 @@ retarget a relationship or change its type): ```java -ResourceForm plant = new ResourceForm(); +Resource plant = new Resource(); plant.setExternalId("plant_oslo"); plant.setName("Oslo Plant"); plant.setLabels(List.of("Plant")); -ResourceForm pump = new ResourceForm(); +Resource pump = new Resource(); pump.setExternalId("pump_1"); pump.setName("Pump 1"); pump.setLabels(List.of("Pump")); @@ -281,7 +281,7 @@ contains.setName("contains"); contains.setFromExternalId("plant_oslo"); contains.setToExternalId("pump_1"); -GraphDataWrapper created = client.resources() +GraphDataWrapper created = client.resources() .create(List.of(plant, pump), List.of(contains)); System.out.println(created.getNodes().size() + " resources, " @@ -518,7 +518,7 @@ search query itself, everything else is applied to the hits afterwards. ```java -ResourceSearch search = new ResourceSearch(); +SearchBody search = new SearchBody<>(); search.setLimit(10); search.getSearch().setQuery("pump"); DataWrapper matches = client.resources().search(search); diff --git a/docs/reference/timeseries.md b/docs/reference/timeseries.md index b916e86..8afa883 100644 --- a/docs/reference/timeseries.md +++ b/docs/reference/timeseries.md @@ -19,9 +19,9 @@ exactly as you send it. [External ids & naming →](./external-ids) ```java -Timeseries series = new Timeseries() - .setExternalId("engine_temperature") - .setName("Engine temperature"); +Timeseries series = new Timeseries(); +series.setExternalId("engine_temperature"); +series.setName("Engine temperature"); series.setUnit("celsius"); client.timeseries().create(List.of(series)); @@ -121,9 +121,9 @@ For a value that must reconcile exactly, use `numeric`: ```java -Timeseries price = new Timeseries() - .setExternalId("book_value_usd") - .setName("Book value (USD)"); +Timeseries price = new Timeseries(); +price.setExternalId("book_value_usd"); +price.setName("Book value (USD)"); price.setUnit("usd"); price.setValueType("numeric"); // exact decimals, no float rounding @@ -375,7 +375,11 @@ because the stored points would no longer parse; create a new series instead. import ai.intellistream.datahub.timeseries.UpdateTimeseries; DataWrapper newest = client.timeseries().list(100); -DataWrapper inSet = client.timeseries().list(100, "engine_data"); + +// Java takes the numeric dataSetId, so look the data set up by external id first. +long engineData = client.datasets().byIds(List.of( + IdCollection.createFromExternalId("engine_data"))).getItems().get(0).getId(); +DataWrapper inSet = client.timeseries().list(100, engineData); UpdateTimeseries change = new UpdateTimeseries().setExternalId("engine_temperature"); change.getUpdate().getDescription().set("Engine block temperature, port side"); @@ -799,7 +803,7 @@ It is much cheaper than [retrieve](#retrieve-datapoints) with a limit of one: th is served from the cache the ingest path writes, not from a range scan. ```java -DataWrapper> now = client.timeseries().latest(List.of( +DataWrapper> now = client.timeseries().latest(List.of( IdCollection.createFromExternalId("engine_temperature"), IdCollection.createFromExternalId("engine_pressure"))); ``` diff --git a/docs/reference/units.md b/docs/reference/units.md index 98a9671..b143b53 100644 --- a/docs/reference/units.md +++ b/docs/reference/units.md @@ -76,12 +76,12 @@ DataWrapper byId = client.units().byIds(List.of(IdCollection.createFr ```python import intellistream_datahub_sdk -by_ext = client.units.by_external_ids("temperature_deg_c") +by_ext = client.units.by_external_id("temperature_deg_c") by_id = client.units.by_ids([intellistream_datahub_sdk.IdCollection(id=7)]) ``` -`by_external_ids` takes one external id and returns a list, empty when no unit has it. The -`AsyncDataHubClient` spells the same call in the singular: +`by_external_id` takes one external id and returns a list, empty when no unit has it. The +`AsyncDataHubClient` awaits the same call: ```python by_ext = await client.units.by_external_id("temperature_deg_c") @@ -109,6 +109,6 @@ An external id no unit has is an error here, not an empty result: `by_external_i | --- | --- | --- | --- | | List all | `units().list` | `units.list` | `units.list` | | Look up by id | `units().byIds` | `units.by_ids` | `units.by_ids` | -| Look up by external id | `units().byIds` | `units.by_external_ids` (sync), `units.by_external_id` (async) | `units.by_external_id` | +| Look up by external id | `units().byIds` | `units.by_external_id` | `units.by_external_id` | The unit catalogue is read-only in every client: units are platform-managed, not tenant data. diff --git a/docs/tutorial.mdx b/docs/tutorial.mdx index 948e5ad..89d7044 100644 --- a/docs/tutorial.mdx +++ b/docs/tutorial.mdx @@ -252,6 +252,13 @@ that's expected, not a bug. ```java +record Metric(String baseId, String name) {} + +List METRICS = List.of( + new Metric("system_memory_used", "System memory used"), + new Metric("system_memory_available", "System memory available"), + new Metric("system_swap_used", "System swap used")); + List lookups = METRICS.stream() .map(m -> IdCollection.createFromExternalId(m.baseId() + "_" + host)) .toList(); @@ -262,9 +269,10 @@ Set existing = client.timeseries().byIds(lookups).getItems().stream() List missing = METRICS.stream() .filter(m -> !existing.contains(m.baseId() + "_" + host)) .map(m -> { - Timeseries ts = Timeseries.of(m.baseId() + "_" + host) - .name(m.name() + " (" + host + ")") - .setValueType("BIGINT"); + Timeseries ts = new Timeseries(); + ts.setExternalId(m.baseId() + "_" + host); + ts.setName(m.name() + " (" + host + ")"); + ts.setValueType("BIGINT"); ts.setUnit("bytes"); return ts; }) @@ -296,6 +304,9 @@ if missing: ```rust +use intellistream_datahub_sdk::generic::{DataWrapper, IdAndExtId}; +use intellistream_datahub_sdk::timeseries::TimeSeries; + let lookups: Vec = METRICS.iter() .map(|(base, _)| IdAndExtId::from_external_id(&format!("{base}_{host}"))) .collect(); @@ -320,6 +331,9 @@ for (base, name) in METRICS { ```rust +use intellistream_datahub_sdk::generic::{DataWrapper, IdAndExtId}; +use intellistream_datahub_sdk::timeseries::TimeSeries; + let lookups: Vec = METRICS.iter() .map(|(base, _)| IdAndExtId::from_external_id(&format!("{base}_{host}"))) .collect(); @@ -397,6 +411,9 @@ The sampler is plain synchronous code, identical in both Rust flavors. `sysinfo` exposes `used_memory()`/`available_memory()`/`used_swap()` directly: ```rust +use std::collections::HashMap; +use sysinfo::System; + fn sample() -> HashMap<&'static str, i64> { let mut sys = System::new(); sys.refresh_memory(); @@ -415,6 +432,9 @@ The sampler is plain synchronous code, identical in both Rust flavors. `sysinfo` exposes `used_memory()`/`available_memory()`/`used_swap()` directly: ```rust +use std::collections::HashMap; +use sysinfo::System; + fn sample() -> HashMap<&'static str, i64> { let mut sys = System::new(); sys.refresh_memory(); @@ -472,6 +492,8 @@ for base in METRICS: One `insert_datapoint` call per series: ```rust +use chrono::Utc; + let now = Utc::now(); let values = sample(); for (base, _) in METRICS { @@ -487,6 +509,8 @@ for (base, _) in METRICS { One `insert_datapoint` call per series: ```rust +use chrono::Utc; + let now = Utc::now(); let values = sample(); for (base, _) in METRICS { @@ -742,9 +766,10 @@ public final class MemoryIngestTutorial { List missing = METRICS.stream() .filter(m -> !existing.contains(m.baseId() + "_" + host)) .map(m -> { - Timeseries ts = Timeseries.of(m.baseId() + "_" + host) - .name(m.name() + " (" + host + ")") - .setValueType("BIGINT"); + Timeseries ts = new Timeseries(); + ts.setExternalId(m.baseId() + "_" + host); + ts.setName(m.name() + " (" + host + ")"); + ts.setValueType("BIGINT"); ts.setUnit("bytes"); return ts; }) diff --git a/doctests/compile_check.py b/doctests/compile_check.py index 67a3ff8..125107b 100644 --- a/doctests/compile_check.py +++ b/doctests/compile_check.py @@ -334,6 +334,23 @@ def check_rust(units: list[Unit], workdir: Path, sdk: Path, timeout: int = 1800) rust_placeholder(code, m["message"]))) if proc.returncode != 0 and not reached: raise ToolchainMissing(f"cargo check failed before it reached the docs:\n{proc.stderr[-3000:]}") + + # "Type annotations needed", on a page that leaves something to the reader, is rustc saying it + # lacks information the reader supplies — not a claim about the SDK. There is no Rust + # equivalent of the Java stubbed pass to prove it: a stub would need a type of its own, and + # every constraint on the value is another call the page does not show, so rustc has nowhere to + # infer from either way. It cannot be narrowed by line, because an annotation does not survive + # being destructured: `if let Some(level) = reader_fn(..)` reports E0282 at the *use* of + # `level`, and no annotation the page could write reaches it. + # + # Dropping it costs one thing worth naming: a page whose own code is genuinely ambiguous stops + # being caught, if it also leaves a name to the reader. That is accepted, because the + # alternative was contorting the prose — the tailings page had `unwrap_or("")` and an + # `is_empty()` test in place of a plain `if let Some(..)` purely to satisfy this. A removed or + # renamed SDK symbol is E0425, E0433, E0412 or E0599, none of which this touches. + for name, found in out.items(): + if any(d.placeholder for d in found): + out[name] = [d for d in found if d.placeholder or not d.message.startswith("E0282")] return out @@ -555,12 +572,16 @@ def check_java(units: list[Unit], workdir: Path, classpath: str, timeout: int = u.segments = [replace(s, first_line=s.first_line + shift) for s in u.segments] out: dict[str, list[Diagnostic]] = {u.name: [] for u in units} + # line and "could a stub's type have caused this", so the second pass can retract it. + first: dict[str, list[tuple[int, Diagnostic, bool]]] = {u.name: [] for u in units} stubs: dict[str, dict[int, list[tuple[str, str]]]] = {} # unit -> line -> (kind, name) for e in _javac({f"{u.name}.java": u for u in units}, workdir, classpath, timeout): symbol, location = e.field("symbol"), e.field("location") text = e.message + (f": {symbol}" if symbol else "") + (f" (in {location})" if symbol and location else "") name = java_placeholder(e.message, symbol, location, e.unit.name) - out[e.unit.name].append(Diagnostic(e.unit.page, "java", e.unit.locate(e.line), text, name)) + diag = Diagnostic(e.unit.page, "java", e.unit.locate(e.line), text, name) + out[e.unit.name].append(diag) + first[e.unit.name].append((e.line, diag, name is None and _typing_failed(e))) if name and e.unit.program is None: kind = symbol.split()[0] stubs.setdefault(e.unit.name, {}).setdefault(e.line, []).append((kind, name)) @@ -590,7 +611,8 @@ def check_java(units: list[Unit], workdir: Path, classpath: str, timeout: int = if ln.startswith(f"public class {u.name} {{") else ln for ln in lines] stubbed[f"{u.name}.java"] = replace(u, source="\n".join(lines)) if stubbed: - for e in _javac(stubbed, workdir / "stubbed", classpath, timeout): + second = _javac(stubbed, workdir / "stubbed", classpath, timeout) + for e in second: if e.line not in stubs[e.unit.name] or not _lookup_failed(e): continue symbol, location = e.field("symbol"), e.field("location") @@ -599,6 +621,21 @@ def check_java(units: list[Unit], workdir: Path, classpath: str, timeout: int = diag = Diagnostic(e.unit.page, "java", e.unit.locate(e.line), text) if all((d.where, d.message) != (diag.where, diag.message) for d in out[e.unit.name]): out[e.unit.name].append(diag) + + # …and the same pass retracts, which the first one cannot do for itself. javac + # resolves neither an overload nor a target type through an argument it could not + # resolve, so an unresolved reader-supplied name shows up a second time as a type + # error — on the *enclosing call*, which is a different line from the name itself. + # Once every such name has a type, a type error that disappears was the name's and + # not the page's. Only typing errors are dropped this way; a missing method or type + # still fails however the reader's values are typed. + still: dict[str, set[int]] = {} + for e in second: + still.setdefault(e.unit.name, set()).add(e.line) + for unit_name in stubs: + resolved = [d for line, d, droppable in first[unit_name] + if droppable and line not in still.get(unit_name, set())] + out[unit_name] = [d for d in out[unit_name] if d not in resolved] return out @@ -621,6 +658,24 @@ def _lookup_failed(e: _JavacError) -> bool: return False +def _typing_failed(e: _JavacError) -> bool: + """An error about argument or target *types* — the kind an unresolved name also produces. + + The mirror of `_lookup_failed`, and used only to retract: a diagnostic of this kind that + the stubbed pass no longer reports came from a name the reader supplies, because javac + gives up on overload resolution and on inference as soon as one argument is erroneous. + + `invalid method reference` is deliberately not here. A method reference names its + receiver type outright, so it is a claim about the SDK's shape rather than about what + flows into a call, and it stays hard whatever the reader passes. + """ + if "invalid method reference" in e.message: + return False + return (e.message.startswith("incompatible types") + or e.message.startswith("no suitable method") + or "cannot be applied to given types" in e.message) + + def java_placeholder(msg: str, symbol: str | None, location: str | None, cls: str) -> str | None: """The name, when an error only says "this page never defines value/method X". diff --git a/doctests/plans/guides__ingest-timeseries.toml b/doctests/plans/guides__ingest-timeseries.toml index d978b89..d227a41 100644 --- a/doctests/plans/guides__ingest-timeseries.toml +++ b/doctests/plans/guides__ingest-timeseries.toml @@ -3,9 +3,9 @@ page = "docs/guides/ingest-timeseries.mdx" # java #1 L46 · python #1 L79 · rust #1 L106 — Ingest a million readings # java #2 L170 · java #3 L208 — Binary ingest (Java) [blocks] -python = 1 +python = 2 java = 3 -rust = 1 +rust = 2 # The page opens on a reader who already has a series. Rather than conjuring one, # the quickstart runs first: this tests that the two pages compose, which is how diff --git a/doctests/plans/reference__binary-datapoints.toml b/doctests/plans/reference__binary-datapoints.toml index c274266..18bddd3 100644 --- a/doctests/plans/reference__binary-datapoints.toml +++ b/doctests/plans/reference__binary-datapoints.toml @@ -5,6 +5,7 @@ page = "docs/reference/binary-datapoints.md" [blocks] python = 1 +rust = 1 [python] # The page's banner: it writes into `engine_temperature`, which section A of the diff --git a/doctests/plans/reference__datasets.toml b/doctests/plans/reference__datasets.toml index fc35bde..d090029 100644 --- a/doctests/plans/reference__datasets.toml +++ b/doctests/plans/reference__datasets.toml @@ -10,7 +10,7 @@ page = "docs/reference/datasets.md" [blocks] python = 3 -java = 3 +java = 4 rust = 3 [python] diff --git a/doctests/plans/reference__files.toml b/doctests/plans/reference__files.toml index 09e9ec4..ce68a7d 100644 --- a/doctests/plans/reference__files.toml +++ b/doctests/plans/reference__files.toml @@ -14,7 +14,7 @@ page = "docs/reference/files.md" [blocks] python = 5 -java = 5 +java = 6 rust = 5 [python] diff --git a/doctests/plans/reference__labels.toml b/doctests/plans/reference__labels.toml new file mode 100644 index 0000000..fe3fe3f --- /dev/null +++ b/doctests/plans/reference__labels.toml @@ -0,0 +1,20 @@ +page = "docs/reference/labels.md" + +# Blocks on this page: +# java #1 L26 Read +# java #2 L37 Create and update +# java #3 L52 Create and update +# java #4 L61 Create and update +# java #5 L70 Delete + +# Pinned so an edit to the page fails this plan instead of silently +# re-pointing its block selections. Update deliberately, after re-reading. +[blocks] +java = 5 + +[java] +disabled = "Java scenario not written yet; compiled by test_compile.py." +# A reference page, not a tutorial: the blocks are separate examples of one call +# each, and #5 deletes the label #2 to #4 create. Compiled one at a time, so +# reusing a name across them is not a redeclaration. +independent = true diff --git a/doctests/plans/reference__policies.toml b/doctests/plans/reference__policies.toml new file mode 100644 index 0000000..45f30ca --- /dev/null +++ b/doctests/plans/reference__policies.toml @@ -0,0 +1,21 @@ +page = "docs/reference/policies.md" + +# Blocks on this page: +# java #1 L25 Policy types {#types} +# java #2 L46 Read, create, update, delete +# java #3 L64 Read, create, update, delete +# java #4 L75 Read, create, update, delete +# java #5 L84 Dry-run a name against the naming policy {#naming-check} +# java #6 L116 Governance templates {#governance-templates} + +# Pinned so an edit to the page fails this plan instead of silently +# re-pointing its block selections. Update deliberately, after re-reading. +[blocks] +java = 6 + +[java] +disabled = "Java scenario not written yet; compiled by test_compile.py." +# A reference page, not a tutorial: each block is a separate example, and the +# create/update/delete trio walks the same policy through its life. Compiled one +# at a time, so the name each reuses is not a redeclaration. +independent = true diff --git a/doctests/plans/reference__resources.toml b/doctests/plans/reference__resources.toml index 7026679..5d50d46 100644 --- a/doctests/plans/reference__resources.toml +++ b/doctests/plans/reference__resources.toml @@ -18,9 +18,9 @@ page = "docs/reference/resources.md" # rust #5 L264 Traverse the graph [blocks] -python = 9 -java = 8 -rust = 8 +python = 10 +java = 11 +rust = 9 [python] timeout = 600 diff --git a/doctests/plans/reference__tenant.toml b/doctests/plans/reference__tenant.toml new file mode 100644 index 0000000..af02469 --- /dev/null +++ b/doctests/plans/reference__tenant.toml @@ -0,0 +1,16 @@ +page = "docs/reference/tenant.md" + +# Blocks on this page: +# java #1 L16 Feature flags {#features} +# java #2 L46 What you may change {#settings-permissions} +# java #3 L61 Model configuration {#llm-settings} + +# Pinned so an edit to the page fails this plan instead of silently +# re-pointing its block selections. Update deliberately, after re-reading. +[blocks] +java = 3 + +[java] +disabled = "Java scenario not written yet; compiled by test_compile.py." +# A reference page, not a tutorial: three unrelated reads of tenant settings. +independent = true diff --git a/doctests/plans/reference__timeseries.toml b/doctests/plans/reference__timeseries.toml index ccc542f..12b8ea6 100644 --- a/doctests/plans/reference__timeseries.toml +++ b/doctests/plans/reference__timeseries.toml @@ -35,9 +35,9 @@ page = "docs/reference/timeseries.md" # java #14 L734 IngestResult [blocks] -python = 9 -java = 14 -rust = 9 +python = 10 +java = 17 +rust = 10 [python] timeout = 600 @@ -58,10 +58,10 @@ client = intellistream_datahub_sdk.DataHubClient.from_env() [java] disabled = "Java scenario not written yet." -# Independent examples, as for Python. #13 is a list of IngestResult's method signatures, +# Independent examples, as for Python. #16 is a list of IngestResult's method signatures, # not code. independent = true -exclude = [13] +exclude = [16] [owns] timeseries = ["book_value_usd", "engine_temperature"] diff --git a/doctests/test_compile.py b/doctests/test_compile.py index fa1ebf9..b7df21c 100644 --- a/doctests/test_compile.py +++ b/doctests/test_compile.py @@ -68,6 +68,12 @@ def page(self, lang: str) -> docblocks.Page: placeholders=frozenset({"readerValue", "recordReading"})), Control("missing_method_with_reader_argument", "client.timeseries().noSuchMethodForDoctest(readerValue);", hard_lines=(1,), placeholders=frozenset({"readerValue"})), + # `ingest` is overloaded (List and Map>), + # so javac reports the unresolved argument *and* an overload failure on the call. The + # call is the page's own and compiles once the reader's value has a type; only the + # argument is left to the reader. See `_typing_failed`. + Control("overload_with_reader_argument", 'client.timeseries().ingest(Map.of("x", readerReadings));', + placeholders=frozenset({"readerReadings"})), ], "rust": [ Control("compiles", "use intellistream_datahub_sdk::timeseries::TimeSeries;\n" @@ -80,6 +86,14 @@ def page(self, lang: str) -> docblocks.Page: Control("missing_method_with_reader_argument", "api.time_series.no_such_method_for_doctest(reader_value).await?;", hard_lines=(1,), placeholders=frozenset({"reader_value"})), + # rustc reports E0282 at the *use* of a value destructured out of a reader-supplied call, + # where no annotation the page could write reaches it. The page is what a reader needs; + # only the function is theirs to write. See the note at the end of `check_rust`. + Control("reader_supplied_destructured", + 'if let Some(level) = reader_trigger(&payload) {\n' + ' let owned: String = level.into();\n' + ' println!("{owned}");\n}', + placeholders=frozenset({"reader_trigger", "payload"})), ], }