Files

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)