Skip to content
Snippets Groups Projects
Commit 315c1dc6 authored by Saket Agrahari's avatar Saket Agrahari
Browse files

BE Changes Initial

parent 1645e52a
Branches
Tags
No related merge requests found
...@@ -31,4 +31,5 @@ htmlcov/ ...@@ -31,4 +31,5 @@ htmlcov/
node_modules node_modules
# sphinx # sphinx
/docs/build/ /docs/build/
\ No newline at end of file /config.json
...@@ -20,8 +20,15 @@ CONFIG_SCHEMA = { ...@@ -20,8 +20,15 @@ CONFIG_SCHEMA = {
}, },
'additionalProperties': False 'additionalProperties': False
}, },
'SURVEY_DATABASE_URI': {
'type': 'string',
'properties': {
'database-uri': {'$ref': '#definitions/database-uri'}
},
'additionalProperties': False
}
}, },
'required': ['SQLALCHEMY_DATABASE_URI'], 'required': ['SQLALCHEMY_DATABASE_URI', 'SURVEY_DATABASE_URI'],
'additionalProperties': False 'additionalProperties': False
} }
......
...@@ -17,18 +17,11 @@ def _enum_names(enum_class): ...@@ -17,18 +17,11 @@ def _enum_names(enum_class):
return [x.name for x in list(enum_class)] return [x.name for x in list(enum_class)]
class BudgetType(enum.Enum):
YEARLY = 1
NREN = 2
class BudgetEntry(base_schema): class BudgetEntry(base_schema):
__tablename__ = 'budgets' __tablename__ = 'budgets'
id = sa.Column(sa.Integer, primary_key=True) id = sa.Column(sa.Integer, autoincrement=True)
budget_type = sa.Column( nren = sa.Column(sa.String(128), primary_key=True)
'budget_type', budget = sa.Column(sa.String(128), nullable=True)
sa.Enum(*_enum_names(BudgetType), name='budget_type'), year = sa.Column(sa.String(128), primary_key=True)
nullable=False)
name = sa.Column(sa.String(128))
description = sa.Column(sa.String(2048))
"""Initial DB """Initial DB setup
Revision ID: 95577456fcfd Revision ID: 366dfd333305
Revises: Revises:
Create Date: 2022-12-26 08:08:09.711624 Create Date: 2023-02-07 11:37:56.576183
""" """
from alembic import op from alembic import op
...@@ -10,22 +10,19 @@ import sqlalchemy as sa ...@@ -10,22 +10,19 @@ import sqlalchemy as sa
# revision identifiers, used by Alembic. # revision identifiers, used by Alembic.
revision = '95577456fcfd' revision = '366dfd333305'
down_revision = None down_revision = None
branch_labels = None branch_labels = None
depends_on = None depends_on = None
def upgrade(): def upgrade():
op.create_table( op.create_table('budgets',
'budgets', sa.Column('id', sa.Integer(), autoincrement=True, nullable=True),
sa.Column('id', sa.Integer(), nullable=False), sa.Column('nren', sa.String(length=128), nullable=False),
sa.Column('budget_type', sa.Enum( sa.Column('budget', sa.String(length=128), nullable=True),
'YEARLY', 'NREN', name='budget_type'), nullable=False), sa.Column('year', sa.String(length=128), nullable=False),
sa.Column('name', sa.String(length=128), nullable=True), sa.PrimaryKeyConstraint('nren', 'year')
sa.Column('description', sa.String(
length=2048), nullable=True),
sa.PrimaryKeyConstraint('id')
) )
......
...@@ -3,8 +3,8 @@ from typing import Any ...@@ -3,8 +3,8 @@ from typing import Any
from flask import Blueprint, jsonify, current_app from flask import Blueprint, jsonify, current_app
from compendium_v2 import db from compendium_v2 import db, survey_db
from compendium_v2.db import model from compendium_v2.survey_db import model as survey_model
from compendium_v2.routes import common from compendium_v2.routes import common
routes = Blueprint('budget', __name__) routes = Blueprint('budget', __name__)
...@@ -13,8 +13,11 @@ routes = Blueprint('budget', __name__) ...@@ -13,8 +13,11 @@ routes = Blueprint('budget', __name__)
@routes.before_request @routes.before_request
def before_request(): def before_request():
config = current_app.config['CONFIG_PARAMS'] config = current_app.config['CONFIG_PARAMS']
dsn = config['SQLALCHEMY_DATABASE_URI'] dsn_prn = config['SQLALCHEMY_DATABASE_URI']
db.init_db_model(dsn) db.init_db_model(dsn_prn)
dsn_survey = config['SURVEY_DATABASE_URI']
survey_db.init_db_model(dsn_survey)
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
...@@ -31,12 +34,11 @@ BUDGET_RESPONSE_SCHEMA = { ...@@ -31,12 +34,11 @@ BUDGET_RESPONSE_SCHEMA = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'id': {'type': 'number'}, 'id': {'type': 'number'},
'name': {'type': 'string'}, 'NREN': {'type': 'string'},
'type': {'type': 'string'}, 'BUDGET': {'type': 'string'},
'description': {'type': 'string'}, 'BUDGET_YEAR': {'type': 'string'},
'url': {'type': 'string'}
}, },
'required': ['id', 'name', 'type', 'description', 'url'], 'required': ['id'],
'additionalProperties': False 'additionalProperties': False
} }
}, },
...@@ -59,18 +61,24 @@ def budget_view() -> Any: ...@@ -59,18 +61,24 @@ def budget_view() -> Any:
:return: :return:
""" """
with db.session_scope() as session: try:
data = session.query(model.BudgetEntry).all() with survey_db.session_scope() as session:
data = session.query(survey_model.Nrens).join(survey_model.Budgets,
def _extract_data(entry: model.BudgetEntry): survey_model.Budgets.country_code == survey_model.Nrens.country_code)
return { for nren in data:
'id': entry.id, print(nren)
'type': entry.budget_type, except Exception as e:
'name': entry.name, print(e)
'description': entry.description,
'url': ''
} # def _extract_data(entry: model.BudgetEntry):
# return {
entries = [_extract_data(entry) for entry in data] # 'id': entry.id,
# 'NREN': entry.NREN,
return jsonify(entries) # 'BUDGET': entry.BUDGET,
# 'BUDGET_YEAR': entry.BUDGET_YEAR,
# }
# entries = [_extract_data(entry) for entry in data]
#
# return jsonify(entries)
import contextlib
import logging
from typing import Optional, Union, Callable, Iterator
from sqlalchemy import create_engine
from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import sessionmaker, Session
logger = logging.getLogger(__name__)
_SESSION_MAKER: Union[None, sessionmaker] = None
@contextlib.contextmanager
def session_scope(
callback_before_close: Optional[Callable] = None) -> Iterator[Session]:
# best practice is to keep session scope separate from data processing
# cf. https://docs.sqlalchemy.org/en/13/orm/session_basics.html
assert _SESSION_MAKER
session = _SESSION_MAKER()
try:
yield session
session.commit()
if callback_before_close:
callback_before_close()
except SQLAlchemyError:
logger.error('caught sql layer exception, rolling back')
session.rollback()
raise # re-raise, will be handled by main consumer
finally:
session.close()
def postgresql_dsn(db_username, db_password, db_hostname, db_name, port=5432):
return (f'postgresql://{db_username}:{db_password}'
f'@{db_hostname}:{port}/{db_name}')
def init_db_model(dsn):
global _SESSION_MAKER
# cf. https://docs.sqlalchemy.org/en
# /latest/orm/extensions/automap.html
engine = create_engine(dsn, pool_size=10, max_overflow=0)
_SESSION_MAKER = sessionmaker(bind=engine)
import enum
import logging
import sqlalchemy as sa
from sqlalchemy.orm import sessionmaker
from typing import Any
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
logger = logging.getLogger(__name__)
# https://github.com/python/mypy/issues/2477
base_schema: Any = declarative_base()
def _enum_names(enum_class):
return [x.name for x in list(enum_class)]
class Budgets(base_schema):
__tablename__ = 'budgets'
id = sa.Column(sa.Integer, primary_key=True)
budget = sa.Column(sa.String)
year = sa.Column(sa.Integer)
country_code = sa.Column(sa.String)
# nren = relationship(
# 'Nrens', foreign_keys=[country_code],
# primaryjoin='Nrens.country_code == Budgets.country_code',
# back_populates='budgets')
class Nrens(base_schema):
__tablename__ = 'nrens'
id = sa.Column(sa.Integer, primary_key=True)
abbreviation = sa.Column(sa.String)
country_code = sa.Column(sa.String)
# budgets = relationship(
# 'Budgets', foreign_keys=[country_code],
# primaryjoin='Nrens.country_code == Budgets.country_code')
# class BudgetEntry(base_schema):
# # Session = sessionmaker(bind=engine)
# # session = Session()
#
# __tablename__ = 'budgets'
# session.query(Budget).all()
# id = sa.Column(sa.Integer, autoincrement=True)
# nren = sa.Column(sa.String(128), primary_key=True)
# budget = sa.Column(sa.String(128), nullable=True)
# year = sa.Column(sa.String(128), primary_key=True)
...@@ -12,4 +12,4 @@ services: ...@@ -12,4 +12,4 @@ services:
ports: ports:
- "65000:5432" - "65000:5432"
volumes: volumes:
- ./build/db:/var/lib/postgresql - ./build/db:/var/lib/postgresql
\ No newline at end of file
...@@ -18,4 +18,4 @@ types-docutils ...@@ -18,4 +18,4 @@ types-docutils
types-jsonschema types-jsonschema
types-Flask-Cors types-Flask-Cors
types-setuptools types-setuptools
types-sqlalchemy types-sqlalchemy
\ No newline at end of file
...@@ -65,7 +65,7 @@ function DataAnalysis(): ReactElement { ...@@ -65,7 +65,7 @@ function DataAnalysis(): ReactElement {
return; return;
} }
api<BudgetMatrix>('/api/data-entries/item/' + selectedDataEntry,{ api<BudgetMatrix>('/api/budget' + selectedDataEntry,{
referrerPolicy: "unsafe-url", referrerPolicy: "unsafe-url",
headers: { headers: {
"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Origin": "*",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment