Skip to content

Commit

Permalink
backend/search: add api/handler for search3
Browse files Browse the repository at this point in the history
  • Loading branch information
vnghia committed Nov 27, 2024
1 parent 70ddb37 commit 1131161
Show file tree
Hide file tree
Showing 8 changed files with 188 additions and 1 deletion.
1 change: 1 addition & 0 deletions nghe-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ pub mod media_retrieval;
pub mod music_folder;
pub mod permission;
pub mod scan;
pub mod search;
pub mod system;
pub mod user;
1 change: 1 addition & 0 deletions nghe-api/src/search/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod search3;
33 changes: 33 additions & 0 deletions nghe-api/src/search/search3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use nghe_proc_macro::api_derive;
use uuid::Uuid;

use crate::id3;

#[api_derive]
#[endpoint(path = "search3")]
pub struct Request {
pub query: String,
pub artist_count: Option<u32>,
pub artist_offset: Option<u32>,
pub album_count: Option<u32>,
pub album_offset: Option<u32>,
pub song_count: Option<u32>,
pub song_offset: Option<u32>,
#[serde(rename = "musicFolderId")]
pub music_folder_ids: Option<Vec<Uuid>>,
}

#[serde_with::apply(
Vec => #[serde(skip_serializing_if = "Vec::is_empty")],
)]
#[api_derive(response = true)]
pub struct SearchResult3 {
pub artist: Vec<id3::artist::Artist>,
pub album: Vec<id3::album::Album>,
pub song: Vec<id3::song::Song>,
}

#[api_derive]
pub struct Response {
pub search_result3: SearchResult3,
}
1 change: 1 addition & 0 deletions nghe-backend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ pub async fn build(config: config::Config) -> Router {
.merge(route::browsing::router())
.merge(route::lists::router())
.merge(route::media_annotation::router())
.merge(route::search::router())
.merge(route::system::router())
.with_state(database::Database::new(&config.database))
.layer(TraceLayer::new_for_http().make_span_with(|request: &Request<Body>| {
Expand Down
14 changes: 13 additions & 1 deletion nghe-backend/src/orm/id3/song/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub mod query {
use diesel::dsl::{auto_type, AsSelect};

use super::*;
use crate::orm::{albums, songs_artists};
use crate::orm::{albums, permission, songs_artists};

#[auto_type]
pub fn unchecked_no_group_by() -> _ {
Expand All @@ -126,6 +126,18 @@ pub mod query {
let song: AsSelect<Song, crate::orm::Type> = Song::as_select();
unchecked_no_group_by().group_by(songs::id).select(song)
}

#[auto_type]
pub fn with_user_id(user_id: Uuid) -> _ {
let permission: permission::with_album = permission::with_album(user_id);
unchecked().filter(permission)
}

#[auto_type]
pub fn with_music_folder<'ids>(user_id: Uuid, music_folder_ids: &'ids [Uuid]) -> _ {
let with_user_id: with_user_id = with_user_id(user_id);
with_user_id.filter(albums::music_folder_id.eq_any(music_folder_ids))
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions nghe-backend/src/route/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ pub mod media_retrieval;
pub mod music_folder;
pub mod permission;
pub mod scan;
pub mod search;
pub mod system;
pub mod user;
5 changes: 5 additions & 0 deletions nghe-backend/src/route/search/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod search3;

nghe_proc_macro::build_router! {
modules = [search3],
}
133 changes: 133 additions & 0 deletions nghe-backend/src/route/search/search3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use diesel::{ExpressionMethods, QueryDsl};
use diesel_async::RunQueryDsl;
use diesel_full_text_search::configuration::TsConfigurationByName;
use diesel_full_text_search::{
ts_rank_cd, websearch_to_tsquery_with_search_config, TsVectorExtensions,
};
use nghe_api::search::search3::SearchResult3;
pub use nghe_api::search::search3::{Request, Response};
use nghe_proc_macro::{check_music_folder, handler};
use uuid::Uuid;

use crate::database::Database;
use crate::orm::{albums, artists, id3, songs};
use crate::Error;

const USIMPLE_TS_CONFIGURATION: TsConfigurationByName = TsConfigurationByName("usimple");

#[handler]
pub async fn handler(
database: &Database,
user_id: Uuid,
request: Request,
) -> Result<Response, Error> {
let search_query = &request.query;
let sync = search_query.is_empty() || search_query == "\"\"";

#[check_music_folder]
{
let count = request.artist_count.unwrap_or(20).into();
let artist = if count > 0 {
let offset = request.artist_offset.unwrap_or(0).into();
let query = id3::artist::query::with_user_id(user_id).limit(count).offset(offset);
if sync {
query
.order_by((artists::name, artists::mbz_id))
.get_results(&mut database.get().await?)
.await?
} else {
query
.filter(artists::ts.matches(websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
)))
.order_by(
ts_rank_cd(
artists::ts,
websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
),
)
.desc(),
)
.get_results(&mut database.get().await?)
.await?
}
} else {
vec![]
};

let count = request.album_count.unwrap_or(20).into();
let album = if count > 0 {
let offset = request.album_offset.unwrap_or(0).into();
let query = id3::album::short::query::with_user_id(user_id).limit(count).offset(offset);
if sync {
query
.order_by((albums::name, albums::mbz_id))
.get_results(&mut database.get().await?)
.await?
} else {
query
.filter(albums::ts.matches(websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
)))
.order_by(
ts_rank_cd(
albums::ts,
websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
),
)
.desc(),
)
.get_results(&mut database.get().await?)
.await?
}
} else {
vec![]
};

let count = request.song_count.unwrap_or(20).into();
let song = if count > 0 {
let offset = request.song_offset.unwrap_or(0).into();
let query = id3::song::query::with_user_id(user_id).limit(count).offset(offset);
if sync {
query
.order_by((songs::title, songs::mbz_id))
.get_results(&mut database.get().await?)
.await?
} else {
query
.filter(songs::ts.matches(websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
)))
.order_by(
ts_rank_cd(
songs::ts,
websearch_to_tsquery_with_search_config(
USIMPLE_TS_CONFIGURATION,
search_query,
),
)
.desc(),
)
.get_results(&mut database.get().await?)
.await?
}
} else {
vec![]
};

Ok(Response {
search_result3: SearchResult3 {
artist: artist.into_iter().map(id3::artist::Artist::try_into).try_collect()?,
album: album.into_iter().map(id3::album::short::Short::try_into).try_collect()?,
song: song.into_iter().map(id3::song::Song::try_into).try_collect()?,
},
})
}
}

0 comments on commit 1131161

Please sign in to comment.