diff --git a/registry/sqlx-data.json b/registry/sqlx-data.json index 07356fa9..08c5cd4d 100644 --- a/registry/sqlx-data.json +++ b/registry/sqlx-data.json @@ -714,6 +714,26 @@ }, "query": "SELECT name FROM extensions WHERE id = $1" }, + "77bc7af1c8979c4519568aa27fb67eb5a9eb32dc126321999e8ed545f7d320df": { + "describe": { + "columns": [ + { + "name": "result", + "ordinal": 0, + "type_info": "Json" + } + ], + "nullable": [ + null + ], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "SELECT\n json_build_object(\n 'name', tpv.trunk_project_name,\n 'description', tpv.description,\n 'version', tpv.version,\n 'documentation_link', tpv.documentation_link,\n 'repository_link', tpv.repository_link,\n 'extensions', (\n SELECT json_agg(json_build_object(\n 'extension_name', ev.extension_name,\n 'version', ev.version,\n 'trunk_project_name', tpv.trunk_project_name,\n 'dependencies_extension_names', (\n SELECT json_agg(ed.depends_on_extension_name)\n FROM v1.extension_dependency ed\n WHERE ed.extension_version_id = ev.id\n ),\n 'requires_restart', (\n SELECT CASE\n WHEN count(*) > 0 THEN true\n ELSE false\n END\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\n AND requires_restart = true\n ),\n 'configurations', (\n SELECT json_agg(json_build_object(\n 'name', ec.configuration_name,\n 'is_required', ec.is_required,\n 'recommended_default', ec.recommended_default_value\n ))\n FROM v1.extension_configurations ec\n WHERE ec.extension_version_id = ev.id\n )\n ))\n FROM v1.extension_versions ev\n WHERE ev.trunk_project_version_id = tpv.id\n )\n ) AS result\n FROM\n v1.trunk_project_versions tpv\n WHERE\n tpv.trunk_project_name = $1" + }, "7a931ec93bcc1516737bfc65fd24b339401996a7f23891c7770a3b5b5c79ffc2": { "describe": { "columns": [ @@ -1074,6 +1094,27 @@ }, "query": "SELECT id, repository FROM extensions WHERE extensions.name = $1" }, + "ab5d2b882cb1fc20e95568c00cc8f47299072f1d65009b3e43dd29503962645c": { + "describe": { + "columns": [ + { + "name": "result", + "ordinal": 0, + "type_info": "Json" + } + ], + "nullable": [ + null + ], + "parameters": { + "Left": [ + "Text", + "Text" + ] + } + }, + "query": "SELECT json_build_object(\n 'name', tpv.trunk_project_name,\n 'description', tpv.description,\n 'version', tpv.version,\n 'documentation_link', tpv.documentation_link,\n 'repository_link', tpv.repository_link,\n 'extensions', (\n SELECT json_agg(json_build_object(\n 'extension_name', ev.extension_name,\n 'version', ev.version,\n 'trunk_project_name', tpv.trunk_project_name,\n 'dependencies_extension_names', (\n SELECT json_agg(ed.depends_on_extension_name)\n FROM v1.extension_dependency ed\n WHERE ed.extension_version_id = ev.id\n ),\n 'requires_restart', (\n SELECT CASE\n WHEN count(*) > 0 THEN true\n ELSE false\n END\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\n AND requires_restart = true\n ),\n 'configurations', (\n SELECT json_agg(json_build_object(\n 'name', ec.configuration_name,\n 'is_required', ec.is_required,\n 'recommended_default', ec.recommended_default_value\n ))\n FROM v1.extension_configurations ec\n WHERE ec.extension_version_id = ev.id\n )\n ))\n FROM v1.extension_versions ev\n WHERE ev.trunk_project_version_id = tpv.id\n )\n ) AS result\n FROM\n v1.trunk_project_versions tpv\n WHERE\n tpv.trunk_project_name = $1\n AND tpv.version = $2" + }, "ac75c8170d5f5bc2fa5c48cdec0ec8899a2cfd1fd679e3656fe95c19650e5bd3": { "describe": { "columns": [ diff --git a/registry/src/server.rs b/registry/src/server.rs index aeffcf2c..6a74fd3f 100644 --- a/registry/src/server.rs +++ b/registry/src/server.rs @@ -32,7 +32,12 @@ pub fn routes_config(configuration: &mut web::ServiceConfig) { .service(routes::extensions::delete_extension) .service(routes::extensions::put_shared_preload_libraries), ) - .service(web::scope("/api/v1").service(v1::routes::all_trunk_projects)); + .service( + web::scope("/api/v1") + .service(v1::routes::all_trunk_projects) + .service(v1::routes::trunk_projects_by_name) + .service(v1::routes::trunk_project_by_name_and_version), + ); } pub async fn server() -> std::io::Result<()> { diff --git a/registry/src/v1/repository.rs b/registry/src/v1/repository.rs index 34575087..3dbf2977 100644 --- a/registry/src/v1/repository.rs +++ b/registry/src/v1/repository.rs @@ -160,4 +160,128 @@ impl Registry { .flat_map(serde_json::from_value) .collect()) } + + pub async fn trunk_projects_by_name( + &self, + trunk_project_name: &str, + ) -> Result> { + let records = sqlx::query!( + "SELECT + json_build_object( + 'name', tpv.trunk_project_name, + 'description', tpv.description, + 'version', tpv.version, + 'documentation_link', tpv.documentation_link, + 'repository_link', tpv.repository_link, + 'extensions', ( + SELECT json_agg(json_build_object( + 'extension_name', ev.extension_name, + 'version', ev.version, + 'trunk_project_name', tpv.trunk_project_name, + 'dependencies_extension_names', ( + SELECT json_agg(ed.depends_on_extension_name) + FROM v1.extension_dependency ed + WHERE ed.extension_version_id = ev.id + ), + 'requires_restart', ( + SELECT CASE + WHEN count(*) > 0 THEN true + ELSE false + END + FROM v1.extensions_loadable_libraries ell + WHERE ell.extension_version_id = ev.id + AND requires_restart = true + ), + 'configurations', ( + SELECT json_agg(json_build_object( + 'name', ec.configuration_name, + 'is_required', ec.is_required, + 'recommended_default', ec.recommended_default_value + )) + FROM v1.extension_configurations ec + WHERE ec.extension_version_id = ev.id + ) + )) + FROM v1.extension_versions ev + WHERE ev.trunk_project_version_id = tpv.id + ) + ) AS result + FROM + v1.trunk_project_versions tpv + WHERE + tpv.trunk_project_name = $1", + trunk_project_name + ) + .fetch_all(&self.pool) + .await?; + + Ok(records + .into_iter() + .flat_map(|record| record.result) + .flat_map(serde_json::from_value) + .collect()) + } + + pub async fn trunk_projects_by_name_and_version( + &self, + trunk_project_name: &str, + trunk_project_version: &str, + ) -> Result> { + let records = sqlx::query!( + "SELECT json_build_object( + 'name', tpv.trunk_project_name, + 'description', tpv.description, + 'version', tpv.version, + 'documentation_link', tpv.documentation_link, + 'repository_link', tpv.repository_link, + 'extensions', ( + SELECT json_agg(json_build_object( + 'extension_name', ev.extension_name, + 'version', ev.version, + 'trunk_project_name', tpv.trunk_project_name, + 'dependencies_extension_names', ( + SELECT json_agg(ed.depends_on_extension_name) + FROM v1.extension_dependency ed + WHERE ed.extension_version_id = ev.id + ), + 'requires_restart', ( + SELECT CASE + WHEN count(*) > 0 THEN true + ELSE false + END + FROM v1.extensions_loadable_libraries ell + WHERE ell.extension_version_id = ev.id + AND requires_restart = true + ), + 'configurations', ( + SELECT json_agg(json_build_object( + 'name', ec.configuration_name, + 'is_required', ec.is_required, + 'recommended_default', ec.recommended_default_value + )) + FROM v1.extension_configurations ec + WHERE ec.extension_version_id = ev.id + ) + )) + FROM v1.extension_versions ev + WHERE ev.trunk_project_version_id = tpv.id + ) + ) AS result + FROM + v1.trunk_project_versions tpv + WHERE + tpv.trunk_project_name = $1 + AND tpv.version = $2", + trunk_project_name, + trunk_project_version + ) + .fetch_all(&self.pool) + .await?; + + Ok(records + .into_iter() + .flat_map(|record| record.result) + .flat_map(serde_json::from_value) + .collect()) + } } diff --git a/registry/src/v1/routes.rs b/registry/src/v1/routes.rs index 427c6462..4b511505 100644 --- a/registry/src/v1/routes.rs +++ b/registry/src/v1/routes.rs @@ -8,7 +8,7 @@ use crate::{errors::Result, repository::Registry, v1::repository::TrunkProjectVi #[derive(Debug, Deserialize)] #[serde(rename_all = "kebab-case")] -pub struct Params { +pub struct ExtensionNameQueryParams { extension_name: Option, } @@ -19,10 +19,8 @@ pub struct Params { #[get("/trunk-projects")] pub async fn all_trunk_projects( registry: web::Data, - query: web::Query, + query: web::Query, ) -> Result>> { - tracing::info!("Got params: {:?}", query); - tracing::info!("Query is {:?}", query.extension_name); if let Some(extension_name) = &query.extension_name { let trunk_projects = registry .trunk_projects_by_extension_name(extension_name) @@ -33,3 +31,29 @@ pub async fn all_trunk_projects( Ok(Json(trunk_projects)) } } + +/// Retrieve a list of all versions of the Trunk project with the given name. +#[get("/trunk-projects/{trunk_project_name}")] +pub async fn trunk_projects_by_name( + registry: web::Data, + path: web::Path, +) -> Result>> { + let trunk_project_name = path.into_inner(); + let trunk_projects = registry.trunk_projects_by_name(&trunk_project_name).await?; + + Ok(Json(trunk_projects)) +} + +/// Retrieve info on the Trunk project with the given name and version +#[get("/trunk-projects/{trunk_project_name}/version/{version}")] +pub async fn trunk_project_by_name_and_version( + registry: web::Data, + path: web::Path<(String, String)>, +) -> Result>> { + let (trunk_project_name, trunk_project_version) = path.into_inner(); + let trunk_projects = registry + .trunk_projects_by_name_and_version(&trunk_project_name, &trunk_project_version) + .await?; + + Ok(Json(trunk_projects)) +}