diff --git a/registry/sqlx-data.json b/registry/sqlx-data.json index 08c5cd4d..679efef3 100644 --- a/registry/sqlx-data.json +++ b/registry/sqlx-data.json @@ -60,24 +60,6 @@ }, "query": "DELETE FROM extensions\n WHERE id = $1" }, - "0898c1efb7b3be44bf5be61c5e3d2c3de6ddfadca25aad79963c7e435101d12e": { - "describe": { - "columns": [ - { - "name": "result", - "ordinal": 0, - "type_info": "Json" - } - ], - "nullable": [ - null - ], - "parameters": { - "Left": [] - } - }, - "query": "\n SELECT\n json_build_object(\n 'name', tp.name,\n 'description', latest_tpvs.description,\n 'documentation_link', latest_tpvs.documentation_link,\n 'repository_link', latest_tpvs.repository_link,\n 'version', latest_tpvs.version,\n 'extensions', (\n SELECT json_agg(json_build_object(\n 'extension_name', ev.extension_name,\n 'version', ev.version,\n 'trunk_project_name', tp.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 = latest_tpvs.id\n )\n ) AS result\n FROM\n v1.trunk_project tp\n JOIN (\n SELECT tpv.*\n FROM v1.trunk_project_versions tpv\n JOIN (\n SELECT trunk_project_name, MAX(string_to_array(version, '.')::int[]) as max_version\n FROM v1.trunk_project_versions\n GROUP BY trunk_project_name\n ) sub_tpv\n ON tpv.trunk_project_name = sub_tpv.trunk_project_name\n AND string_to_array(tpv.version, '.')::int[] = sub_tpv.max_version\n ) latest_tpvs\n ON tp.name = latest_tpvs.trunk_project_name\n ORDER BY tp.name" - }, "0a50fee432e167aa3029cebb8c6393ec5ef754131301b698199a4fefa43e2e33": { "describe": { "columns": [], @@ -97,6 +79,28 @@ }, "query": "\n INSERT INTO versions(extension_id, num, created_at, yanked, license, published_by, extension_name, system_dependencies, libraries)\n VALUES ($1, $2, (now() at time zone 'utc'), $3, $4, $5, $6, $7::jsonb, $8::jsonb)\n " }, + "0ded5a80e97ecba538fd7aa7ab891eda7a8f0376764d08251786189c58a30116": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text", + "Int4", + "Text" + ] + } + }, + "query": "INSERT INTO v1.extension_versions (extension_name, trunk_project_version_id, version)\n VALUES ($1, $2, $3)\n ON CONFLICT (extension_name, trunk_project_version_id, version) \n DO NOTHING\n RETURNING id" + }, "12ce7de3da92187f4468a89f5e1795da2b0471f90373200a5870448dae264aa0": { "describe": { "columns": [ @@ -406,6 +410,26 @@ }, "query": "UPDATE versions\n SET updated_at = (now() at time zone 'utc'), license = $1, published_by = $2, extension_name = $5, system_dependencies = $6::jsonb, libraries = $7::jsonb\n WHERE extension_id = $3\n AND num = $4" }, + "33dbfeede4d01448246b1c6741efb4655302625534140ec6be0ecf5e1ed43aa1": { + "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 'loadable_libraries', (\n SELECT json_agg(json_build_object(\n 'library_name', ell.library_name,\n 'requires_restart', ell.requires_restart,\n 'priority', ell.priority\n ))\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\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" + }, "36bc3613b2f0f2bf8347edc3ddc1c117a164f45f16195ff92c05f2eb764779bd": { "describe": { "columns": [ @@ -518,6 +542,27 @@ }, "query": "SELECT user_name\n FROM api_tokens\n WHERE\n token = $1" }, + "44f8993884a03b9b1bd8b8197a31fadd834fd4d029d40d4c83a13c0e6a48bc28": { + "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 'loadable_libraries', (\n SELECT json_agg(json_build_object(\n 'library_name', ell.library_name,\n 'requires_restart', ell.requires_restart,\n 'priority', ell.priority\n ))\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\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" + }, "49a41631cfe21efe58022e6e4026e6f3d388d8bb12ac478dbf30addab78d430e": { "describe": { "columns": [ @@ -644,6 +689,21 @@ }, "query": "SELECT id FROM extensions WHERE name = $1" }, + "580c2476466e3831640ab78b7f314d258f6f26b305ebd798a2bcdf06fbd0b01c": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4", + "Bool", + "Text", + "Text" + ] + } + }, + "query": "INSERT INTO v1.extension_configurations (extension_version_id, is_required, configuration_name, recommended_default_value)\n VALUES ($1, $2, $3, $4)" + }, "6991d9aae9d130b3d209ea5816847f661979e07c07f754c15e9b05eee3d61cb6": { "describe": { "columns": [ @@ -714,26 +774,6 @@ }, "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": [ @@ -955,6 +995,18 @@ }, "query": "SELECT * FROM versions WHERE extension_id = $1" }, + "7fa6e9c87a3295c5e95d71b9cad78194203613d041aea85816a4a71c3f4ac3df": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Text" + ] + } + }, + "query": "INSERT INTO v1.trunk_project (name) \n VALUES ($1)\n ON CONFLICT (name) DO NOTHING" + }, "805d20f064e4a323d42c611f4719bd0fa4c152c330ff572609310fa306971468": { "describe": { "columns": [], @@ -969,6 +1021,19 @@ }, "query": "\n INSERT INTO api_tokens(user_id, user_name, token, created_at)\n VALUES ($1, $2, $3, (now() at time zone 'utc'))\n " }, + "8937136b4deb49610728a789a022f48c42064d13df598b8c38a90662443f02ae": { + "describe": { + "columns": [], + "nullable": [], + "parameters": { + "Left": [ + "Int4", + "Text" + ] + } + }, + "query": "INSERT INTO v1.extension_dependency (extension_version_id, depends_on_extension_name)\n VALUES ($1, $2)" + }, "8a3643fa646f1768ce6b3abdc949b6daade8f796a8f2b9a388f436e486425299": { "describe": { "columns": [], @@ -1094,7 +1159,7 @@ }, "query": "SELECT id, repository FROM extensions WHERE extensions.name = $1" }, - "ab5d2b882cb1fc20e95568c00cc8f47299072f1d65009b3e43dd29503962645c": { + "a8a9f2cc263abfb2cb9153fd30854c7aaf6977221746b18ebf45af67baf32768": { "describe": { "columns": [ { @@ -1107,13 +1172,10 @@ null ], "parameters": { - "Left": [ - "Text", - "Text" - ] + "Left": [] } }, - "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" + "query": "\n SELECT\n json_build_object(\n 'name', tp.name,\n 'description', latest_tpvs.description,\n 'documentation_link', latest_tpvs.documentation_link,\n 'repository_link', latest_tpvs.repository_link,\n 'version', latest_tpvs.version,\n 'extensions', (\n SELECT json_agg(json_build_object(\n 'extension_name', ev.extension_name,\n 'version', ev.version,\n 'trunk_project_name', tp.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 'loadable_libraries', (\n SELECT json_agg(json_build_object(\n 'library_name', ell.library_name,\n 'requires_restart', ell.requires_restart,\n 'priority', ell.priority\n ))\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\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 = latest_tpvs.id\n )\n ) AS result\n FROM\n v1.trunk_project tp\n JOIN (\n SELECT tpv.*\n FROM v1.trunk_project_versions tpv\n JOIN (\n SELECT trunk_project_name, MAX(string_to_array(version, '.')::int[]) as max_version\n FROM v1.trunk_project_versions\n GROUP BY trunk_project_name\n ) sub_tpv\n ON tpv.trunk_project_name = sub_tpv.trunk_project_name\n AND string_to_array(tpv.version, '.')::int[] = sub_tpv.max_version\n ) latest_tpvs\n ON tp.name = latest_tpvs.trunk_project_name\n ORDER BY tp.name" }, "ac75c8170d5f5bc2fa5c48cdec0ec8899a2cfd1fd679e3656fe95c19650e5bd3": { "describe": { @@ -1250,6 +1312,30 @@ }, "query": "DELETE FROM extension_owners\n WHERE extension_id = $1" }, + "bec42c1371290afccacf2534f6e80c397d562b5b878f335690734bb22d2a6e9f": { + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Int4" + } + ], + "nullable": [ + false + ], + "parameters": { + "Left": [ + "Text", + "Text", + "Text", + "Text", + "Text" + ] + } + }, + "query": "INSERT INTO v1.trunk_project_versions (trunk_project_name, version, description, repository_link, documentation_link)\n VALUES ($1, $2, $3, $4, $5)\n RETURNING id" + }, "c390e218569ef66621ae5e01addfe5ee1d83cd86496f388846604862bd3510c4": { "describe": { "columns": [ @@ -1328,25 +1414,20 @@ }, "query": "SELECT * FROM extension_detail_vw" }, - "c784f637020112a948971e733b1973d3092af511541f9ba8272509f460a1d586": { + "cff34205e2334651e696df107dac775cff18f102ca67898d9d68303ddfa314c5": { "describe": { - "columns": [ - { - "name": "result", - "ordinal": 0, - "type_info": "Json" - } - ], - "nullable": [ - null - ], + "columns": [], + "nullable": [], "parameters": { "Left": [ - "Text" + "Int4", + "Text", + "Bool", + "Int4" ] } }, - "query": "SELECT\n json_build_object(\n 'name', tpv.trunk_project_name,\n 'description', tpv.description,\n 'documentation_link', tpv.documentation_link,\n 'repository_link', tpv.repository_link,\n 'version', tpv.version,\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 JOIN v1.extension_versions ev ON ev.trunk_project_version_id = tpv.id\n JOIN (\n SELECT extension_name, MAX(string_to_array(version, '.')::int[]) as max_version\n FROM v1.extension_versions\n WHERE extension_name = $1\n GROUP BY extension_name\n ) sub_ev ON ev.extension_name = sub_ev.extension_name AND string_to_array(ev.version, '.')::int[] = sub_ev.max_version\n " + "query": "INSERT INTO v1.extensions_loadable_libraries (extension_version_id, library_name, requires_restart, priority)\n VALUES ($1, $2, $3, $4)" }, "e41ccd0b4b07c1761d78d4de2efdba33979114f1b055db3261af653afca8be56": { "describe": { @@ -1367,6 +1448,26 @@ }, "query": "\n INSERT INTO versions(extension_id, num, created_at, yanked, license, published_by, extension_name, system_dependencies, libraries)\n VALUES ($1, $2, (now() at time zone 'utc'), $3, $4, $5, $6, $7::jsonb, $8::jsonb)\n " }, + "e76de020f649e65247b5b4d24346eddbf53fe5d28cb97e4b96ad27caa800550d": { + "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 'documentation_link', tpv.documentation_link,\n 'repository_link', tpv.repository_link,\n 'version', tpv.version,\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 'loadable_libraries', (\n SELECT json_agg(json_build_object(\n 'library_name', ell.library_name,\n 'requires_restart', ell.requires_restart,\n 'priority', ell.priority\n ))\n FROM v1.extensions_loadable_libraries ell\n WHERE ell.extension_version_id = ev.id\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 JOIN v1.extension_versions ev ON ev.trunk_project_version_id = tpv.id\n JOIN (\n SELECT extension_name, MAX(string_to_array(version, '.')::int[]) as max_version\n FROM v1.extension_versions\n WHERE extension_name = $1\n GROUP BY extension_name\n ) sub_ev ON ev.extension_name = sub_ev.extension_name AND string_to_array(ev.version, '.')::int[] = sub_ev.max_version\n " + }, "f29a9769c67e94ef0eb534c3ea009496dc13426c6d46f545ada1f9ebc9def26b": { "describe": { "columns": [], diff --git a/registry/src/server.rs b/registry/src/server.rs index 6a74fd3f..74b9c42b 100644 --- a/registry/src/server.rs +++ b/registry/src/server.rs @@ -27,7 +27,7 @@ pub fn routes_config(configuration: &mut web::ServiceConfig) { ) .service( web::scope("/admin") - .wrap(ClerkMiddleware::new(clerk_cfg, None, false)) + .wrap(ClerkMiddleware::new(clerk_cfg.clone(), None, false)) .service(routes::root::auth_ok) .service(routes::extensions::delete_extension) .service(routes::extensions::put_shared_preload_libraries), @@ -37,6 +37,11 @@ pub fn routes_config(configuration: &mut web::ServiceConfig) { .service(v1::routes::all_trunk_projects) .service(v1::routes::trunk_projects_by_name) .service(v1::routes::trunk_project_by_name_and_version), + ) + .service( + web::scope("/admin/api/v1") + .wrap(ClerkMiddleware::new(clerk_cfg, None, false)) + .service(v1::routes::insert_trunk_project), ); } diff --git a/registry/src/v1/repository.rs b/registry/src/v1/repository.rs index 3dbf2977..abac7d33 100644 --- a/registry/src/v1/repository.rs +++ b/registry/src/v1/repository.rs @@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize}; use crate::errors::Result; use crate::repository::Registry; -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct TrunkProjectView { pub name: String, pub description: String, @@ -20,13 +20,20 @@ pub struct ExtensionConfigurationView { pub recommended_default: Option, } -#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ExtensionPreloadLibrariesView { + library_name: String, + requires_restart: bool, + priority: i32, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ExtensionView { pub extension_name: String, pub version: String, pub trunk_project_name: String, pub dependencies_extension_names: Option>, - pub requires_restart: bool, + pub loadable_libraries: Option>, pub configurations: Option>, } @@ -50,14 +57,14 @@ impl Registry { FROM v1.extension_dependency ed WHERE ed.extension_version_id = ev.id ), - 'requires_restart', ( - SELECT CASE - WHEN count(*) > 0 THEN true - ELSE false - END + 'loadable_libraries', ( + SELECT json_agg(json_build_object( + 'library_name', ell.library_name, + 'requires_restart', ell.requires_restart, + 'priority', ell.priority + )) FROM v1.extensions_loadable_libraries ell WHERE ell.extension_version_id = ev.id - AND requires_restart = true ), 'configurations', ( SELECT json_agg(json_build_object( @@ -119,14 +126,14 @@ impl Registry { FROM v1.extension_dependency ed WHERE ed.extension_version_id = ev.id ), - 'requires_restart', ( - SELECT CASE - WHEN count(*) > 0 THEN true - ELSE false - END + 'loadable_libraries', ( + SELECT json_agg(json_build_object( + 'library_name', ell.library_name, + 'requires_restart', ell.requires_restart, + 'priority', ell.priority + )) FROM v1.extensions_loadable_libraries ell WHERE ell.extension_version_id = ev.id - AND requires_restart = true ), 'configurations', ( SELECT json_agg(json_build_object( @@ -183,14 +190,14 @@ impl Registry { FROM v1.extension_dependency ed WHERE ed.extension_version_id = ev.id ), - 'requires_restart', ( - SELECT CASE - WHEN count(*) > 0 THEN true - ELSE false - END + 'loadable_libraries', ( + SELECT json_agg(json_build_object( + 'library_name', ell.library_name, + 'requires_restart', ell.requires_restart, + 'priority', ell.priority + )) FROM v1.extensions_loadable_libraries ell WHERE ell.extension_version_id = ev.id - AND requires_restart = true ), 'configurations', ( SELECT json_agg(json_build_object( @@ -244,14 +251,14 @@ impl Registry { FROM v1.extension_dependency ed WHERE ed.extension_version_id = ev.id ), - 'requires_restart', ( - SELECT CASE - WHEN count(*) > 0 THEN true - ELSE false - END + 'loadable_libraries', ( + SELECT json_agg(json_build_object( + 'library_name', ell.library_name, + 'requires_restart', ell.requires_restart, + 'priority', ell.priority + )) FROM v1.extensions_loadable_libraries ell WHERE ell.extension_version_id = ev.id - AND requires_restart = true ), 'configurations', ( SELECT json_agg(json_build_object( @@ -284,4 +291,97 @@ impl Registry { .flat_map(serde_json::from_value) .collect()) } + + /// Insert a Trunk project (and related information) into the database. + /// Follows the given steps: + /// 1. insert trunk project name + /// 2. insert trunk project version + /// 3. insert extension version + /// 4. insert extension dependencies + /// 5. insert extension configurations + /// 6. insert shared preload libraries + pub async fn insert_trunk_project(&self, trunk_project: TrunkProjectView) -> Result<()> { + // 1. insert trunk project name + sqlx::query!( + "INSERT INTO v1.trunk_project (name) + VALUES ($1) + ON CONFLICT (name) DO NOTHING", + trunk_project.name + ) + .execute(&self.pool) + .await?; + + // 2. insert trunk project version + // Note: UNIQUE constraint will avoid re-inserting a previously existing tuple of Trunk name and version + let record = sqlx::query!( + "INSERT INTO v1.trunk_project_versions (trunk_project_name, version, description, repository_link, documentation_link) + VALUES ($1, $2, $3, $4, $5) + RETURNING id", + trunk_project.name, trunk_project.version, trunk_project.description, trunk_project.repository_link, trunk_project.documentation_link + ).fetch_one(&self.pool).await?; + let trunk_project_version_id = record.id; + + for extension in &trunk_project.extensions { + // 3. insert extension version (or versions) + let record = sqlx::query!( + "INSERT INTO v1.extension_versions (extension_name, trunk_project_version_id, version) + VALUES ($1, $2, $3) + ON CONFLICT (extension_name, trunk_project_version_id, version) + DO NOTHING + RETURNING id", + extension.extension_name, + trunk_project_version_id, + extension.version + ).fetch_one(&self.pool).await?; + let extension_version_id = record.id; + + let dependencies = extension + .dependencies_extension_names + .iter() + .flat_map(|deps| deps.iter()); + let configurations = extension + .configurations + .iter() + .flat_map(|configs| configs.iter()); + let loadable_libraries = extension + .loadable_libraries + .iter() + .flat_map(|libs| libs.iter()); + + // 4. insert extension dependencies + for dependency_name in dependencies { + sqlx::query!( + "INSERT INTO v1.extension_dependency (extension_version_id, depends_on_extension_name) + VALUES ($1, $2)", + extension_version_id, + dependency_name, + ).execute(&self.pool).await?; + } + + // 5. insert extension configurations + for config in configurations { + sqlx::query!( + "INSERT INTO v1.extension_configurations (extension_version_id, is_required, configuration_name, recommended_default_value) + VALUES ($1, $2, $3, $4)", + extension_version_id, + config.is_required, + config.name, + config.recommended_default, + ).execute(&self.pool).await?; + } + + // 6. insert shared preload libraries + for library in loadable_libraries { + sqlx::query!( + "INSERT INTO v1.extensions_loadable_libraries (extension_version_id, library_name, requires_restart, priority) + VALUES ($1, $2, $3, $4)", + extension_version_id, + library.library_name, + library.requires_restart, + library.priority, + ).execute(&self.pool).await?; + } + } + Ok(()) + } } diff --git a/registry/src/v1/routes.rs b/registry/src/v1/routes.rs index 4b511505..31cd9515 100644 --- a/registry/src/v1/routes.rs +++ b/registry/src/v1/routes.rs @@ -1,7 +1,9 @@ use actix_web::{ - get, + get, post, web::{self, Json}, + HttpResponse, }; +use actix_web_httpauth::extractors::bearer::BearerAuth; use serde::Deserialize; use crate::{errors::Result, repository::Registry, v1::repository::TrunkProjectView}; @@ -57,3 +59,19 @@ pub async fn trunk_project_by_name_and_version( Ok(Json(trunk_projects)) } + +/// Post a new Trunk project version +#[post("/trunk-projects")] +pub async fn insert_trunk_project( + registry: web::Data, + body: web::Json, + _auth: BearerAuth, +) -> Result { + let trunk_project_to_insert = body.into_inner(); + + registry + .insert_trunk_project(trunk_project_to_insert) + .await?; + + Ok(HttpResponse::Ok().finish()) +}