mirror of
https://github.com/Haiti-Distributed-Healthcare-System/hdhs.git
synced 2026-10-26 17:35:23 +00:00
169 lines
5.3 KiB
Python
169 lines
5.3 KiB
Python
import json
|
|
from datetime import datetime
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pyodbc
|
|
from tqdm import tqdm
|
|
|
|
from db import DB
|
|
from utils import edit_distance
|
|
|
|
|
|
"""
|
|
File Maker Pro Connection Object
|
|
|
|
Desc:
|
|
This file contains the primary logic for interacting with the file maker pro database
|
|
"""
|
|
|
|
|
|
class FMP(DB):
|
|
def __init__(self, dsn=None, username=None, password=None, connect=True):
|
|
DB.__init__(self)
|
|
if dsn is None:
|
|
dsn = input("Enter the FMP DSN: ")
|
|
if username is None:
|
|
username = input("Enter your FMP username: ")
|
|
if password is None:
|
|
password = input("Enter your FMP password: ")
|
|
|
|
self.__dsn = dsn
|
|
self.__username = username
|
|
self.__password = password
|
|
|
|
self.__connection_string = "DSN={0};UID={1};PWD={2}".format(
|
|
self.__dsn, self.__username, self.__password
|
|
)
|
|
|
|
# TODO: consider extracting this list to the DB class
|
|
self._table_names = [
|
|
"globals",
|
|
"clinics",
|
|
"patients",
|
|
"visits",
|
|
"diagnoses",
|
|
"diagnoses_made",
|
|
"meds",
|
|
"meds_dispensed",
|
|
"geonames",
|
|
"settings",
|
|
]
|
|
|
|
self._join_tables = [
|
|
"diagnoses_made",
|
|
"meds_dispensed"
|
|
]
|
|
|
|
self.__python_types_to_sql = {
|
|
"str": "VARCHAR",
|
|
"date": "TIMESTAMP",
|
|
"float64": "FLOAT",
|
|
"NoneType": "VARCHAR",
|
|
}
|
|
|
|
self.__pyodbc_connection = None
|
|
self.__cursor = None
|
|
if connect:
|
|
self.__connect()
|
|
|
|
# METHODS FROM DB SUPER CLASS
|
|
# ###########################
|
|
|
|
def read_table(self, table_name) -> pd.DataFrame:
|
|
query = "select * from {table}".format(table=table_name)
|
|
df = pd.read_sql(query, self.connection)
|
|
return df
|
|
|
|
def write_table(self, data, table_name):
|
|
# TODO: implement write_table in FMP class
|
|
print("IMPLEMENT WRITE_TABLE IN FMP")
|
|
|
|
# ###########################
|
|
|
|
def __connect(self):
|
|
if self.__pyodbc_connection is None:
|
|
self.__pyodbc_connection = pyodbc.connect(self.__connection_string)
|
|
self.__pyodbc_connection
|
|
|
|
def execute_command(self, command_string):
|
|
result = None
|
|
try:
|
|
result = pd.read_sql(command_string, self.connection)
|
|
except Exception as e:
|
|
print(f"Failure to execute: ['{command_string}']")
|
|
raise (e) # TODO: determine if crashing is appropriate
|
|
return result
|
|
|
|
@property
|
|
def python_types_to_sql(self):
|
|
return self.__python_types_to_sql
|
|
|
|
@property
|
|
def connection(self):
|
|
if self.__pyodbc_connection is None:
|
|
self.__connect()
|
|
return self.__pyodbc_connection
|
|
|
|
@property
|
|
def cursor(self):
|
|
if self.__cursor is None:
|
|
self.__cursor = self.connection.cursor()
|
|
return self.__cursor
|
|
|
|
# ABSTRACT BASE CLASS MEHTODS
|
|
def parse_database(self) -> dict():
|
|
self._model = dict()
|
|
|
|
for table_name in tqdm(self.table_names):
|
|
df = self.read_table(table_name)
|
|
|
|
self._model[table_name] = {}
|
|
col_types = [
|
|
df.iloc[0, index].__class__.__name__ for index in range(len(df.columns))
|
|
]
|
|
|
|
smallest_pk_edit_distance = float("inf")
|
|
previous_pk_field = None
|
|
for field_name, field_type in zip(df.columns, col_types):
|
|
self._model[table_name][field_name] = {}
|
|
self._model[table_name][field_name]["type"] = field_type
|
|
|
|
# extract primary keys
|
|
if field_name[:3] == "pk_":
|
|
# possible primary key
|
|
distance = edit_distance(field_name[3:-3], table_name)
|
|
if distance < smallest_pk_edit_distance:
|
|
# closest primary key so far
|
|
if previous_pk_field is not None:
|
|
# remove previously assumed pk
|
|
self._model[table_name][previous_pk_field]["pk"] = False
|
|
|
|
# set current pk
|
|
self._model[table_name][field_name]["pk"] = True
|
|
previous_pk_field = field_name
|
|
smallest_pk_edit_distance = distance
|
|
else:
|
|
self._model[table_name][field_name]["pk"] = False
|
|
else:
|
|
self._model[table_name][field_name]["pk"] = False
|
|
|
|
# extract foreign keys
|
|
if field_name[:3] == "fk_":
|
|
self._model[table_name][field_name]["fk"] = True
|
|
self._model[table_name][field_name][
|
|
"fk_table"
|
|
] = self.get_tablename_from_fieldname(field_name)
|
|
else:
|
|
self._model[table_name][field_name]["fk"] = False
|
|
|
|
return self._model
|
|
|
|
def write_model(self, model_object: dict = None):
|
|
curr_time = datetime.now().strftime(self.datetime_format)
|
|
with open("./models/{time}_model.json".format(time=curr_time), "w") as f:
|
|
if model_object is not None:
|
|
json.dump(model_object, f, indent=4)
|
|
else:
|
|
json.dump(self._model, f, indent=4)
|