Skip to content

Commit

Permalink
Collection Inversion Filter (#945)
Browse files Browse the repository at this point in the history
* Added collection inversion filter

* Added a better variable name

* fix(frontend): make select box bigger

* fix(backend): do not force unwrap

* Updated to use Bool instead of string

* fix(frontend): do not send useless redirect parameter

* Removed redundant if statement

* Added inversion filter for people

* Resolved bug where incorrect number of items is shown for people

* do not send useless redirect parameter groups

* Fixed bug where inversion wasnt working in non-metadata searches

* Added Group filters

* Added comments for the new collection filter function since its not clear what the params do

* Linted code

* chore(backend): address minor issues

* fix(frontend): minor typing errors

* fix(frontend): show on filter

* chore(frontend): no conditionals when displaying all collections

* Corrected incorrect column query

* chore(backend): remove comment

* refactor(backend): extract function to utils

---------

Co-authored-by: Diptesh Choudhuri <[email protected]>
  • Loading branch information
Jacob-Tate and IgnisDa authored Aug 9, 2024
1 parent a451df4 commit 2d4da19
Show file tree
Hide file tree
Showing 10 changed files with 335 additions and 79 deletions.
81 changes: 68 additions & 13 deletions apps/backend/src/miscellaneous.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ use crate::{
UserPreferences, UserReviewScale,
},
utils::{
add_entity_to_collection, associate_user_with_entity, entity_in_collections,
get_current_date, get_user_to_entity_association, ilike_sql, user_by_id,
user_id_from_token, AUTHOR, SHOW_SPECIAL_SEASON_NAMES, TEMP_DIR, VERSION,
add_entity_to_collection, apply_collection_filter, associate_user_with_entity,
entity_in_collections, get_current_date, get_user_to_entity_association, ilike_sql,
user_by_id, user_id_from_token, AUTHOR, SHOW_SPECIAL_SEASON_NAMES, TEMP_DIR, VERSION,
},
};

Expand Down Expand Up @@ -541,12 +541,23 @@ struct MetadataListInput {
lot: Option<MediaLot>,
filter: Option<MediaFilter>,
sort: Option<SortInput<MediaSortBy>>,
invert_collection: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, InputObject, Clone)]
struct PeopleListInput {
search: SearchInput,
sort: Option<SortInput<PersonSortBy>>,
filter: Option<MediaFilter>,
invert_collection: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, InputObject, Clone)]
struct MetadataGroupsListInput {
search: SearchInput,
sort: Option<SortInput<PersonSortBy>>,
filter: Option<MediaFilter>,
invert_collection: Option<bool>,
}

#[derive(Debug, Serialize, Deserialize, InputObject, Clone)]
Expand Down Expand Up @@ -919,7 +930,7 @@ impl MiscellaneousQuery {
async fn metadata_groups_list(
&self,
gql_ctx: &Context<'_>,
input: SearchInput,
input: MetadataGroupsListInput,
) -> Result<SearchResults<String>> {
let service = gql_ctx.data_unchecked::<Arc<MiscellaneousService>>();
let user_id = self.user_id_from_ctx(gql_ctx).await?;
Expand Down Expand Up @@ -2287,9 +2298,13 @@ impl MiscellaneousService {
.apply_if(
input.filter.clone().and_then(|f| f.collection),
|query, v| {
query
.inner_join(CollectionToEntity)
.filter(collection_to_entity::Column::CollectionId.eq(v))
apply_collection_filter(
query,
Some(v),
input.invert_collection,
metadata::Column::Id,
collection_to_entity::Column::MetadataId,
)
},
)
.apply_if(input.filter.and_then(|f| f.general), |query, v| match v {
Expand Down Expand Up @@ -6377,19 +6392,47 @@ impl MiscellaneousService {
async fn metadata_groups_list(
&self,
user_id: String,
input: SearchInput,
input: MetadataGroupsListInput,
) -> Result<SearchResults<String>> {
let page: u64 = input.page.unwrap_or(1).try_into().unwrap();
let page: u64 = input.search.page.unwrap_or(1).try_into().unwrap();
let alias = "parts";
let media_items_col = Expr::col(Alias::new(alias));
let (order_by, sort_order) = match input.sort {
None => (media_items_col, Order::Desc),
Some(ord) => (
match ord.by {
PersonSortBy::Name => Expr::col(metadata_group::Column::Title),
PersonSortBy::MediaItems => media_items_col,
},
ord.order.into(),
),
};
let query = MetadataGroup::find()
.apply_if(input.query, |query, v| {
.select_only()
.column(metadata_group::Column::Id)
.group_by(metadata_group::Column::Id)
.inner_join(UserToEntity)
.filter(user_to_entity::Column::UserId.eq(&user_id))
.filter(metadata_group::Column::Id.is_not_null())
.apply_if(input.search.query, |query, v| {
query.filter(
Condition::all()
.add(Expr::col(metadata_group::Column::Title).ilike(ilike_sql(&v))),
)
})
.filter(user_to_entity::Column::UserId.eq(user_id))
.inner_join(UserToEntity)
.order_by_asc(metadata_group::Column::Title);
.apply_if(
input.filter.clone().and_then(|f| f.collection),
|query, v| {
apply_collection_filter(
query,
Some(v),
input.invert_collection,
metadata_group::Column::Id,
collection_to_entity::Column::MetadataGroupId,
)
},
)
.order_by(order_by, sort_order);
let paginator = query
.column(metadata_group::Column::Id)
.clone()
Expand Down Expand Up @@ -6444,6 +6487,18 @@ impl MiscellaneousService {
Condition::all().add(Expr::col(person::Column::Name).ilike(ilike_sql(&v))),
)
})
.apply_if(
input.filter.clone().and_then(|f| f.collection),
|query, v| {
apply_collection_filter(
query,
Some(v),
input.invert_collection,
person::Column::Id,
collection_to_entity::Column::PersonId,
)
},
)
.column_as(
Expr::expr(Func::count(Expr::col((
Alias::new("metadata_to_person"),
Expand Down
29 changes: 28 additions & 1 deletion apps/backend/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use reqwest::{
use rs_utils::PROJECT_NAME;
use sea_orm::{
ActiveModelTrait, ActiveValue, ColumnTrait, ConnectionTrait, DatabaseConnection, EntityTrait,
QueryFilter,
QueryFilter, QuerySelect, QueryTrait, Select,
};

use crate::{
Expand Down Expand Up @@ -361,6 +361,33 @@ pub async fn add_entity_to_collection(
Ok(resp)
}

pub fn apply_collection_filter<E, C, D>(
query: Select<E>,
collection_id: Option<String>,
invert_collection: Option<bool>,
entity_column: C,
id_column: D,
) -> Select<E>
where
E: EntityTrait,
C: ColumnTrait,
D: ColumnTrait,
{
query.apply_if(collection_id, |query, v| {
let subquery = CollectionToEntity::find()
.select_only()
.column(id_column)
.filter(collection_to_entity::Column::CollectionId.eq(v))
.filter(id_column.is_not_null())
.into_query();
if invert_collection.unwrap_or_default() {
query.filter(entity_column.not_in_subquery(subquery))
} else {
query.filter(entity_column.in_subquery(subquery))
}
})
}

pub fn get_current_date(timezone: &chrono_tz::Tz) -> NaiveDate {
Utc::now().with_timezone(timezone).date_naive()
}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/components/media.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ export const PersonDisplayItem = (props: {
imageUrl={personDetails?.details.displayImages.at(0)}
labels={{
left: personDetails
? `${personDetails.contents.length} items`
? `${personDetails.contents.reduce((sum, content) => sum + content.items.length, 0)} items`
: undefined,
right: props.rightLabel,
}}
Expand Down
32 changes: 15 additions & 17 deletions apps/frontend/app/routes/_dashboard.fitness.exercises.list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -363,23 +363,21 @@ const FiltersModalForm = () => {
onChange={(v) => setP(f, v)}
/>
))}
{collections.length > 0 ? (
<Select
label="Collection"
defaultValue={loaderData.query.collection?.toString()}
data={[
{
group: "My collections",
items: collections.map((c) => ({
value: c.id.toString(),
label: c.name,
})),
},
]}
onChange={(v) => setP("collection", v)}
clearable
/>
) : null}
<Select
label="Collection"
defaultValue={loaderData.query.collection?.toString()}
data={[
{
group: "My collections",
items: collections.map((c) => ({
value: c.id.toString(),
label: c.name,
})),
},
]}
onChange={(v) => setP("collection", v)}
clearable
/>
</Stack>
</MantineThemeProvider>
);
Expand Down
13 changes: 11 additions & 2 deletions apps/frontend/app/routes/_dashboard.media.$action.$lot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Box,
Button,
Center,
Checkbox,
Container,
Flex,
Group,
Expand Down Expand Up @@ -135,6 +136,7 @@ export const loader = unstable_defineLoader(async ({ request, params }) => {
.nativeEnum(MediaGeneralFilter)
.default(defaultFilters.mineGeneralFilter),
collection: z.string().optional(),
invertCollection: zx.BoolAsString.optional(),
});
const { metadataList } = await serverGqlService.authenticatedRequest(
request,
Expand All @@ -148,6 +150,7 @@ export const loader = unstable_defineLoader(async ({ request, params }) => {
general: urlParse.generalFilter,
collection: urlParse.collection,
},
invertCollection: urlParse.invertCollection,
},
},
);
Expand Down Expand Up @@ -574,8 +577,9 @@ const FiltersModalForm = () => {
)}
</ActionIcon>
</Flex>
{collections.length > 0 ? (
<Flex gap="xs" align="center">
<Select
flex={1}
placeholder="Select a collection"
defaultValue={loaderData.mediaList.url.collection?.toString()}
data={[
Expand All @@ -591,7 +595,12 @@ const FiltersModalForm = () => {
clearable
searchable
/>
) : null}
<Checkbox
label="Invert"
checked={loaderData.mediaList.url.invertCollection}
onChange={(e) => setP("invertCollection", String(e.target.checked))}
/>
</Flex>
</>
);
};
Loading

0 comments on commit 2d4da19

Please sign in to comment.