Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds support for reading schemas from database #249

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

83 changes: 83 additions & 0 deletions tesseract-clickhouse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use futures::{future, Future, Stream};
use log::*;
use std::time::{Duration, Instant};
use tesseract_core::{Backend, DataFrame, QueryIr};
use tesseract_core::schema::metadata::SchemaPhysicalData;

mod df;
mod sql;
Expand Down Expand Up @@ -84,5 +85,87 @@ impl Backend for Clickhouse {
&query_ir
)
}

fn retrieve_schemas(&self, tablepath: &str, id: Option<&str>) -> Box<dyn Future<Item=Vec<SchemaPhysicalData>, Error=Error>> {
let sql = match id {
None => format!("SELECT id, schema FROM {}", tablepath),
Some(id_val) => format!("SELECT id, schema FROM {} WHERE id = '{}'", tablepath, id_val),
};
let time_start = Instant::now();
let fut = self.pool
.get_handle()
.and_then(move |c| c.query(&sql).fetch_all())
.from_err()
.and_then(move |(_, block): (_, Block<Complex>)| {
let timing = time_start.elapsed();
info!("Time for sql schema retrieval: {}.{:03}", timing.as_secs(), timing.subsec_millis());
let schema_vec: Vec<SchemaPhysicalData> = block.rows().map(|row| {
SchemaPhysicalData {
id: row.get("id").expect("missing id"),
content: row.get("schema").expect("missing schema"),
format: "json".to_string(),
}
}).collect();
Ok(schema_vec)
});

Box::new(fut)
}

fn update_schema(&self, tablepath: &str, schema_name_id: &str, schema_content: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
let sql = format!("ALTER TABLE {} UPDATE schema = '{}' WHERE id = '{}'", tablepath, schema_content, schema_name_id);
let time_start = Instant::now();
let fut = self.pool
.get_handle()
.and_then(move |c| {
c.execute(sql)
})
.and_then(move |c| {
let timing = time_start.elapsed();
info!("Time for updating schema: {}.{:03}", timing.as_secs(), timing.subsec_millis());
Ok(true)
})
.from_err();

Box::new(fut)
}


fn add_schema(&self, tablepath: &str, schema_name_id: &str, content: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
let block = Block::new()
.column("id", vec![schema_name_id])
.column("schema", vec![content]);
let table_name_copy = tablepath.to_string();
let time_start = Instant::now();
let fut = self.pool
.get_handle()
.and_then(move |c| {
c.insert(table_name_copy, block)
})
.and_then(move |c| {
let timing = time_start.elapsed();
info!("Time for adding schema: {}.{:03}", timing.as_secs(), timing.subsec_millis());
Ok(true)
})
.from_err();

Box::new(fut)
}

fn delete_schema(&self, tablepath: &str, schema_name_id: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
let sql = format!("ALTER TABLE {} DELETE WHERE id = '{}'", tablepath, schema_name_id);
let time_start = Instant::now();
let fut = self.pool
.get_handle()
.and_then(move |c| c.execute(sql))
.and_then(move |c| {
let timing = time_start.elapsed();
info!("Time for deleting schema: {}.{:03}", timing.as_secs(), timing.subsec_millis());
Ok(true)
})
.from_err();

Box::new(fut)
}
}

22 changes: 21 additions & 1 deletion tesseract-core/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ use futures::{Future, Stream};
use crate::dataframe::DataFrame;
use crate::query_ir::QueryIr;
use crate::sql;

use crate::schema::metadata::SchemaPhysicalData;

pub trait Backend {
/// Takes in a fully-qualfiied path to a table name
/// assumes table is in the structure of: id (integer), name (text), schema (json)
/// desired query output format.
fn retrieve_schemas(&self, tablepath: &str, id: Option<&str>) -> Box<dyn Future<Item=Vec<SchemaPhysicalData>, Error=Error>> {
unimplemented!()
}

/// Takes in a SQL string, outputs a DataFrame, which will go on to be formatted into the
/// desired query output format.
fn exec_sql(&self, sql: String) -> Box<dyn Future<Item=DataFrame, Error=Error>>;
Expand Down Expand Up @@ -38,6 +45,19 @@ pub trait Backend {
&query_ir.growth,
)
}

/// This function allows administrators to update the content of a given schema.
fn update_schema(&self, tablepath: &str, schema_name_id: &str, schema_content: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
unimplemented!()
}

fn delete_schema(&self, tablepath: &str, schema_name_id: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
unimplemented!()
}

fn add_schema(&self, tablepath: &str, schema_name_id: &str, schema_content: &str) -> Box<dyn Future<Item=bool, Error=Error>> {
unimplemented!()
}
}

impl Clone for Box<dyn Backend + Send + Sync> {
Expand Down
2 changes: 1 addition & 1 deletion tesseract-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use self::names::{
Mask,
};
pub use self::schema::{Schema, Cube, Dimension, Table, Aggregator};
use self::schema::metadata::{SchemaMetadata, CubeMetadata};
use self::schema::metadata::{SchemaMetadata, SchemaPhysicalData, CubeMetadata};
use self::query_ir::{
CutSql,
DrilldownSql,
Expand Down
2 changes: 1 addition & 1 deletion tesseract-core/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use failure::{Error, format_err};

pub mod aggregator;
pub mod metadata;
mod json;
pub mod json;
mod xml;

const DEFAULT_LOCALE_STR: &str = "en";
Expand Down
32 changes: 16 additions & 16 deletions tesseract-core/src/schema/json.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use serde_derive::Deserialize;
use serde_derive::{Deserialize, Serialize};

use crate::query_ir::MemberType;
use super::aggregator::Aggregator;
use super::{DimensionType, MeasureType};


#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct SchemaConfigJson {
pub name: String,
pub shared_dimensions: Option<Vec<SharedDimensionConfigJson>>,
Expand All @@ -14,7 +14,7 @@ pub struct SchemaConfigJson {
pub default_locale: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct CubeConfigJson {
pub name: String,
pub public: Option<String>,
Expand All @@ -25,7 +25,7 @@ pub struct CubeConfigJson {
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DimensionConfigJson {
pub name: String,
pub foreign_key: Option<String>, // does not exist for shared dims
Expand All @@ -36,7 +36,7 @@ pub struct DimensionConfigJson {
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct SharedDimensionConfigJson {
pub name: String,
pub hierarchies: Vec<HierarchyConfigJson>,
Expand All @@ -46,15 +46,15 @@ pub struct SharedDimensionConfigJson {
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct DimensionUsageJson {
pub source: String,
pub name: Option<String>,
pub foreign_key: String,
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct HierarchyConfigJson {
pub name: String,
pub table: Option<TableConfigJson>,
Expand All @@ -65,33 +65,33 @@ pub struct HierarchyConfigJson {
pub default_member: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct InlineTableJson {
pub alias: String,
pub column_definitions: Vec<InlineTableColumnDefinitionJson>,
pub rows: Vec<InlineTableRowJson>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct InlineTableColumnDefinitionJson {
pub name: String,
pub key_type: MemberType,
pub key_column_type: Option<String>,
pub caption_set: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct InlineTableRowJson {
pub row_values: Vec<InlineTableRowValueJson>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct InlineTableRowValueJson {
pub column: String,
pub value: String,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct LevelConfigJson {
pub name: String,
pub key_column: String,
Expand All @@ -101,7 +101,7 @@ pub struct LevelConfigJson {
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct MeasureConfigJson {
pub name: String,
pub column: String,
Expand All @@ -111,22 +111,22 @@ pub struct MeasureConfigJson {
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct TableConfigJson {
pub name: String,
pub schema: Option<String>,
pub primary_key: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct PropertyConfigJson {
pub name: String,
pub column: String,
pub caption_set: Option<String>,
pub annotations: Option<Vec<AnnotationConfigJson>>,
}

#[derive(Debug, Clone, PartialEq, Deserialize)]
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct AnnotationConfigJson {
pub name: String,
pub text: String,
Expand Down
23 changes: 23 additions & 0 deletions tesseract-core/src/schema/metadata.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use serde_derive::Serialize;
use std::collections::HashMap;
use std::convert::From;
use serde_json::value::Value;
use serde::ser::{Serialize as CustomSerialize, SerializeStruct, Serializer};

use super::{
Schema,
Expand All @@ -16,6 +18,27 @@ use super::{
aggregator::Aggregator,
};

#[derive(Debug, Clone, PartialEq)]
pub struct SchemaPhysicalData {
pub id: String,
pub content: String,
pub format: String,
}

impl CustomSerialize for SchemaPhysicalData {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// this section allows the API to return the raw string as a formatted JSON object.
let mut s = serializer.serialize_struct("SchemaPhysicalData", 2)?;
s.serialize_field("id", &self.id)?;
let raw_json: HashMap<String, Value> = serde_json::from_str(&self.content).expect("failed to parse json");
s.serialize_field("content", &raw_json)?;
s.end()
}
}

#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SchemaMetadata {
pub name: String,
Expand Down
Loading