use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize)]
pub struct LeadResponse {
pub id: String,
pub score: f64,
pub name: String,
pub source: String,
pub description: Option<String>,
pub address: Option<String>,
pub city: Option<String>,
pub state: Option<String>,
pub country: Option<String>,
pub postal_code: Option<String>,
pub latitude: Option<f64>,
pub longitude: Option<f64>,
pub phone: Option<String>,
pub email: Option<String>,
pub website: Option<String>,
pub rating: Option<f64>,
pub review_count: Option<u32>,
pub category: Option<String>,
pub tags: Vec<String>,
pub source_id: Option<String>,
pub logo_url: Option<String>,
pub attributes: Vec<AttributeResponse>,
pub created_at: i64,
pub updated_at: i64,
pub last_interaction_at: i64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AttributeResponse {
pub id: String,
pub name: String,
#[serde(rename = "type")]
pub attr_type: String,
pub value: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Attribute {
pub name: String,
#[serde(rename = "type")]
pub attr_type: String,
pub value: serde_json::Value,
}
impl Attribute {
pub fn text(name: &str, value: &str) -> Self {
Self {
name: name.to_owned(),
attr_type: "text".to_owned(),
value: serde_json::Value::String(value.to_owned()),
}
}
pub fn number(name: &str, value: f64) -> Self {
Self {
name: name.to_owned(),
attr_type: "number".to_owned(),
value: serde_json::json!(value),
}
}
pub fn bool(name: &str, value: bool) -> Self {
Self {
name: name.to_owned(),
attr_type: "bool".to_owned(),
value: serde_json::Value::Bool(value),
}
}
pub fn list(name: &str, value: Vec<String>) -> Self {
Self {
name: name.to_owned(),
attr_type: "list".to_owned(),
value: serde_json::to_value(value).expect("Vec<String> is always serialisable"),
}
}
pub fn object(name: &str, value: serde_json::Value) -> Self {
Self {
name: name.to_owned(),
attr_type: "object".to_owned(),
value,
}
}
}
#[derive(Debug, Clone, Serialize)]
pub struct LeadInput {
pub name: String,
pub source: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub postal_code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub latitude: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub longitude: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub website: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rating: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub review_count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub tags: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logo_url: Option<String>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub attributes: Vec<Attribute>,
}
impl LeadInput {
pub fn builder() -> LeadInputBuilder {
LeadInputBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct LeadInputBuilder {
name: Option<String>,
source: Option<String>,
description: Option<String>,
address: Option<String>,
city: Option<String>,
state: Option<String>,
country: Option<String>,
postal_code: Option<String>,
latitude: Option<f64>,
longitude: Option<f64>,
phone: Option<String>,
email: Option<String>,
website: Option<String>,
rating: Option<f64>,
review_count: Option<u32>,
category: Option<String>,
tags: Vec<String>,
source_id: Option<String>,
logo_url: Option<String>,
attributes: Vec<Attribute>,
}
impl LeadInputBuilder {
pub fn name(mut self, v: impl Into<String>) -> Self {
self.name = Some(v.into());
self
}
pub fn source(mut self, v: impl Into<String>) -> Self {
self.source = Some(v.into());
self
}
pub fn description(mut self, v: impl Into<String>) -> Self {
self.description = Some(v.into());
self
}
pub fn address(mut self, v: impl Into<String>) -> Self {
self.address = Some(v.into());
self
}
pub fn city(mut self, v: impl Into<String>) -> Self {
self.city = Some(v.into());
self
}
pub fn state(mut self, v: impl Into<String>) -> Self {
self.state = Some(v.into());
self
}
pub fn country(mut self, v: impl Into<String>) -> Self {
self.country = Some(v.into());
self
}
pub fn postal_code(mut self, v: impl Into<String>) -> Self {
self.postal_code = Some(v.into());
self
}
pub fn latitude(mut self, v: f64) -> Self {
self.latitude = Some(v);
self
}
pub fn longitude(mut self, v: f64) -> Self {
self.longitude = Some(v);
self
}
pub fn phone(mut self, v: impl Into<String>) -> Self {
self.phone = Some(v.into());
self
}
pub fn email(mut self, v: impl Into<String>) -> Self {
self.email = Some(v.into());
self
}
pub fn website(mut self, v: impl Into<String>) -> Self {
self.website = Some(v.into());
self
}
pub fn rating(mut self, v: f64) -> Self {
self.rating = Some(v);
self
}
pub fn review_count(mut self, v: u32) -> Self {
self.review_count = Some(v);
self
}
pub fn category(mut self, v: impl Into<String>) -> Self {
self.category = Some(v.into());
self
}
pub fn tags(mut self, v: Vec<String>) -> Self {
self.tags = v;
self
}
pub fn source_id(mut self, v: impl Into<String>) -> Self {
self.source_id = Some(v.into());
self
}
pub fn logo_url(mut self, v: impl Into<String>) -> Self {
self.logo_url = Some(v.into());
self
}
pub fn attributes(mut self, v: Vec<Attribute>) -> Self {
self.attributes = v;
self
}
pub fn build(self) -> LeadInput {
LeadInput {
name: self.name.expect("LeadInput requires `name`"),
source: self.source.expect("LeadInput requires `source`"),
description: self.description,
address: self.address,
city: self.city,
state: self.state,
country: self.country,
postal_code: self.postal_code,
latitude: self.latitude,
longitude: self.longitude,
phone: self.phone,
email: self.email,
website: self.website,
rating: self.rating,
review_count: self.review_count,
category: self.category,
tags: self.tags,
source_id: self.source_id,
logo_url: self.logo_url,
attributes: self.attributes,
}
}
}
#[derive(Debug, Clone, Serialize, Default)]
pub struct UpdateLeadInput {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub address: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub city: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub country: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub postal_code: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub latitude: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub longitude: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub website: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rating: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub review_count: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub category: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tags: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub logo_url: Option<String>,
}
impl UpdateLeadInput {
pub fn builder() -> UpdateLeadInputBuilder {
UpdateLeadInputBuilder::default()
}
}
#[derive(Debug, Default)]
pub struct UpdateLeadInputBuilder(UpdateLeadInput);
impl UpdateLeadInputBuilder {
pub fn name(mut self, v: impl Into<String>) -> Self {
self.0.name = Some(v.into());
self
}
pub fn source(mut self, v: impl Into<String>) -> Self {
self.0.source = Some(v.into());
self
}
pub fn description(mut self, v: impl Into<String>) -> Self {
self.0.description = Some(v.into());
self
}
pub fn address(mut self, v: impl Into<String>) -> Self {
self.0.address = Some(v.into());
self
}
pub fn city(mut self, v: impl Into<String>) -> Self {
self.0.city = Some(v.into());
self
}
pub fn state(mut self, v: impl Into<String>) -> Self {
self.0.state = Some(v.into());
self
}
pub fn country(mut self, v: impl Into<String>) -> Self {
self.0.country = Some(v.into());
self
}
pub fn postal_code(mut self, v: impl Into<String>) -> Self {
self.0.postal_code = Some(v.into());
self
}
pub fn latitude(mut self, v: f64) -> Self {
self.0.latitude = Some(v);
self
}
pub fn longitude(mut self, v: f64) -> Self {
self.0.longitude = Some(v);
self
}
pub fn phone(mut self, v: impl Into<String>) -> Self {
self.0.phone = Some(v.into());
self
}
pub fn email(mut self, v: impl Into<String>) -> Self {
self.0.email = Some(v.into());
self
}
pub fn website(mut self, v: impl Into<String>) -> Self {
self.0.website = Some(v.into());
self
}
pub fn rating(mut self, v: f64) -> Self {
self.0.rating = Some(v);
self
}
pub fn review_count(mut self, v: u32) -> Self {
self.0.review_count = Some(v);
self
}
pub fn category(mut self, v: impl Into<String>) -> Self {
self.0.category = Some(v.into());
self
}
pub fn tags(mut self, v: Vec<String>) -> Self {
self.0.tags = Some(v);
self
}
pub fn source_id(mut self, v: impl Into<String>) -> Self {
self.0.source_id = Some(v.into());
self
}
pub fn logo_url(mut self, v: impl Into<String>) -> Self {
self.0.logo_url = Some(v.into());
self
}
pub fn build(self) -> UpdateLeadInput {
self.0
}
}
#[derive(Debug, Clone, Deserialize)]
pub struct CreateResponse {
pub id: String,
pub message: String,
pub created_at: i64,
pub duplicate: Option<bool>,
pub potential_duplicate_id: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ListResult {
pub leads: Vec<LeadResponse>,
pub next_cursor: Option<String>,
pub has_more: bool,
pub count: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchCreatedItem {
pub index: usize,
pub id: String,
pub created_at: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchErrorItem {
pub index: usize,
pub message: String,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchCreateResult {
pub created: Vec<BatchCreatedItem>,
pub errors: Vec<BatchErrorItem>,
pub total: u32,
pub success: u32,
pub failed: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchResultItem {
pub index: usize,
pub id: String,
pub success: bool,
pub message: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct BatchResult {
pub results: Vec<BatchResultItem>,
pub total: u32,
pub success: u32,
pub failed: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Note {
pub id: String,
pub lead_id: String,
pub content: String,
pub created_at: i64,
pub updated_at: i64,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScoringRule {
pub id: String,
pub name: String,
pub expression: String,
pub priority: i32,
pub created_at: i64,
pub updated_at: i64,
}
#[derive(Debug, Clone, Serialize)]
pub struct ScoringRuleInput {
pub name: String,
pub expression: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<i32>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct Webhook {
pub id: String,
pub url: String,
pub events: Option<Vec<String>>,
pub active: bool,
pub created_at: String,
}
#[derive(Debug, Clone, Serialize)]
pub struct WebhookInput {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub events: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub secret: Option<String>,
}
#[derive(Debug, Clone, Deserialize)]
pub struct ScoreResponse {
pub id: String,
pub score: f64,
}
#[derive(Debug, Clone, Copy)]
pub enum ExportFormat {
Csv,
Json,
Xlsx,
}
impl ExportFormat {
pub(crate) fn as_str(self) -> &'static str {
match self {
ExportFormat::Csv => "csv",
ExportFormat::Json => "json",
ExportFormat::Xlsx => "xlsx",
}
}
}
#[derive(Default)]
pub struct ExportOptions {
pub filters: Vec<Box<dyn crate::filters::Filter>>,
pub sort_by: Option<SortField>,
pub sort_order: Option<SortOrder>,
}
impl ExportOptions {
pub fn builder() -> ExportOptionsBuilder {
ExportOptionsBuilder::default()
}
}
#[derive(Default)]
pub struct ExportOptionsBuilder {
filters: Vec<Box<dyn crate::filters::Filter>>,
sort_by: Option<SortField>,
sort_order: Option<SortOrder>,
}
impl ExportOptionsBuilder {
pub fn filter(mut self, f: impl crate::filters::Filter + 'static) -> Self {
self.filters.push(Box::new(f));
self
}
pub fn sort(mut self, field: SortField, order: SortOrder) -> Self {
self.sort_by = Some(field);
self.sort_order = Some(order);
self
}
pub fn build(self) -> ExportOptions {
ExportOptions {
filters: self.filters,
sort_by: self.sort_by,
sort_order: self.sort_order,
}
}
}
#[derive(Default)]
pub struct ListOptions {
pub filters: Vec<Box<dyn crate::filters::Filter>>,
pub sort_by: Option<SortField>,
pub sort_order: Option<SortOrder>,
pub limit: Option<u32>,
pub cursor: Option<String>,
}
impl ListOptions {
pub fn builder() -> ListOptionsBuilder {
ListOptionsBuilder::default()
}
}
#[derive(Default)]
pub struct ListOptionsBuilder {
filters: Vec<Box<dyn crate::filters::Filter>>,
sort_by: Option<SortField>,
sort_order: Option<SortOrder>,
limit: Option<u32>,
cursor: Option<String>,
}
impl ListOptionsBuilder {
pub fn filter(mut self, f: impl crate::filters::Filter + 'static) -> Self {
self.filters.push(Box::new(f));
self
}
pub fn sort(mut self, field: SortField, order: SortOrder) -> Self {
self.sort_by = Some(field);
self.sort_order = Some(order);
self
}
pub fn limit(mut self, v: u32) -> Self {
self.limit = Some(v);
self
}
pub fn cursor(mut self, v: impl Into<String>) -> Self {
self.cursor = Some(v.into());
self
}
pub fn build(self) -> ListOptions {
ListOptions {
filters: self.filters,
sort_by: self.sort_by,
sort_order: self.sort_order,
limit: self.limit,
cursor: self.cursor,
}
}
}
#[derive(Debug, Clone)]
pub enum SortField {
Name,
City,
Country,
State,
Category,
Source,
Email,
Phone,
Website,
Rating,
ReviewCount,
CreatedAt,
UpdatedAt,
LastInteractionAt,
Attr(String),
}
impl SortField {
pub fn as_str(&self) -> std::borrow::Cow<'_, str> {
match self {
SortField::Name => "name".into(),
SortField::City => "city".into(),
SortField::Country => "country".into(),
SortField::State => "state".into(),
SortField::Category => "category".into(),
SortField::Source => "source".into(),
SortField::Email => "email".into(),
SortField::Phone => "phone".into(),
SortField::Website => "website".into(),
SortField::Rating => "rating".into(),
SortField::ReviewCount => "review_count".into(),
SortField::CreatedAt => "created_at".into(),
SortField::UpdatedAt => "updated_at".into(),
SortField::LastInteractionAt => "last_interaction_at".into(),
SortField::Attr(name) => format!("attr:{name}").into(),
}
}
}
#[derive(Debug, Clone, Copy)]
pub enum SortOrder {
Asc,
Desc,
}
impl SortOrder {
pub(crate) fn as_str(self) -> &'static str {
match self {
SortOrder::Asc => "ASC",
SortOrder::Desc => "DESC",
}
}
}
#[derive(Debug, Clone)]
pub struct RateLimitState {
pub limit: u64,
pub remaining: u64,
}