Skip to main content

tvdata_rs/scanner/
field.rs

1use std::borrow::Cow;
2use std::fmt;
3
4use serde::{Serialize, Serializer};
5
6use crate::scanner::filter::{
7    FilterCondition, FilterOperator, IntoFilterValue, SortOrder, SortSpec,
8};
9
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
11pub struct Column(Cow<'static, str>);
12
13impl Column {
14    pub const fn from_static(name: &'static str) -> Self {
15        Self(Cow::Borrowed(name))
16    }
17
18    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
19        Self(name.into())
20    }
21
22    pub fn as_str(&self) -> &str {
23        self.0.as_ref()
24    }
25
26    pub fn with_interval(&self, interval: &str) -> Self {
27        Self::new(format!("{}|{interval}", self.as_str()))
28    }
29
30    pub fn with_history(&self, periods: u16) -> Self {
31        Self::new(format!("{}[{periods}]", self.as_str()))
32    }
33
34    pub fn recommendation(&self) -> Self {
35        Self::new(format!("Rec.{}", self.as_str()))
36    }
37
38    pub fn gt(self, value: impl IntoFilterValue) -> FilterCondition {
39        FilterCondition::new(self, FilterOperator::Greater, value.into_filter_value())
40    }
41
42    pub fn ge(self, value: impl IntoFilterValue) -> FilterCondition {
43        FilterCondition::new(self, FilterOperator::EGreater, value.into_filter_value())
44    }
45
46    pub fn lt(self, value: impl IntoFilterValue) -> FilterCondition {
47        FilterCondition::new(self, FilterOperator::Less, value.into_filter_value())
48    }
49
50    pub fn le(self, value: impl IntoFilterValue) -> FilterCondition {
51        FilterCondition::new(self, FilterOperator::ELess, value.into_filter_value())
52    }
53
54    pub fn eq(self, value: impl IntoFilterValue) -> FilterCondition {
55        FilterCondition::new(self, FilterOperator::Equal, value.into_filter_value())
56    }
57
58    pub fn ne(self, value: impl IntoFilterValue) -> FilterCondition {
59        FilterCondition::new(self, FilterOperator::NotEqual, value.into_filter_value())
60    }
61
62    pub fn between(
63        self,
64        lower: impl IntoFilterValue,
65        upper: impl IntoFilterValue,
66    ) -> FilterCondition {
67        FilterCondition::new(
68            self,
69            FilterOperator::InRange,
70            vec![lower.into_filter_value(), upper.into_filter_value()].into_filter_value(),
71        )
72    }
73
74    pub fn not_between(
75        self,
76        lower: impl IntoFilterValue,
77        upper: impl IntoFilterValue,
78    ) -> FilterCondition {
79        FilterCondition::new(
80            self,
81            FilterOperator::NotInRange,
82            vec![lower.into_filter_value(), upper.into_filter_value()].into_filter_value(),
83        )
84    }
85
86    pub fn isin<I, V>(self, values: I) -> FilterCondition
87    where
88        I: IntoIterator<Item = V>,
89        V: IntoFilterValue,
90    {
91        FilterCondition::new(
92            self,
93            FilterOperator::InRange,
94            values
95                .into_iter()
96                .map(IntoFilterValue::into_filter_value)
97                .collect::<Vec<_>>()
98                .into_filter_value(),
99        )
100    }
101
102    pub fn not_in<I, V>(self, values: I) -> FilterCondition
103    where
104        I: IntoIterator<Item = V>,
105        V: IntoFilterValue,
106    {
107        FilterCondition::new(
108            self,
109            FilterOperator::NotInRange,
110            values
111                .into_iter()
112                .map(IntoFilterValue::into_filter_value)
113                .collect::<Vec<_>>()
114                .into_filter_value(),
115        )
116    }
117
118    pub fn crosses(self, value: impl IntoFilterValue) -> FilterCondition {
119        FilterCondition::new(self, FilterOperator::Crosses, value.into_filter_value())
120    }
121
122    pub fn crosses_above(self, value: impl IntoFilterValue) -> FilterCondition {
123        FilterCondition::new(
124            self,
125            FilterOperator::CrossesAbove,
126            value.into_filter_value(),
127        )
128    }
129
130    pub fn crosses_below(self, value: impl IntoFilterValue) -> FilterCondition {
131        FilterCondition::new(
132            self,
133            FilterOperator::CrossesBelow,
134            value.into_filter_value(),
135        )
136    }
137
138    pub fn matches(self, value: impl IntoFilterValue) -> FilterCondition {
139        FilterCondition::new(self, FilterOperator::Match, value.into_filter_value())
140    }
141
142    pub fn empty(self) -> FilterCondition {
143        FilterCondition::new(self, FilterOperator::Empty, serde_json::Value::Null)
144    }
145
146    pub fn not_empty(self) -> FilterCondition {
147        FilterCondition::new(self, FilterOperator::NotEmpty, serde_json::Value::Null)
148    }
149
150    pub fn above_pct(
151        self,
152        base: impl IntoFilterValue,
153        pct: impl IntoFilterValue,
154    ) -> FilterCondition {
155        FilterCondition::new(
156            self,
157            FilterOperator::AbovePercent,
158            vec![base.into_filter_value(), pct.into_filter_value()].into_filter_value(),
159        )
160    }
161
162    pub fn below_pct(
163        self,
164        base: impl IntoFilterValue,
165        pct: impl IntoFilterValue,
166    ) -> FilterCondition {
167        FilterCondition::new(
168            self,
169            FilterOperator::BelowPercent,
170            vec![base.into_filter_value(), pct.into_filter_value()].into_filter_value(),
171        )
172    }
173
174    pub fn sort(self, order: SortOrder) -> SortSpec {
175        SortSpec::new(self, order)
176    }
177}
178
179impl fmt::Display for Column {
180    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181        f.write_str(self.as_str())
182    }
183}
184
185impl Serialize for Column {
186    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
187    where
188        S: Serializer,
189    {
190        serializer.serialize_str(self.as_str())
191    }
192}
193
194impl From<&'static str> for Column {
195    fn from(value: &'static str) -> Self {
196        Self::from_static(value)
197    }
198}
199
200impl From<String> for Column {
201    fn from(value: String) -> Self {
202        Self::new(value)
203    }
204}
205
206impl From<&String> for Column {
207    fn from(value: &String) -> Self {
208        Self::new(value.clone())
209    }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Hash)]
213pub struct Market(Cow<'static, str>);
214
215impl Market {
216    pub const fn from_static(name: &'static str) -> Self {
217        Self(Cow::Borrowed(name))
218    }
219
220    pub fn new(name: impl Into<Cow<'static, str>>) -> Self {
221        Self(name.into())
222    }
223
224    pub fn as_str(&self) -> &str {
225        self.0.as_ref()
226    }
227}
228
229impl Serialize for Market {
230    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
231    where
232        S: Serializer,
233    {
234        serializer.serialize_str(self.as_str())
235    }
236}
237
238impl From<&'static str> for Market {
239    fn from(value: &'static str) -> Self {
240        Self::from_static(value)
241    }
242}
243
244impl From<String> for Market {
245    fn from(value: String) -> Self {
246        Self::new(value)
247    }
248}
249
250#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
251pub struct Ticker(Cow<'static, str>);
252
253impl Ticker {
254    pub fn from_parts(exchange: &str, symbol: &str) -> Self {
255        Self(Cow::Owned(format!("{exchange}:{symbol}")))
256    }
257
258    pub const fn from_static(raw: &'static str) -> Self {
259        Self(Cow::Borrowed(raw))
260    }
261
262    pub fn new(raw: impl Into<Cow<'static, str>>) -> Self {
263        Self(raw.into())
264    }
265
266    pub fn as_str(&self) -> &str {
267        self.0.as_ref()
268    }
269}
270
271impl fmt::Display for Ticker {
272    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273        f.write_str(self.as_str())
274    }
275}
276
277impl Serialize for Ticker {
278    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
279    where
280        S: Serializer,
281    {
282        serializer.serialize_str(self.as_str())
283    }
284}
285
286impl From<&'static str> for Ticker {
287    fn from(value: &'static str) -> Self {
288        Self::from_static(value)
289    }
290}
291
292impl From<String> for Ticker {
293    fn from(value: String) -> Self {
294        Self::new(value)
295    }
296}