use super::SchemaStoreOperations;
use crate::{
error::InternalError,
paging::Paging,
schema::{
store::{
diesel::{
models::{GridPropertyDefinition, GridSchema},
schema::{grid_property_definition, grid_schema},
},
error::SchemaStoreError,
PropertyDefinition, Schema, SchemaList,
},
MAX_COMMIT_NUM,
},
};
use diesel::prelude::*;
use std::convert::TryInto;
pub(in crate::schema) trait ListSchemasOperation {
fn list_schemas(
&self,
service_id: Option<&str>,
offset: i64,
limit: i64,
) -> Result<SchemaList, SchemaStoreError>;
}
#[cfg(feature = "postgres")]
impl<'a> ListSchemasOperation for SchemaStoreOperations<'a, diesel::pg::PgConnection> {
fn list_schemas(
&self,
service_id: Option<&str>,
offset: i64,
limit: i64,
) -> Result<SchemaList, SchemaStoreError> {
self.conn.transaction::<_, SchemaStoreError, _>(|| {
let (db_schemas, total) =
pg::fetch_grid_schemas(&*self.conn, service_id, offset, limit)?;
let mut schemas = Vec::new();
for schema in db_schemas {
let roots = pg::get_root_definitions(&*self.conn, &schema.name)?;
let properties = pg::get_property_definitions_for_schema(&*self.conn, roots)?;
schemas.push(Schema::from((schema, properties)));
}
Ok(SchemaList::new(schemas, Paging::new(offset, limit, total)))
})
}
}
#[cfg(feature = "sqlite")]
impl<'a> ListSchemasOperation for SchemaStoreOperations<'a, diesel::sqlite::SqliteConnection> {
fn list_schemas(
&self,
service_id: Option<&str>,
offset: i64,
limit: i64,
) -> Result<SchemaList, SchemaStoreError> {
self.conn.transaction::<_, SchemaStoreError, _>(|| {
let (db_schemas, total) =
sqlite::fetch_grid_schemas(&*self.conn, service_id, offset, limit)?;
let mut schemas = Vec::new();
for schema in db_schemas {
let roots = sqlite::get_root_definitions(&*self.conn, &schema.name)?;
let properties = sqlite::get_property_definitions_for_schema(&*self.conn, roots)?;
schemas.push(Schema::from((schema, properties)));
}
Ok(SchemaList::new(schemas, Paging::new(offset, limit, total)))
})
}
}
#[cfg(feature = "postgres")]
mod pg {
use super::*;
pub fn fetch_grid_schemas(
conn: &PgConnection,
service_id: Option<&str>,
offset: i64,
limit: i64,
) -> Result<(Vec<GridSchema>, i64), SchemaStoreError> {
let mut query = grid_schema::table
.into_boxed()
.select(grid_schema::all_columns)
.offset(offset)
.limit(limit)
.filter(grid_schema::end_commit_num.eq(MAX_COMMIT_NUM));
if let Some(service_id) = service_id {
query = query.filter(grid_schema::service_id.eq(service_id));
} else {
query = query.filter(grid_schema::service_id.is_null());
}
let models = query.load(conn).map_err(|err| {
SchemaStoreError::InternalError(InternalError::from_source(Box::new(err)))
})?;
let total = models.len().try_into().map_err(|err| {
SchemaStoreError::InternalError(InternalError::from_source(Box::new(err)))
})?;
Ok((models, total))
}
pub fn get_root_definitions(
conn: &PgConnection,
schema_name: &str,
) -> QueryResult<Vec<GridPropertyDefinition>> {
grid_property_definition::table
.select(grid_property_definition::all_columns)
.filter(
grid_property_definition::schema_name
.eq(schema_name)
.and(grid_property_definition::parent_name.is_null())
.and(grid_property_definition::end_commit_num.eq(MAX_COMMIT_NUM)),
)
.load::<GridPropertyDefinition>(conn)
}
pub fn get_property_definitions_for_schema(
conn: &PgConnection,
root_definitions: Vec<GridPropertyDefinition>,
) -> Result<Vec<PropertyDefinition>, SchemaStoreError> {
let mut definitions = Vec::new();
for root_def in root_definitions {
let children = grid_property_definition::table
.select(grid_property_definition::all_columns)
.filter(grid_property_definition::parent_name.eq(&root_def.name))
.load(conn)?;
if children.is_empty() {
definitions.push(PropertyDefinition::from(root_def));
} else {
definitions.push(PropertyDefinition::from((
root_def,
get_property_definitions_for_schema(conn, children)?,
)));
}
}
Ok(definitions)
}
}
#[cfg(feature = "sqlite")]
mod sqlite {
use super::*;
pub fn fetch_grid_schemas(
conn: &SqliteConnection,
service_id: Option<&str>,
offset: i64,
limit: i64,
) -> Result<(Vec<GridSchema>, i64), SchemaStoreError> {
let mut query = grid_schema::table
.into_boxed()
.select(grid_schema::all_columns)
.offset(offset)
.limit(limit)
.filter(grid_schema::end_commit_num.eq(MAX_COMMIT_NUM));
if let Some(service_id) = service_id {
query = query.filter(grid_schema::service_id.eq(service_id));
} else {
query = query.filter(grid_schema::service_id.is_null());
}
let models = query.load(conn).map_err(|err| {
SchemaStoreError::InternalError(InternalError::from_source(Box::new(err)))
})?;
let total = models.len().try_into().map_err(|err| {
SchemaStoreError::InternalError(InternalError::from_source(Box::new(err)))
})?;
Ok((models, total))
}
pub fn get_root_definitions(
conn: &SqliteConnection,
schema_name: &str,
) -> QueryResult<Vec<GridPropertyDefinition>> {
grid_property_definition::table
.select(grid_property_definition::all_columns)
.filter(
grid_property_definition::schema_name
.eq(schema_name)
.and(grid_property_definition::parent_name.is_null())
.and(grid_property_definition::end_commit_num.eq(MAX_COMMIT_NUM)),
)
.load::<GridPropertyDefinition>(conn)
}
pub fn get_property_definitions_for_schema(
conn: &SqliteConnection,
root_definitions: Vec<GridPropertyDefinition>,
) -> Result<Vec<PropertyDefinition>, SchemaStoreError> {
let mut definitions = Vec::new();
for root_def in root_definitions {
let children = grid_property_definition::table
.select(grid_property_definition::all_columns)
.filter(grid_property_definition::parent_name.eq(&root_def.name))
.load(conn)?;
if children.is_empty() {
definitions.push(PropertyDefinition::from(root_def));
} else {
definitions.push(PropertyDefinition::from((
root_def,
get_property_definitions_for_schema(conn, children)?,
)));
}
}
Ok(definitions)
}
}