Skip to content

Commit 0ea4b3f

Browse files
committed
TableOutput -> OxqlTable, move to views.rs
into -> from
1 parent dfc2cf4 commit 0ea4b3f

File tree

6 files changed

+96
-90
lines changed

6 files changed

+96
-90
lines changed

nexus/tests/integration_tests/metrics.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use nexus_test_utils::resource_helpers::{
2222
use nexus_test_utils::wait_for_producer;
2323
use nexus_test_utils_macros::nexus_test;
2424
use nexus_types::external_api::shared::ProjectRole;
25-
use nexus_types::external_api::views::OxqlQueryResult;
25+
use nexus_types::external_api::views;
2626
use nexus_types::silo::DEFAULT_SILO_ID;
2727
use omicron_uuid_kinds::{GenericUuid, InstanceUuid};
2828
use oximeter::TimeseriesSchema;
@@ -270,7 +270,7 @@ async fn test_instance_watcher_metrics(
270270

271271
#[track_caller]
272272
fn count_state(
273-
table: &oxql_types::TableOutput,
273+
table: &views::OxqlTable,
274274
instance_id: InstanceUuid,
275275
state: &'static str,
276276
) -> Result<i64, MetricsNotYet> {
@@ -639,7 +639,7 @@ async fn test_project_timeseries_query(
639639
.expect_status(Some(StatusCode::OK));
640640
let result = NexusRequest::new(request)
641641
.authn_as(AuthnMode::UnprivilegedUser)
642-
.execute_and_parse_unwrap::<OxqlQueryResult>()
642+
.execute_and_parse_unwrap::<views::OxqlQueryResult>()
643643
.await;
644644
assert_eq!(result.tables.len(), 1);
645645
assert_eq!(result.tables[0].timeseries().len(), 2); // two instances

nexus/tests/integration_tests/metrics_querier.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use nexus_test_utils::http_testing::NexusRequest;
1313
use nexus_test_utils::http_testing::RequestBuilder;
1414
use nexus_test_utils::resource_helpers::objects_list_page_authz;
1515
use nexus_types::external_api::params;
16-
use nexus_types::external_api::views::OxqlQueryResult;
16+
use nexus_types::external_api::views;
1717
use omicron_test_utils::dev::poll;
1818
use omicron_test_utils::dev::poll::CondCheckError;
1919
use omicron_test_utils::dev::poll::wait_for_condition;
@@ -93,7 +93,7 @@ impl<'a, N> MetricsQuerier<'a, N> {
9393
cond: F,
9494
) -> T
9595
where
96-
F: Fn(Vec<oxql_types::TableOutput>) -> Result<T, MetricsNotYet>,
96+
F: Fn(Vec<views::OxqlTable>) -> Result<T, MetricsNotYet>,
9797
{
9898
self.timeseries_query_until("/v1/system/timeseries/query", query, cond)
9999
.await
@@ -108,7 +108,7 @@ impl<'a, N> MetricsQuerier<'a, N> {
108108
cond: F,
109109
) -> T
110110
where
111-
F: Fn(Vec<oxql_types::TableOutput>) -> Result<T, MetricsNotYet>,
111+
F: Fn(Vec<views::OxqlTable>) -> Result<T, MetricsNotYet>,
112112
{
113113
self.timeseries_query_until(
114114
&format!("/v1/timeseries/query?project={project}"),
@@ -128,7 +128,7 @@ impl<'a, N> MetricsQuerier<'a, N> {
128128
&self,
129129
project: &str,
130130
query: &str,
131-
) -> Vec<oxql_types::TableOutput> {
131+
) -> Vec<views::OxqlTable> {
132132
self.project_timeseries_query_until(project, query, |tables| Ok(tables))
133133
.await
134134
}
@@ -270,7 +270,7 @@ impl<'a, N> MetricsQuerier<'a, N> {
270270
cond: F,
271271
) -> T
272272
where
273-
F: Fn(Vec<oxql_types::TableOutput>) -> Result<T, MetricsNotYet>,
273+
F: Fn(Vec<views::OxqlTable>) -> Result<T, MetricsNotYet>,
274274
{
275275
let result = wait_for_condition(
276276
|| async {
@@ -375,7 +375,7 @@ impl<'a, N> MetricsQuerier<'a, N> {
375375
// Try to parse the query as usual, which will fail on other kinds of
376376
// errors.
377377
TimeseriesQueryResult::Ok(
378-
rsp.parsed_body::<OxqlQueryResult>()
378+
rsp.parsed_body::<views::OxqlQueryResult>()
379379
.unwrap_or_else(|e| {
380380
panic!(
381381
"could not parse timeseries query response: {e:?}\n\
@@ -389,5 +389,5 @@ impl<'a, N> MetricsQuerier<'a, N> {
389389

390390
enum TimeseriesQueryResult {
391391
TimeseriesNotFound,
392-
Ok(Vec<oxql_types::TableOutput>),
392+
Ok(Vec<views::OxqlTable>),
393393
}

nexus/types/src/external_api/views.rs

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1113,11 +1113,74 @@ pub struct AllowList {
11131113

11141114
// OxQL QUERIES
11151115

1116+
/// A table represents one or more timeseries with the same schema.
1117+
///
1118+
/// A table is the result of an OxQL query. It contains a name, usually the name
1119+
/// of the timeseries schema from which the data is derived, and any number of
1120+
/// timeseries, which contain the actual data.
1121+
//
1122+
// # Motivation
1123+
//
1124+
// This struct is derived from [`oxql_types::Table`] but presents timeseries data as a `Vec`
1125+
// rather than a map keyed by [`TimeseriesKey`]. This provides a cleaner JSON
1126+
// representation for external consumers, as these numeric keys are ephemeral
1127+
// identifiers that have no meaning to API consumers. Key ordering is retained
1128+
// as this is contructed from the already sorted values present in [`Table`].
1129+
//
1130+
// When serializing a [`Table`] to JSON, the `BTreeMap<TimeseriesKey, Timeseries>`
1131+
// structure produces output with numeric keys like:
1132+
// ```json
1133+
// {
1134+
// "timeseries": {
1135+
// "2352746367989923131": { ... },
1136+
// "3940108470521992408": { ... }
1137+
// }
1138+
// }
1139+
// ```
1140+
//
1141+
// The `Table` view instead serializes timeseries as an array:
1142+
// ```json
1143+
// {
1144+
// "timeseries": [ { ... }, { ... } ]
1145+
// }
1146+
// ```
1147+
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
1148+
pub struct OxqlTable {
1149+
/// The name of the table.
1150+
pub name: String,
1151+
/// The set of timeseries in the table, ordered by key.
1152+
pub timeseries: Vec<oxql_types::Timeseries>,
1153+
}
1154+
1155+
impl From<oxql_types::Table> for OxqlTable {
1156+
fn from(table: oxql_types::Table) -> Self {
1157+
OxqlTable {
1158+
name: table.name.clone(),
1159+
timeseries: table.into_iter().collect(),
1160+
}
1161+
}
1162+
}
1163+
1164+
// these methods are only used in tests
1165+
impl OxqlTable {
1166+
/// Return the name of the table.
1167+
pub fn name(&self) -> &str {
1168+
self.name.as_str()
1169+
}
1170+
1171+
/// Return the list of timeseries in this table, ordered by key.
1172+
pub fn timeseries(
1173+
&self,
1174+
) -> impl ExactSizeIterator<Item = &oxql_types::Timeseries> {
1175+
self.timeseries.iter()
1176+
}
1177+
}
1178+
11161179
/// The result of a successful OxQL query.
11171180
#[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)]
11181181
pub struct OxqlQueryResult {
11191182
/// Tables resulting from the query, each containing timeseries.
1120-
pub tables: Vec<oxql_types::TableOutput>,
1183+
pub tables: Vec<OxqlTable>,
11211184
}
11221185

11231186
// ALERTS

openapi/nexus.json

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22275,14 +22275,35 @@
2227522275
"description": "Tables resulting from the query, each containing timeseries.",
2227622276
"type": "array",
2227722277
"items": {
22278-
"$ref": "#/components/schemas/TableOutput"
22278+
"$ref": "#/components/schemas/OxqlTable"
2227922279
}
2228022280
}
2228122281
},
2228222282
"required": [
2228322283
"tables"
2228422284
]
2228522285
},
22286+
"OxqlTable": {
22287+
"description": "A table represents one or more timeseries with the same schema.\n\nA table is the result of an OxQL query. It contains a name, usually the name of the timeseries schema from which the data is derived, and any number of timeseries, which contain the actual data.",
22288+
"type": "object",
22289+
"properties": {
22290+
"name": {
22291+
"description": "The name of the table.",
22292+
"type": "string"
22293+
},
22294+
"timeseries": {
22295+
"description": "The set of timeseries in the table, ordered by key.",
22296+
"type": "array",
22297+
"items": {
22298+
"$ref": "#/components/schemas/Timeseries"
22299+
}
22300+
}
22301+
},
22302+
"required": [
22303+
"name",
22304+
"timeseries"
22305+
]
22306+
},
2228622307
"Password": {
2228722308
"title": "A password used to authenticate a user",
2228822309
"description": "Passwords may be subject to additional constraints.",
@@ -25523,25 +25544,6 @@
2552325544
"vlan_id"
2552425545
]
2552525546
},
25526-
"TableOutput": {
25527-
"description": "A table represents one or more timeseries with the same schema.\n\nA table is the result of an OxQL query. It contains a name, usually the name of the timeseries schema from which the data is derived, and any number of timeseries, which contain the actual data.",
25528-
"type": "object",
25529-
"properties": {
25530-
"name": {
25531-
"type": "string"
25532-
},
25533-
"timeseries": {
25534-
"type": "array",
25535-
"items": {
25536-
"$ref": "#/components/schemas/Timeseries"
25537-
}
25538-
}
25539-
},
25540-
"required": [
25541-
"name",
25542-
"timeseries"
25543-
]
25544-
},
2554525547
"TargetRelease": {
2554625548
"description": "View of a system software target release.",
2554725549
"type": "object",

oximeter/oxql-types/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ pub mod point;
1111
pub mod table;
1212

1313
pub use self::table::Table;
14-
pub use self::table::TableOutput;
1514
pub use self::table::Timeseries;
1615

1716
/// Describes the time alignment for an OxQL query.

oximeter/oxql-types/src/table.rs

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -360,61 +360,3 @@ impl Table {
360360
}
361361
}
362362
}
363-
364-
/// A table represents one or more timeseries with the same schema.
365-
///
366-
/// A table is the result of an OxQL query. It contains a name, usually the name
367-
/// of the timeseries schema from which the data is derived, and any number of
368-
/// timeseries, which contain the actual data.
369-
//
370-
// # Motivation
371-
//
372-
// This struct is derived from [`Table`] but presents timeseries data as a `Vec`
373-
// rather than a map keyed by [`TimeseriesKey`]. This provides a cleaner JSON
374-
// representation for external consumers, as these numeric keys are ephemeral
375-
// identifiers that have no meaning to API consumers. Key ordering is retained
376-
// as this is contructed from the already sorted values present in [`Table`].
377-
//
378-
// When serializing a [`Table`] to JSON, the `BTreeMap<TimeseriesKey, Timeseries>`
379-
// structure produces output with numeric keys like:
380-
// ```json
381-
// {
382-
// "timeseries": {
383-
// "2352746367989923131": { ... },
384-
// "3940108470521992408": { ... }
385-
// }
386-
// }
387-
// ```
388-
//
389-
// `TableOutput` instead serializes timeseries as an array:
390-
// ```json
391-
// {
392-
// "timeseries": [ { ... }, { ... } ]
393-
// }
394-
// ```
395-
#[derive(Clone, Debug, Deserialize, JsonSchema, PartialEq, Serialize)]
396-
pub struct TableOutput {
397-
// The name of the table.
398-
pub name: String,
399-
// The set of timeseries in the table, ordered by key.
400-
timeseries: Vec<Timeseries>,
401-
}
402-
403-
impl From<Table> for TableOutput {
404-
fn from(table: Table) -> Self {
405-
let timeseries: Vec<_> = table.timeseries.into_values().collect();
406-
TableOutput { name: table.name, timeseries }
407-
}
408-
}
409-
410-
impl TableOutput {
411-
/// Return the name of the table.
412-
pub fn name(&self) -> &str {
413-
self.name.as_str()
414-
}
415-
416-
/// Return the list of timeseries in this table, ordered by key.
417-
pub fn timeseries(&self) -> impl ExactSizeIterator<Item = &Timeseries> {
418-
self.timeseries.iter()
419-
}
420-
}

0 commit comments

Comments
 (0)