1use std::collections::HashMap;
4use std::collections::HashSet;
5
6use crate::prelude::*;
7use crate::warrant::Warrant;
8use holo_hash::EntryHash;
9use holo_hash::HasHash;
10use holo_hash::{ActionHash, AgentPubKey, AnyLinkableHash};
11use holochain_integrity_types::{LinkTag, LinkTypeFilter};
12pub use holochain_serialized_bytes::prelude::*;
13
14#[derive(serde::Serialize, serde::Deserialize, PartialEq, Clone, Debug)]
33pub enum ChainQueryFilterRange {
34    Unbounded,
36    ActionSeqRange(u32, u32),
41    ActionHashRange(ActionHash, ActionHash),
45    ActionHashTerminated(ActionHash, u32),
50}
51
52impl Default for ChainQueryFilterRange {
53    fn default() -> Self {
54        Self::Unbounded
55    }
56}
57
58#[derive(
63    serde::Serialize, serde::Deserialize, SerializedBytes, Default, PartialEq, Clone, Debug,
64)]
65pub struct ChainQueryFilter {
68    pub sequence_range: ChainQueryFilterRange,
70    pub entry_type: Option<Vec<EntryType>>,
74    pub entry_hashes: Option<HashSet<EntryHash>>,
76    pub action_type: Option<Vec<ActionType>>,
80    pub include_entries: bool,
82    pub order_descending: bool,
85}
86
87#[derive(serde::Serialize, serde::Deserialize, SerializedBytes, PartialEq, Clone, Debug)]
89pub struct LinkQuery {
90    pub base: AnyLinkableHash,
92
93    pub link_type: LinkTypeFilter,
95
96    pub tag_prefix: Option<LinkTag>,
98
99    pub before: Option<Timestamp>,
101
102    pub after: Option<Timestamp>,
104
105    pub author: Option<AgentPubKey>,
107}
108
109#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize, SerializedBytes)]
110pub struct AgentActivity {
112    pub valid_activity: Vec<(u32, ActionHash)>,
114    pub rejected_activity: Vec<(u32, ActionHash)>,
116    pub status: ChainStatus,
118    pub highest_observed: Option<HighestObserved>,
121    pub warrants: Vec<Warrant>,
124}
125
126#[derive(Clone, Copy, Debug, PartialEq, serde::Serialize, serde::Deserialize, SerializedBytes)]
127pub enum ActivityRequest {
129    Status,
131    Full,
133}
134
135#[derive(Clone, Debug, PartialEq, Hash, Eq, serde::Serialize, serde::Deserialize)]
136pub struct HighestObserved {
146    pub action_seq: u32,
148    pub hash: Vec<ActionHash>,
151}
152
153#[derive(Clone, Debug, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
154#[derive(Default)]
159pub enum ChainStatus {
160    #[default]
162    Empty,
163    Valid(ChainHead),
165    Forked(ChainFork),
167    Invalid(ChainHead),
169}
170
171#[derive(Clone, Debug, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
172pub struct ChainHead {
176    pub action_seq: u32,
178    pub hash: ActionHash,
180}
181
182#[derive(Clone, Debug, Hash, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
183pub struct ChainFork {
185    pub fork_seq: u32,
187    pub first_action: ActionHash,
189    pub second_action: ActionHash,
191}
192
193impl ChainQueryFilter {
194    pub fn new() -> Self {
196        Self {
197            include_entries: false,
198            ..Self::default()
199        }
200    }
201
202    pub fn sequence_range(mut self, sequence_range: ChainQueryFilterRange) -> Self {
204        self.sequence_range = sequence_range;
205        self
206    }
207
208    pub fn entry_type(mut self, entry_type: EntryType) -> Self {
211        match self.entry_type {
212            Some(ref mut types) => {
213                types.push(entry_type);
214            }
215            None => {
216                self.entry_type = Some(vec![entry_type]);
217            }
218        }
219
220        self
221    }
222
223    pub fn entry_hashes(mut self, entry_hashes: HashSet<EntryHash>) -> Self {
225        self.entry_hashes = Some(entry_hashes);
226        self
227    }
228
229    pub fn action_type(mut self, action_type: ActionType) -> Self {
232        match self.action_type {
233            Some(ref mut types) => {
234                types.push(action_type);
235            }
236            None => {
237                self.action_type = Some(vec![action_type]);
238            }
239        }
240
241        self
242    }
243
244    pub fn include_entries(mut self, include_entries: bool) -> Self {
246        self.include_entries = include_entries;
247        self
248    }
249
250    pub fn ascending(mut self) -> Self {
252        self.order_descending = false;
253        self
254    }
255
256    pub fn descending(mut self) -> Self {
258        self.order_descending = true;
259        self
260    }
261
262    pub fn disambiguate_forks<T: ActionHashedContainer + Clone>(&self, actions: Vec<T>) -> Vec<T> {
267        match &self.sequence_range {
268            ChainQueryFilterRange::Unbounded => actions,
269            ChainQueryFilterRange::ActionSeqRange(start, end) => actions
270                .into_iter()
271                .filter(|action| {
272                    *start <= action.action().action_seq() && action.action().action_seq() <= *end
273                })
274                .collect(),
275            ChainQueryFilterRange::ActionHashRange(start, end) => {
276                let mut action_hashmap = actions
277                    .into_iter()
278                    .map(|action| (action.action_hash().clone(), action))
279                    .collect::<HashMap<ActionHash, T>>();
280                let mut filtered_actions = Vec::new();
281                let mut maybe_next_action = action_hashmap.remove(end);
282                while let Some(next_action) = maybe_next_action {
283                    maybe_next_action = next_action
284                        .action()
285                        .prev_action()
286                        .and_then(|prev_action| action_hashmap.remove(prev_action));
287                    let is_start = next_action.action_hash() == start;
288                    filtered_actions.push(next_action);
289                    if is_start {
291                        break;
292                    }
293                }
294                filtered_actions
295            }
296            ChainQueryFilterRange::ActionHashTerminated(end, n) => {
297                let mut action_hashmap = actions
298                    .iter()
299                    .map(|action| (action.action_hash().clone(), action.clone()))
300                    .collect::<HashMap<ActionHash, T>>();
301                let mut filtered_actions = Vec::new();
302                let mut maybe_next_action = action_hashmap.remove(end);
303                let mut i = 0;
304                while let Some(next_action) = maybe_next_action {
305                    maybe_next_action = next_action
306                        .action()
307                        .prev_action()
308                        .and_then(|prev_action| action_hashmap.remove(prev_action));
309                    filtered_actions.push(next_action.clone());
310                    if i == *n {
312                        break;
313                    }
314                    i += 1;
315                }
316                filtered_actions
317            }
318        }
319    }
320
321    pub fn filter_actions<T: ActionHashedContainer + Clone>(&self, actions: Vec<T>) -> Vec<T> {
323        self.disambiguate_forks(actions)
324            .into_iter()
325            .filter(|action| {
326                self.action_type
327                    .as_ref()
328                    .map(|action_types| action_types.contains(&action.action().action_type()))
329                    .unwrap_or(true)
330                    && self
331                        .entry_type
332                        .as_ref()
333                        .map(|entry_types| {
334                            action
335                                .action()
336                                .entry_type()
337                                .map(|entry_type| entry_types.contains(entry_type))
338                                .unwrap_or(false)
339                        })
340                        .unwrap_or(true)
341                    && self
342                        .entry_hashes
343                        .as_ref()
344                        .map(|entry_hashes| match action.action().entry_hash() {
345                            Some(entry_hash) => entry_hashes.contains(entry_hash),
346                            None => false,
347                        })
348                        .unwrap_or(true)
349            })
350            .collect()
351    }
352
353    pub fn filter_records(&self, records: Vec<Record>) -> Vec<Record> {
355        let actions = self.filter_actions(
356            records
357                .iter()
358                .map(|record| record.action_hashed().clone())
359                .collect(),
360        );
361        let action_hashset = actions
362            .iter()
363            .map(|action| action.as_hash().clone())
364            .collect::<HashSet<ActionHash>>();
365        records
366            .into_iter()
367            .filter(|record| action_hashset.contains(record.action_address()))
368            .collect()
369    }
370}
371
372impl LinkQuery {
373    pub fn new(base: impl Into<AnyLinkableHash>, link_type: LinkTypeFilter) -> Self {
375        LinkQuery {
376            base: base.into(),
377            link_type,
378            tag_prefix: None,
379            before: None,
380            after: None,
381            author: None,
382        }
383    }
384
385    pub fn tag_prefix(mut self, tag_prefix: LinkTag) -> Self {
387        self.tag_prefix = Some(tag_prefix);
388        self
389    }
390
391    pub fn before(mut self, before: Timestamp) -> Self {
393        self.before = Some(before);
394        self
395    }
396
397    pub fn after(mut self, after: Timestamp) -> Self {
399        self.after = Some(after);
400        self
401    }
402
403    pub fn author(mut self, author: AgentPubKey) -> Self {
405        self.author = Some(author);
406        self
407    }
408}
409
410#[cfg(test)]
411#[cfg(feature = "fixturators")]
412mod tests {
413    use super::ChainQueryFilter;
414    use crate::action::EntryType;
415    use crate::fixt::AppEntryDefFixturator;
416    use crate::prelude::*;
417    use ::fixt::prelude::*;
418    use holo_hash::fixt::EntryHashFixturator;
419    use holo_hash::HasHash;
420
421    fn fixtures() -> [ActionHashed; 7] {
424        let entry_type_1 = EntryType::App(fixt!(AppEntryDef));
425        let entry_type_2 = EntryType::AgentPubKey;
426
427        let entry_hash_0 = fixt!(EntryHash);
428
429        let mut h0 = fixt!(Create);
430        h0.entry_type = entry_type_1.clone();
431        h0.action_seq = 0;
432        h0.entry_hash = entry_hash_0.clone();
433        let hh0 = ActionHashed::from_content_sync(h0);
434
435        let mut h1 = fixt!(Update);
436        h1.entry_type = entry_type_2.clone();
437        h1.action_seq = 1;
438        h1.prev_action = hh0.as_hash().clone();
439        let hh1 = ActionHashed::from_content_sync(h1);
440
441        let mut h2 = fixt!(CreateLink);
442        h2.action_seq = 2;
443        h2.prev_action = hh1.as_hash().clone();
444        let hh2 = ActionHashed::from_content_sync(h2);
445
446        let mut h3 = fixt!(Create);
447        h3.entry_type = entry_type_2.clone();
448        h3.action_seq = 3;
449        h3.prev_action = hh2.as_hash().clone();
450        let hh3 = ActionHashed::from_content_sync(h3);
451
452        let mut h3a = fixt!(Create);
454        h3a.entry_type = entry_type_1.clone();
455        h3a.action_seq = 3;
456        h3a.prev_action = hh2.as_hash().clone();
457        let hh3a = ActionHashed::from_content_sync(h3a);
458
459        let mut h4 = fixt!(Update);
460        h4.entry_type = entry_type_1.clone();
461        h4.entry_hash = entry_hash_0;
463        h4.action_seq = 4;
464        h4.prev_action = hh3.as_hash().clone();
465        let hh4 = ActionHashed::from_content_sync(h4);
466
467        let mut h5 = fixt!(CreateLink);
468        h5.action_seq = 5;
469        h5.prev_action = hh4.as_hash().clone();
470        let hh5 = ActionHashed::from_content_sync(h5);
471
472        [hh0, hh1, hh2, hh3, hh3a, hh4, hh5]
473    }
474
475    fn map_query(query: &ChainQueryFilter, actions: &[ActionHashed]) -> Vec<bool> {
476        let filtered = query.filter_actions(actions.to_vec());
477        actions
478            .iter()
479            .map(|h| filtered.contains(h))
480            .collect::<Vec<_>>()
481    }
482
483    #[test]
484    fn filter_by_entry_type() {
485        let actions = fixtures();
486
487        let query_1 =
488            ChainQueryFilter::new().entry_type(actions[0].entry_type().unwrap().to_owned());
489        let query_2 =
490            ChainQueryFilter::new().entry_type(actions[1].entry_type().unwrap().to_owned());
491
492        assert_eq!(
493            map_query(&query_1, &actions),
494            [true, false, false, false, true, true, false].to_vec()
495        );
496        assert_eq!(
497            map_query(&query_2, &actions),
498            [false, true, false, true, false, false, false].to_vec()
499        );
500    }
501
502    #[test]
503    fn filter_by_entry_hash() {
504        let actions = fixtures();
505
506        let query = ChainQueryFilter::new().entry_hashes(
507            vec![
508                actions[3].entry_hash().unwrap().clone(),
509                actions[5].entry_hash().unwrap().clone(),
511            ]
512            .into_iter()
513            .collect(),
514        );
515
516        assert_eq!(
517            map_query(&query, &actions),
518            vec![true, false, false, true, false, true, false]
519        );
520    }
521
522    #[test]
523    fn filter_by_action_type() {
524        let actions = fixtures();
525
526        let query_1 = ChainQueryFilter::new().action_type(actions[0].action_type());
527        let query_2 = ChainQueryFilter::new().action_type(actions[1].action_type());
528        let query_3 = ChainQueryFilter::new().action_type(actions[2].action_type());
529
530        assert_eq!(
531            map_query(&query_1, &actions),
532            [true, false, false, true, true, false, false].to_vec()
533        );
534        assert_eq!(
535            map_query(&query_2, &actions),
536            [false, true, false, false, false, true, false].to_vec()
537        );
538        assert_eq!(
539            map_query(&query_3, &actions),
540            [false, false, true, false, false, false, true].to_vec()
541        );
542    }
543
544    #[test]
545    fn filter_by_chain_sequence() {
546        let actions = fixtures();
547
548        for (sequence_range, expected, name) in vec![
549            (
550                ChainQueryFilterRange::Unbounded,
551                vec![true, true, true, true, true, true, true],
552                "unbounded",
553            ),
554            (
555                ChainQueryFilterRange::ActionSeqRange(0, 0),
556                vec![true, false, false, false, false, false, false],
557                "first only",
558            ),
559            (
560                ChainQueryFilterRange::ActionSeqRange(0, 1),
561                vec![true, true, false, false, false, false, false],
562                "several from start",
563            ),
564            (
565                ChainQueryFilterRange::ActionSeqRange(1, 2),
566                vec![false, true, true, false, false, false, false],
567                "several not start",
568            ),
569            (
570                ChainQueryFilterRange::ActionSeqRange(2, 999),
571                vec![false, false, true, true, true, true, true],
572                "exceeds chain length, not start",
573            ),
574            (
575                ChainQueryFilterRange::ActionHashRange(
576                    actions[2].as_hash().clone(),
577                    actions[6].as_hash().clone(),
578                ),
579                vec![false, false, true, true, false, true, true],
580                "hash bounded not 3a",
581            ),
582            (
583                ChainQueryFilterRange::ActionHashRange(
584                    actions[2].as_hash().clone(),
585                    actions[4].as_hash().clone(),
586                ),
587                vec![false, false, true, false, true, false, false],
588                "hash bounded 3a",
589            ),
590            (
591                ChainQueryFilterRange::ActionHashTerminated(actions[2].as_hash().clone(), 1),
592                vec![false, true, true, false, false, false, false],
593                "hash terminated not start",
594            ),
595            (
596                ChainQueryFilterRange::ActionHashTerminated(actions[2].as_hash().clone(), 0),
597                vec![false, false, true, false, false, false, false],
598                "hash terminated not start 0 prior",
599            ),
600            (
601                ChainQueryFilterRange::ActionHashTerminated(actions[5].as_hash().clone(), 7),
602                vec![true, true, true, true, false, true, false],
603                "hash terminated main chain before chain start",
604            ),
605            (
606                ChainQueryFilterRange::ActionHashTerminated(actions[4].as_hash().clone(), 7),
607                vec![true, true, true, false, true, false, false],
608                "hash terminated 3a chain before chain start",
609            ),
610        ] {
611            assert_eq!(
612                (
613                    map_query(
614                        &ChainQueryFilter::new().sequence_range(sequence_range),
615                        &actions,
616                    ),
617                    name
618                ),
619                (expected, name),
620            );
621        }
622    }
623
624    #[test]
625    fn filter_by_multi() {
626        let actions = fixtures();
627
628        assert_eq!(
629            map_query(
630                &ChainQueryFilter::new()
631                    .action_type(actions[0].action_type())
632                    .entry_type(actions[0].entry_type().unwrap().clone())
633                    .sequence_range(ChainQueryFilterRange::ActionSeqRange(0, 0)),
634                &actions
635            ),
636            [true, false, false, false, false, false, false].to_vec()
637        );
638
639        assert_eq!(
640            map_query(
641                &ChainQueryFilter::new()
642                    .action_type(actions[1].action_type())
643                    .entry_type(actions[0].entry_type().unwrap().clone())
644                    .sequence_range(ChainQueryFilterRange::ActionSeqRange(0, 999)),
645                &actions
646            ),
647            [false, false, false, false, false, true, false].to_vec()
648        );
649
650        assert_eq!(
651            map_query(
652                &ChainQueryFilter::new()
653                    .entry_type(actions[0].entry_type().unwrap().clone())
654                    .sequence_range(ChainQueryFilterRange::ActionSeqRange(0, 999)),
655                &actions
656            ),
657            [true, false, false, false, true, true, false].to_vec()
658        );
659    }
660
661    #[test]
662    fn filter_by_multiple_action_types() {
663        let actions = fixtures();
664
665        assert_eq!(
667            map_query(
668                &ChainQueryFilter::new()
669                    .action_type(actions[0].action_type())
670                    .action_type(actions[1].action_type()),
671                &actions
672            ),
673            [true, true, false, true, true, true, false].to_vec()
674        );
675
676        assert_eq!(
678            map_query(
679                &ChainQueryFilter::new().action_type(actions[0].action_type()),
680                &actions
681            ),
682            [true, false, false, true, true, false, false].to_vec()
683        );
684    }
685
686    #[test]
687    fn filter_by_multiple_entry_types() {
688        let actions = fixtures();
689
690        assert_eq!(
692            map_query(
693                &ChainQueryFilter::new()
694                    .entry_type(actions[0].entry_type().unwrap().clone())
695                    .entry_type(actions[1].entry_type().unwrap().clone()),
696                &actions
697            ),
698            [true, true, false, true, true, true, false].to_vec()
699        );
700
701        assert_eq!(
703            map_query(
704                &ChainQueryFilter::new().entry_type(actions[0].entry_type().unwrap().clone()),
705                &actions
706            ),
707            [true, false, false, false, true, true, false].to_vec()
708        );
709    }
710}