Initial commit
This commit is contained in:
commit
a6bc84dfb3
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
/target
|
||||
.env
|
1608
Cargo.lock
generated
Normal file
1608
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
Cargo.toml
Normal file
22
Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "realtor-lp-types"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
[dependencies]
|
||||
chrono = { version = "0.4.23", features = [ "serde" ] }
|
||||
chrono-tz = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0.88"
|
||||
uuid = { version = "1.3.0", features = ["v4", "fast-rng", "macro-diagnostics", "serde"] }
|
||||
format_num = "0.1.0"
|
||||
sqlx = { version = "0.6.0", features = [ "runtime-tokio-rustls", "postgres", "chrono", "uuid" ], optional = true }
|
||||
bincode = "1.3.3"
|
||||
rand = "0.8.5"
|
||||
|
||||
[features]
|
||||
default = ["all"]
|
||||
all = ["sqlx", "wasm"]
|
||||
sqlx = ["dep:sqlx"]
|
||||
wasm = ["uuid/js"]
|
20
src/domain/click.rs
Normal file
20
src/domain/click.rs
Normal file
@ -0,0 +1,20 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::clickable::Clickable;
|
||||
|
||||
/// This is a click on a realtors page. Can be many things.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Click {
|
||||
pub id: Uuid,
|
||||
#[serde(rename = "realtorId")]
|
||||
pub realtor_id: Uuid,
|
||||
pub clickable: Clickable,
|
||||
#[serde(rename = "trackableId")]
|
||||
pub trackable_id: Uuid,
|
||||
#[serde(rename = "timeCreated")]
|
||||
pub time_created: DateTime<Utc>,
|
||||
#[serde(rename = "lastUpdated")]
|
||||
pub last_updated: DateTime<Utc>
|
||||
}
|
35
src/domain/clickable/impls.rs
Normal file
35
src/domain/clickable/impls.rs
Normal file
@ -0,0 +1,35 @@
|
||||
use sqlx::{
|
||||
encode::IsNull,
|
||||
error::BoxDynError,
|
||||
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef},
|
||||
Postgres,
|
||||
};
|
||||
|
||||
use super::Clickable;
|
||||
|
||||
impl sqlx::Encode<'_, Postgres> for Clickable {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let binding = serde_json::to_string(self).unwrap();
|
||||
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Decode<'_, Postgres> for Clickable {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
let column = value.as_str()?;
|
||||
match serde_json::from_str(column) {
|
||||
Ok(listing_state) => Ok(listing_state),
|
||||
Err(error) => Err(Box::new(error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<Postgres> for Clickable {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::with_name("TEXT")
|
||||
}
|
||||
|
||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
*ty == Self::type_info()
|
||||
}
|
||||
}
|
16
src/domain/clickable/mod.rs
Normal file
16
src/domain/clickable/mod.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#[cfg(feature = "sqlx")]
|
||||
pub mod impls;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Clickable {
|
||||
/// When clicking on a contact button. Could be anything really, but most importantly could be either a phone number or an email.
|
||||
Contact(String),
|
||||
}
|
||||
|
||||
impl Default for Clickable {
|
||||
fn default() -> Self {
|
||||
Self::Contact(String::default())
|
||||
}
|
||||
}
|
13
src/domain/error.rs
Normal file
13
src/domain/error.rs
Normal file
@ -0,0 +1,13 @@
|
||||
use std::fmt::Display;
|
||||
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct FromStrError;
|
||||
|
||||
impl Display for FromStrError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "Error converting string to Type specified.")
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for FromStrError {}
|
62
src/domain/media/impls.rs
Normal file
62
src/domain/media/impls.rs
Normal file
@ -0,0 +1,62 @@
|
||||
use sqlx::{
|
||||
encode::IsNull,
|
||||
error::BoxDynError,
|
||||
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef},
|
||||
Postgres,
|
||||
};
|
||||
|
||||
use super::{Media, MediaList};
|
||||
|
||||
impl sqlx::Encode<'_, Postgres> for Media {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let binding = serde_json::to_string(self).unwrap();
|
||||
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Decode<'_, Postgres> for Media {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
let column = value.as_str()?;
|
||||
match serde_json::from_str(column) {
|
||||
Ok(listing_state) => Ok(listing_state),
|
||||
Err(error) => Err(Box::new(error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<Postgres> for Media {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::with_name("TEXT")
|
||||
}
|
||||
|
||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
*ty == Self::type_info()
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Encode<'_, Postgres> for MediaList {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let binding = serde_json::to_string(self).unwrap();
|
||||
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Decode<'_, Postgres> for MediaList {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
let column = value.as_str()?;
|
||||
match serde_json::from_str(column) {
|
||||
Ok(listing_state) => Ok(listing_state),
|
||||
Err(error) => Err(Box::new(error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl sqlx::Type<Postgres> for MediaList {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::with_name("TEXT")
|
||||
}
|
||||
|
||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
*ty == Self::type_info()
|
||||
}
|
||||
}
|
16
src/domain/media/mod.rs
Normal file
16
src/domain/media/mod.rs
Normal file
@ -0,0 +1,16 @@
|
||||
#[cfg(feature = "sqlx")]
|
||||
pub mod impls;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum Media {
|
||||
Photo(String),
|
||||
Video(String),
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct MediaList {
|
||||
#[serde(rename = "mediaList")]
|
||||
pub media_list: Vec<Media>,
|
||||
}
|
12
src/domain/mod.rs
Normal file
12
src/domain/mod.rs
Normal file
@ -0,0 +1,12 @@
|
||||
pub mod property;
|
||||
pub mod realtor;
|
||||
pub mod view;
|
||||
pub mod project;
|
||||
pub mod media;
|
||||
pub mod thing_pk;
|
||||
pub mod click;
|
||||
pub mod clickable;
|
||||
pub mod trackable;
|
||||
|
||||
|
||||
pub mod error;
|
25
src/domain/project.rs
Normal file
25
src/domain/project.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::media::MediaList;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Project {
|
||||
pub id: Uuid,
|
||||
pub title: Option<String>,
|
||||
pub description: String,
|
||||
|
||||
#[serde(rename = "realtorId")]
|
||||
pub realtor_id: Uuid,
|
||||
pub media: MediaList,
|
||||
|
||||
/// This gives the realtor the option to order the projects/properties. On birth,
|
||||
#[serde(rename = "orderIndex")]
|
||||
pub order_index: u16,
|
||||
|
||||
#[serde(rename = "timeCreated")]
|
||||
pub time_created: DateTime<Utc>,
|
||||
#[serde(rename = "lastUpdated")]
|
||||
pub last_updated: DateTime<Utc>
|
||||
}
|
22
src/domain/property.rs
Normal file
22
src/domain/property.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::media::MediaList;
|
||||
|
||||
/// A property can belong to a project, or not. It should always belong to a realtor.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Property {
|
||||
pub id: Uuid,
|
||||
|
||||
#[serde(rename = "projectId")]
|
||||
pub project_id: Option<Uuid>,
|
||||
#[serde(rename = "realtorId")]
|
||||
pub realtor_id: Uuid,
|
||||
pub media: MediaList,
|
||||
|
||||
#[serde(rename = "timeCreated")]
|
||||
pub time_created: DateTime<Utc>,
|
||||
#[serde(rename = "lastUpdated")]
|
||||
pub last_updated: DateTime<Utc>
|
||||
}
|
21
src/domain/realtor.rs
Normal file
21
src/domain/realtor.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Realtor {
|
||||
pub id: Uuid,
|
||||
pub name: String,
|
||||
pub bio: String,
|
||||
#[serde(rename = "phoneNumber")]
|
||||
pub phone_number: String,
|
||||
pub email: Option<String>,
|
||||
#[serde(rename = "profilePictureUrl")]
|
||||
pub profile_picture_url: String,
|
||||
#[serde(rename = "remaxAgentId")]
|
||||
pub remax_agent_id: Option<i32>,
|
||||
#[serde(rename = "timeCreated")]
|
||||
pub time_created: DateTime<Utc>,
|
||||
#[serde(rename = "lastUpdated")]
|
||||
pub last_updated: DateTime<Utc>,
|
||||
}
|
64
src/domain/thing_pk/impls.rs
Normal file
64
src/domain/thing_pk/impls.rs
Normal file
@ -0,0 +1,64 @@
|
||||
use std::{str::FromStr, fmt::Display};
|
||||
|
||||
use sqlx::{
|
||||
encode::IsNull,
|
||||
error::BoxDynError,
|
||||
postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef},
|
||||
Postgres,
|
||||
};
|
||||
|
||||
use crate::domain::error::FromStrError;
|
||||
|
||||
use super::ThingPk;
|
||||
|
||||
|
||||
impl Display for ThingPk {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ThingPk::Realtor => write!(f, "Realtor"),
|
||||
ThingPk::Property => write!(f, "Property"),
|
||||
ThingPk::Project => write!(f, "Project"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for ThingPk {
|
||||
type Err = FromStrError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
match s {
|
||||
"Project" => Ok(Self::Project),
|
||||
"Realtor" => Ok(Self::Realtor),
|
||||
"Property" => Ok(Self::Property),
|
||||
_ => Err(FromStrError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlx")]
|
||||
impl sqlx::Encode<'_, Postgres> for ThingPk {
|
||||
fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> IsNull {
|
||||
let binding = self.to_string();
|
||||
<&str as sqlx::Encode<Postgres>>::encode(&binding, buf)
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "sqlx")]
|
||||
impl sqlx::Decode<'_, Postgres> for ThingPk {
|
||||
fn decode(value: PgValueRef<'_>) -> Result<Self, BoxDynError> {
|
||||
let column = value.as_str()?;
|
||||
match Self::from_str(column) {
|
||||
Ok(listing_state) => Ok(listing_state),
|
||||
Err(error) => Err(Box::new(error)),
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "sqlx")]
|
||||
impl sqlx::Type<Postgres> for ThingPk {
|
||||
fn type_info() -> PgTypeInfo {
|
||||
PgTypeInfo::with_name("TEXT")
|
||||
}
|
||||
|
||||
fn compatible(ty: &<Postgres as sqlx::Database>::TypeInfo) -> bool {
|
||||
*ty == Self::type_info()
|
||||
}
|
||||
}
|
11
src/domain/thing_pk/mod.rs
Normal file
11
src/domain/thing_pk/mod.rs
Normal file
@ -0,0 +1,11 @@
|
||||
pub mod impls;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub enum ThingPk {
|
||||
#[default]
|
||||
Realtor,
|
||||
Property,
|
||||
Project,
|
||||
}
|
24
src/domain/trackable.rs
Normal file
24
src/domain/trackable.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// A user that can be tracked. All the info that you can gather from the user based on their browser & IP network.
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Trackable {
|
||||
pub id: Uuid,
|
||||
/// This field is used to indetify if a user has been to the website before. Pretty much checks to see if the user already has a Trackable UUID in record.
|
||||
/// But has changed things like IpAddress or user agent.
|
||||
#[serde(rename = "whoWas")]
|
||||
pub who_was: Option<Uuid>,
|
||||
#[serde(rename = "ipAddress")]
|
||||
pub ip_address: String,
|
||||
/// Used to determine on what device the user is
|
||||
#[serde(rename = "browserWidth")]
|
||||
pub browser_width: u32,
|
||||
/// Used to determine on what device the user is
|
||||
#[serde(rename = "browserWidth")]
|
||||
pub browser_height: u32,
|
||||
#[serde(rename = "userAgent")]
|
||||
pub user_agent: String,
|
||||
pub time_created: DateTime<Utc>,
|
||||
}
|
18
src/domain/view.rs
Normal file
18
src/domain/view.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Serialize, Deserialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::thing_pk::ThingPk;
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct View {
|
||||
pub id: Uuid,
|
||||
#[serde(rename = "thingId")]
|
||||
pub thing_id: Uuid,
|
||||
#[serde(rename = "thingPk")]
|
||||
pub thing_pk: ThingPk,
|
||||
#[serde(rename = "trackableId")]
|
||||
pub trackable_id: Uuid,
|
||||
#[serde(rename = "timeCreated")]
|
||||
pub time_created: DateTime<Utc>
|
||||
}
|
1
src/dto/mod.rs
Normal file
1
src/dto/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod payloads;
|
0
src/dto/payloads/mod.rs
Normal file
0
src/dto/payloads/mod.rs
Normal file
2
src/lib.rs
Normal file
2
src/lib.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod domain;
|
||||
pub mod dto;
|
Loading…
Reference in New Issue
Block a user