Commit cf4dde4d authored by mouadh's avatar mouadh

web config file

parent 682e4901
......@@ -96,6 +96,7 @@ class MdxEngine:
MdxEngine.postgres_db_cubes = [
database[0] for database in cursor.fetchall()
]
except Exception:
print('no database connexion')
pass
......@@ -258,6 +259,68 @@ class MdxEngine:
return fusion
def _construct_web_star_schema_config_file(self, cube_name, cubes_obj):
"""
Construct star schema DataFrame from configuration file.
:param cube_name: cube name (or database name)
:param cubes_obj: cubes object
:return: star schema DataFrame
"""
all_columns = []
self.facts = cubes_obj.facts[0].table_name
db = MyDB(db=cube_name)
# load facts table
# measures in config-file only
if cubes_obj.facts[0].measures:
self.measures = cubes_obj.facts[0].measures
all_columns += cubes_obj.facts[0].measures
fusion = psql.read_sql_query("SELECT * FROM {0}".format(self.facts),
db.connection)
tables = {}
for table in cubes_obj.tables:
tab = psql.read_sql_query("SELECT * FROM {0}".format(table.name),
db.connection)
try:
if table.columns:
tab = tab[table.columns]
except:
print("table columns doesn't exist")
print('pass with all columns')
try:
if table.new_names:
tab = tab.rename(columns=table.new_names)
except:
print("verify your old and new columns names")
print('pass with no change')
all_columns += list(tab.columns)
tables.update({table.name: tab})
for fact_key, dimension_and_key in cubes_obj.facts[0].keys.items():
dimension_name = dimension_and_key.split('.')[0]
if dimension_name in tables.keys():
df = tables[dimension_name]
else:
df = psql.read_sql_query(
"SELECT * FROM {0}".format(dimension_and_key.split('.')[0]),
db.connection)
fusion = fusion.merge(
df, left_on=fact_key, right_on=dimension_and_key.split('.')[1])
return fusion[[column for column in all_columns if 'id' != column[-2:]]]
def _construct_star_schema_csv_files(self, cube_name):
"""
Construct star schema DataFrame from csv files.
......@@ -306,7 +369,7 @@ class MdxEngine:
return fusion
def get_star_schema_dataframe(self, cube_name):
def get_star_schema_dataframe(self, cube_name, client_type='excel'):
"""
Merge all DataFrames as star schema.
......@@ -316,11 +379,16 @@ class MdxEngine:
fusion = None
config_file_parser = ConfigParser(self.cube_path)
if config_file_parser.config_file_exist(
if config_file_parser.config_file_exist(client_type
) and cube_name in config_file_parser.get_cubes_names():
for cubes in config_file_parser.construct_cubes():
for cubes in config_file_parser.construct_cubes(client_type):
# TODO cubes.source == 'csv'
if cubes.source == 'postgres':
# TODO one config file (I will try to merge dimensions between them in web part)
if client_type == 'web':
fusion = self._construct_web_star_schema_config_file(
cube_name, cubes)
else:
fusion = self._construct_star_schema_config_file(
cube_name, cubes)
......
......@@ -4,7 +4,7 @@ import os
from lxml import etree
from .models import Cube, Dimension, Facts
from .models import Cube, Dimension, Facts, Table
class ConfigParser:
......@@ -15,7 +15,7 @@ class ConfigParser:
Config file should be under 'home-directory/olapy-data/cubes/cubes-config.xml'
Config file Structure::
Excel Config file Structure::
<?xml version="1.0" encoding="UTF-8"?>
......@@ -113,8 +113,109 @@ class ConfigParser:
</cubes>
WEB Config file Structure::
<?xml version="1.0" encoding="UTF-8"?>
<cubes>
<cube>
<!-- cube name => db name -->
<name>mpr</name>
<!-- source : postgres | csv -->
<source>postgres</source>
<!--
star building customized star schema
-->
<facts>
<!-- facts table name -->
<table_name>projet</table_name>
<keys>
<!-- ref = table_name.column -->
<column_name ref="vocabulary_crm_status.id">status_id</column_name>
<column_name ref="vocabulary_crm_pole_leader.id">pole_leader_id</column_name>
<column_name ref="contact.id">contact_id</column_name>
<column_name ref="compte.id">compte_porteur_id</column_name>
<column_name ref="vocabulary_crm_aap_type.id">aap_name_id</column_name>
</keys>
<!-- specify measures explicitly -->
<measures>
<!-- by default, all number type columns in facts table, or you can specify them here -->
<name>budget_total</name>
<name>subvention_totale</name>
<name>duree_projet</name>
</measures>
</facts>
<!--
end building customized star schema
-->
<!-- -------------------------------------------------------- -->
<!-- FOR WEB -->
<tables>
<!-- Table name -->
<table name="vocabulary_crm_status">
<!-- Columns to keep (exclude id)-->
<!-- They must be seperated with comma ',' -->
<columns>label,active</columns>
<!-- Change insignificant table columns names -->
<!-- {IMPORTANT} Renaming COMMUN columns between dimensions and other columns if you want, other than ids column -->
<new_name old_column_name="label">status_label</new_name>
</table>
<!-- *********************** -->
<!-- Table name -->
<table name="vocabulary_crm_pole_leader">
<!-- Columns to keep (exclude id)-->
<!-- They must be seperated with comma ',' -->
<columns>label</columns>
<!-- Change insignificant table columns names -->
<!-- {IMPORTANT} Renaming COMMUN columns between dimensions and other columns if you want, other than ids column -->
<new_name old_column_name="label">pole_leader_label</new_name>
</table>
<!-- *********************** -->
<!-- Table name -->
<table name="contact">
<!-- Columns to keep (exclude id)-->
<!-- They must be seperated with comma ',' -->
<columns>nom,prenom,fonction</columns>
</table>
</tables>
<!-- END FOR WEB -->
<!-- -------------------------------------------------------- -->
</cube>
</cubes>
"""
def __init__(self, cube_path, file_name='cubes-config.xml'):
# TODO one config file (I will try to merge dimensions between them in web part)
def __init__(self, cube_path, file_name='cubes-config.xml', web_config_file_name='web_cube_config.xml'):
"""
:param cube_path: path to cube (csv folders)
......@@ -122,13 +223,16 @@ class ConfigParser:
"""
self.cube_path = cube_path
self.file_name = file_name
self.web_config_file_name = web_config_file_name
def config_file_exist(self):
def config_file_exist(self,client_type='excel'):
"""
Check whether the config file exists or not.
:return: True | False
"""
if client_type == 'web':
return os.path.isfile(os.path.join(self.cube_path, self.web_config_file_name))
return os.path.isfile(os.path.join(self.cube_path, self.file_name))
def xmla_authentication(self):
......@@ -167,13 +271,7 @@ class ConfigParser:
except:
raise ('missed name or source tags')
def construct_cubes(self):
"""
Construct cube (with it dimensions) and facts from the config file.
:return: list of Cubes instance
"""
if self.config_file_exist():
def _construct_cubes_excel(self):
try:
with open(os.path.join(self.cube_path,
self.file_name)) as config_file:
......@@ -218,5 +316,69 @@ class ConfigParser:
]
except:
raise ('Bad configuration in the configuration file')
def _construct_cubes_web(self):
# try:
with open(os.path.join(self.cube_path,
self.web_config_file_name)) as config_file:
parser = etree.XMLParser()
tree = etree.parse(config_file, parser)
facts = [
Facts(
table_name=xml_facts.find('table_name').text,
keys={
key.text: key.attrib['ref']
for key in xml_facts.findall(
'keys/column_name')
},
measures=[
mes.text
for mes in xml_facts.findall('measures/name')
]) for xml_facts in tree.xpath('/cubes/cube/facts')
]
tables = [
Table(
name=xml_column.attrib['name'],
columns = xml_column.find('columns').text.split(','),
new_names={
new_col.attrib['old_column_name'] : new_col.text
for new_col in xml_column.findall('new_name')
}
)
for xml_column in tree.xpath(
'/cubes/cube/tables/table')
]
return [
Cube(
name=xml_cube.find('name').text,
source=xml_cube.find('source').text,
facts=facts,
tables = tables
)
for xml_cube in tree.xpath('/cubes/cube')
]
# except:
# raise ('Bad configuration in the configuration file')
def construct_cubes(self,client_type='excel'):
"""
Construct cube (with it dimensions) and facts from the config file.
:param client_type: excel | web
:return: list of Cubes instance
"""
if self.config_file_exist(client_type):
if client_type == 'excel':
return self._construct_cubes_excel()
elif client_type == 'web':
return self._construct_cubes_web()
else:
raise ("Config file don't exist")
......@@ -51,3 +51,19 @@ class Cube:
def __str__(self):
return str(self.__dict__)
class Table:
"""Column class used to encapsulate config file attributes for web client."""
def __init__(self, **kwargs):
"""
:param kwargs: {
table_name : 'something',
old_column_name : 'something',
new_column_name : 'something'
}
"""
self.__dict__.update(kwargs)
def __str__(self):
return str(self.__dict__)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment