From 35db2b4cf13a593a95ef6374e115a948feabe628 Mon Sep 17 00:00:00 2001 From: leone Date: Wed, 20 Dec 2023 14:03:42 +0100 Subject: [PATCH] refactor/nanocld: resource repository (#741) --- bin/nanocld/src/models/resource.rs | 159 +------------------ bin/nanocld/src/repositories/mod.rs | 1 + bin/nanocld/src/repositories/resource.rs | 186 +++++++++++++++++++++++ bin/nanocld/src/services/resource.rs | 4 +- bin/nanocld/src/utils/resource.rs | 4 +- 5 files changed, 194 insertions(+), 160 deletions(-) create mode 100644 bin/nanocld/src/repositories/resource.rs diff --git a/bin/nanocld/src/models/resource.rs b/bin/nanocld/src/models/resource.rs index 7eca832df..b96a03caa 100644 --- a/bin/nanocld/src/models/resource.rs +++ b/bin/nanocld/src/models/resource.rs @@ -1,22 +1,11 @@ -use std::sync::Arc; - use diesel::prelude::*; -use ntex::rt::JoinHandle; use serde::{Serialize, Deserialize}; -use nanocl_error::io::{IoError, IoResult}; - -use nanocl_stubs::{ - generic::{GenericFilter, GenericClause}, - resource::{Resource, ResourcePartial}, -}; +use nanocl_stubs::resource::Resource; -use crate::{ - utils, gen_where4string, gen_where4json, schema::resources, - repositories::generic::*, -}; +use crate::schema::resources; -use super::{Pool, Repository, WithSpec, ResourceSpecDb}; +use super::{WithSpec, ResourceSpecDb}; /// This structure represent a resource in the database. /// A resource is a representation of a specification for internal nanocl services (controllers). @@ -62,145 +51,3 @@ pub struct ResourceUpdateDb { /// The spec key reference pub spec_key: Option, } - -impl Repository for ResourceDb { - type Table = resources::table; - type Item = Resource; - type UpdateItem = ResourceUpdateDb; - - fn find_one( - filter: &GenericFilter, - pool: &Pool, - ) -> JoinHandle> { - use crate::schema::resource_specs; - log::trace!("ResourceDb::find_one: {filter:?}"); - let r#where = filter.r#where.to_owned().unwrap_or_default(); - let mut query = resources::dsl::resources - .inner_join(resource_specs::table) - .into_boxed(); - if let Some(value) = r#where.get("key") { - gen_where4string!(query, resources::dsl::key, value); - } - if let Some(value) = r#where.get("kind") { - gen_where4string!(query, resources::dsl::kind, value); - } - if let Some(value) = r#where.get("data") { - gen_where4json!(query, resource_specs::dsl::data, value); - } - if let Some(value) = r#where.get("metadata") { - gen_where4json!(query, resource_specs::dsl::metadata, value); - } - let pool = Arc::clone(pool); - ntex::rt::spawn_blocking(move || { - let mut conn = utils::store::get_pool_conn(&pool)?; - let item = query - .get_result::<(ResourceDb, ResourceSpecDb)>(&mut conn) - .map_err(Self::map_err_context)?; - let item = item.0.with_spec(&item.1); - Ok::<_, IoError>(item) - }) - } - - fn find( - filter: &GenericFilter, - pool: &Pool, - ) -> JoinHandle>> { - use crate::schema::resource_specs; - log::trace!("ResourceDb::find: {filter:?}"); - let mut query = resources::dsl::resources - .order(resources::dsl::created_at.desc()) - .inner_join(resource_specs::table) - .into_boxed(); - let r#where = filter.r#where.to_owned().unwrap_or_default(); - if let Some(value) = r#where.get("key") { - gen_where4string!(query, resources::dsl::key, value); - } - if let Some(value) = r#where.get("kind") { - gen_where4string!(query, resources::dsl::kind, value); - } - if let Some(value) = r#where.get("data") { - gen_where4json!(query, resource_specs::dsl::data, value); - } - if let Some(value) = r#where.get("metadata") { - gen_where4json!(query, resource_specs::dsl::metadata, value); - } - let limit = filter.limit.unwrap_or(100); - query = query.limit(limit as i64); - if let Some(offset) = filter.offset { - query = query.offset(offset as i64); - } - let pool = Arc::clone(pool); - ntex::rt::spawn_blocking(move || { - let mut conn = utils::store::get_pool_conn(&pool)?; - let items = query - .get_results::<(ResourceDb, ResourceSpecDb)>(&mut conn) - .map_err(Self::map_err_context)? - .into_iter() - .map(|(r, s)| r.with_spec(&s)) - .collect(); - Ok::<_, IoError>(items) - }) - } -} - -impl ResourceDb { - /// Create a new resource from a spec. - pub(crate) async fn create_from_spec( - item: &ResourcePartial, - pool: &Pool, - ) -> IoResult { - let spec = ResourceSpecDb { - key: uuid::Uuid::new_v4(), - created_at: chrono::Utc::now().naive_utc(), - resource_key: item.name.to_owned(), - version: item.version.to_owned(), - data: item.data.clone(), - metadata: item.metadata.clone(), - }; - let spec = ResourceSpecDb::create_from(spec, pool).await??; - let new_item = ResourceDb { - key: item.name.to_owned(), - created_at: chrono::Utc::now().naive_utc(), - kind: item.kind.clone(), - spec_key: spec.key.to_owned(), - }; - let dbmodel = ResourceDb::create(new_item, pool).await??; - let item = dbmodel.with_spec(&spec); - Ok(item) - } - - /// Update a resource from a spec. - pub(crate) async fn update_from_spec( - item: &ResourcePartial, - pool: &Pool, - ) -> IoResult { - let key = item.name.clone(); - let resource = ResourceDb::inspect_by_pk(&item.name, pool).await?; - let spec = ResourceSpecDb { - key: uuid::Uuid::new_v4(), - created_at: chrono::Utc::now().naive_utc(), - resource_key: resource.spec.resource_key, - version: item.version.clone(), - data: item.data.clone(), - metadata: item.metadata.clone(), - }; - let spec = ResourceSpecDb::create_from(spec, pool).await??; - let resource_update = ResourceUpdateDb { - key: None, - spec_key: Some(spec.key.to_owned()), - }; - let dbmodel = - ResourceDb::update_by_pk(&key, resource_update, pool).await??; - let item = dbmodel.with_spec(&spec); - Ok(item) - } - - pub(crate) async fn inspect_by_pk( - pk: &str, - pool: &Pool, - ) -> IoResult { - let filter = - GenericFilter::new().r#where("key", GenericClause::Eq(pk.to_owned())); - Self::find_one(&filter, pool).await? - } -} diff --git a/bin/nanocld/src/repositories/mod.rs b/bin/nanocld/src/repositories/mod.rs index 3eb3a38a3..edb775be5 100644 --- a/bin/nanocld/src/repositories/mod.rs +++ b/bin/nanocld/src/repositories/mod.rs @@ -11,5 +11,6 @@ mod job; mod metric; mod http_metric; mod vm_spec; +mod resource; pub mod generic; diff --git a/bin/nanocld/src/repositories/resource.rs b/bin/nanocld/src/repositories/resource.rs new file mode 100644 index 000000000..4500e5976 --- /dev/null +++ b/bin/nanocld/src/repositories/resource.rs @@ -0,0 +1,186 @@ +use std::sync::Arc; + +use ntex::rt::JoinHandle; +use diesel::prelude::*; + +use nanocl_error::io::{IoError, IoResult}; + +use nanocl_stubs::{ + generic::{GenericFilter, GenericClause}, + resource::Resource, + resource::ResourcePartial, +}; + +use crate::{ + utils, gen_where4string, gen_where4json, + models::{Pool, ResourceDb, ResourceSpecDb, ResourceUpdateDb, WithSpec}, + schema::{resources, resource_specs}, +}; + +use super::generic::*; + +impl RepositoryBase for ResourceDb {} + +impl RepositoryCreate for ResourceDb {} + +impl RepositoryUpdate for ResourceDb { + type UpdateItem = ResourceUpdateDb; +} + +impl RepositoryDelByPk for ResourceDb {} + +impl RepositoryReadWithSpec for ResourceDb { + type Output = Resource; + + fn read_pk_with_spec( + pk: &str, + pool: &Pool, + ) -> JoinHandle> { + log::trace!("ResourceDb::find_by_pk: {pk}"); + let pool = Arc::clone(pool); + let pk = pk.to_owned(); + ntex::rt::spawn_blocking(move || { + let mut conn = utils::store::get_pool_conn(&pool)?; + let item = resources::dsl::resources + .inner_join(crate::schema::resource_specs::table) + .filter(resources::dsl::key.eq(pk)) + .get_result::<(Self, ResourceSpecDb)>(&mut conn) + .map_err(Self::map_err)?; + let item = item.0.with_spec(&item.1); + Ok::<_, IoError>(item) + }) + } + + fn read_one_with_spec( + filter: &GenericFilter, + pool: &Pool, + ) -> JoinHandle> { + log::trace!("ResourceDb::find_one: {filter:?}"); + let r#where = filter.r#where.to_owned().unwrap_or_default(); + let mut query = resources::dsl::resources + .inner_join(resource_specs::table) + .into_boxed(); + if let Some(value) = r#where.get("key") { + gen_where4string!(query, resources::dsl::key, value); + } + if let Some(value) = r#where.get("kind") { + gen_where4string!(query, resources::dsl::kind, value); + } + if let Some(value) = r#where.get("data") { + gen_where4json!(query, resource_specs::dsl::data, value); + } + if let Some(value) = r#where.get("metadata") { + gen_where4json!(query, resource_specs::dsl::metadata, value); + } + let pool = Arc::clone(pool); + ntex::rt::spawn_blocking(move || { + let mut conn = utils::store::get_pool_conn(&pool)?; + let item = query + .get_result::<(Self, ResourceSpecDb)>(&mut conn) + .map_err(Self::map_err)?; + let item = item.0.with_spec(&item.1); + Ok::<_, IoError>(item) + }) + } + + fn read_with_spec( + filter: &GenericFilter, + pool: &Pool, + ) -> JoinHandle>> { + log::trace!("ResourceDb::find: {filter:?}"); + let r#where = filter.r#where.to_owned().unwrap_or_default(); + let mut query = resources::dsl::resources + .inner_join(resource_specs::table) + .into_boxed(); + if let Some(value) = r#where.get("key") { + gen_where4string!(query, resources::dsl::key, value); + } + if let Some(value) = r#where.get("kind") { + gen_where4string!(query, resources::dsl::kind, value); + } + if let Some(value) = r#where.get("data") { + gen_where4json!(query, resource_specs::dsl::data, value); + } + if let Some(value) = r#where.get("metadata") { + gen_where4json!(query, resource_specs::dsl::metadata, value); + } + let limit = filter.limit.unwrap_or(100); + query = query.limit(limit as i64); + if let Some(offset) = filter.offset { + query = query.offset(offset as i64); + } + let pool = Arc::clone(pool); + ntex::rt::spawn_blocking(move || { + let mut conn = utils::store::get_pool_conn(&pool)?; + let items = query + .get_results::<(Self, ResourceSpecDb)>(&mut conn) + .map_err(Self::map_err)?; + let items = items + .into_iter() + .map(|item| item.0.with_spec(&item.1)) + .collect::>(); + Ok::<_, IoError>(items) + }) + } +} + +impl ResourceDb { + /// Create a new resource from a spec. + pub(crate) async fn create_from_spec( + item: &ResourcePartial, + pool: &Pool, + ) -> IoResult { + let spec = ResourceSpecDb { + key: uuid::Uuid::new_v4(), + created_at: chrono::Utc::now().naive_utc(), + resource_key: item.name.to_owned(), + version: item.version.to_owned(), + data: item.data.clone(), + metadata: item.metadata.clone(), + }; + let spec = ResourceSpecDb::create_from(spec, pool).await??; + let new_item = ResourceDb { + key: item.name.to_owned(), + created_at: chrono::Utc::now().naive_utc(), + kind: item.kind.clone(), + spec_key: spec.key.to_owned(), + }; + let dbmodel = ResourceDb::create_from(new_item, pool).await??; + let item = dbmodel.with_spec(&spec); + Ok(item) + } + + /// Update a resource from a spec. + pub(crate) async fn update_from_spec( + item: &ResourcePartial, + pool: &Pool, + ) -> IoResult { + let key = item.name.clone(); + let resource = ResourceDb::read_pk_with_spec(&item.name, pool).await??; + let spec = ResourceSpecDb { + key: uuid::Uuid::new_v4(), + created_at: chrono::Utc::now().naive_utc(), + resource_key: resource.spec.resource_key, + version: item.version.clone(), + data: item.data.clone(), + metadata: item.metadata.clone(), + }; + let spec = ResourceSpecDb::create_from(spec, pool).await??; + let resource_update = ResourceUpdateDb { + key: None, + spec_key: Some(spec.key.to_owned()), + }; + let dbmodel = ResourceDb::update_pk(&key, resource_update, pool).await??; + let item = dbmodel.with_spec(&spec); + Ok(item) + } + + pub(crate) async fn inspect_by_pk( + pk: &str, + pool: &Pool, + ) -> IoResult { + let filter = + GenericFilter::new().r#where("key", GenericClause::Eq(pk.to_owned())); + Self::read_one_with_spec(&filter, pool).await? + } +} diff --git a/bin/nanocld/src/services/resource.rs b/bin/nanocld/src/services/resource.rs index 51686b8c2..b4e7ca93e 100644 --- a/bin/nanocld/src/services/resource.rs +++ b/bin/nanocld/src/services/resource.rs @@ -13,7 +13,7 @@ use nanocl_stubs::{ use crate::{ utils, repositories::generic::*, - models::{DaemonState, ResourceSpecDb, Repository, ResourceDb}, + models::{DaemonState, ResourceSpecDb, ResourceDb}, }; /// List resources @@ -35,7 +35,7 @@ pub(crate) async fn list_resource( ) -> HttpResult { let filter = GenericFilter::try_from(query.into_inner()) .map_err(|err| HttpError::bad_request(err.to_string()))?; - let items = ResourceDb::find(&filter, &state.pool).await??; + let items = ResourceDb::read_with_spec(&filter, &state.pool).await??; Ok(web::HttpResponse::Ok().json(&items)) } diff --git a/bin/nanocld/src/utils/resource.rs b/bin/nanocld/src/utils/resource.rs index f86c6d1b2..f94f74fd7 100644 --- a/bin/nanocld/src/utils/resource.rs +++ b/bin/nanocld/src/utils/resource.rs @@ -12,7 +12,7 @@ use nanocl_stubs::{ use crate::{ repositories::generic::*, models::{ - Pool, ResourceKindPartial, DaemonState, ResourceKindVersionDb, Repository, + Pool, ResourceKindPartial, DaemonState, ResourceKindVersionDb, ResourceKindDb, ResourceSpecDb, ResourceDb, }, }; @@ -167,7 +167,7 @@ pub(crate) async fn delete( ResourceKindDb::del_by_pk(&resource.spec.resource_key, &state.pool) .await??; } - ResourceDb::delete_by_pk(&resource.spec.resource_key, &state.pool).await??; + ResourceDb::del_by_pk(&resource.spec.resource_key, &state.pool).await??; let filter = GenericFilter::new().r#where( "resource_key", GenericClause::Eq(resource.spec.resource_key.to_owned()),