You've already forked AstralRinth
forked from didirus/AstralRinth
Fix clippy errors + lint, use turbo CI
This commit is contained in:
@@ -86,7 +86,10 @@ impl Category {
|
||||
Ok(result.map(|r| CategoryId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<Category>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<Category>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -128,7 +131,10 @@ impl Category {
|
||||
}
|
||||
|
||||
impl LinkPlatform {
|
||||
pub async fn get_id<'a, E>(id: &str, exec: E) -> Result<Option<LinkPlatformId>, DatabaseError>
|
||||
pub async fn get_id<'a, E>(
|
||||
id: &str,
|
||||
exec: E,
|
||||
) -> Result<Option<LinkPlatformId>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -145,7 +151,10 @@ impl LinkPlatform {
|
||||
Ok(result.map(|r| LinkPlatformId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<LinkPlatform>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<LinkPlatform>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -174,7 +183,12 @@ impl LinkPlatform {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(TAGS_NAMESPACE, "link_platform", &result, None)
|
||||
.set_serialized_to_json(
|
||||
TAGS_NAMESPACE,
|
||||
"link_platform",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -182,7 +196,10 @@ impl LinkPlatform {
|
||||
}
|
||||
|
||||
impl ReportType {
|
||||
pub async fn get_id<'a, E>(name: &str, exec: E) -> Result<Option<ReportTypeId>, DatabaseError>
|
||||
pub async fn get_id<'a, E>(
|
||||
name: &str,
|
||||
exec: E,
|
||||
) -> Result<Option<ReportTypeId>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -199,7 +216,10 @@ impl ReportType {
|
||||
Ok(result.map(|r| ReportTypeId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<String>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<String>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -224,7 +244,12 @@ impl ReportType {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(TAGS_NAMESPACE, "report_type", &result, None)
|
||||
.set_serialized_to_json(
|
||||
TAGS_NAMESPACE,
|
||||
"report_type",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -232,7 +257,10 @@ impl ReportType {
|
||||
}
|
||||
|
||||
impl ProjectType {
|
||||
pub async fn get_id<'a, E>(name: &str, exec: E) -> Result<Option<ProjectTypeId>, DatabaseError>
|
||||
pub async fn get_id<'a, E>(
|
||||
name: &str,
|
||||
exec: E,
|
||||
) -> Result<Option<ProjectTypeId>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -249,7 +277,10 @@ impl ProjectType {
|
||||
Ok(result.map(|r| ProjectTypeId(r.id)))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<String>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<String>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -274,7 +305,12 @@ impl ProjectType {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(TAGS_NAMESPACE, "project_type", &result, None)
|
||||
.set_serialized_to_json(
|
||||
TAGS_NAMESPACE,
|
||||
"project_type",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
|
||||
@@ -122,9 +122,12 @@ impl ChargeItem {
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<Vec<ChargeItem>, DatabaseError> {
|
||||
let user_id = user_id.0;
|
||||
let res = select_charges_with_predicate!("WHERE user_id = $1 ORDER BY due DESC", user_id)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let res = select_charges_with_predicate!(
|
||||
"WHERE user_id = $1 ORDER BY due DESC",
|
||||
user_id
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(res
|
||||
.into_iter()
|
||||
|
||||
@@ -212,7 +212,10 @@ impl Collection {
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
pub async fn clear_cache(id: CollectionId, redis: &RedisPool) -> Result<(), DatabaseError> {
|
||||
pub async fn clear_cache(
|
||||
id: CollectionId,
|
||||
redis: &RedisPool,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
redis.delete(COLLECTIONS_NAMESPACE, id.0).await?;
|
||||
|
||||
@@ -68,12 +68,20 @@ impl Flow {
|
||||
.collect::<String>();
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(FLOWS_NAMESPACE, &flow, &self, Some(expires.num_seconds()))
|
||||
.set_serialized_to_json(
|
||||
FLOWS_NAMESPACE,
|
||||
&flow,
|
||||
&self,
|
||||
Some(expires.num_seconds()),
|
||||
)
|
||||
.await?;
|
||||
Ok(flow)
|
||||
}
|
||||
|
||||
pub async fn get(id: &str, redis: &RedisPool) -> Result<Option<Flow>, DatabaseError> {
|
||||
pub async fn get(
|
||||
id: &str,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Option<Flow>, DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
redis.get_deserialized_from_json(FLOWS_NAMESPACE, id).await
|
||||
@@ -95,7 +103,10 @@ impl Flow {
|
||||
Ok(flow)
|
||||
}
|
||||
|
||||
pub async fn remove(id: &str, redis: &RedisPool) -> Result<Option<()>, DatabaseError> {
|
||||
pub async fn remove(
|
||||
id: &str,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Option<()>, DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
redis.delete(FLOWS_NAMESPACE, id).await?;
|
||||
|
||||
@@ -264,25 +264,35 @@ generate_ids!(
|
||||
ChargeId
|
||||
);
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Type, Hash, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, PartialEq, Eq, Type, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct UserId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Eq, Hash, PartialEq, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct TeamId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct TeamMemberId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct OrganizationId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ProjectId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ProjectTypeId(pub i32);
|
||||
|
||||
@@ -292,16 +302,30 @@ pub struct StatusId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct GameId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LinkPlatformId(pub i32);
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, PartialEq, Eq, Hash, Serialize, Deserialize, PartialOrd, Ord,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Type,
|
||||
PartialEq,
|
||||
Eq,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct VersionId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, PartialEq, Eq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LoaderId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize)]
|
||||
@@ -319,11 +343,15 @@ pub struct ReportId(pub i64);
|
||||
#[sqlx(transparent)]
|
||||
pub struct ReportTypeId(pub i32);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Hash, Eq, PartialEq, Deserialize, Serialize)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Hash, Eq, PartialEq, Deserialize, Serialize,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct FileId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Deserialize, Serialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Deserialize, Serialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct PatId(pub i64);
|
||||
|
||||
@@ -337,64 +365,102 @@ pub struct NotificationActionId(pub i32);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ThreadId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ThreadMessageId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct SessionId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ImageId(pub i64);
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash, PartialOrd, Ord,
|
||||
Copy,
|
||||
Clone,
|
||||
Debug,
|
||||
Type,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Eq,
|
||||
PartialEq,
|
||||
Hash,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LoaderFieldId(pub i32);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LoaderFieldEnumId(pub i32);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct LoaderFieldEnumValueId(pub i32);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct OAuthClientId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct OAuthClientAuthorizationId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct OAuthRedirectUriId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct OAuthAccessTokenId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct PayoutId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ProductId(pub i64);
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ProductPriceId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct UserSubscriptionId(pub i64);
|
||||
|
||||
#[derive(Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Type, Serialize, Deserialize, Eq, PartialEq, Hash,
|
||||
)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct ChargeId(pub i64);
|
||||
|
||||
|
||||
@@ -223,7 +223,10 @@ impl Image {
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
pub async fn clear_cache(id: ImageId, redis: &RedisPool) -> Result<(), DatabaseError> {
|
||||
pub async fn clear_cache(
|
||||
id: ImageId,
|
||||
redis: &RedisPool,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
redis.delete(IMAGES_NAMESPACE, id.0).await?;
|
||||
|
||||
@@ -12,7 +12,9 @@ use serde_json::json;
|
||||
use crate::database::redis::RedisPool;
|
||||
|
||||
use super::{
|
||||
loader_fields::{LoaderFieldEnum, LoaderFieldEnumValue, VersionField, VersionFieldValue},
|
||||
loader_fields::{
|
||||
LoaderFieldEnum, LoaderFieldEnumValue, VersionField, VersionFieldValue,
|
||||
},
|
||||
DatabaseError, LoaderFieldEnumValueId,
|
||||
};
|
||||
|
||||
@@ -44,13 +46,17 @@ impl MinecraftGameVersion {
|
||||
E: sqlx::Acquire<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut exec = exec.acquire().await?;
|
||||
let game_version_enum = LoaderFieldEnum::get(Self::FIELD_NAME, &mut *exec, redis)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
DatabaseError::SchemaError("Could not find game version enum.".to_string())
|
||||
})?;
|
||||
let game_version_enum =
|
||||
LoaderFieldEnum::get(Self::FIELD_NAME, &mut *exec, redis)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
DatabaseError::SchemaError(
|
||||
"Could not find game version enum.".to_string(),
|
||||
)
|
||||
})?;
|
||||
let game_version_enum_values =
|
||||
LoaderFieldEnumValue::list(game_version_enum.id, &mut *exec, redis).await?;
|
||||
LoaderFieldEnumValue::list(game_version_enum.id, &mut *exec, redis)
|
||||
.await?;
|
||||
|
||||
let game_versions = game_version_enum_values
|
||||
.into_iter()
|
||||
@@ -105,7 +111,9 @@ impl MinecraftGameVersion {
|
||||
Ok(game_versions)
|
||||
}
|
||||
|
||||
pub fn from_enum_value(loader_field_enum_value: LoaderFieldEnumValue) -> MinecraftGameVersion {
|
||||
pub fn from_enum_value(
|
||||
loader_field_enum_value: LoaderFieldEnumValue,
|
||||
) -> MinecraftGameVersion {
|
||||
MinecraftGameVersion {
|
||||
id: loader_field_enum_value.id,
|
||||
version: loader_field_enum_value.value,
|
||||
@@ -157,7 +165,10 @@ impl<'a> MinecraftGameVersionBuilder<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn created(self, created: &'a DateTime<Utc>) -> MinecraftGameVersionBuilder<'a> {
|
||||
pub fn created(
|
||||
self,
|
||||
created: &'a DateTime<Utc>,
|
||||
) -> MinecraftGameVersionBuilder<'a> {
|
||||
Self {
|
||||
date: Some(created),
|
||||
..self
|
||||
@@ -172,11 +183,12 @@ impl<'a> MinecraftGameVersionBuilder<'a> {
|
||||
where
|
||||
E: sqlx::Executor<'b, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let game_versions_enum = LoaderFieldEnum::get("game_versions", exec, redis)
|
||||
.await?
|
||||
.ok_or(DatabaseError::SchemaError(
|
||||
"Missing loaders field: 'game_versions'".to_string(),
|
||||
))?;
|
||||
let game_versions_enum =
|
||||
LoaderFieldEnum::get("game_versions", exec, redis)
|
||||
.await?
|
||||
.ok_or(DatabaseError::SchemaError(
|
||||
"Missing loaders field: 'game_versions'".to_string(),
|
||||
))?;
|
||||
|
||||
// Get enum id for game versions
|
||||
let metadata = json!({
|
||||
|
||||
@@ -43,7 +43,10 @@ impl Game {
|
||||
.find(|x| x.slug == slug))
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<Game>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<Game>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -72,7 +75,12 @@ impl Game {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(GAMES_LIST_NAMESPACE, "games", &result, None)
|
||||
.set_serialized_to_json(
|
||||
GAMES_LIST_NAMESPACE,
|
||||
"games",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -99,7 +107,8 @@ impl Loader {
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let mut redis = redis.connect().await?;
|
||||
let cached_id: Option<i32> = redis.get_deserialized_from_json(LOADER_ID, name).await?;
|
||||
let cached_id: Option<i32> =
|
||||
redis.get_deserialized_from_json(LOADER_ID, name).await?;
|
||||
if let Some(cached_id) = cached_id {
|
||||
return Ok(Some(LoaderId(cached_id)));
|
||||
}
|
||||
@@ -124,7 +133,10 @@ impl Loader {
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<Loader>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<Loader>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -169,7 +181,12 @@ impl Loader {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(LOADERS_LIST_NAMESPACE, "all", &result, None)
|
||||
.set_serialized_to_json(
|
||||
LOADERS_LIST_NAMESPACE,
|
||||
"all",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -198,7 +215,10 @@ pub enum LoaderFieldType {
|
||||
ArrayBoolean,
|
||||
}
|
||||
impl LoaderFieldType {
|
||||
pub fn build(field_type_name: &str, loader_field_enum: Option<i32>) -> Option<LoaderFieldType> {
|
||||
pub fn build(
|
||||
field_type_name: &str,
|
||||
loader_field_enum: Option<i32>,
|
||||
) -> Option<LoaderFieldType> {
|
||||
Some(match (field_type_name, loader_field_enum) {
|
||||
("integer", _) => LoaderFieldType::Integer,
|
||||
("text", _) => LoaderFieldType::Text,
|
||||
@@ -207,7 +227,9 @@ impl LoaderFieldType {
|
||||
("array_text", _) => LoaderFieldType::ArrayText,
|
||||
("array_boolean", _) => LoaderFieldType::ArrayBoolean,
|
||||
("enum", Some(id)) => LoaderFieldType::Enum(LoaderFieldEnumId(id)),
|
||||
("array_enum", Some(id)) => LoaderFieldType::ArrayEnum(LoaderFieldEnumId(id)),
|
||||
("array_enum", Some(id)) => {
|
||||
LoaderFieldType::ArrayEnum(LoaderFieldEnumId(id))
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
@@ -303,7 +325,10 @@ impl QueryVersionField {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_enum_value(mut self, enum_value: LoaderFieldEnumValueId) -> Self {
|
||||
pub fn with_enum_value(
|
||||
mut self,
|
||||
enum_value: LoaderFieldEnumValueId,
|
||||
) -> Self {
|
||||
self.enum_value = Some(enum_value);
|
||||
self
|
||||
}
|
||||
@@ -359,7 +384,8 @@ impl LoaderField {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let found_loader_fields = Self::get_fields_per_loader(loader_ids, exec, redis).await?;
|
||||
let found_loader_fields =
|
||||
Self::get_fields_per_loader(loader_ids, exec, redis).await?;
|
||||
let result = found_loader_fields
|
||||
.into_values()
|
||||
.flatten()
|
||||
@@ -464,7 +490,12 @@ impl LoaderField {
|
||||
.collect();
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(LOADER_FIELDS_NAMESPACE_ALL, "", &result, None)
|
||||
.set_serialized_to_json(
|
||||
LOADER_FIELDS_NAMESPACE_ALL,
|
||||
"",
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -482,7 +513,10 @@ impl LoaderFieldEnum {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
let cached_enum = redis
|
||||
.get_deserialized_from_json(LOADER_FIELD_ENUMS_ID_NAMESPACE, enum_name)
|
||||
.get_deserialized_from_json(
|
||||
LOADER_FIELD_ENUMS_ID_NAMESPACE,
|
||||
enum_name,
|
||||
)
|
||||
.await?;
|
||||
if let Some(cached_enum) = cached_enum {
|
||||
return Ok(cached_enum);
|
||||
@@ -507,7 +541,12 @@ impl LoaderFieldEnum {
|
||||
});
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(LOADER_FIELD_ENUMS_ID_NAMESPACE, enum_name, &result, None)
|
||||
.set_serialized_to_json(
|
||||
LOADER_FIELD_ENUMS_ID_NAMESPACE,
|
||||
enum_name,
|
||||
&result,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(result)
|
||||
@@ -540,7 +579,9 @@ impl LoaderFieldEnumValue {
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
let get_enum_id = |x: &LoaderField| match x.field_type {
|
||||
LoaderFieldType::Enum(id) | LoaderFieldType::ArrayEnum(id) => Some(id),
|
||||
LoaderFieldType::Enum(id) | LoaderFieldType::ArrayEnum(id) => {
|
||||
Some(id)
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
|
||||
@@ -556,7 +597,10 @@ impl LoaderFieldEnumValue {
|
||||
let mut res = HashMap::new();
|
||||
for lf in loader_fields {
|
||||
if let Some(id) = get_enum_id(lf) {
|
||||
res.insert(lf.id, values.get(&id).unwrap_or(&Vec::new()).to_vec());
|
||||
res.insert(
|
||||
lf.id,
|
||||
values.get(&id).unwrap_or(&Vec::new()).to_vec(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
@@ -566,7 +610,10 @@ impl LoaderFieldEnumValue {
|
||||
loader_field_enum_ids: &[LoaderFieldEnumId],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<HashMap<LoaderFieldEnumId, Vec<LoaderFieldEnumValue>>, DatabaseError>
|
||||
) -> Result<
|
||||
HashMap<LoaderFieldEnumId, Vec<LoaderFieldEnumValue>>,
|
||||
DatabaseError,
|
||||
>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -665,34 +712,33 @@ impl VersionField {
|
||||
VersionFieldValue::Text(s) => {
|
||||
query_version_fields.push(base.clone().with_string_value(s))
|
||||
}
|
||||
VersionFieldValue::Boolean(b) => {
|
||||
query_version_fields.push(base.clone().with_int_value(if b { 1 } else { 0 }))
|
||||
}
|
||||
VersionFieldValue::Boolean(b) => query_version_fields
|
||||
.push(base.clone().with_int_value(if b { 1 } else { 0 })),
|
||||
VersionFieldValue::ArrayInteger(v) => {
|
||||
for i in v {
|
||||
query_version_fields.push(base.clone().with_int_value(i));
|
||||
query_version_fields
|
||||
.push(base.clone().with_int_value(i));
|
||||
}
|
||||
}
|
||||
VersionFieldValue::ArrayText(v) => {
|
||||
for s in v {
|
||||
query_version_fields.push(base.clone().with_string_value(s));
|
||||
query_version_fields
|
||||
.push(base.clone().with_string_value(s));
|
||||
}
|
||||
}
|
||||
VersionFieldValue::ArrayBoolean(v) => {
|
||||
for b in v {
|
||||
query_version_fields.push(base.clone().with_int_value(if b {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}));
|
||||
query_version_fields.push(
|
||||
base.clone().with_int_value(if b { 1 } else { 0 }),
|
||||
);
|
||||
}
|
||||
}
|
||||
VersionFieldValue::Enum(_, v) => {
|
||||
query_version_fields.push(base.clone().with_enum_value(v.id))
|
||||
}
|
||||
VersionFieldValue::Enum(_, v) => query_version_fields
|
||||
.push(base.clone().with_enum_value(v.id)),
|
||||
VersionFieldValue::ArrayEnum(_, v) => {
|
||||
for ev in v {
|
||||
query_version_fields.push(base.clone().with_enum_value(ev.id));
|
||||
query_version_fields
|
||||
.push(base.clone().with_enum_value(ev.id));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -740,7 +786,8 @@ impl VersionField {
|
||||
value: serde_json::Value,
|
||||
enum_variants: Vec<LoaderFieldEnumValue>,
|
||||
) -> Result<VersionField, String> {
|
||||
let value = VersionFieldValue::parse(&loader_field, value, enum_variants)?;
|
||||
let value =
|
||||
VersionFieldValue::parse(&loader_field, value, enum_variants)?;
|
||||
|
||||
// Ensure, if applicable, that the value is within the min/max bounds
|
||||
let countable = match &value {
|
||||
@@ -802,11 +849,13 @@ impl VersionField {
|
||||
query_loader_fields
|
||||
.iter()
|
||||
.flat_map(|q| {
|
||||
let loader_field_type =
|
||||
match LoaderFieldType::build(&q.field_type, q.enum_type.map(|l| l.0)) {
|
||||
Some(lft) => lft,
|
||||
None => return vec![],
|
||||
};
|
||||
let loader_field_type = match LoaderFieldType::build(
|
||||
&q.field_type,
|
||||
q.enum_type.map(|l| l.0),
|
||||
) {
|
||||
Some(lft) => lft,
|
||||
None => return vec![],
|
||||
};
|
||||
let loader_field = LoaderField {
|
||||
id: q.id,
|
||||
field: q.field.clone(),
|
||||
@@ -908,7 +957,8 @@ impl VersionFieldValue {
|
||||
|
||||
Ok(match field_type {
|
||||
LoaderFieldType::Integer => VersionFieldValue::Integer(
|
||||
serde_json::from_value(value).map_err(|_| incorrect_type_error("integer"))?,
|
||||
serde_json::from_value(value)
|
||||
.map_err(|_| incorrect_type_error("integer"))?,
|
||||
),
|
||||
LoaderFieldType::Text => VersionFieldValue::Text(
|
||||
value
|
||||
@@ -928,7 +978,9 @@ impl VersionFieldValue {
|
||||
}),
|
||||
LoaderFieldType::ArrayText => VersionFieldValue::ArrayText({
|
||||
let array_values: Vec<String> = serde_json::from_value(value)
|
||||
.map_err(|_| incorrect_type_error("array of strings"))?;
|
||||
.map_err(|_| {
|
||||
incorrect_type_error("array of strings")
|
||||
})?;
|
||||
array_values.into_iter().collect()
|
||||
}),
|
||||
LoaderFieldType::ArrayBoolean => VersionFieldValue::ArrayBoolean({
|
||||
@@ -937,8 +989,12 @@ impl VersionFieldValue {
|
||||
array_values.into_iter().map(|v| v != 0).collect()
|
||||
}),
|
||||
LoaderFieldType::Enum(id) => VersionFieldValue::Enum(*id, {
|
||||
let enum_value = value.as_str().ok_or_else(|| incorrect_type_error("enum"))?;
|
||||
if let Some(ev) = enum_array.into_iter().find(|v| v.value == enum_value) {
|
||||
let enum_value = value
|
||||
.as_str()
|
||||
.ok_or_else(|| incorrect_type_error("enum"))?;
|
||||
if let Some(ev) =
|
||||
enum_array.into_iter().find(|v| v.value == enum_value)
|
||||
{
|
||||
ev
|
||||
} else {
|
||||
return Err(format!(
|
||||
@@ -946,21 +1002,27 @@ impl VersionFieldValue {
|
||||
));
|
||||
}
|
||||
}),
|
||||
LoaderFieldType::ArrayEnum(id) => VersionFieldValue::ArrayEnum(*id, {
|
||||
let array_values: Vec<String> = serde_json::from_value(value)
|
||||
.map_err(|_| incorrect_type_error("array of enums"))?;
|
||||
let mut enum_values = vec![];
|
||||
for av in array_values {
|
||||
if let Some(ev) = enum_array.iter().find(|v| v.value == av) {
|
||||
enum_values.push(ev.clone());
|
||||
} else {
|
||||
return Err(format!(
|
||||
LoaderFieldType::ArrayEnum(id) => {
|
||||
VersionFieldValue::ArrayEnum(*id, {
|
||||
let array_values: Vec<String> =
|
||||
serde_json::from_value(value).map_err(|_| {
|
||||
incorrect_type_error("array of enums")
|
||||
})?;
|
||||
let mut enum_values = vec![];
|
||||
for av in array_values {
|
||||
if let Some(ev) =
|
||||
enum_array.iter().find(|v| v.value == av)
|
||||
{
|
||||
enum_values.push(ev.clone());
|
||||
} else {
|
||||
return Err(format!(
|
||||
"Provided value '{av}' is not a valid variant for {field_name}"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
enum_values
|
||||
}),
|
||||
enum_values
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1046,141 +1108,180 @@ impl VersionFieldValue {
|
||||
)));
|
||||
}
|
||||
|
||||
let mut value = match field_type {
|
||||
// Singleton fields
|
||||
// If there are multiple, we assume multiple versions are being concatenated
|
||||
LoaderFieldType::Integer => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Integer(
|
||||
qvf.int_value
|
||||
.ok_or(did_not_exist_error(field_name, "int_value"))?,
|
||||
),
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<(VersionId, VersionFieldValue)>, DatabaseError>>()?,
|
||||
LoaderFieldType::Text => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Text(
|
||||
qvf.string_value
|
||||
.ok_or(did_not_exist_error(field_name, "string_value"))?,
|
||||
),
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<(VersionId, VersionFieldValue)>, DatabaseError>>()?,
|
||||
LoaderFieldType::Boolean => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Boolean(
|
||||
qvf.int_value
|
||||
.ok_or(did_not_exist_error(field_name, "int_value"))?
|
||||
!= 0,
|
||||
),
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<(VersionId, VersionFieldValue)>, DatabaseError>>()?,
|
||||
LoaderFieldType::Enum(id) => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Enum(*id, {
|
||||
let enum_id = qvf
|
||||
.enum_value
|
||||
.ok_or(did_not_exist_error(field_name, "enum_value"))?;
|
||||
let lfev = qlfev
|
||||
.iter()
|
||||
.find(|x| x.id == enum_id)
|
||||
.ok_or(did_not_exist_error(field_name, "enum_value"))?;
|
||||
LoaderFieldEnumValue {
|
||||
id: lfev.id,
|
||||
enum_id: lfev.enum_id,
|
||||
value: lfev.value.clone(),
|
||||
ordering: lfev.ordering,
|
||||
created: lfev.created,
|
||||
metadata: lfev.metadata.clone().unwrap_or_default(),
|
||||
}
|
||||
}),
|
||||
))
|
||||
})
|
||||
.collect::<Result<Vec<(VersionId, VersionFieldValue)>, DatabaseError>>()?,
|
||||
let mut value =
|
||||
match field_type {
|
||||
// Singleton fields
|
||||
// If there are multiple, we assume multiple versions are being concatenated
|
||||
LoaderFieldType::Integer => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Integer(qvf.int_value.ok_or(
|
||||
did_not_exist_error(field_name, "int_value"),
|
||||
)?),
|
||||
))
|
||||
})
|
||||
.collect::<Result<
|
||||
Vec<(VersionId, VersionFieldValue)>,
|
||||
DatabaseError,
|
||||
>>()?,
|
||||
LoaderFieldType::Text => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Text(qvf.string_value.ok_or(
|
||||
did_not_exist_error(field_name, "string_value"),
|
||||
)?),
|
||||
))
|
||||
})
|
||||
.collect::<Result<
|
||||
Vec<(VersionId, VersionFieldValue)>,
|
||||
DatabaseError,
|
||||
>>()?,
|
||||
LoaderFieldType::Boolean => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Boolean(
|
||||
qvf.int_value.ok_or(did_not_exist_error(
|
||||
field_name,
|
||||
"int_value",
|
||||
))? != 0,
|
||||
),
|
||||
))
|
||||
})
|
||||
.collect::<Result<
|
||||
Vec<(VersionId, VersionFieldValue)>,
|
||||
DatabaseError,
|
||||
>>()?,
|
||||
LoaderFieldType::Enum(id) => qvfs
|
||||
.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok((
|
||||
qvf.version_id,
|
||||
VersionFieldValue::Enum(*id, {
|
||||
let enum_id = qvf.enum_value.ok_or(
|
||||
did_not_exist_error(
|
||||
field_name,
|
||||
"enum_value",
|
||||
),
|
||||
)?;
|
||||
let lfev = qlfev
|
||||
.iter()
|
||||
.find(|x| x.id == enum_id)
|
||||
.ok_or(did_not_exist_error(
|
||||
field_name,
|
||||
"enum_value",
|
||||
))?;
|
||||
LoaderFieldEnumValue {
|
||||
id: lfev.id,
|
||||
enum_id: lfev.enum_id,
|
||||
value: lfev.value.clone(),
|
||||
ordering: lfev.ordering,
|
||||
created: lfev.created,
|
||||
metadata: lfev
|
||||
.metadata
|
||||
.clone()
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
}),
|
||||
))
|
||||
})
|
||||
.collect::<Result<
|
||||
Vec<(VersionId, VersionFieldValue)>,
|
||||
DatabaseError,
|
||||
>>()?,
|
||||
|
||||
// Array fields
|
||||
// We concatenate into one array
|
||||
LoaderFieldType::ArrayInteger => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayInteger(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
qvf.int_value
|
||||
.ok_or(did_not_exist_error(field_name, "int_value"))
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayText => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayText(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
qvf.string_value
|
||||
.ok_or(did_not_exist_error(field_name, "string_value"))
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayBoolean => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayBoolean(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok::<bool, DatabaseError>(
|
||||
qvf.int_value
|
||||
.ok_or(did_not_exist_error(field_name, "int_value"))?
|
||||
!= 0,
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayEnum(id) => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayEnum(
|
||||
*id,
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
let enum_id = qvf
|
||||
.enum_value
|
||||
.ok_or(did_not_exist_error(field_name, "enum_value"))?;
|
||||
let lfev = qlfev
|
||||
.iter()
|
||||
.find(|x| x.id == enum_id)
|
||||
.ok_or(did_not_exist_error(field_name, "enum_value"))?;
|
||||
Ok::<_, DatabaseError>(LoaderFieldEnumValue {
|
||||
id: lfev.id,
|
||||
enum_id: lfev.enum_id,
|
||||
value: lfev.value.clone(),
|
||||
ordering: lfev.ordering,
|
||||
created: lfev.created,
|
||||
metadata: lfev.metadata.clone().unwrap_or_default(),
|
||||
// Array fields
|
||||
// We concatenate into one array
|
||||
LoaderFieldType::ArrayInteger => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayInteger(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
qvf.int_value.ok_or(did_not_exist_error(
|
||||
field_name,
|
||||
"int_value",
|
||||
))
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
};
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayText => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayText(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
qvf.string_value.ok_or(did_not_exist_error(
|
||||
field_name,
|
||||
"string_value",
|
||||
))
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayBoolean => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayBoolean(
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
Ok::<bool, DatabaseError>(
|
||||
qvf.int_value.ok_or(
|
||||
did_not_exist_error(
|
||||
field_name,
|
||||
"int_value",
|
||||
),
|
||||
)? != 0,
|
||||
)
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
LoaderFieldType::ArrayEnum(id) => vec![(
|
||||
version_id,
|
||||
VersionFieldValue::ArrayEnum(
|
||||
*id,
|
||||
qvfs.into_iter()
|
||||
.map(|qvf| {
|
||||
let enum_id = qvf.enum_value.ok_or(
|
||||
did_not_exist_error(
|
||||
field_name,
|
||||
"enum_value",
|
||||
),
|
||||
)?;
|
||||
let lfev = qlfev
|
||||
.iter()
|
||||
.find(|x| x.id == enum_id)
|
||||
.ok_or(did_not_exist_error(
|
||||
field_name,
|
||||
"enum_value",
|
||||
))?;
|
||||
Ok::<_, DatabaseError>(LoaderFieldEnumValue {
|
||||
id: lfev.id,
|
||||
enum_id: lfev.enum_id,
|
||||
value: lfev.value.clone(),
|
||||
ordering: lfev.ordering,
|
||||
created: lfev.created,
|
||||
metadata: lfev
|
||||
.metadata
|
||||
.clone()
|
||||
.unwrap_or_default(),
|
||||
})
|
||||
})
|
||||
.collect::<Result<_, _>>()?,
|
||||
),
|
||||
)],
|
||||
};
|
||||
|
||||
// Sort arrayenums by ordering, then by created
|
||||
for (_, v) in value.iter_mut() {
|
||||
if let VersionFieldValue::ArrayEnum(_, v) = v {
|
||||
v.sort_by(|a, b| a.ordering.cmp(&b.ordering).then(a.created.cmp(&b.created)));
|
||||
v.sort_by(|a, b| {
|
||||
a.ordering.cmp(&b.ordering).then(a.created.cmp(&b.created))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,7 +1291,9 @@ impl VersionFieldValue {
|
||||
// Serialize to internal value, such as for converting to user-facing JSON
|
||||
pub fn serialize_internal(&self) -> serde_json::Value {
|
||||
match self {
|
||||
VersionFieldValue::Integer(i) => serde_json::Value::Number((*i).into()),
|
||||
VersionFieldValue::Integer(i) => {
|
||||
serde_json::Value::Number((*i).into())
|
||||
}
|
||||
VersionFieldValue::Text(s) => serde_json::Value::String(s.clone()),
|
||||
VersionFieldValue::Boolean(b) => serde_json::Value::Bool(*b),
|
||||
VersionFieldValue::ArrayInteger(v) => serde_json::Value::Array(
|
||||
@@ -1203,10 +1306,12 @@ impl VersionFieldValue {
|
||||
.map(|s| serde_json::Value::String(s.clone()))
|
||||
.collect(),
|
||||
),
|
||||
VersionFieldValue::ArrayBoolean(v) => {
|
||||
serde_json::Value::Array(v.iter().map(|b| serde_json::Value::Bool(*b)).collect())
|
||||
VersionFieldValue::ArrayBoolean(v) => serde_json::Value::Array(
|
||||
v.iter().map(|b| serde_json::Value::Bool(*b)).collect(),
|
||||
),
|
||||
VersionFieldValue::Enum(_, v) => {
|
||||
serde_json::Value::String(v.value.clone())
|
||||
}
|
||||
VersionFieldValue::Enum(_, v) => serde_json::Value::String(v.value.clone()),
|
||||
VersionFieldValue::ArrayEnum(_, v) => serde_json::Value::Array(
|
||||
v.iter()
|
||||
.map(|v| serde_json::Value::String(v.value.clone()))
|
||||
@@ -1222,11 +1327,17 @@ impl VersionFieldValue {
|
||||
VersionFieldValue::Integer(i) => vec![i.to_string()],
|
||||
VersionFieldValue::Text(s) => vec![s.clone()],
|
||||
VersionFieldValue::Boolean(b) => vec![b.to_string()],
|
||||
VersionFieldValue::ArrayInteger(v) => v.iter().map(|i| i.to_string()).collect(),
|
||||
VersionFieldValue::ArrayInteger(v) => {
|
||||
v.iter().map(|i| i.to_string()).collect()
|
||||
}
|
||||
VersionFieldValue::ArrayText(v) => v.clone(),
|
||||
VersionFieldValue::ArrayBoolean(v) => v.iter().map(|b| b.to_string()).collect(),
|
||||
VersionFieldValue::ArrayBoolean(v) => {
|
||||
v.iter().map(|b| b.to_string()).collect()
|
||||
}
|
||||
VersionFieldValue::Enum(_, v) => vec![v.value.clone()],
|
||||
VersionFieldValue::ArrayEnum(_, v) => v.iter().map(|v| v.value.clone()).collect(),
|
||||
VersionFieldValue::ArrayEnum(_, v) => {
|
||||
v.iter().map(|v| v.value.clone()).collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@ impl NotificationBuilder {
|
||||
redis: &RedisPool,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let notification_ids =
|
||||
generate_many_notification_ids(users.len(), &mut *transaction).await?;
|
||||
generate_many_notification_ids(users.len(), &mut *transaction)
|
||||
.await?;
|
||||
|
||||
let body = serde_json::value::to_value(&self.body)?;
|
||||
let bodies = notification_ids
|
||||
@@ -97,7 +98,8 @@ impl Notification {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
let notification_ids_parsed: Vec<i64> = notification_ids.iter().map(|x| x.0).collect();
|
||||
let notification_ids_parsed: Vec<i64> =
|
||||
notification_ids.iter().map(|x| x.0).collect();
|
||||
sqlx::query!(
|
||||
"
|
||||
SELECT n.id, n.user_id, n.name, n.text, n.link, n.created, n.read, n.type notification_type, n.body,
|
||||
@@ -153,7 +155,10 @@ impl Notification {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
let cached_notifications: Option<Vec<Notification>> = redis
|
||||
.get_deserialized_from_json(USER_NOTIFICATIONS_NAMESPACE, &user_id.0.to_string())
|
||||
.get_deserialized_from_json(
|
||||
USER_NOTIFICATIONS_NAMESPACE,
|
||||
&user_id.0.to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(notifications) = cached_notifications {
|
||||
@@ -227,7 +232,8 @@ impl Notification {
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Option<()>, DatabaseError> {
|
||||
let notification_ids_parsed: Vec<i64> = notification_ids.iter().map(|x| x.0).collect();
|
||||
let notification_ids_parsed: Vec<i64> =
|
||||
notification_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
let affected_users = sqlx::query!(
|
||||
"
|
||||
@@ -243,7 +249,11 @@ impl Notification {
|
||||
.try_collect::<Vec<_>>()
|
||||
.await?;
|
||||
|
||||
Notification::clear_user_notifications_cache(affected_users.iter(), redis).await?;
|
||||
Notification::clear_user_notifications_cache(
|
||||
affected_users.iter(),
|
||||
redis,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Some(()))
|
||||
}
|
||||
@@ -261,7 +271,8 @@ impl Notification {
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Option<()>, DatabaseError> {
|
||||
let notification_ids_parsed: Vec<i64> = notification_ids.iter().map(|x| x.0).collect();
|
||||
let notification_ids_parsed: Vec<i64> =
|
||||
notification_ids.iter().map(|x| x.0).collect();
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
@@ -286,7 +297,11 @@ impl Notification {
|
||||
.try_collect::<Vec<_>>()
|
||||
.await?;
|
||||
|
||||
Notification::clear_user_notifications_cache(affected_users.iter(), redis).await?;
|
||||
Notification::clear_user_notifications_cache(
|
||||
affected_users.iter(),
|
||||
redis,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(Some(()))
|
||||
}
|
||||
@@ -298,11 +313,9 @@ impl Notification {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
redis
|
||||
.delete_many(
|
||||
user_ids
|
||||
.into_iter()
|
||||
.map(|id| (USER_NOTIFICATIONS_NAMESPACE, Some(id.0.to_string()))),
|
||||
)
|
||||
.delete_many(user_ids.into_iter().map(|id| {
|
||||
(USER_NOTIFICATIONS_NAMESPACE, Some(id.0.to_string()))
|
||||
}))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -91,10 +91,12 @@ impl OAuthClient {
|
||||
) -> Result<Vec<OAuthClient>, DatabaseError> {
|
||||
let ids = ids.iter().map(|id| id.0).collect_vec();
|
||||
let ids_ref: &[i64] = &ids;
|
||||
let results =
|
||||
select_clients_with_predicate!("WHERE clients.id = ANY($1::bigint[])", ids_ref)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let results = select_clients_with_predicate!(
|
||||
"WHERE clients.id = ANY($1::bigint[])",
|
||||
ids_ref
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results.into_iter().map(|r| r.into()).collect_vec())
|
||||
}
|
||||
@@ -104,9 +106,12 @@ impl OAuthClient {
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<Vec<OAuthClient>, DatabaseError> {
|
||||
let user_id_param = user_id.0;
|
||||
let clients = select_clients_with_predicate!("WHERE created_by = $1", user_id_param)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let clients = select_clients_with_predicate!(
|
||||
"WHERE created_by = $1",
|
||||
user_id_param
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(clients.into_iter().map(|r| r.into()).collect())
|
||||
}
|
||||
@@ -153,7 +158,8 @@ impl OAuthClient {
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
Self::insert_redirect_uris(&self.redirect_uris, &mut **transaction).await?;
|
||||
Self::insert_redirect_uris(&self.redirect_uris, &mut **transaction)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -231,7 +237,9 @@ impl OAuthClient {
|
||||
|
||||
impl From<ClientQueryResult> for OAuthClient {
|
||||
fn from(r: ClientQueryResult) -> Self {
|
||||
let redirects = if let (Some(ids), Some(uris)) = (r.uri_ids.as_ref(), r.uri_vals.as_ref()) {
|
||||
let redirects = if let (Some(ids), Some(uris)) =
|
||||
(r.uri_ids.as_ref(), r.uri_vals.as_ref())
|
||||
{
|
||||
ids.iter()
|
||||
.zip(uris.iter())
|
||||
.map(|(id, uri)| OAuthRedirectUri {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use super::{DatabaseError, OAuthAccessTokenId, OAuthClientAuthorizationId, OAuthClientId, UserId};
|
||||
use super::{
|
||||
DatabaseError, OAuthAccessTokenId, OAuthClientAuthorizationId,
|
||||
OAuthClientId, UserId,
|
||||
};
|
||||
use crate::models::pats::Scopes;
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{database::redis::RedisPool, models::ids::base62_impl::parse_base62};
|
||||
use crate::{
|
||||
database::redis::RedisPool, models::ids::base62_impl::parse_base62,
|
||||
};
|
||||
use dashmap::DashMap;
|
||||
use futures::TryStreamExt;
|
||||
use std::fmt::{Debug, Display};
|
||||
@@ -100,7 +102,11 @@ impl Organization {
|
||||
Self::get_many(&ids, exec, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get_many<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
organization_strings: &[T],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
|
||||
@@ -55,7 +55,11 @@ impl PersonalAccessToken {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
id: T,
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -83,7 +87,11 @@ impl PersonalAccessToken {
|
||||
PersonalAccessToken::get_many(&ids, exec, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get_many<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
pat_strings: &[T],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -151,7 +159,10 @@ impl PersonalAccessToken {
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
let res = redis
|
||||
.get_deserialized_from_json::<Vec<i64>>(PATS_USERS_NAMESPACE, &user_id.0.to_string())
|
||||
.get_deserialized_from_json::<Vec<i64>>(
|
||||
PATS_USERS_NAMESPACE,
|
||||
&user_id.0.to_string(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(res) = res {
|
||||
@@ -194,13 +205,18 @@ impl PersonalAccessToken {
|
||||
}
|
||||
|
||||
redis
|
||||
.delete_many(clear_pats.into_iter().flat_map(|(id, token, user_id)| {
|
||||
[
|
||||
(PATS_NAMESPACE, id.map(|i| i.0.to_string())),
|
||||
(PATS_TOKENS_NAMESPACE, token),
|
||||
(PATS_USERS_NAMESPACE, user_id.map(|i| i.0.to_string())),
|
||||
]
|
||||
}))
|
||||
.delete_many(clear_pats.into_iter().flat_map(
|
||||
|(id, token, user_id)| {
|
||||
[
|
||||
(PATS_NAMESPACE, id.map(|i| i.0.to_string())),
|
||||
(PATS_TOKENS_NAMESPACE, token),
|
||||
(
|
||||
PATS_USERS_NAMESPACE,
|
||||
user_id.map(|i| i.0.to_string()),
|
||||
),
|
||||
]
|
||||
},
|
||||
))
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -48,7 +48,10 @@ impl Payout {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get<'a, 'b, E>(id: PayoutId, executor: E) -> Result<Option<Payout>, DatabaseError>
|
||||
pub async fn get<'a, 'b, E>(
|
||||
id: PayoutId,
|
||||
executor: E,
|
||||
) -> Result<Option<Payout>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::database::models::{product_item, DatabaseError, ProductId, ProductPriceId};
|
||||
use crate::database::models::{
|
||||
product_item, DatabaseError, ProductId, ProductPriceId,
|
||||
};
|
||||
use crate::database::redis::RedisPool;
|
||||
use crate::models::billing::{Price, ProductMetadata};
|
||||
use dashmap::DashMap;
|
||||
@@ -61,9 +63,12 @@ impl ProductItem {
|
||||
) -> Result<Vec<ProductItem>, DatabaseError> {
|
||||
let ids = ids.iter().map(|id| id.0).collect_vec();
|
||||
let ids_ref: &[i64] = &ids;
|
||||
let results = select_products_with_predicate!("WHERE id = ANY($1::bigint[])", ids_ref)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let results = select_products_with_predicate!(
|
||||
"WHERE id = ANY($1::bigint[])",
|
||||
ids_ref
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
@@ -95,7 +100,10 @@ pub struct QueryProduct {
|
||||
}
|
||||
|
||||
impl QueryProduct {
|
||||
pub async fn list<'a, E>(exec: E, redis: &RedisPool) -> Result<Vec<QueryProduct>, DatabaseError>
|
||||
pub async fn list<'a, E>(
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<QueryProduct>, DatabaseError>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
@@ -201,9 +209,12 @@ impl ProductPriceItem {
|
||||
) -> Result<Vec<ProductPriceItem>, DatabaseError> {
|
||||
let ids = ids.iter().map(|id| id.0).collect_vec();
|
||||
let ids_ref: &[i64] = &ids;
|
||||
let results = select_prices_with_predicate!("WHERE id = ANY($1::bigint[])", ids_ref)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let results = select_prices_with_predicate!(
|
||||
"WHERE id = ANY($1::bigint[])",
|
||||
ids_ref
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
@@ -228,20 +239,25 @@ impl ProductPriceItem {
|
||||
let ids_ref: &[i64] = &ids;
|
||||
|
||||
use futures_util::TryStreamExt;
|
||||
let prices = select_prices_with_predicate!("WHERE product_id = ANY($1::bigint[])", ids_ref)
|
||||
.fetch(exec)
|
||||
.try_fold(
|
||||
DashMap::new(),
|
||||
|acc: DashMap<ProductId, Vec<ProductPriceItem>>, x| {
|
||||
if let Ok(item) = <ProductPriceResult as TryInto<ProductPriceItem>>::try_into(x)
|
||||
{
|
||||
acc.entry(item.product_id).or_default().push(item);
|
||||
}
|
||||
let prices = select_prices_with_predicate!(
|
||||
"WHERE product_id = ANY($1::bigint[])",
|
||||
ids_ref
|
||||
)
|
||||
.fetch(exec)
|
||||
.try_fold(
|
||||
DashMap::new(),
|
||||
|acc: DashMap<ProductId, Vec<ProductPriceItem>>, x| {
|
||||
if let Ok(item) = <ProductPriceResult as TryInto<
|
||||
ProductPriceItem,
|
||||
>>::try_into(x)
|
||||
{
|
||||
acc.entry(item.product_id).or_default().push(item);
|
||||
}
|
||||
|
||||
async move { Ok(acc) }
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
async move { Ok(acc) }
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(prices)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::loader_fields::{
|
||||
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField, VersionField,
|
||||
QueryLoaderField, QueryLoaderFieldEnumValue, QueryVersionField,
|
||||
VersionField,
|
||||
};
|
||||
use super::{ids::*, User};
|
||||
use crate::database::models;
|
||||
@@ -72,15 +73,15 @@ impl GalleryItem {
|
||||
project_id: ProjectId,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), sqlx::error::Error> {
|
||||
let (project_ids, image_urls, raw_image_urls, featureds, names, descriptions, orderings): (
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
) = items
|
||||
let (
|
||||
project_ids,
|
||||
image_urls,
|
||||
raw_image_urls,
|
||||
featureds,
|
||||
names,
|
||||
descriptions,
|
||||
orderings,
|
||||
): (Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>, Vec<_>) = items
|
||||
.into_iter()
|
||||
.map(|gi| {
|
||||
(
|
||||
@@ -128,7 +129,11 @@ impl ModCategory {
|
||||
items: Vec<Self>,
|
||||
transaction: &mut sqlx::Transaction<'_, sqlx::Postgres>,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let (project_ids, category_ids, is_additionals): (Vec<_>, Vec<_>, Vec<_>) = items
|
||||
let (project_ids, category_ids, is_additionals): (
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
Vec<_>,
|
||||
) = items
|
||||
.into_iter()
|
||||
.map(|mc| (mc.project_id.0, mc.category_id.0, mc.is_additional))
|
||||
.multiunzip();
|
||||
@@ -223,9 +228,19 @@ impl ProjectBuilder {
|
||||
version.insert(&mut *transaction).await?;
|
||||
}
|
||||
|
||||
LinkUrl::insert_many_projects(link_urls, self.project_id, &mut *transaction).await?;
|
||||
LinkUrl::insert_many_projects(
|
||||
link_urls,
|
||||
self.project_id,
|
||||
&mut *transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
GalleryItem::insert_many(gallery_items, self.project_id, &mut *transaction).await?;
|
||||
GalleryItem::insert_many(
|
||||
gallery_items,
|
||||
self.project_id,
|
||||
&mut *transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let project_id = self.project_id;
|
||||
let mod_categories = categories
|
||||
@@ -323,7 +338,8 @@ impl Project {
|
||||
let project = Self::get_id(id, &mut **transaction, redis).await?;
|
||||
|
||||
if let Some(project) = project {
|
||||
Project::clear_cache(id, project.inner.slug, Some(true), redis).await?;
|
||||
Project::clear_cache(id, project.inner.slug, Some(true), redis)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
@@ -389,7 +405,8 @@ impl Project {
|
||||
.await?;
|
||||
|
||||
for version in project.versions {
|
||||
super::Version::remove_full(version, redis, transaction).await?;
|
||||
super::Version::remove_full(version, redis, transaction)
|
||||
.await?;
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
@@ -422,7 +439,8 @@ impl Project {
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
models::TeamMember::clear_cache(project.inner.team_id, redis).await?;
|
||||
models::TeamMember::clear_cache(project.inner.team_id, redis)
|
||||
.await?;
|
||||
|
||||
let affected_user_ids = sqlx::query!(
|
||||
"
|
||||
@@ -476,9 +494,13 @@ impl Project {
|
||||
where
|
||||
E: sqlx::Acquire<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
Project::get_many(&[crate::models::ids::ProjectId::from(id)], executor, redis)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
Project::get_many(
|
||||
&[crate::models::ids::ProjectId::from(id)],
|
||||
executor,
|
||||
redis,
|
||||
)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many_ids<'a, E>(
|
||||
@@ -496,7 +518,11 @@ impl Project {
|
||||
Project::get_many(&ids, exec, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get_many<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
project_strings: &[T],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -837,11 +863,15 @@ impl Project {
|
||||
id: ProjectId,
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
) -> Result<Vec<(Option<VersionId>, Option<ProjectId>, Option<ProjectId>)>, DatabaseError>
|
||||
) -> Result<
|
||||
Vec<(Option<VersionId>, Option<ProjectId>, Option<ProjectId>)>,
|
||||
DatabaseError,
|
||||
>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
type Dependencies = Vec<(Option<VersionId>, Option<ProjectId>, Option<ProjectId>)>;
|
||||
type Dependencies =
|
||||
Vec<(Option<VersionId>, Option<ProjectId>, Option<ProjectId>)>;
|
||||
|
||||
let mut redis = redis.connect().await?;
|
||||
|
||||
@@ -881,7 +911,12 @@ impl Project {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(PROJECTS_DEPENDENCIES_NAMESPACE, id.0, &dependencies, None)
|
||||
.set_serialized_to_json(
|
||||
PROJECTS_DEPENDENCIES_NAMESPACE,
|
||||
id.0,
|
||||
&dependencies,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok(dependencies)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,10 @@ impl Report {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn get<'a, E>(id: ReportId, exec: E) -> Result<Option<QueryReport>, sqlx::Error>
|
||||
pub async fn get<'a, E>(
|
||||
id: ReportId,
|
||||
exec: E,
|
||||
) -> Result<Option<QueryReport>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
@@ -74,7 +77,8 @@ impl Report {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let report_ids_parsed: Vec<i64> = report_ids.iter().map(|x| x.0).collect();
|
||||
let report_ids_parsed: Vec<i64> =
|
||||
report_ids.iter().map(|x| x.0).collect();
|
||||
let reports = sqlx::query!(
|
||||
"
|
||||
SELECT r.id, rt.name, r.mod_id, r.version_id, r.user_id, r.body, r.reporter, r.created, t.id thread_id, r.closed
|
||||
@@ -133,8 +137,11 @@ impl Report {
|
||||
.await?;
|
||||
|
||||
if let Some(thread_id) = thread_id {
|
||||
crate::database::models::Thread::remove_full(ThreadId(thread_id.id), transaction)
|
||||
.await?;
|
||||
crate::database::models::Thread::remove_full(
|
||||
ThreadId(thread_id.id),
|
||||
transaction,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
|
||||
@@ -82,7 +82,11 @@ pub struct Session {
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub async fn get<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
id: T,
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -103,9 +107,13 @@ impl Session {
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres>,
|
||||
{
|
||||
Session::get_many(&[crate::models::ids::SessionId::from(id)], executor, redis)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
Session::get_many(
|
||||
&[crate::models::ids::SessionId::from(id)],
|
||||
executor,
|
||||
redis,
|
||||
)
|
||||
.await
|
||||
.map(|x| x.into_iter().next())
|
||||
}
|
||||
|
||||
pub async fn get_many_ids<'a, E>(
|
||||
@@ -123,7 +131,11 @@ impl Session {
|
||||
Session::get_many(&ids, exec, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get_many<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
session_strings: &[T],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -226,14 +238,23 @@ impl Session {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(SESSIONS_USERS_NAMESPACE, user_id.0, &db_sessions, None)
|
||||
.set_serialized_to_json(
|
||||
SESSIONS_USERS_NAMESPACE,
|
||||
user_id.0,
|
||||
&db_sessions,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(db_sessions)
|
||||
}
|
||||
|
||||
pub async fn clear_cache(
|
||||
clear_sessions: Vec<(Option<SessionId>, Option<String>, Option<UserId>)>,
|
||||
clear_sessions: Vec<(
|
||||
Option<SessionId>,
|
||||
Option<String>,
|
||||
Option<UserId>,
|
||||
)>,
|
||||
redis: &RedisPool,
|
||||
) -> Result<(), DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
@@ -243,17 +264,18 @@ impl Session {
|
||||
}
|
||||
|
||||
redis
|
||||
.delete_many(
|
||||
clear_sessions
|
||||
.into_iter()
|
||||
.flat_map(|(id, session, user_id)| {
|
||||
[
|
||||
(SESSIONS_NAMESPACE, id.map(|i| i.0.to_string())),
|
||||
(SESSIONS_IDS_NAMESPACE, session),
|
||||
(SESSIONS_USERS_NAMESPACE, user_id.map(|i| i.0.to_string())),
|
||||
]
|
||||
}),
|
||||
)
|
||||
.delete_many(clear_sessions.into_iter().flat_map(
|
||||
|(id, session, user_id)| {
|
||||
[
|
||||
(SESSIONS_NAMESPACE, id.map(|i| i.0.to_string())),
|
||||
(SESSIONS_IDS_NAMESPACE, session),
|
||||
(
|
||||
SESSIONS_USERS_NAMESPACE,
|
||||
user_id.map(|i| i.0.to_string()),
|
||||
),
|
||||
]
|
||||
},
|
||||
))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -149,10 +149,12 @@ impl Team {
|
||||
// Only one of project_id or organization_id will be set
|
||||
let mut team_association_id = None;
|
||||
if let Some(pid) = t.pid {
|
||||
team_association_id = Some(TeamAssociationId::Project(ProjectId(pid)));
|
||||
team_association_id =
|
||||
Some(TeamAssociationId::Project(ProjectId(pid)));
|
||||
}
|
||||
if let Some(oid) = t.oid {
|
||||
team_association_id = Some(TeamAssociationId::Organization(OrganizationId(oid)));
|
||||
team_association_id =
|
||||
Some(TeamAssociationId::Organization(OrganizationId(oid)));
|
||||
}
|
||||
return Ok(team_association_id);
|
||||
}
|
||||
@@ -257,7 +259,10 @@ impl TeamMember {
|
||||
Ok(val.into_iter().flatten().collect())
|
||||
}
|
||||
|
||||
pub async fn clear_cache(id: TeamId, redis: &RedisPool) -> Result<(), super::DatabaseError> {
|
||||
pub async fn clear_cache(
|
||||
id: TeamId,
|
||||
redis: &RedisPool,
|
||||
) -> Result<(), super::DatabaseError> {
|
||||
let mut redis = redis.connect().await?;
|
||||
redis.delete(TEAMS_NAMESPACE, id.0).await?;
|
||||
Ok(())
|
||||
@@ -354,11 +359,14 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
permissions: ProjectPermissions::from_bits(
|
||||
m.permissions as u64,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m.organization_permissions.map(|p| {
|
||||
OrganizationPermissions::from_bits(p as u64)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
@@ -574,11 +582,14 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
permissions: ProjectPermissions::from_bits(
|
||||
m.permissions as u64,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m.organization_permissions.map(|p| {
|
||||
OrganizationPermissions::from_bits(p as u64)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
@@ -623,11 +634,14 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
permissions: ProjectPermissions::from_bits(
|
||||
m.permissions as u64,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m.organization_permissions.map(|p| {
|
||||
OrganizationPermissions::from_bits(p as u64)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
@@ -666,11 +680,14 @@ impl TeamMember {
|
||||
user_id,
|
||||
role: m.role,
|
||||
is_owner: m.is_owner,
|
||||
permissions: ProjectPermissions::from_bits(m.permissions as u64)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m
|
||||
.organization_permissions
|
||||
.map(|p| OrganizationPermissions::from_bits(p as u64).unwrap_or_default()),
|
||||
permissions: ProjectPermissions::from_bits(
|
||||
m.permissions as u64,
|
||||
)
|
||||
.unwrap_or_default(),
|
||||
organization_permissions: m.organization_permissions.map(|p| {
|
||||
OrganizationPermissions::from_bits(p as u64)
|
||||
.unwrap_or_default()
|
||||
}),
|
||||
accepted: m.accepted,
|
||||
payouts_split: m.payouts_split,
|
||||
ordering: m.ordering,
|
||||
@@ -695,10 +712,15 @@ impl TeamMember {
|
||||
Self::get_from_user_id(project.team_id, user_id, executor).await?;
|
||||
|
||||
let organization =
|
||||
Organization::get_associated_organization_project_id(project.id, executor).await?;
|
||||
Organization::get_associated_organization_project_id(
|
||||
project.id, executor,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let organization_team_member = if let Some(organization) = &organization {
|
||||
Self::get_from_user_id(organization.team_id, user_id, executor).await?
|
||||
let organization_team_member = if let Some(organization) = &organization
|
||||
{
|
||||
Self::get_from_user_id(organization.team_id, user_id, executor)
|
||||
.await?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -112,7 +112,10 @@ impl ThreadBuilder {
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
pub async fn get<'a, E>(id: ThreadId, exec: E) -> Result<Option<Thread>, sqlx::Error>
|
||||
pub async fn get<'a, E>(
|
||||
id: ThreadId,
|
||||
exec: E,
|
||||
) -> Result<Option<Thread>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
@@ -130,7 +133,8 @@ impl Thread {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let thread_ids_parsed: Vec<i64> = thread_ids.iter().map(|x| x.0).collect();
|
||||
let thread_ids_parsed: Vec<i64> =
|
||||
thread_ids.iter().map(|x| x.0).collect();
|
||||
let threads = sqlx::query!(
|
||||
"
|
||||
SELECT t.id, t.thread_type, t.mod_id, t.report_id,
|
||||
@@ -225,7 +229,8 @@ impl ThreadMessage {
|
||||
{
|
||||
use futures::stream::TryStreamExt;
|
||||
|
||||
let message_ids_parsed: Vec<i64> = message_ids.iter().map(|x| x.0).collect();
|
||||
let message_ids_parsed: Vec<i64> =
|
||||
message_ids.iter().map(|x| x.0).collect();
|
||||
let messages = sqlx::query!(
|
||||
"
|
||||
SELECT tm.id, tm.author_id, tm.thread_id, tm.body, tm.created, tm.hide_identity
|
||||
@@ -261,7 +266,8 @@ impl ThreadMessage {
|
||||
WHERE id = $1
|
||||
",
|
||||
id as ThreadMessageId,
|
||||
serde_json::to_value(MessageBody::Deleted { private }).unwrap_or(serde_json::json!({}))
|
||||
serde_json::to_value(MessageBody::Deleted { private })
|
||||
.unwrap_or(serde_json::json!({}))
|
||||
)
|
||||
.execute(&mut **transaction)
|
||||
.await?;
|
||||
|
||||
@@ -135,7 +135,11 @@ impl User {
|
||||
User::get_many(&ids, exec, redis).await
|
||||
}
|
||||
|
||||
pub async fn get_many<'a, E, T: Display + Hash + Eq + PartialEq + Clone + Debug>(
|
||||
pub async fn get_many<
|
||||
'a,
|
||||
E,
|
||||
T: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
>(
|
||||
users_strings: &[T],
|
||||
exec: E,
|
||||
redis: &RedisPool,
|
||||
@@ -213,7 +217,10 @@ impl User {
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
pub async fn get_email<'a, E>(email: &str, exec: E) -> Result<Option<UserId>, sqlx::Error>
|
||||
pub async fn get_email<'a, E>(
|
||||
email: &str,
|
||||
exec: E,
|
||||
) -> Result<Option<UserId>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
@@ -268,7 +275,12 @@ impl User {
|
||||
.await?;
|
||||
|
||||
redis
|
||||
.set_serialized_to_json(USERS_PROJECTS_NAMESPACE, user_id.0, &db_projects, None)
|
||||
.set_serialized_to_json(
|
||||
USERS_PROJECTS_NAMESPACE,
|
||||
user_id.0,
|
||||
&db_projects,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(db_projects)
|
||||
@@ -323,7 +335,10 @@ impl User {
|
||||
Ok(projects)
|
||||
}
|
||||
|
||||
pub async fn get_follows<'a, E>(user_id: UserId, exec: E) -> Result<Vec<ProjectId>, sqlx::Error>
|
||||
pub async fn get_follows<'a, E>(
|
||||
user_id: UserId,
|
||||
exec: E,
|
||||
) -> Result<Vec<ProjectId>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
@@ -344,7 +359,10 @@ impl User {
|
||||
Ok(projects)
|
||||
}
|
||||
|
||||
pub async fn get_reports<'a, E>(user_id: UserId, exec: E) -> Result<Vec<ReportId>, sqlx::Error>
|
||||
pub async fn get_reports<'a, E>(
|
||||
user_id: UserId,
|
||||
exec: E,
|
||||
) -> Result<Vec<ReportId>, sqlx::Error>
|
||||
where
|
||||
E: sqlx::Executor<'a, Database = sqlx::Postgres> + Copy,
|
||||
{
|
||||
@@ -417,9 +435,9 @@ impl User {
|
||||
|
||||
redis
|
||||
.delete_many(
|
||||
user_ids
|
||||
.iter()
|
||||
.map(|id| (USERS_PROJECTS_NAMESPACE, Some(id.0.to_string()))),
|
||||
user_ids.iter().map(|id| {
|
||||
(USERS_PROJECTS_NAMESPACE, Some(id.0.to_string()))
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -434,9 +452,11 @@ impl User {
|
||||
let user = Self::get_id(id, &mut **transaction, redis).await?;
|
||||
|
||||
if let Some(delete_user) = user {
|
||||
User::clear_caches(&[(id, Some(delete_user.username))], redis).await?;
|
||||
User::clear_caches(&[(id, Some(delete_user.username))], redis)
|
||||
.await?;
|
||||
|
||||
let deleted_user: UserId = crate::models::users::DELETED_USER.into();
|
||||
let deleted_user: UserId =
|
||||
crate::models::users::DELETED_USER.into();
|
||||
|
||||
sqlx::query!(
|
||||
"
|
||||
@@ -509,7 +529,8 @@ impl User {
|
||||
.await?;
|
||||
|
||||
for collection_id in user_collections {
|
||||
models::Collection::remove(collection_id, transaction, redis).await?;
|
||||
models::Collection::remove(collection_id, transaction, redis)
|
||||
.await?;
|
||||
}
|
||||
|
||||
let report_threads = sqlx::query!(
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
use crate::database::models::{DatabaseError, ProductPriceId, UserId, UserSubscriptionId};
|
||||
use crate::models::billing::{PriceDuration, SubscriptionMetadata, SubscriptionStatus};
|
||||
use crate::database::models::{
|
||||
DatabaseError, ProductPriceId, UserId, UserSubscriptionId,
|
||||
};
|
||||
use crate::models::billing::{
|
||||
PriceDuration, SubscriptionMetadata, SubscriptionStatus,
|
||||
};
|
||||
use chrono::{DateTime, Utc};
|
||||
use itertools::Itertools;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
@@ -69,10 +73,12 @@ impl UserSubscriptionItem {
|
||||
) -> Result<Vec<UserSubscriptionItem>, DatabaseError> {
|
||||
let ids = ids.iter().map(|id| id.0).collect_vec();
|
||||
let ids_ref: &[i64] = &ids;
|
||||
let results =
|
||||
select_user_subscriptions_with_predicate!("WHERE us.id = ANY($1::bigint[])", ids_ref)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let results = select_user_subscriptions_with_predicate!(
|
||||
"WHERE us.id = ANY($1::bigint[])",
|
||||
ids_ref
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
@@ -85,9 +91,12 @@ impl UserSubscriptionItem {
|
||||
exec: impl sqlx::Executor<'_, Database = sqlx::Postgres>,
|
||||
) -> Result<Vec<UserSubscriptionItem>, DatabaseError> {
|
||||
let user_id = user_id.0;
|
||||
let results = select_user_subscriptions_with_predicate!("WHERE us.user_id = $1", user_id)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
let results = select_user_subscriptions_with_predicate!(
|
||||
"WHERE us.user_id = $1",
|
||||
user_id
|
||||
)
|
||||
.fetch_all(exec)
|
||||
.await?;
|
||||
|
||||
Ok(results
|
||||
.into_iter()
|
||||
|
||||
@@ -220,7 +220,12 @@ impl VersionBuilder {
|
||||
file.insert(version_id, transaction).await?;
|
||||
}
|
||||
|
||||
DependencyBuilder::insert_many(dependencies, self.version_id, transaction).await?;
|
||||
DependencyBuilder::insert_many(
|
||||
dependencies,
|
||||
self.version_id,
|
||||
transaction,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let loader_versions = loaders
|
||||
.iter()
|
||||
@@ -898,13 +903,20 @@ impl Version {
|
||||
|
||||
redis
|
||||
.delete_many(
|
||||
iter::once((VERSIONS_NAMESPACE, Some(version.inner.id.0.to_string()))).chain(
|
||||
version.files.iter().flat_map(|file| {
|
||||
iter::once((
|
||||
VERSIONS_NAMESPACE,
|
||||
Some(version.inner.id.0.to_string()),
|
||||
))
|
||||
.chain(version.files.iter().flat_map(
|
||||
|file| {
|
||||
file.hashes.iter().map(|(algo, hash)| {
|
||||
(VERSION_FILES_NAMESPACE, Some(format!("{}_{}", algo, hash)))
|
||||
(
|
||||
VERSION_FILES_NAMESPACE,
|
||||
Some(format!("{}_{}", algo, hash)),
|
||||
)
|
||||
})
|
||||
}),
|
||||
),
|
||||
},
|
||||
)),
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
@@ -1016,7 +1028,11 @@ mod tests {
|
||||
Utc::now().checked_sub_months(Months::new(months)).unwrap()
|
||||
}
|
||||
|
||||
fn get_version(id: i64, ordering: Option<i32>, date_published: DateTime<Utc>) -> Version {
|
||||
fn get_version(
|
||||
id: i64,
|
||||
ordering: Option<i32>,
|
||||
date_published: DateTime<Utc>,
|
||||
) -> Version {
|
||||
Version {
|
||||
id: VersionId(id),
|
||||
ordering,
|
||||
|
||||
@@ -6,7 +6,8 @@ use std::time::Duration;
|
||||
|
||||
pub async fn connect() -> Result<PgPool, sqlx::Error> {
|
||||
info!("Initializing database connection");
|
||||
let database_url = dotenvy::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
|
||||
let database_url =
|
||||
dotenvy::var("DATABASE_URL").expect("`DATABASE_URL` not in .env");
|
||||
let pool = PgPoolOptions::new()
|
||||
.min_connections(
|
||||
dotenvy::var("DATABASE_MIN_CONNECTIONS")
|
||||
|
||||
@@ -32,18 +32,20 @@ impl RedisPool {
|
||||
// testing pool uses a hashmap to mimic redis behaviour for very small data sizes (ie: tests)
|
||||
// PANICS: production pool will panic if redis url is not set
|
||||
pub fn new(meta_namespace: Option<String>) -> Self {
|
||||
let redis_pool = Config::from_url(dotenvy::var("REDIS_URL").expect("Redis URL not set"))
|
||||
.builder()
|
||||
.expect("Error building Redis pool")
|
||||
.max_size(
|
||||
dotenvy::var("DATABASE_MAX_CONNECTIONS")
|
||||
.ok()
|
||||
.and_then(|x| x.parse().ok())
|
||||
.unwrap_or(10000),
|
||||
)
|
||||
.runtime(Runtime::Tokio1)
|
||||
.build()
|
||||
.expect("Redis connection failed");
|
||||
let redis_pool = Config::from_url(
|
||||
dotenvy::var("REDIS_URL").expect("Redis URL not set"),
|
||||
)
|
||||
.builder()
|
||||
.expect("Error building Redis pool")
|
||||
.max_size(
|
||||
dotenvy::var("DATABASE_MAX_CONNECTIONS")
|
||||
.ok()
|
||||
.and_then(|x| x.parse().ok())
|
||||
.unwrap_or(10000),
|
||||
)
|
||||
.runtime(Runtime::Tokio1)
|
||||
.build()
|
||||
.expect("Redis connection failed");
|
||||
|
||||
RedisPool {
|
||||
pool: redis_pool,
|
||||
@@ -68,7 +70,14 @@ impl RedisPool {
|
||||
F: FnOnce(Vec<K>) -> Fut,
|
||||
Fut: Future<Output = Result<DashMap<K, T>, DatabaseError>>,
|
||||
T: Serialize + DeserializeOwned,
|
||||
K: Display + Hash + Eq + PartialEq + Clone + DeserializeOwned + Serialize + Debug,
|
||||
K: Display
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ PartialEq
|
||||
+ Clone
|
||||
+ DeserializeOwned
|
||||
+ Serialize
|
||||
+ Debug,
|
||||
{
|
||||
Ok(self
|
||||
.get_cached_keys_raw(namespace, keys, closure)
|
||||
@@ -88,15 +97,28 @@ impl RedisPool {
|
||||
F: FnOnce(Vec<K>) -> Fut,
|
||||
Fut: Future<Output = Result<DashMap<K, T>, DatabaseError>>,
|
||||
T: Serialize + DeserializeOwned,
|
||||
K: Display + Hash + Eq + PartialEq + Clone + DeserializeOwned + Serialize + Debug,
|
||||
K: Display
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ PartialEq
|
||||
+ Clone
|
||||
+ DeserializeOwned
|
||||
+ Serialize
|
||||
+ Debug,
|
||||
{
|
||||
self.get_cached_keys_raw_with_slug(namespace, None, false, keys, |ids| async move {
|
||||
Ok(closure(ids)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(key, val)| (key, (None::<String>, val)))
|
||||
.collect())
|
||||
})
|
||||
self.get_cached_keys_raw_with_slug(
|
||||
namespace,
|
||||
None,
|
||||
false,
|
||||
keys,
|
||||
|ids| async move {
|
||||
Ok(closure(ids)
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(key, val)| (key, (None::<String>, val)))
|
||||
.collect())
|
||||
},
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -113,7 +135,13 @@ impl RedisPool {
|
||||
Fut: Future<Output = Result<DashMap<K, (Option<S>, T)>, DatabaseError>>,
|
||||
T: Serialize + DeserializeOwned,
|
||||
I: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
K: Display + Hash + Eq + PartialEq + Clone + DeserializeOwned + Serialize,
|
||||
K: Display
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ PartialEq
|
||||
+ Clone
|
||||
+ DeserializeOwned
|
||||
+ Serialize,
|
||||
S: Display + Clone + DeserializeOwned + Serialize + Debug,
|
||||
{
|
||||
Ok(self
|
||||
@@ -143,7 +171,13 @@ impl RedisPool {
|
||||
Fut: Future<Output = Result<DashMap<K, (Option<S>, T)>, DatabaseError>>,
|
||||
T: Serialize + DeserializeOwned,
|
||||
I: Display + Hash + Eq + PartialEq + Clone + Debug,
|
||||
K: Display + Hash + Eq + PartialEq + Clone + DeserializeOwned + Serialize,
|
||||
K: Display
|
||||
+ Hash
|
||||
+ Eq
|
||||
+ PartialEq
|
||||
+ Clone
|
||||
+ DeserializeOwned
|
||||
+ Serialize,
|
||||
S: Display + Clone + DeserializeOwned + Serialize + Debug,
|
||||
{
|
||||
let connection = self.connect().await?.connection;
|
||||
@@ -158,7 +192,8 @@ impl RedisPool {
|
||||
}
|
||||
|
||||
let get_cached_values =
|
||||
|ids: DashMap<String, I>, mut connection: deadpool_redis::Connection| async move {
|
||||
|ids: DashMap<String, I>,
|
||||
mut connection: deadpool_redis::Connection| async move {
|
||||
let slug_ids = if let Some(slug_namespace) = slug_namespace {
|
||||
cmd("MGET")
|
||||
.arg(
|
||||
@@ -176,7 +211,7 @@ impl RedisPool {
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.query_async::<_, Vec<Option<String>>>(&mut connection)
|
||||
.query_async::<Vec<Option<String>>>(&mut connection)
|
||||
.await?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
@@ -195,15 +230,23 @@ impl RedisPool {
|
||||
.map(|x| x.to_string())
|
||||
}))
|
||||
.chain(slug_ids)
|
||||
.map(|x| format!("{}_{namespace}:{x}", self.meta_namespace))
|
||||
.map(|x| {
|
||||
format!(
|
||||
"{}_{namespace}:{x}",
|
||||
self.meta_namespace
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.query_async::<_, Vec<Option<String>>>(&mut connection)
|
||||
.query_async::<Vec<Option<String>>>(&mut connection)
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|x| {
|
||||
x.and_then(|val| serde_json::from_str::<RedisValue<T, K, S>>(&val).ok())
|
||||
.map(|val| (val.key.clone(), val))
|
||||
x.and_then(|val| {
|
||||
serde_json::from_str::<RedisValue<T, K, S>>(&val)
|
||||
.ok()
|
||||
})
|
||||
.map(|val| (val.key.clone(), val))
|
||||
})
|
||||
.collect::<HashMap<_, _>>();
|
||||
|
||||
@@ -213,11 +256,14 @@ impl RedisPool {
|
||||
let current_time = Utc::now();
|
||||
let mut expired_values = HashMap::new();
|
||||
|
||||
let (cached_values_raw, mut connection, ids) = get_cached_values(ids, connection).await?;
|
||||
let (cached_values_raw, mut connection, ids) =
|
||||
get_cached_values(ids, connection).await?;
|
||||
let mut cached_values = cached_values_raw
|
||||
.into_iter()
|
||||
.filter_map(|(key, val)| {
|
||||
if Utc.timestamp_opt(val.iat + ACTUAL_EXPIRY, 0).unwrap() < current_time {
|
||||
if Utc.timestamp_opt(val.iat + ACTUAL_EXPIRY, 0).unwrap()
|
||||
< current_time
|
||||
{
|
||||
expired_values.insert(val.key.to_string(), val);
|
||||
|
||||
None
|
||||
@@ -244,7 +290,8 @@ impl RedisPool {
|
||||
if !ids.is_empty() {
|
||||
let mut pipe = redis::pipe();
|
||||
|
||||
let fetch_ids = ids.iter().map(|x| x.key().clone()).collect::<Vec<_>>();
|
||||
let fetch_ids =
|
||||
ids.iter().map(|x| x.key().clone()).collect::<Vec<_>>();
|
||||
|
||||
fetch_ids.iter().for_each(|key| {
|
||||
pipe.atomic().set_options(
|
||||
@@ -257,7 +304,7 @@ impl RedisPool {
|
||||
);
|
||||
});
|
||||
let results = pipe
|
||||
.query_async::<_, Vec<Option<i32>>>(&mut connection)
|
||||
.query_async::<Vec<Option<i32>>>(&mut connection)
|
||||
.await?;
|
||||
|
||||
for (idx, key) in fetch_ids.into_iter().enumerate() {
|
||||
@@ -288,12 +335,22 @@ impl RedisPool {
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
let mut fetch_tasks: Vec<
|
||||
Pin<Box<dyn Future<Output = Result<HashMap<K, RedisValue<T, K, S>>, DatabaseError>>>>,
|
||||
Pin<
|
||||
Box<
|
||||
dyn Future<
|
||||
Output = Result<
|
||||
HashMap<K, RedisValue<T, K, S>>,
|
||||
DatabaseError,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
>,
|
||||
> = Vec::new();
|
||||
|
||||
if !ids.is_empty() {
|
||||
fetch_tasks.push(Box::pin(async {
|
||||
let fetch_ids = ids.iter().map(|x| x.value().clone()).collect::<Vec<_>>();
|
||||
let fetch_ids =
|
||||
ids.iter().map(|x| x.value().clone()).collect::<Vec<_>>();
|
||||
|
||||
let vals = closure(fetch_ids).await?;
|
||||
let mut return_values = HashMap::new();
|
||||
@@ -309,7 +366,10 @@ impl RedisPool {
|
||||
};
|
||||
|
||||
pipe.atomic().set_ex(
|
||||
format!("{}_{namespace}:{key}", self.meta_namespace),
|
||||
format!(
|
||||
"{}_{namespace}:{key}",
|
||||
self.meta_namespace
|
||||
),
|
||||
serde_json::to_string(&value)?,
|
||||
DEFAULT_EXPIRY as u64,
|
||||
);
|
||||
@@ -347,23 +407,29 @@ impl RedisPool {
|
||||
let base62 = to_base62(value);
|
||||
ids.remove(&base62);
|
||||
|
||||
pipe.atomic()
|
||||
.del(format!("{}_{namespace}:{base62}/lock", self.meta_namespace));
|
||||
pipe.atomic().del(format!(
|
||||
"{}_{namespace}:{base62}/lock",
|
||||
self.meta_namespace
|
||||
));
|
||||
}
|
||||
|
||||
pipe.atomic()
|
||||
.del(format!("{}_{namespace}:{key}/lock", self.meta_namespace));
|
||||
pipe.atomic().del(format!(
|
||||
"{}_{namespace}:{key}/lock",
|
||||
self.meta_namespace
|
||||
));
|
||||
|
||||
return_values.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
for (key, _) in ids {
|
||||
pipe.atomic()
|
||||
.del(format!("{}_{namespace}:{key}/lock", self.meta_namespace));
|
||||
pipe.atomic().del(format!(
|
||||
"{}_{namespace}:{key}/lock",
|
||||
self.meta_namespace
|
||||
));
|
||||
}
|
||||
|
||||
pipe.query_async(&mut connection).await?;
|
||||
pipe.query_async::<()>(&mut connection).await?;
|
||||
|
||||
Ok(return_values)
|
||||
}));
|
||||
@@ -373,7 +439,8 @@ impl RedisPool {
|
||||
fetch_tasks.push(Box::pin(async {
|
||||
let mut connection = self.pool.get().await?;
|
||||
|
||||
let mut interval = tokio::time::interval(Duration::from_millis(100));
|
||||
let mut interval =
|
||||
tokio::time::interval(Duration::from_millis(100));
|
||||
let start = Utc::now();
|
||||
loop {
|
||||
let results = cmd("MGET")
|
||||
@@ -381,11 +448,15 @@ impl RedisPool {
|
||||
subscribe_ids
|
||||
.iter()
|
||||
.map(|x| {
|
||||
format!("{}_{namespace}:{}/lock", self.meta_namespace, x.key())
|
||||
format!(
|
||||
"{}_{namespace}:{}/lock",
|
||||
self.meta_namespace,
|
||||
x.key()
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.query_async::<_, Vec<Option<String>>>(&mut connection)
|
||||
.query_async::<Vec<Option<String>>>(&mut connection)
|
||||
.await?;
|
||||
|
||||
if results.into_iter().all(|x| x.is_none()) {
|
||||
@@ -399,7 +470,8 @@ impl RedisPool {
|
||||
interval.tick().await;
|
||||
}
|
||||
|
||||
let (return_values, _, _) = get_cached_values(subscribe_ids, connection).await?;
|
||||
let (return_values, _, _) =
|
||||
get_cached_values(subscribe_ids, connection).await?;
|
||||
|
||||
Ok(return_values)
|
||||
}));
|
||||
@@ -436,7 +508,7 @@ impl RedisConnection {
|
||||
]
|
||||
.as_slice(),
|
||||
);
|
||||
redis_execute(&mut cmd, &mut self.connection).await?;
|
||||
redis_execute::<()>(&mut cmd, &mut self.connection).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -468,7 +540,8 @@ impl RedisConnection {
|
||||
let mut cmd = cmd("GET");
|
||||
redis_args(
|
||||
&mut cmd,
|
||||
vec![format!("{}_{}:{}", self.meta_namespace, namespace, id)].as_slice(),
|
||||
vec![format!("{}_{}:{}", self.meta_namespace, namespace, id)]
|
||||
.as_slice(),
|
||||
);
|
||||
let res = redis_execute(&mut cmd, &mut self.connection).await?;
|
||||
Ok(res)
|
||||
@@ -488,16 +561,21 @@ impl RedisConnection {
|
||||
.and_then(|x| serde_json::from_str(&x).ok()))
|
||||
}
|
||||
|
||||
pub async fn delete<T1>(&mut self, namespace: &str, id: T1) -> Result<(), DatabaseError>
|
||||
pub async fn delete<T1>(
|
||||
&mut self,
|
||||
namespace: &str,
|
||||
id: T1,
|
||||
) -> Result<(), DatabaseError>
|
||||
where
|
||||
T1: Display,
|
||||
{
|
||||
let mut cmd = cmd("DEL");
|
||||
redis_args(
|
||||
&mut cmd,
|
||||
vec![format!("{}_{}:{}", self.meta_namespace, namespace, id)].as_slice(),
|
||||
vec![format!("{}_{}:{}", self.meta_namespace, namespace, id)]
|
||||
.as_slice(),
|
||||
);
|
||||
redis_execute(&mut cmd, &mut self.connection).await?;
|
||||
redis_execute::<()>(&mut cmd, &mut self.connection).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -511,14 +589,15 @@ impl RedisConnection {
|
||||
if let Some(id) = id {
|
||||
redis_args(
|
||||
&mut cmd,
|
||||
[format!("{}_{}:{}", self.meta_namespace, namespace, id)].as_slice(),
|
||||
[format!("{}_{}:{}", self.meta_namespace, namespace, id)]
|
||||
.as_slice(),
|
||||
);
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
|
||||
if any {
|
||||
redis_execute(&mut cmd, &mut self.connection).await?;
|
||||
redis_execute::<()>(&mut cmd, &mut self.connection).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -547,6 +626,6 @@ pub async fn redis_execute<T>(
|
||||
where
|
||||
T: redis::FromRedisValue,
|
||||
{
|
||||
let res = cmd.query_async::<_, T>(redis).await?;
|
||||
let res = cmd.query_async::<T>(redis).await?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user