#firestore #gcloud #google #structured-query

firestore-structured-query

A Firestore StructuredQuery builder

65 releases (28 breaking)

Uses new Rust 2024

new 0.29.0 Mar 25, 2026
0.27.0 Jan 18, 2026
0.26.3 Nov 10, 2025
0.23.0 Jul 14, 2025
0.9.0 Mar 27, 2024

#788 in Algorithms

Download history 32/week @ 2025-12-03 41/week @ 2025-12-10 64/week @ 2025-12-17 7/week @ 2025-12-24 29/week @ 2025-12-31 60/week @ 2026-01-07 64/week @ 2026-01-14 45/week @ 2026-01-21 33/week @ 2026-01-28 95/week @ 2026-02-04 80/week @ 2026-02-11 115/week @ 2026-02-18 70/week @ 2026-02-25 125/week @ 2026-03-04 174/week @ 2026-03-11 116/week @ 2026-03-18

517 downloads per month

MIT/Apache

92KB
420 lines

firestore-structured-query

A Firestore StructuredQuery builder.

ci crates.io docs.rs license

Examples

use firestore_structured_query::{FieldPath, Filter, Query};
use googleapis_tonic_google_firestore_v1::google::firestore::v1::{
    structured_query, value::ValueType, ArrayValue, Cursor, StructuredQuery, Value,
};

let _ = StructuredQuery::from(
    // or Query::collection_group(...)
    Query::collection("collection_id1")
        .select([FieldPath::raw("field1"), FieldPath::raw("field2")])
        .r#where(Filter::and([
            // field filters
            FieldPath::raw("field1").less_than(Value { value_type: Some(ValueType::IntegerValue(1)) })?,
            FieldPath::raw("field2").less_than_or_equal(Value { value_type: Some(ValueType::IntegerValue(2)) })?,
            FieldPath::raw("field3").greater_than(Value { value_type: Some(ValueType::IntegerValue(3)) })?,
            FieldPath::raw("field4").greater_than_or_equal(Value { value_type: Some(ValueType::IntegerValue(4)) })?,
            FieldPath::raw("field5").equal(Value { value_type: Some(ValueType::IntegerValue(5)) })?,
            FieldPath::raw("field6").not_equal(Value { value_type: Some(ValueType::IntegerValue(6)) })?,
            FieldPath::raw("field7").array_contains(Value { value_type: Some(ValueType::IntegerValue(7)) })?,
            FieldPath::raw("field8").r#in(Value { value_type: Some(ValueType::ArrayValue(ArrayValue { values: vec![Value { value_type: Some(ValueType::IntegerValue(8)) }] })) })?,
            FieldPath::raw("field9").array_contains_any(Value { value_type: Some(ValueType::ArrayValue(ArrayValue { values: vec![Value { value_type: Some(ValueType::IntegerValue(9)) }] })) })?,
            FieldPath::raw("field10").not_in(Value { value_type: Some(ValueType::ArrayValue(ArrayValue { values: vec![Value { value_type: Some(ValueType::IntegerValue(10)) }] })) })?,
            // unary filters
            FieldPath::raw("field11").is_nan()?,
            FieldPath::raw("field12").is_not_nan()?,
            FieldPath::raw("field13").is_not_null()?,
            FieldPath::raw("field14").is_null()?,
            // composite filters
            Filter::and([
                FieldPath::raw("f").equal(Value { value_type: Some(ValueType::StringValue("a".to_string())) })?,
                FieldPath::raw("f").equal(Value { value_type: Some(ValueType::StringValue("b".to_string())) })?,
            ]),
            Filter::or([
                FieldPath::raw("f").equal(Value { value_type: Some(ValueType::StringValue("a".to_string())) })?,
                FieldPath::raw("f").equal(Value { value_type: Some(ValueType::StringValue("b".to_string())) })?,
            ]),
        ]))
        .order_by([
            FieldPath::raw("field1").ascending(),
            FieldPath::raw("field2").descending(),
        ])
        // .start_after(...)
        .start_at([
            Value { value_type: Some(ValueType::IntegerValue(1))},
            Value { value_type: Some(ValueType::IntegerValue(2))},
        ])
        // .end_before(...)
        .end_at([
            Value { value_type: Some(ValueType::IntegerValue(1))},
            Value { value_type: Some(ValueType::IntegerValue(2))},
        ])
        .offset(1_i32)
        .limit(2_i32),
);

// If "serde" feature is enabled.
use firestore_structured_query::to_value;
let _ = StructuredQuery::from(
    // or Query::collection_group(...)
    Query::collection("collection_id1")
        .select([FieldPath::raw("field1"), FieldPath::raw("field2")])
        .r#where(Filter::and([
            // field filters
            FieldPath::raw("field1").less_than(&1)?,
            FieldPath::raw("field2").less_than_or_equal(&2)?,
            FieldPath::raw("field3").greater_than(&3)?,
            FieldPath::raw("field4").greater_than_or_equal(&4)?,
            FieldPath::raw("field5").equal(&5)?,
            FieldPath::raw("field6").not_equal(&6)?,
            FieldPath::raw("field7").array_contains(&7)?,
            FieldPath::raw("field8").r#in(&[8])?,
            FieldPath::raw("field9").array_contains_any(&[9])?,
            FieldPath::raw("field10").not_in(&[10])?,
            // unary filters
            FieldPath::raw("field11").is_nan()?,
            FieldPath::raw("field12").is_not_nan()?,
            FieldPath::raw("field13").is_not_null()?,
            FieldPath::raw("field14").is_null()?,
            // composite filters
            Filter::and([
                FieldPath::raw("f").equal(&"a")?,
                FieldPath::raw("f").equal(&"b")?,
            ]),
            Filter::or([
                FieldPath::raw("f").equal(&"a")?,
                FieldPath::raw("f").equal(&"b")?,
            ]),
        ]))
        .order_by([
            FieldPath::raw("field1").ascending(),
            FieldPath::raw("field2").descending(),
        ])
        // .start_after(...)
        .start_at([
            to_value(&1)?,
            to_value(&2)?
        ])
        // .end_before(...)
        .end_at([
            to_value(&1)?,
            to_value(&2)?,
        ])
        .offset(1_i32)
        .limit(2_i32),
);

TODOs

  • StructuredQuery::find_nearest support

Dependencies

~10–14MB
~155K SLoC