Fix clippy errors + lint, use turbo CI

This commit is contained in:
Jai A
2024-10-18 16:07:35 -07:00
parent 663ab83b08
commit 8dd955563e
186 changed files with 10615 additions and 6433 deletions

View File

@@ -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)

View File

@@ -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()

View File

@@ -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?;

View File

@@ -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?;

View File

@@ -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);

View File

@@ -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?;

View File

@@ -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!({

View File

@@ -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()
}
}
}

View File

@@ -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(())

View File

@@ -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 {

View File

@@ -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};

View File

@@ -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,

View File

@@ -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(())

View File

@@ -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>,
{

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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!(

View File

@@ -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(())
}

View File

@@ -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
};

View File

@@ -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?;

View File

@@ -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!(

View File

@@ -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()

View File

@@ -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,

View File

@@ -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")

View File

@@ -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)
}