QueryBuilder

Struct QueryBuilder 

Source
pub struct QueryBuilder { /* private fields */ }
Expand description

Fluent query builder

Implementations§

Source§

impl QueryBuilder

Source

pub fn new(resource: impl Into<String>) -> Self

Create a new query builder for a resource

§Examples
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin' and ListPrice gt 500000")
    .top(10)
    .build()?;
Source

pub fn by_key(resource: impl Into<String>, key: impl Into<String>) -> Self

Create a query builder for direct key access

Direct key access is more efficient than using filters for single-record lookups. Returns a single object instead of an array wrapped in {"value": [...]}.

Key access supports $select and $expand, but not $filter, $top, $skip, $orderby, or $apply.

§Examples
// Basic key access
let query = QueryBuilder::by_key("Property", "12345")
    .build()?;

// With select
let query = QueryBuilder::by_key("Property", "12345")
    .select(&["ListingKey", "City", "ListPrice"])
    .build()?;

// With expand
let query = QueryBuilder::by_key("Property", "12345")
    .expand(&["ListOffice", "ListAgent"])
    .build()?;
Source

pub fn filter(self, expression: impl Into<String>) -> Self

Add an OData filter expression

Pass a complete OData filter string. The library does not parse or validate the filter - it simply URL-encodes it and adds it to the query.

§Examples
// Simple equality
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin'")
    .build()?;

// Complex conditions
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin' and ListPrice gt 500000")
    .build()?;

// Enumeration with 'has' operator
let query = QueryBuilder::new("Property")
    .filter("Appliances has PropertyEnums.Appliances'Dishwasher'")
    .build()?;

// Collection operations
let query = QueryBuilder::new("Property")
    .filter("OpenHouse/any(x:x/OpenHouseDate eq 2025-06-01)")
    .build()?;
Source

pub fn apply(self, expression: impl Into<String>) -> Self

Add an OData apply expression for aggregations

⚠️ Server Compatibility Required: This feature requires server support for OData v4.0 Aggregation Extensions. Not all RESO servers support $apply. If unsupported, the server will return a 400 error.

Pass a complete OData apply string. The library does not parse or validate the apply expression - it simply URL-encodes it and adds it to the query.

§Examples
// Group by city with count
let query = QueryBuilder::new("Property")
    .apply("groupby((City), aggregate($count as Count))")
    .build()?;

// Group by multiple fields
let query = QueryBuilder::new("Property")
    .apply("groupby((City, PropertyType), aggregate($count as Count))")
    .build()?;
§Alternative for servers without $apply support

If your server doesn’t support aggregation, use multiple filtered queries instead:

let statuses = ["Active", "Pending", "Closed"];
for status in statuses {
    let query = QueryBuilder::new("Property")
        .filter(format!("StandardStatus eq '{}'", status))
        .count()
        .build()?;

    let response = client.execute(&query).await?;
    let count = response.as_u64().unwrap_or(0);
    println!("{}: {}", status, count);
}
Source

pub fn select(self, fields: &[&str]) -> Self

Select specific fields

§Examples
let query = QueryBuilder::new("Property")
    .select(&["ListingKey", "City", "ListPrice"])
    .build()?;
Source

pub fn expand(self, fields: &[&str]) -> Self

Expand related entities

The $expand parameter allows you to include related data in a single request, reducing the number of API calls needed. Common examples include expanding ListOffice or ListAgent for Property resources.

Note: When using $select, you must include the expanded field names in the select list, otherwise the expansion will be ignored.

§Examples
// Expand a single related entity
let query = QueryBuilder::new("Property")
    .expand(&["ListOffice"])
    .build()?;

// Expand multiple related entities
let query = QueryBuilder::new("Property")
    .expand(&["ListOffice", "ListAgent"])
    .build()?;

// When using select, include expanded fields
let query = QueryBuilder::new("Property")
    .select(&["ListingKey", "City", "ListPrice", "ListOffice", "ListAgent"])
    .expand(&["ListOffice", "ListAgent"])
    .build()?;
Source

pub fn order_by(self, field: &str, direction: &str) -> Self

Order by a field

§Examples
let query = QueryBuilder::new("Property")
    .order_by("ListPrice", "desc")
    .build()?;
Source

pub fn top(self, n: u32) -> Self

Limit number of results

§Examples
let query = QueryBuilder::new("Property")
    .top(10)
    .build()?;
Source

pub fn skip(self, n: u32) -> Self

Skip results (for pagination)

§Examples
let query = QueryBuilder::new("Property")
    .skip(100)
    .top(10)
    .build()?;
Source

pub fn with_count(self) -> Self

Include count in response

§Examples
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin'")
    .with_count()
    .build()?;
Source

pub fn count(self) -> Self

Create a count-only query

§Examples
let query = QueryBuilder::new("Property")
    .filter("City eq 'Austin'")
    .count()
    .build()?;
Source

pub fn build(self) -> Result<Query>

Build the query

§Errors

Returns an error if:

  • Key access is used with incompatible parameters ($filter, $top, $skip, $orderby, $apply, $count)

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more