graphrecords_query/capabilities/numeric/
clip.rs1use crate::{
2 AttributeName, Failure, IndexValue, Positional, QueryResult, Scalar, ValueDomain,
3 error::{
4 comparison::IncomparableValues,
5 numeric::{InvalidClipBounds, NonNumericValue},
6 },
7};
8use graphrecords_core::graphrecord::{
9 EdgeIndex, GraphRecordAttribute, GraphRecordValue, NodeIndex,
10};
11use std::{
12 cmp::Ordering,
13 fmt::{Debug, Display},
14};
15
16pub trait ValueClip: ValueDomain {
17 fn clip<'a>(
18 label: &'static str,
19 value: Self::Value<'a>,
20 lower: Self::Value<'a>,
21 upper: Self::Value<'a>,
22 ) -> QueryResult<Self::Value<'a>>;
23}
24
25fn clip_ordered<T>(label: &'static str, value: T, lower: T, upper: T) -> QueryResult<T>
26where
27 T: Debug + Display + PartialOrd + Send + Sync + 'static,
28{
29 match lower.partial_cmp(&upper) {
30 Some(Ordering::Greater) => {
31 return Err(Failure::new(label, InvalidClipBounds::new(lower, upper)));
32 }
33 None => {
34 return Err(Failure::new(label, IncomparableValues::new(lower, upper)));
35 }
36 Some(Ordering::Less | Ordering::Equal) => {}
37 }
38
39 match value.partial_cmp(&lower) {
40 Some(Ordering::Less) => return Ok(lower),
41 None => {
42 return Err(Failure::new(label, IncomparableValues::new(value, lower)));
43 }
44 Some(Ordering::Equal | Ordering::Greater) => {}
45 }
46
47 match value.partial_cmp(&upper) {
48 Some(Ordering::Greater) => Ok(upper),
49 Some(Ordering::Less | Ordering::Equal) => Ok(value),
50 None => Err(Failure::new(label, IncomparableValues::new(value, upper))),
51 }
52}
53
54fn clip_graphrecord_attribute(
55 label: &'static str,
56 value: GraphRecordAttribute,
57 lower: GraphRecordAttribute,
58 upper: GraphRecordAttribute,
59) -> QueryResult<GraphRecordAttribute> {
60 let value = match value {
61 GraphRecordAttribute::Int(_) => value,
62 value @ GraphRecordAttribute::String(_) => {
63 return Err(Failure::new(label, NonNumericValue::new(value)));
64 }
65 };
66 let lower = match lower {
67 GraphRecordAttribute::Int(_) => lower,
68 lower @ GraphRecordAttribute::String(_) => {
69 return Err(Failure::new(label, NonNumericValue::new(lower)));
70 }
71 };
72 let upper = match upper {
73 GraphRecordAttribute::Int(_) => upper,
74 upper @ GraphRecordAttribute::String(_) => {
75 return Err(Failure::new(label, NonNumericValue::new(upper)));
76 }
77 };
78
79 clip_ordered(label, value, lower, upper)
80}
81
82fn clip_graphrecord_value(
83 label: &'static str,
84 value: GraphRecordValue,
85 lower: GraphRecordValue,
86 upper: GraphRecordValue,
87) -> QueryResult<GraphRecordValue> {
88 let value = match value {
89 GraphRecordValue::Int(_)
90 | GraphRecordValue::Float(_)
91 | GraphRecordValue::DateTime(_)
92 | GraphRecordValue::Duration(_) => value,
93 value => return Err(Failure::new(label, NonNumericValue::new(value))),
94 };
95 let lower = match lower {
96 GraphRecordValue::Int(_)
97 | GraphRecordValue::Float(_)
98 | GraphRecordValue::DateTime(_)
99 | GraphRecordValue::Duration(_) => lower,
100 lower => return Err(Failure::new(label, NonNumericValue::new(lower))),
101 };
102 let upper = match upper {
103 GraphRecordValue::Int(_)
104 | GraphRecordValue::Float(_)
105 | GraphRecordValue::DateTime(_)
106 | GraphRecordValue::Duration(_) => upper,
107 upper => return Err(Failure::new(label, NonNumericValue::new(upper))),
108 };
109
110 clip_ordered(label, value, lower, upper)
111}
112
113impl ValueClip for Scalar {
114 fn clip<'a>(
115 label: &'static str,
116 value: Self::Value<'a>,
117 lower: Self::Value<'a>,
118 upper: Self::Value<'a>,
119 ) -> QueryResult<Self::Value<'a>> {
120 clip_graphrecord_value(label, value, lower, upper)
121 }
122}
123
124impl ValueClip for AttributeName {
125 fn clip<'a>(
126 label: &'static str,
127 value: Self::Value<'a>,
128 lower: Self::Value<'a>,
129 upper: Self::Value<'a>,
130 ) -> QueryResult<Self::Value<'a>> {
131 clip_graphrecord_attribute(label, value, lower, upper)
132 }
133}
134
135impl ValueClip for IndexValue<Positional> {
136 fn clip<'a>(
137 label: &'static str,
138 value: Self::Value<'a>,
139 lower: Self::Value<'a>,
140 upper: Self::Value<'a>,
141 ) -> QueryResult<Self::Value<'a>> {
142 clip_ordered(label, value, lower, upper)
143 }
144}
145
146impl ValueClip for IndexValue<NodeIndex> {
147 fn clip<'a>(
148 label: &'static str,
149 value: Self::Value<'a>,
150 lower: Self::Value<'a>,
151 upper: Self::Value<'a>,
152 ) -> QueryResult<Self::Value<'a>> {
153 clip_graphrecord_attribute(label, value, lower, upper)
154 }
155}
156
157impl ValueClip for IndexValue<AttributeName> {
158 fn clip<'a>(
159 label: &'static str,
160 value: Self::Value<'a>,
161 lower: Self::Value<'a>,
162 upper: Self::Value<'a>,
163 ) -> QueryResult<Self::Value<'a>> {
164 clip_graphrecord_attribute(label, value, lower, upper)
165 }
166}
167
168impl ValueClip for IndexValue<EdgeIndex> {
169 fn clip<'a>(
170 label: &'static str,
171 value: Self::Value<'a>,
172 lower: Self::Value<'a>,
173 upper: Self::Value<'a>,
174 ) -> QueryResult<Self::Value<'a>> {
175 clip_ordered(label, value, lower, upper)
176 }
177}
178
179impl ValueClip for IndexValue<GraphRecordValue> {
180 fn clip<'a>(
181 label: &'static str,
182 value: Self::Value<'a>,
183 lower: Self::Value<'a>,
184 upper: Self::Value<'a>,
185 ) -> QueryResult<Self::Value<'a>> {
186 clip_graphrecord_value(label, value, lower, upper)
187 }
188}