1use crate::{
5 Error, PackageId,
6 graph::{
7 DependencyDirection, LinkVisitorFn, PackageGraph, PackageIx, PackageLink,
8 PackageLinkContext, PackageLinkVisitor, PackageSet,
9 feature::{FeatureFilter, FeatureQuery},
10 },
11};
12use camino::Utf8Path;
13use petgraph::prelude::*;
14
15#[derive(Clone, Debug)]
20pub struct PackageQuery<'g> {
21 pub(super) initials: PackageSet<'g>,
23 pub(super) direction: DependencyDirection,
24}
25
26assert_covariant!(PackageQuery);
27
28impl PackageGraph {
33 pub fn query_workspace(&self) -> PackageQuery<'_> {
38 self.query_forward(self.workspace().member_ids())
39 .expect("workspace packages should all be known")
40 }
41
42 pub fn query_workspace_paths(
46 &self,
47 paths: impl IntoIterator<Item = impl AsRef<Utf8Path>>,
48 ) -> Result<PackageQuery<'_>, Error> {
49 let workspace = self.workspace();
50 let package_ixs = paths
51 .into_iter()
52 .map(|path| {
53 workspace
54 .member_by_path(path.as_ref())
55 .map(|package| package.package_ix())
56 })
57 .collect::<Result<Vec<_>, Error>>()?;
58
59 Ok(self.query_from_parts(package_ixs, DependencyDirection::Forward))
60 }
61
62 pub fn query_workspace_names(
68 &self,
69 names: impl IntoIterator<Item = impl AsRef<str>>,
70 ) -> Result<PackageQuery<'_>, Error> {
71 let workspace = self.workspace();
72 let package_ixs = names
73 .into_iter()
74 .map(|name| {
75 workspace
76 .member_by_name(name.as_ref())
77 .map(|package| package.package_ix())
78 })
79 .collect::<Result<Vec<_>, Error>>()?;
80
81 Ok(self.query_from_parts(package_ixs, DependencyDirection::Forward))
82 }
83
84 pub fn query_directed<'g, 'a>(
89 &'g self,
90 package_ids: impl IntoIterator<Item = &'a PackageId>,
91 dep_direction: DependencyDirection,
92 ) -> Result<PackageQuery<'g>, Error> {
93 match dep_direction {
94 DependencyDirection::Forward => self.query_forward(package_ids),
95 DependencyDirection::Reverse => self.query_reverse(package_ids),
96 }
97 }
98
99 pub fn query_forward<'g, 'a>(
103 &'g self,
104 package_ids: impl IntoIterator<Item = &'a PackageId>,
105 ) -> Result<PackageQuery<'g>, Error> {
106 let package_ixs: Vec<_> = self.package_ixs(package_ids)?;
107 Ok(self.query_from_parts(package_ixs, DependencyDirection::Forward))
108 }
109
110 pub fn query_reverse<'g, 'a>(
114 &'g self,
115 package_ids: impl IntoIterator<Item = &'a PackageId>,
116 ) -> Result<PackageQuery<'g>, Error> {
117 let package_ixs: Vec<_> = self.package_ixs(package_ids)?;
118 Ok(self.query_from_parts(package_ixs, DependencyDirection::Reverse))
119 }
120
121 pub(super) fn query_from_parts(
122 &self,
123 package_ixs: impl IntoIterator<Item = NodeIndex<PackageIx>>,
124 direction: DependencyDirection,
125 ) -> PackageQuery<'_> {
126 PackageQuery {
127 initials: PackageSet::from_ixs(self, package_ixs),
128 direction,
129 }
130 }
131}
132
133impl<'g> PackageQuery<'g> {
134 pub fn graph(&self) -> &'g PackageGraph {
136 self.initials.graph()
137 }
138
139 pub fn direction(&self) -> DependencyDirection {
141 self.direction
142 }
143
144 pub fn initials(&self) -> &PackageSet<'g> {
146 &self.initials
147 }
148
149 pub fn to_feature_query(&self, filter: impl FeatureFilter<'g>) -> FeatureQuery<'g> {
153 let feature_graph = self.graph().feature_graph();
154 let feature_ixs: Vec<_> =
155 feature_graph.feature_ixs_for_package_ixs_filtered(self.initials.sorted_ixs(), filter);
156 feature_graph.query_from_parts(feature_ixs, self.direction)
157 }
158
159 pub fn resolve(self) -> PackageSet<'g> {
164 PackageSet::new(self)
165 }
166
167 pub fn resolve_with(self, visitor: impl PackageLinkVisitor<'g>) -> PackageSet<'g> {
170 PackageSet::with_link_visitor(self, visitor)
171 }
172
173 pub fn resolve_with_fn(
176 self,
177 visitor_fn: impl FnMut(&PackageLinkContext<'g>, PackageLink<'g>) -> bool,
178 ) -> PackageSet<'g> {
179 self.resolve_with(LinkVisitorFn(visitor_fn))
180 }
181}