pub trait Filter: Send + Sync {
fn to_param(&self) -> String;
}
#[derive(Debug, Clone, Copy)]
enum Logic {
And,
Or,
}
impl Logic {
fn as_str(self) -> &'static str {
match self {
Logic::And => "and",
Logic::Or => "or",
}
}
}
#[derive(Debug, Clone)]
pub struct GenericFilter {
logic: Logic,
operator: String,
field: String,
value: String,
}
impl Filter for GenericFilter {
fn to_param(&self) -> String {
if self.value.is_empty() {
format!("{}.{}.{}", self.logic.as_str(), self.operator, self.field)
} else {
format!("{}.{}.{}.{}", self.logic.as_str(), self.operator, self.field, self.value)
}
}
}
#[derive(Debug, Clone)]
pub struct TextFilterBuilder {
logic: Logic,
field: String,
}
impl TextFilterBuilder {
fn new(logic: Logic, field: impl Into<String>) -> Self {
Self { logic, field: field.into() }
}
fn make(&self, op: &str, val: impl Into<String>) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: self.field.clone(),
value: val.into(),
}
}
fn make_no_val(&self, op: &str) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: self.field.clone(),
value: String::new(),
}
}
pub fn eq(self, value: impl Into<String>) -> GenericFilter {
self.make("eq", value)
}
pub fn neq(self, value: impl Into<String>) -> GenericFilter {
self.make("neq", value)
}
pub fn contains(self, value: impl Into<String>) -> GenericFilter {
self.make("contains", value)
}
pub fn not_contains(self, value: impl Into<String>) -> GenericFilter {
self.make("not_contains", value)
}
pub fn is_empty(self) -> GenericFilter {
self.make_no_val("is_empty")
}
pub fn is_not_empty(self) -> GenericFilter {
self.make_no_val("is_not_empty")
}
}
#[derive(Debug, Clone)]
pub struct NumberFilterBuilder {
logic: Logic,
field: String,
}
impl NumberFilterBuilder {
fn new(logic: Logic, field: impl Into<String>) -> Self {
Self { logic, field: field.into() }
}
fn make(&self, op: &str, val: f64) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: self.field.clone(),
value: val.to_string(),
}
}
pub fn eq(self, value: f64) -> GenericFilter { self.make("eq", value) }
pub fn neq(self, value: f64) -> GenericFilter { self.make("neq", value) }
pub fn gt(self, value: f64) -> GenericFilter { self.make("gt", value) }
pub fn gte(self, value: f64) -> GenericFilter { self.make("gte", value) }
pub fn lt(self, value: f64) -> GenericFilter { self.make("lt", value) }
pub fn lte(self, value: f64) -> GenericFilter { self.make("lte", value) }
}
#[derive(Debug, Clone)]
pub struct TagsFilterBuilder {
logic: Logic,
}
impl TagsFilterBuilder {
fn new(logic: Logic) -> Self { Self { logic } }
fn make(&self, op: &str, val: impl Into<String>) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: "tags".to_owned(),
value: val.into(),
}
}
fn make_no_val(&self, op: &str) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: "tags".to_owned(),
value: String::new(),
}
}
pub fn contains(self, value: impl Into<String>) -> GenericFilter {
self.make("array_contains", value)
}
pub fn not_contains(self, value: impl Into<String>) -> GenericFilter {
self.make("array_not_contains", value)
}
pub fn is_empty(self) -> GenericFilter { self.make_no_val("array_empty") }
pub fn is_not_empty(self) -> GenericFilter { self.make_no_val("array_not_empty") }
}
#[derive(Debug, Clone)]
pub struct LocationFilterBuilder {
logic: Logic,
}
impl LocationFilterBuilder {
fn new(logic: Logic) -> Self { Self { logic } }
pub fn within_radius(self, lat: f64, lng: f64, km: f64) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: "within_radius".to_owned(),
field: "location".to_owned(),
value: format!("{lat},{lng},{km}"),
}
}
pub fn is_set(self) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: "is_set".to_owned(),
field: "location".to_owned(),
value: String::new(),
}
}
pub fn is_not_set(self) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: "is_not_set".to_owned(),
field: "location".to_owned(),
value: String::new(),
}
}
}
#[derive(Debug, Clone)]
pub struct AttrFilterBuilder {
logic: Logic,
name: String,
}
impl AttrFilterBuilder {
fn new(logic: Logic, name: impl Into<String>) -> Self {
Self { logic, name: name.into() }
}
fn field(&self) -> String {
format!("attr:{}", self.name)
}
fn make(&self, op: &str, val: impl Into<String>) -> GenericFilter {
GenericFilter {
logic: self.logic,
operator: op.to_owned(),
field: self.field(),
value: val.into(),
}
}
pub fn eq(self, value: impl Into<String>) -> GenericFilter {
self.make("eq", value)
}
pub fn neq(self, value: impl Into<String>) -> GenericFilter {
self.make("neq", value)
}
pub fn contains(self, value: impl Into<String>) -> GenericFilter {
self.make("contains", value)
}
pub fn eq_number(self, value: f64) -> GenericFilter {
self.make("eq", value.to_string())
}
pub fn gt(self, value: f64) -> GenericFilter {
self.make("gt", value.to_string())
}
pub fn gte(self, value: f64) -> GenericFilter {
self.make("gte", value.to_string())
}
pub fn lt(self, value: f64) -> GenericFilter {
self.make("lt", value.to_string())
}
pub fn lte(self, value: f64) -> GenericFilter {
self.make("lte", value.to_string())
}
}
#[derive(Debug, Clone)]
pub struct OrBuilder;
impl OrBuilder {
pub fn name(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "name") }
pub fn city(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "city") }
pub fn country(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "country") }
pub fn state(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "state") }
pub fn category(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "category") }
pub fn source(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "source") }
pub fn email(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "email") }
pub fn phone(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "phone") }
pub fn website(self) -> TextFilterBuilder { TextFilterBuilder::new(Logic::Or, "website") }
pub fn rating(self) -> NumberFilterBuilder { NumberFilterBuilder::new(Logic::Or, "rating") }
pub fn review_count(self) -> NumberFilterBuilder { NumberFilterBuilder::new(Logic::Or, "review_count") }
pub fn tags(self) -> TagsFilterBuilder { TagsFilterBuilder::new(Logic::Or) }
pub fn location(self) -> LocationFilterBuilder { LocationFilterBuilder::new(Logic::Or) }
pub fn attr(self, name: impl Into<String>) -> AttrFilterBuilder {
AttrFilterBuilder::new(Logic::Or, name)
}
}
pub fn name() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "name") }
pub fn city() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "city") }
pub fn country() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "country") }
pub fn state() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "state") }
pub fn category() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "category") }
pub fn source() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "source") }
pub fn email() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "email") }
pub fn phone() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "phone") }
pub fn website() -> TextFilterBuilder { TextFilterBuilder::new(Logic::And, "website") }
pub fn rating() -> NumberFilterBuilder { NumberFilterBuilder::new(Logic::And, "rating") }
pub fn review_count() -> NumberFilterBuilder { NumberFilterBuilder::new(Logic::And, "review_count") }
pub fn tags() -> TagsFilterBuilder { TagsFilterBuilder::new(Logic::And) }
pub fn location() -> LocationFilterBuilder { LocationFilterBuilder::new(Logic::And) }
pub fn attr(name: impl Into<String>) -> AttrFilterBuilder {
AttrFilterBuilder::new(Logic::And, name)
}
pub fn or() -> OrBuilder { OrBuilder }