15 releases

0.4.4 Apr 4, 2024
0.4.2 Oct 25, 2023
0.4.0-alpha.3 Jul 12, 2023

#168 in Parser implementations

Download history 292/week @ 2024-02-01 555/week @ 2024-02-08 432/week @ 2024-02-15 551/week @ 2024-02-22 674/week @ 2024-02-29 619/week @ 2024-03-07 523/week @ 2024-03-14 150/week @ 2024-03-21 91/week @ 2024-03-28 639/week @ 2024-04-04 876/week @ 2024-04-11 887/week @ 2024-04-18 227/week @ 2024-04-25 206/week @ 2024-05-02 305/week @ 2024-05-09 399/week @ 2024-05-16

1,325 downloads per month

Apache-2.0

65KB
1.5K SLoC

SiKuLa

CI GitHub release (latest SemVer) crates.io docs.rs

Simple Query Language - [ˈziːˈkuːˈlaː]

Rationale

Another query language, are you serious?

Actually it isn't that new. But naming it "Query language similar to GitHub's search syntax" (QLSTGHSS) wasn't a real option.

Think of it more as an implementation of a familiar syntax.

What's the difference then?

They are subtle. But I don't want to spoil the surprise. Or maybe I am just too lazy documenting it. 🤷

Example

Assuming you have an enum defined for searching e-mails:

use sikula::prelude::*;

#[derive(Search, Clone, Debug, PartialEq, Eq)]
enum DeriveResource<'a> {
    /// Standard qualifier: `author:someone`
    #[search(sort, scope)]
    Author(&'a str),
    /// Default primary: `warranty`
    #[search(default)]
    Subject(Primary<'a>),
    /// Non-default primary: `warranty in:message`, to search in both: `warranty in:message in:subject`
    #[search(scope)]
    Message(Primary<'a>),

    /// Predicate: `is:read`
    Read,

    /// Numeric qualifier example:
    /// * `size:100` (equals)
    /// * `size:>=100` (size greater than or equals 100)
    /// * `size:100..200` (size between 100 inclusive and 200 exclusive)
    /// * `size:*..200` (size up to 200 exclusive)
    #[search(sort)]
    Size(Ordered<usize>),

    #[search(sort)]
    Sent(Ordered<time::OffsetDateTime>),

    Label(Qualified<'a, &'a str>),
}

The Query derive provides the trait implementation. The #[query(scope)] attribute flags the variant Subject as Body scopes for the primary search terms, marking Subject as the default if none was selected.

In general, there are three types of terms: Primary, Qualifiers, Predicates. Predicates are simple "is this condition true" style of filters. If an enum variant doesn't have any value, it is a predicate.

Qualifiers are additional matching criteria, which depend on the type of the value.

With the #[query(sort)] flag, a field can be used for sorting the result.

Now, you can do the following queries:

Query Retrieves all entries…
foo … containing "foo" in the "subject"
foo in:subject in:message … containing "foo" in either "subject" or "body"
foo in:subject in:message is:read … containing "foo" in either "subject" or "body" being "read"
foo bar … containing "foo" and "bar" in the subject
size:>10000 … having a size greater than 10000
size:100..200 … having a size between 100 (inclusive) and 200 (exclusive)
-is:read … being "not read"
foo sort:sent … containing "foo" in the subject, sorted by "sent" ascending
foo -sort:sent … containing "foo" in the subject, sorted by "sent" descending
sender:"Max Mustermann" … having a sender of Max Mustermann
sender:"Max Mustermann" sender:"Eva Mustermann" … having a sender of Max Mustermann and Eva Mustermann (most likely no results will be found)
sender:"Max Mustermann","Eva Mustermann" … having a sender of Max Mustermann or Eva Mustermann
foo OR bar … containing "foo" or "bar" in the "subject"
foo AND bar … containing "foo" and "bar" in the "subject"
foo OR bar AND baz … containing either "foo" or ( "bar" and "baz" ) in the "subject"
(foo OR bar) AND baz … containing ( "foo" or "bar" ) and "baz" in the "subject"
foo OR bar baz … containing ( "foo" or "bar" ) and "baz" in the "subject"

For testing more examples with the resource above, you can run the cli example:

cargo run --example cli --features time -- -is:read AND foo

Which will give you a structured output of the parsed query:

Input: '-is:read AND foo'
Query {
    terms: And(
        [
            Not(
                Match(
                    Read,
                ),
            ),
            Match(
                Subject(
                    Partial(
                        "foo",
                    ),
                ),
            ),
        ],
    ),
    sorting: [],
}

Dependencies

~11MB
~197K SLoC