Skip to content

Commit

Permalink
Add route to search for repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
0xMimir committed Oct 17, 2023
1 parent 232456b commit c60d748
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 15 deletions.
34 changes: 32 additions & 2 deletions backend/api/src/api/repository/contract.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,56 @@
use error::Result;
use sea_orm::prelude::Uuid;
use store::objects::{GithubIssue, RepositoryView};
use store::objects::{GithubIssue, RepositoryView, SearchRepository};
use support::pagination::Pagination;

use super::data::GetIssuesParams;
use super::data::{GetIssuesParams, SearchRepositoryParams};

#[async_trait]
pub trait DbRepositoryContract {
///
/// Get paginated list of issues for repository
///
async fn get_issues_for_repository(
&self,
repository_id: Uuid,
params: GetIssuesParams,
) -> Result<Pagination<GithubIssue>>;

///
/// Get repository view
///
async fn get_repository(&self, id: Uuid) -> Result<RepositoryView>;

///
/// Search over repositories
///
async fn search_repositories(
&self,
params: SearchRepositoryParams,
) -> Result<Pagination<SearchRepository>>;
}

#[async_trait]
pub trait RepositoryContract {
///
/// Get paginated list of issues for repository
///
async fn get_issues_for_repository(
&self,
repository_id: Uuid,
params: GetIssuesParams,
) -> Result<Pagination<GithubIssue>>;

///
/// Get repository view
///
async fn get_repository(&self, id: Uuid) -> Result<RepositoryView>;

///
/// Search over repositories
///
async fn search_repositories(
&self,
params: SearchRepositoryParams,
) -> Result<Pagination<SearchRepository>>;
}
3 changes: 3 additions & 0 deletions backend/api/src/api/repository/data/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
mod get_issues;
pub use get_issues::{GetIssuesParams, GetIssuesParamsPayload};

mod search;
pub use search::{SearchRepositoryParams, SearchRepositoryParamsPayload};
17 changes: 17 additions & 0 deletions backend/api/src/api/repository/data/search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use sea_orm::prelude::Uuid;
use support::order::Order;
use utoipa::IntoParams;
use validify::Validify;

#[derive(Validify, Deserialize, IntoParams, Debug)]
pub struct SearchRepositoryParams {
pub order_by: Option<String>,
pub order: Option<Order>,
pub page: Option<u64>,
pub per_page: Option<u64>,
pub language: Option<String>,
pub repository: Option<String>,
pub project_id: Option<Uuid>,
pub project: Option<String>,
pub archived: Option<bool>
}
11 changes: 8 additions & 3 deletions backend/api/src/api/repository/docs.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
use super::handlers::*;
use store::objects::{GithubIssue, RepositoryView};
use support::pagination::PaginatedGithubIssue;
use support::pagination::{PaginatedGithubIssue, PaginatedRepositories};
use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
paths(get_issues, get_repository_by_id),
components(schemas(RepositoryView, PaginatedGithubIssue, GithubIssue))
paths(get_issues, get_repository_by_id, get_search),
components(schemas(
RepositoryView,
PaginatedGithubIssue,
GithubIssue,
PaginatedRepositories
))
)]
pub struct RepositoryDocs;
11 changes: 9 additions & 2 deletions backend/api/src/api/repository/domain.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::{
contract::{DbRepositoryContract, RepositoryContract},
data::GetIssuesParams,
data::{GetIssuesParams, SearchRepositoryParams},
};
use error::Result;
use sea_orm::prelude::Uuid;
use store::objects::{GithubIssue, RepositoryView};
use store::objects::{GithubIssue, RepositoryView, SearchRepository};
use support::pagination::Pagination;

pub struct Repository<A: DbRepositoryContract> {
Expand All @@ -26,4 +26,11 @@ impl<A: DbRepositoryContract + Send + Sync> RepositoryContract for Repository<A>
.get_issues_for_repository(repository_id, params)
.await
}

async fn search_repositories(
&self,
params: SearchRepositoryParams,
) -> Result<Pagination<SearchRepository>> {
self.repository.search_repositories(params).await
}
}
3 changes: 3 additions & 0 deletions backend/api/src/api/repository/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@ pub use get_id::{__path_get_repository_by_id, get_repository_by_id};

mod get_issues;
pub use get_issues::{__path_get_issues, get_issues};

mod search;
pub use search::{__path_get_search, get_search};
31 changes: 31 additions & 0 deletions backend/api/src/api/repository/handlers/search.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use actix_web::web::Query;
use actix_web::{web::Data, HttpResponse};
use error::Result;
use validify::Validate;

use super::super::data::{SearchRepositoryParams, SearchRepositoryParamsPayload};

use super::super::contract::RepositoryContract;

#[utoipa::path(
get,
path = "/api/v1/repository/search",
params(SearchRepositoryParams),
responses(
(
status = 200,
description = "Crypto currency data with all full data for repositories",
body = PaginatedRepositories
)
)
)]
pub async fn get_search<S: RepositoryContract>(
service: Data<S>,
params: Query<SearchRepositoryParamsPayload>,
) -> Result<HttpResponse> {
params.validate()?;

let params = params.into_inner().into();
let value = service.search_repositories(params).await?;
Ok(HttpResponse::Ok().json(value))
}
5 changes: 5 additions & 0 deletions backend/api/src/api/repository/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ pub fn setup(conn: Arc<DatabaseConnection>, config: &mut ServiceConfig) {

config.app_data(Data::new(state));

config.service(
resource("/api/{version}/repository/search")
.route(web::get().to(get_search::<Repository<PgRepository>>)),
);

config.service(
resource("/api/{version}/repository/{id}")
.route(web::get().to(get_repository_by_id::<Repository<PgRepository>>)),
Expand Down
88 changes: 84 additions & 4 deletions backend/api/src/api/repository/repository.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@ use error::{Error, Result};
use sea_orm::{
prelude::Uuid,
sea_query::{extension::postgres::PgExpr, Expr},
ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder,
QuerySelect,
ColumnTrait, DatabaseConnection, EntityTrait, IntoSimpleExpr, PaginatorTrait, QueryFilter,
QueryOrder, QuerySelect,
};
use std::sync::Arc;
use store::{
github_projects, github_repositories, issues,
objects::{GithubIssue, RepositoryView},
objects::{GithubIssue, RepositoryView, SearchRepository},
};
use support::pagination::Pagination;

use super::{contract::DbRepositoryContract, data::GetIssuesParams};
use super::{
contract::DbRepositoryContract,
data::{GetIssuesParams, SearchRepositoryParams},
};

pub struct PgRepository {
conn: Arc<DatabaseConnection>,
Expand Down Expand Up @@ -84,4 +87,81 @@ impl DbRepositoryContract for PgRepository {
.await?
.ok_or(Error::NotFoundWithCause(format!("Repository: {}", id)))
}

async fn search_repositories(
&self,
params: SearchRepositoryParams,
) -> Result<Pagination<SearchRepository>> {
let mut query = github_repositories::Entity::find()
.inner_join(github_projects::Entity)
.select_only()
.columns([
github_repositories::Column::Id,
github_repositories::Column::RepositoryName,
github_repositories::Column::Language,
github_repositories::Column::StargazersCount,
github_repositories::Column::ForksCount,
github_repositories::Column::CreatedAt,
github_repositories::Column::UpdatedAt,
github_repositories::Column::Archived,
])
.column_as(github_repositories::Column::Project, "project_id")
.column_as(github_projects::Column::Name, "project")
.column_as(
Expr::cust_with_exprs(
"concat('https://github.com/', $1, '/', $2)",
[
github_projects::Column::Name.into_simple_expr(),
github_repositories::Column::RepositoryName.into_simple_expr(),
],
),
"url",
);

if let Some(language) = params.language {
query = query.filter(github_repositories::Column::Language.eq(language))
}

if let Some(repository) = params.repository {
query = query.filter(
github_repositories::Column::RepositoryName
.into_expr()
.ilike(format!("%{}%", repository)),
);
}

if let Some(archived) = params.archived {
query = query.filter(github_repositories::Column::Archived.eq(archived));
}

if let Some(project_id) = params.project_id {
query = query.filter(github_projects::Column::Id.eq(project_id));
}

if let Some(project) = params.project {
query = query.filter(github_projects::Column::Name.eq(project));
}

let order_by = params.order_by.unwrap_or("updated_at".to_owned());
let order = params.order.unwrap_or(support::order::Order::Desc);
let per_page = params.per_page.unwrap_or(50);
let page = params.page.unwrap_or_default();

let query = query
.order_by(Expr::cust(order_by), order.into())
.into_model::<SearchRepository>()
.paginate(self.conn.as_ref(), per_page);

let pagination = query.num_items_and_pages().await?;
let data = query.fetch_page(page).await?;

Ok(Pagination {
page,
per_page,
order_by: vec![],
data,
total_items: pagination.number_of_items,
last_page: pagination.number_of_pages,
})
}
}
4 changes: 2 additions & 2 deletions backend/libs/sdks/src/coingecko/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl CoinGecko {
StatusCode::NOT_FOUND => return Err(Error::NotFound),
_ => (),
};

let response = response.text().await?;

let error = match serde_json::from_str(&response) {
Expand All @@ -40,7 +40,7 @@ impl CoinGecko {
return Err(error.into());
}

if response == "Throttled" {
if response.contains("Throttled") {
return Err(Error::RateLimitExceeded);
}

Expand Down
1 change: 1 addition & 0 deletions backend/libs/store/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
chrono.workspace = true
sea-orm.workspace = true
serde.workspace = true
serde_json = "1.0.107"
Expand Down
3 changes: 3 additions & 0 deletions backend/libs/store/src/objects/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ pub use issues::GithubIssue;

mod language_count;
pub use language_count::LanguageCount;

mod search_repository;
pub use search_repository::SearchRepository;
18 changes: 18 additions & 0 deletions backend/libs/store/src/objects/search_repository.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use chrono::NaiveDateTime;
use sea_orm::{prelude::Uuid, FromQueryResult};

#[derive(FromQueryResult, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct SearchRepository {
pub id: Uuid,
pub repository_name: String,
pub language: Option<String>,
pub stargazers_count: i64,
pub forks_count: i64,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub archived: bool,
pub project_id: Uuid,
pub project: String,
pub url: String,
}
5 changes: 3 additions & 2 deletions backend/libs/support/src/pagination.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use store::objects::{CryptoCurrencyView, GithubIssue};
use store::objects::{CryptoCurrencyView, GithubIssue, SearchRepository};
use utoipa::ToSchema;

#[derive(Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
#[aliases(
PaginatedCryptoCurrencyView = Pagination<CryptoCurrencyView>,
PaginatedGithubIssue = Pagination<GithubIssue>
PaginatedGithubIssue = Pagination<GithubIssue>,
PaginatedRepositories = Pagination<SearchRepository>
)]
pub struct Pagination<T> {
pub page: u64,
Expand Down

0 comments on commit c60d748

Please sign in to comment.