1use std::hash::Hash;
10
11use solverforge_core::score::Score;
12
13use super::bi_stream::BiConstraintStream;
14use super::collection_extract::CollectionExtract;
15use super::cross_bi_stream::{
16 Bi, BiPredicatePlan, BiUnaryPlan, ViewComparisonPlan, ViewOverlapPlan,
17};
18use super::filter::{UniBiFilter, UniFilter, UniLeftBiFilter, UniPairFilter};
19use super::joiner::plan::{CompileCondition, ExecutablePlan, IndexedPlan};
20use super::joiner::{
21 AndJoiner, EqualJoiner, GreaterThanJoiner, GreaterThanOrEqualJoiner, LessThanJoiner,
22 LessThanOrEqualJoiner, OverlappingJoiner, Symmetric,
23};
24use super::key_extract::EntityKeyAdapter;
25use super::relational::view_plan::{EntityKey, ViewEqualPlan};
26use super::relational::Leaf;
27use super::UniConstraintStream;
28
29pub trait JoinTarget<S, A, E, F, Sc: Score> {
37 type Output;
39
40 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output;
42}
43
44impl<S, A, E, F, K, KA, Sc> JoinTarget<S, A, E, F, Sc> for EqualJoiner<KA, KA, K, Symmetric>
46where
47 S: Send + Sync + 'static,
48 A: Clone + Hash + PartialEq + Send + Sync + 'static,
49 E: CollectionExtract<S, Item = A>,
50 F: UniFilter<S, A>,
51 K: Eq + Hash + Clone + Send + Sync,
52 KA: Fn(&A) -> K + Send + Sync,
53 Sc: Score + 'static,
54{
55 type Output = BiConstraintStream<S, A, K, E, EntityKeyAdapter<KA>, UniBiFilter<F, A>, Sc>;
56
57 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
58 let (key_fn, _) = self.into_keys();
59 let key_extractor = EntityKeyAdapter::new(key_fn);
60 let bi_filter = UniBiFilter::new(filter_a);
61 BiConstraintStream::new_self_join_with_filter(extractor_a, key_extractor, bi_filter)
62 }
63}
64
65impl<S, A, B, E, F, EB, K, KA, KB, Mode, Sc> JoinTarget<S, A, E, F, Sc>
67 for (EB, EqualJoiner<KA, KB, K, Mode>)
68where
69 S: Send + Sync + 'static,
70 A: Clone + Send + Sync + 'static,
71 B: Clone + Send + Sync + 'static,
72 E: CollectionExtract<S, Item = A>,
73 F: UniFilter<S, A>,
74 EB: CollectionExtract<S, Item = B>,
75 K: Eq + Hash + Clone + Send + Sync,
76 KA: Fn(&A) -> K + Send + Sync,
77 KB: Fn(&B) -> K + Send + Sync,
78 Sc: Score + 'static,
79{
80 type Output = Bi<S, A, B, BiUnaryPlan<K, KA, KB>, E, EB, UniLeftBiFilter<F, B>, Sc>;
81
82 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
83 let (extractor_b, joiner) = self;
84 let (key_a, key_b) = joiner.into_keys();
85 let bi_filter = UniLeftBiFilter::new(filter_a);
86 Bi::from_condition(
87 extractor_a,
88 extractor_b,
89 BiUnaryPlan::new(key_a, key_b),
90 bi_filter,
91 )
92 }
93}
94
95macro_rules! impl_comparison_join_target {
96 ($joiner:ident, $less:expr, $inclusive:expr) => {
97 impl<S, A, B, E, F, EB, K, KA, KB, Sc> JoinTarget<S, A, E, F, Sc>
98 for (EB, $joiner<KA, KB, K>)
99 where
100 S: Send + Sync + 'static,
101 A: Clone + Send + Sync + 'static,
102 B: Clone + Send + Sync + 'static,
103 E: CollectionExtract<S, Item = A>,
104 F: UniFilter<S, A>,
105 EB: CollectionExtract<S, Item = B>,
106 K: Ord + Clone + Send + Sync + 'static,
107 KA: Fn(&A) -> K + Send + Sync + 'static,
108 KB: Fn(&B) -> K + Send + Sync + 'static,
109 Sc: Score + 'static,
110 {
111 type Output = Bi<
112 S,
113 A,
114 B,
115 ViewComparisonPlan<K, KA, KB, $less, $inclusive>,
116 E,
117 EB,
118 UniLeftBiFilter<F, B>,
119 Sc,
120 >;
121
122 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
123 let (extractor_b, joiner) = self;
124 let (key_a, key_b) = joiner.into_keys();
125 let bi_filter = UniLeftBiFilter::new(filter_a);
126 Bi::from_condition(
127 extractor_a,
128 extractor_b,
129 ViewComparisonPlan::<K, KA, KB, $less, $inclusive>::new(key_a, key_b),
130 bi_filter,
131 )
132 }
133 }
134 };
135}
136
137impl_comparison_join_target!(LessThanJoiner, true, false);
140impl_comparison_join_target!(LessThanOrEqualJoiner, true, true);
141impl_comparison_join_target!(GreaterThanJoiner, false, false);
142impl_comparison_join_target!(GreaterThanOrEqualJoiner, false, true);
143
144impl<S, A, B, E, F, EB, K, SA, EA, SB, EBd, Sc> JoinTarget<S, A, E, F, Sc>
146 for (EB, OverlappingJoiner<SA, EA, SB, EBd, K>)
147where
148 S: Send + Sync + 'static,
149 A: Clone + Send + Sync + 'static,
150 B: Clone + Send + Sync + 'static,
151 E: CollectionExtract<S, Item = A>,
152 F: UniFilter<S, A>,
153 EB: CollectionExtract<S, Item = B>,
154 K: Ord + Clone + Send + Sync + 'static,
155 SA: Fn(&A) -> K + Send + Sync + 'static,
156 EA: Fn(&A) -> K + Send + Sync + 'static,
157 SB: Fn(&B) -> K + Send + Sync + 'static,
158 EBd: Fn(&B) -> K + Send + Sync + 'static,
159 Sc: Score + 'static,
160{
161 type Output =
162 Bi<S, A, B, ViewOverlapPlan<K, SA, EA, SB, EBd>, E, EB, UniLeftBiFilter<F, B>, Sc>;
163
164 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
165 let (extractor_b, joiner) = self;
166 let (start_a, end_a, start_b, end_b) = joiner.into_bounds();
167 let bi_filter = UniLeftBiFilter::new(filter_a);
168 Bi::from_condition(
169 extractor_a,
170 extractor_b,
171 ViewOverlapPlan::new(start_a, end_a, start_b, end_b),
172 bi_filter,
173 )
174 }
175}
176
177impl<S, A, B, E, F, EB, J1, J2, Sc> JoinTarget<S, A, E, F, Sc> for (EB, AndJoiner<J1, J2>)
180where
181 S: Send + Sync + 'static,
182 A: Clone + Send + Sync + 'static,
183 B: Clone + Send + Sync + 'static,
184 E: CollectionExtract<S, Item = A>,
185 F: UniFilter<S, A>,
186 EB: CollectionExtract<S, Item = B>,
187 J1: ToViewPlan<A, B> + 'static,
188 J2: ToViewPlan<A, B> + 'static,
189 AndJoiner<J1::ViewPlan, J2::ViewPlan>: CompileCondition<Plan: IndexedPlan> + 'static,
190 for<'a> <AndJoiner<J1::ViewPlan, J2::ViewPlan> as CompileCondition>::Plan:
191 ExecutablePlan<Leaf<'a, A>, Leaf<'a, B>>,
192 Sc: Score + 'static,
193{
194 type Output = Bi<
195 S,
196 A,
197 B,
198 <AndJoiner<J1::ViewPlan, J2::ViewPlan> as CompileCondition>::Plan,
199 E,
200 EB,
201 UniLeftBiFilter<F, B>,
202 Sc,
203 >;
204
205 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
206 let (extractor_b, joiner) = self;
207 let (first, second) = joiner.into_parts();
208 let composed = AndJoiner::new(first.into_view_plan(), second.into_view_plan());
209 let bi_filter = UniLeftBiFilter::new(filter_a);
210 Bi::from_condition(extractor_a, extractor_b, composed.compile(), bi_filter)
211 }
212}
213
214impl<S, A, B, E, F, EB, FB, P, Sc> JoinTarget<S, A, E, F, Sc>
219 for (UniConstraintStream<S, B, EB, FB, Sc>, P)
220where
221 S: Send + Sync + 'static,
222 A: Clone + Send + Sync + 'static,
223 B: Clone + Send + Sync + 'static,
224 E: CollectionExtract<S, Item = A>,
225 F: UniFilter<S, A>,
226 EB: CollectionExtract<S, Item = B>,
227 FB: UniFilter<S, B>,
228 P: Fn(&A, &B) -> bool + Send + Sync + 'static,
229 Sc: Score + 'static,
230{
231 type Output = Bi<S, A, B, BiPredicatePlan<P>, E, EB, UniPairFilter<F, FB>, Sc>;
232
233 fn apply(self, extractor_a: E, filter_a: F) -> Self::Output {
234 let (other_stream, predicate) = self;
235 let (extractor_b, filter_b) = other_stream.into_parts();
236 let combined_filter = UniPairFilter::new(filter_a, filter_b);
237 Bi::from_condition(
238 extractor_a,
239 extractor_b,
240 BiPredicatePlan::new(predicate),
241 combined_filter,
242 )
243 }
244}
245
246pub trait ToViewPlan<A, B> {
251 type ViewPlan;
252 fn into_view_plan(self) -> Self::ViewPlan;
253}
254
255impl<A, B, K, KA, KB, Mode> ToViewPlan<A, B> for EqualJoiner<KA, KB, K, Mode>
256where
257 K: Eq + Hash + Clone,
258 KA: Fn(&A) -> K + Send + Sync,
259 KB: Fn(&B) -> K + Send + Sync,
260{
261 type ViewPlan = ViewEqualPlan<K, EntityKey<KA>, EntityKey<KB>>;
262 fn into_view_plan(self) -> Self::ViewPlan {
263 let (key_a, key_b) = self.into_keys();
264 ViewEqualPlan::new(EntityKey::new(key_a), EntityKey::new(key_b))
265 }
266}
267
268macro_rules! impl_to_view_plan_comparison {
269 ($joiner:ident, $less:expr, $inclusive:expr) => {
270 impl<A, B, K, KA, KB> ToViewPlan<A, B> for $joiner<KA, KB, K>
271 where
272 K: Ord + Clone,
273 KA: Fn(&A) -> K + Send + Sync,
274 KB: Fn(&B) -> K + Send + Sync,
275 {
276 type ViewPlan = ViewComparisonPlan<K, KA, KB, $less, $inclusive>;
277 fn into_view_plan(self) -> Self::ViewPlan {
278 let (key_a, key_b) = self.into_keys();
279 ViewComparisonPlan::new(key_a, key_b)
280 }
281 }
282 };
283}
284impl_to_view_plan_comparison!(LessThanJoiner, true, false);
285impl_to_view_plan_comparison!(LessThanOrEqualJoiner, true, true);
286impl_to_view_plan_comparison!(GreaterThanJoiner, false, false);
287impl_to_view_plan_comparison!(GreaterThanOrEqualJoiner, false, true);
288
289impl<A, B, K, SA, EA, SB, EBd> ToViewPlan<A, B> for OverlappingJoiner<SA, EA, SB, EBd, K>
290where
291 K: Ord + Clone,
292 SA: Fn(&A) -> K + Send + Sync,
293 EA: Fn(&A) -> K + Send + Sync,
294 SB: Fn(&B) -> K + Send + Sync,
295 EBd: Fn(&B) -> K + Send + Sync,
296{
297 type ViewPlan = ViewOverlapPlan<K, SA, EA, SB, EBd>;
298 fn into_view_plan(self) -> Self::ViewPlan {
299 let (start_a, end_a, start_b, end_b) = self.into_bounds();
300 ViewOverlapPlan::new(start_a, end_a, start_b, end_b)
301 }
302}
303
304impl<A, B, J1, J2> ToViewPlan<A, B> for AndJoiner<J1, J2>
305where
306 J1: ToViewPlan<A, B>,
307 J2: ToViewPlan<A, B>,
308{
309 type ViewPlan = AndJoiner<J1::ViewPlan, J2::ViewPlan>;
310 fn into_view_plan(self) -> Self::ViewPlan {
311 let (first, second) = self.into_parts();
312 AndJoiner::new(first.into_view_plan(), second.into_view_plan())
313 }
314}