Skip to content

Builder APIs for BundleDataSelection and EreportFilters#10108

Open
mergeconflict wants to merge 1 commit intomainfrom
mergeconflict/builder-side-quest
Open

Builder APIs for BundleDataSelection and EreportFilters#10108
mergeconflict wants to merge 1 commit intomainfrom
mergeconflict/builder-side-quest

Conversation

@mergeconflict
Copy link
Contributor

@mergeconflict mergeconflict commented Mar 19, 2026

Address @hawkw feedback from #10090 and #10089:

  • EreportFilters should have a builder API that validates datetime ranges.
  • BundleDataSelection should have a builder API that makes it more ergonomic and hides storage details.

@mergeconflict mergeconflict changed the base branch from main to mergeconflict/fm-sb-types March 19, 2026 22:51
@mergeconflict mergeconflict force-pushed the mergeconflict/builder-side-quest branch from 0f23c32 to 8d11f55 Compare March 19, 2026 22:57
Base automatically changed from mergeconflict/fm-sb-types to main March 19, 2026 23:02
@mergeconflict mergeconflict force-pushed the mergeconflict/builder-side-quest branch 2 times, most recently from 9d21ce4 to cbc48df Compare March 19, 2026 23:18
@mergeconflict mergeconflict changed the title EreportFilters: make fields private, add builder API Builder APIs for BundleDataSelection and EreportFilters Mar 19, 2026
@mergeconflict mergeconflict requested review from hawkw and smklein March 19, 2026 23:24
@mergeconflict mergeconflict force-pushed the mergeconflict/builder-side-quest branch 2 times, most recently from bccd77c to e8dec52 Compare March 20, 2026 13:53
@mergeconflict mergeconflict force-pushed the mergeconflict/builder-side-quest branch from e8dec52 to a644452 Compare March 20, 2026 16:10
///
/// ```
/// # use nexus_types::fm::ereport::EreportFilters;
/// let filters = EreportFilters::new()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neat, this usage looks a lot nicer!

/// Builder-style method that inserts a [`BundleData`] value and returns
/// `self`. If multiple BundleData entries with the same type are inserted,
/// the last write wins.
pub fn with(mut self, bundle_data: BundleData) -> Self {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this should be a non-pub method? Seems covered by all the other helpers now, right?

(If we can provide the same functionality with "one path", seems nice to not have "two pub paths" that are equivalent)

Copy link
Contributor Author

@mergeconflict mergeconflict Mar 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had it that way initially, but it turns out to be handy. I get to do this sort of thing:

    fn from_iter<T: IntoIterator<Item = BundleData>>(iter: T) -> Self {
        iter.into_iter().fold(Self::new(), |sel, data| sel.with(data))
    }

rather than having to match on the BundleDataCategory and call the specific with_ variant.

/// Note: deserialization bypasses builder validation, so a deserialized
/// `EreportFilters` may have `start_time > end_time`. This is acceptable
/// for trusted internal use (e.g. JSON stored in
/// [`BundleDataSelection`](crate::support_bundle::BundleDataSelection)).
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally I'd be more worried about this but the failure mode here would be "the database returns invalid start/end times, we ask for an empty / impossible period for our filters, so the returned set is empty", which doesn't seem so bad.

If we foresee other classes of errors here it might be worth it to actually do this validation on construction and deserialization?

Copy link
Member

@hawkw hawkw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had some thoughts about the APIs based on what I can kind of imagine DEs wanting to be able to do eventually --- basically, that it could be helpful to build bundles a bit more bit-by-bit than we are currently doing. It's fine if we don't really want to go change up the API now, though; we could add stuff like that later if it becomes necessary later.

Comment on lines +308 to +320
pub fn with_serials(
mut self,
serials: impl IntoIterator<Item = impl Into<String>>,
) -> Self {
self.only_serials.extend(serials.into_iter().map(Into::into));
self
}

/// Adds ereport classes to the inclusion filter.
///
/// When one or more classes are present, only ereports with those
/// class strings are included.
pub fn with_classes(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that I would kinda like the naming here to make it a bit more obvious that they are saying "include only these serials/classes" (which is why the fields are called "only_classes"/"only_serials"), but I can't really think of something that would make that clearer while not being grammatically super awkward as a builder-y "with" method, while not also incorrectly implying that if you call it multiple times, it clobbers the previous thing. Hm. I guess the current names are fine.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants