1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//! Common types and traits for use in implementing query functionality for a Bindle server. Note
//! that this functionality is quite likely to change
use serde::{Deserialize, Serialize};

mod noop;
mod strict;

pub use noop::NoopEngine;
pub use strict::StrictEngine;

#[derive(Debug)]
/// The search options for performing this query and returning results
pub struct SearchOptions {
    /// The offset from the last search results
    pub offset: u64,
    /// The maximum number of results to return
    pub limit: u8,
    /// Whether to use strict mode (if there are multiple modes supported)
    pub strict: bool,
    /// Whether to return yanked bindles
    pub yanked: bool,
}

impl Default for SearchOptions {
    fn default() -> Self {
        SearchOptions {
            offset: 0,
            limit: 50,
            strict: false,
            yanked: false,
        }
    }
}

/// Describes the matches that are returned from a query
#[derive(Debug, Serialize, Deserialize)]
pub struct Matches {
    /// The query used to find this match set
    pub query: String,
    /// Whether the search engine used strict mode
    pub strict: bool,
    /// The offset of the first result in the matches
    pub offset: u64,
    /// The maximum number of results this query would have returned
    pub limit: u8,
    /// The total number of matches the search engine located
    ///
    /// In many cases, this will not match the number of results returned on this query
    pub total: u64,
    /// Whether there are more results than the ones returned here
    pub more: bool,
    /// Whether this list includes potentially yanked invoices
    pub yanked: bool,
    /// The list of invoices returned as this part of the query
    ///
    /// The length of this Vec will be less than or equal to the limit.
    // This needs to go at the bottom otherwise the table serialization in TOML gets weird. See
    // https://github.com/alexcrichton/toml-rs/issues/258
    pub invoices: Vec<crate::Invoice>,
}

impl Matches {
    fn new(opts: &SearchOptions, query: String) -> Self {
        Matches {
            // Assume options are definitive.
            query,
            strict: opts.strict,
            offset: opts.offset,
            limit: opts.limit,
            yanked: opts.yanked,

            // Defaults
            invoices: vec![],
            more: false,
            total: 0,
        }
    }
}

/// This trait describes the minimal set of features a Bindle provider must implement to provide
/// query support.
///
/// Implementors of this trait should handle any locking of the internal index in their
/// implementation Please note that due to this being an `async_trait`, the types might look
/// complicated. Look at the code directly to see the simpler function signatures for implementation
#[async_trait::async_trait]
pub trait Search {
    /// A high-level function that can take raw search strings (queries and filters) and options.
    ///
    /// This will parse the terms and filters according to its internal rules, and return
    /// a set of matches.
    ///
    /// An error is returned if either there is something incorrect in the terms/filters,
    /// or if the search engine itself fails to process the query.
    async fn query(
        &self,
        term: String,
        filter: String,
        options: SearchOptions,
    ) -> anyhow::Result<Matches>;

    /// Given an invoice, extract information from it that will be useful for searching.
    ///
    /// This high-level feature does not provide any guarantees about how it will
    /// process the invoice. But it may implement Strict and/or Standard modes
    /// described in the protocol specification.
    ///
    /// If the index function is given an invoice it has already indexed, it treats
    /// the call as an update. Otherwise, it adds a new entry to the index.
    ///
    /// As a special note, if an invoice is yanked, the index function will mark it
    /// as such, following the protocol specification's requirements for yanked
    /// invoices.
    async fn index(&self, document: &crate::Invoice) -> anyhow::Result<()>;
}