Skip to content

Commit

Permalink
refactor/nanocld: resource repository (#741)
Browse files Browse the repository at this point in the history
  • Loading branch information
leon3s authored Dec 20, 2023
1 parent 7ba4a43 commit 35db2b4
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 160 deletions.
159 changes: 3 additions & 156 deletions bin/nanocld/src/models/resource.rs
Original file line number Diff line number Diff line change
@@ -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).
Expand Down Expand Up @@ -62,145 +51,3 @@ pub struct ResourceUpdateDb {
/// The spec key reference
pub spec_key: Option<uuid::Uuid>,
}

impl Repository for ResourceDb {
type Table = resources::table;
type Item = Resource;
type UpdateItem = ResourceUpdateDb;

fn find_one(
filter: &GenericFilter,
pool: &Pool,
) -> JoinHandle<IoResult<Self::Item>> {
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<IoResult<Vec<Self::Item>>> {
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<Resource> {
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<Resource> {
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<Resource> {
let filter =
GenericFilter::new().r#where("key", GenericClause::Eq(pk.to_owned()));
Self::find_one(&filter, pool).await?
}
}
1 change: 1 addition & 0 deletions bin/nanocld/src/repositories/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ mod job;
mod metric;
mod http_metric;
mod vm_spec;
mod resource;

pub mod generic;
186 changes: 186 additions & 0 deletions bin/nanocld/src/repositories/resource.rs
Original file line number Diff line number Diff line change
@@ -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<IoResult<Self::Output>> {
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<IoResult<Self::Output>> {
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<IoResult<Vec<Self::Output>>> {
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::<Vec<_>>();
Ok::<_, IoError>(items)
})
}
}

impl ResourceDb {
/// Create a new resource from a spec.
pub(crate) async fn create_from_spec(
item: &ResourcePartial,
pool: &Pool,
) -> IoResult<Resource> {
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<Resource> {
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<Resource> {
let filter =
GenericFilter::new().r#where("key", GenericClause::Eq(pk.to_owned()));
Self::read_one_with_spec(&filter, pool).await?
}
}
4 changes: 2 additions & 2 deletions bin/nanocld/src/services/resource.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use nanocl_stubs::{
use crate::{
utils,
repositories::generic::*,
models::{DaemonState, ResourceSpecDb, Repository, ResourceDb},
models::{DaemonState, ResourceSpecDb, ResourceDb},
};

/// List resources
Expand All @@ -35,7 +35,7 @@ pub(crate) async fn list_resource(
) -> HttpResult<web::HttpResponse> {
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))
}

Expand Down
Loading

0 comments on commit 35db2b4

Please sign in to comment.