Skip to content
This repository has been archived by the owner on Oct 19, 2024. It is now read-only.

Commit

Permalink
alternate context setup version
Browse files Browse the repository at this point in the history
  • Loading branch information
thesuzerain committed Aug 23, 2023
1 parent 43c775d commit 90ef156
Show file tree
Hide file tree
Showing 10 changed files with 199 additions and 287 deletions.
19 changes: 4 additions & 15 deletions migrations/20230816085700_collections_and_more.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,9 @@ CREATE TABLE uploaded_images (
url varchar(2048) NOT NULL,
size integer NOT NULL,
created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
owner_id bigint REFERENCES users NOT NULL
);

-- Currently, images will be associated with mod descriptions and thread messages
-- In the future, we may want to allow images to be associated with other things like reports, comments, etc.
owner_id bigint REFERENCES users NOT NULL,

CREATE TABLE images_mods (
mod_id bigint REFERENCES mods NOT NULL,
image_id bigint REFERENCES uploaded_images NOT NULL,
PRIMARY KEY (mod_id, image_id)
-- Associated with another table
context varchar(64) NOT NULL,
context_id bigint NULL
);

CREATE TABLE images_threads (
thread_message_id bigint REFERENCES threads_messages NOT NULL,
image_id bigint REFERENCES uploaded_images NOT NULL,
PRIMARY KEY (thread_message_id, image_id)
);
141 changes: 17 additions & 124 deletions src/database/models/image_item.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::ids::*;
use crate::database::models::DatabaseError;
use crate::models::ids::base62_impl::{parse_base62, to_base62};
use crate::models::images::ImageContext;
use chrono::{DateTime, Utc};
use redis::cmd;
use serde::{Deserialize, Serialize};
Expand All @@ -16,6 +17,7 @@ pub struct Image {
pub size: u64,
pub created: DateTime<Utc>,
pub owner_id: UserId,
pub context: ImageContext, // uses model Ids, not database Ids
}

impl Image {
Expand All @@ -26,17 +28,19 @@ impl Image {
sqlx::query!(
"
INSERT INTO uploaded_images (
id, url, size, created, owner_id
id, url, size, created, owner_id, context, context_id
)
VALUES (
$1, $2, $3, $4, $5
$1, $2, $3, $4, $5, $6, $7
);
",
self.id as ImageId,
self.url,
self.size as i64,
self.created,
self.owner_id as UserId,
self.context.context_as_str(),
self.context.inner_id().map(|x| x as i64),
)
.execute(&mut *transaction)
.await?;
Expand All @@ -62,82 +66,6 @@ impl Image {
.execute(&mut *transaction)
.await?;

sqlx::query!(
"
DELETE FROM images_mods
WHERE image_id = $1
",
id as ImageId,
)
.execute(&mut *transaction)
.await?;

sqlx::query!(
"
DELETE FROM images_threads
WHERE image_id = $1
",
id as ImageId,
)
.execute(&mut *transaction)
.await?;

Image::clear_cache(image.id, image.url, redis).await?;

Ok(Some(()))
} else {
Ok(None)
}
}

pub async fn remove_from_project(
id: ImageId,
project_id: ProjectId,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
redis: &deadpool_redis::Pool,
) -> Result<Option<()>, DatabaseError> {
let image = Self::get_id(id, &mut *transaction, redis).await?;

if let Some(image) = image {
sqlx::query!(
"
DELETE FROM images_mods
WHERE image_id = $1 AND mod_id = $2
",
id as ImageId,
project_id as ProjectId,
)
.execute(&mut *transaction)
.await?;

Image::clear_cache(image.id, image.url, redis).await?;

Ok(Some(()))
} else {
Ok(None)
}
}

pub async fn remove_from_thread_message(
id: ImageId,
thread_message_id: ThreadMessageId,
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
redis: &deadpool_redis::Pool,
) -> Result<Option<()>, DatabaseError> {
let image = Self::get_id(id, &mut *transaction, redis).await?;

if let Some(image) = image {
sqlx::query!(
"
DELETE FROM images_threads
WHERE image_id = $1 AND thread_message_id = $2
",
id as ImageId,
thread_message_id as ThreadMessageId,
)
.execute(&mut *transaction)
.await?;

Image::clear_cache(image.id, image.url, redis).await?;

Ok(Some(()))
Expand All @@ -146,46 +74,8 @@ impl Image {
}
}

pub async fn get_many_project<'a, E>(
project_id: ProjectId,
exec: E,
) -> Result<Vec<Image>, sqlx::Error>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
use futures::stream::TryStreamExt;

sqlx::query!(
"
SELECT i.id, i.url, i.size, i.created, i.owner_id,
im.mod_id
FROM uploaded_images i
LEFT JOIN images_mods im ON im.image_id = i.id
WHERE im.mod_id = $1
GROUP BY i.id, im.mod_id;
",
project_id as ProjectId
)
.fetch_many(exec)
.try_filter_map(|e| async {
Ok(e.right().map(|row| {
let id = ImageId(row.id);

Image {
id,
url: row.url,
size: row.size as u64,
created: row.created,
owner_id: UserId(row.owner_id),
}
}))
})
.try_collect::<Vec<Image>>()
.await
}

pub async fn get_many_thread_message<'a, E>(
thread_message_id: ThreadMessageId,
pub async fn get_many_contexted<'a, E>(
context: ImageContext,
exec: E,
) -> Result<Vec<Image>, sqlx::Error>
where
Expand All @@ -195,13 +85,14 @@ impl Image {

sqlx::query!(
"
SELECT i.id, i.url, i.size, i.created, i.owner_id,
it.thread_message_id
SELECT i.id, i.url, i.size, i.created, i.owner_id, i.context, i.context_id
FROM uploaded_images i
LEFT JOIN images_threads it ON it.image_id = i.id
WHERE it.thread_message_id = $1
WHERE i.context = $1
AND i.context_id = $2
GROUP BY i.id
",
thread_message_id as ThreadMessageId
context.context_as_str(),
context.inner_id().map(|x| x as i64)
)
.fetch_many(exec)
.try_filter_map(|e| async {
Expand All @@ -214,6 +105,7 @@ impl Image {
size: row.size as u64,
created: row.created,
owner_id: UserId(row.owner_id),
context: ImageContext::from_str(&row.context, row.context_id.map(|x| x as u64)),
}
}))
})
Expand Down Expand Up @@ -320,7 +212,7 @@ impl Image {
.collect();
let db_images: Vec<Image> = sqlx::query!(
"
SELECT i.id, i.url, i.size, i.created, i.owner_id
SELECT i.id, i.url, i.size, i.created, i.owner_id, i.context, i.context_id
FROM uploaded_images i
WHERE i.id = ANY($1) OR i.url = ANY($2)
GROUP BY i.id;
Expand All @@ -342,6 +234,7 @@ impl Image {
size: i.size as u64,
created: i.created,
owner_id: UserId(i.owner_id),
context: ImageContext::from_str(&i.context, i.context_id.map(|x| x as u64)),
}
}))
})
Expand Down
4 changes: 2 additions & 2 deletions src/database/models/thread_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ impl ThreadMessage {
exec: E,
) -> Result<Option<ThreadMessage>, sqlx::Error>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
Self::get_many(&[id], exec)
.await
Expand All @@ -224,7 +224,7 @@ impl ThreadMessage {
exec: E,
) -> Result<Vec<ThreadMessage>, sqlx::Error>
where
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
{
use futures::stream::TryStreamExt;

Expand Down
57 changes: 44 additions & 13 deletions src/models/images.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::ids::Base62Id;
use super::{
ids::{Base62Id, ProjectId, ThreadMessageId},
pats::Scopes,
};
use crate::database::models::image_item::Image as DBImage;
use crate::models::ids::UserId;
use chrono::{DateTime, Utc};
Expand All @@ -16,6 +19,8 @@ pub struct Image {
pub size: u64,
pub created: DateTime<Utc>,
pub owner_id: UserId,

pub context: ImageContext,
}

impl From<DBImage> for Image {
Expand All @@ -26,29 +31,55 @@ impl From<DBImage> for Image {
size: x.size,
created: x.created,
owner_id: x.owner_id.into(),
context: x.context,
}
}
}

#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(tag = "type")]
pub enum ImageContext {
Project,
ThreadMessage,
Project {
project_id: Option<ProjectId>,
},
ThreadMessage {
thread_message_id: Option<ThreadMessageId>,
},
Unknown,
}

impl std::fmt::Display for ImageContext {
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(fmt, "{}", self.as_str())
}
}

impl ImageContext {
pub fn as_str(&self) -> &'static str {
pub fn context_as_str(&self) -> &'static str {
match self {
ImageContext::Project => "project",
ImageContext::ThreadMessage => "thread_message",
ImageContext::Project { .. } => "project",
ImageContext::ThreadMessage { .. } => "thread_message",
ImageContext::Unknown => "unknown",
}
}

pub fn inner_id(&self) -> Option<u64> {
match self {
ImageContext::Project { project_id } => project_id.map(|x| x.0),
ImageContext::ThreadMessage { thread_message_id } => thread_message_id.map(|x| x.0),
ImageContext::Unknown => None,
}
}
pub fn relevant_scope(&self) -> Scopes {
match self {
ImageContext::Project { .. } => Scopes::PROJECT_WRITE,
ImageContext::ThreadMessage { .. } => Scopes::THREAD_WRITE,
ImageContext::Unknown => Scopes::NONE,
}
}
pub fn from_str(context: &str, id: Option<u64>) -> Self {
match context {
"project" => ImageContext::Project {
project_id: id.map(ProjectId),
},
"thread_message" => ImageContext::ThreadMessage {
thread_message_id: id.map(ThreadMessageId),
},
_ => ImageContext::Unknown,
}
}
}
4 changes: 2 additions & 2 deletions src/models/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ use serde::{Deserialize, Serialize};
use validator::Validate;

/// The ID of a specific project, encoded as base62 for usage in the API
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(from = "Base62Id")]
#[serde(into = "Base62Id")]
pub struct ProjectId(pub u64);

/// The ID of a specific version of a project
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Debug)]
#[serde(from = "Base62Id")]
#[serde(into = "Base62Id")]
pub struct VersionId(pub u64);
Expand Down
2 changes: 1 addition & 1 deletion src/models/threads.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
#[serde(into = "Base62Id")]
pub struct ThreadId(pub u64);

#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[derive(Copy, Clone, PartialEq, Eq, Serialize, Deserialize, Debug)]
#[serde(from = "Base62Id")]
#[serde(into = "Base62Id")]
pub struct ThreadMessageId(pub u64);
Expand Down
Loading

0 comments on commit 90ef156

Please sign in to comment.