Skip to content
This repository was archived by the owner on Dec 6, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 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 .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
"editor.defaultFormatter": "charliermarsh.ruff",
"ruff.enable": true,
"ruff.organizeImports": true,
"editor.renderWhitespace": "all",
}
19 changes: 17 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@
"clear": true,
"focus": true
}, "problemMatcher": []
},
{
}, {
"label": "UV Sync ",
"type": "shell",
"command": "uv sync",
Expand All @@ -77,6 +76,22 @@
"focus": true
},
"problemMatcher": []
},
{
"label": "Fix Code with Ruff",
"type": "shell",
"command": "ruff check --fix .",
"options": {
"cwd": "${workspaceFolder}/src"
},
"group": "none",
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true,
"focus": true
},
"problemMatcher": []
}
]
}
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ plugins.jedi_definition.enabled = true
[tool.ruff]
line-length = 100
target-version = "py313"
fix = true

[tool.ruff.lint]
select = ["E", "F", "I", "W"] # Error, F: PyFlakes, I: isort, W: pycodestyle warnings
Expand Down
1 change: 1 addition & 0 deletions src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def __init__(self):
self.CONFIG_FILE_DIRECTORY = "config_files"
self.LOGGING_CONFIG = self.load_config_file("logging_config.yaml")
self.DATABASE_SCHEMA = self.load_config_file("verity_schema.yaml")
self.DEFAULT_DATA = self.load_config_file("default_data.yaml")

def load_config_file(self, file):
config = ""
Expand Down
4 changes: 4 additions & 0 deletions src/config_files/default_data.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
category:
- name: 'internal_master_category'
- name: 'tesing more categories'
budget_value: '100'
23 changes: 23 additions & 0 deletions src/currency_handler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import logging

logger = logging.getLogger(__name__)

# TODO: Make this into a proper class so we can scale currrency handling


def convert_to_universal_currency(input_value: float) -> int:
"""
Converts the the input value to remove all decimal places and return an int.
This will be the starting point for our universal currency,
(see docs/data_dictionary).
for now, we will just focus on making this an int.
it will need change later once we have the basics done
"""
logger.info(f"received {input_value} to convert to universal currency")
input_value = float(input_value)
while input_value % 1 != 0:
logger.debug(f"input value is not a whole number {input_value}")
input_value = input_value * 10
logger.info(f"returning {int(input_value)}")
return int(input_value)

126 changes: 70 additions & 56 deletions src/data_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,56 +14,64 @@ def __init__(self, config) -> None:
self.verity_config = config
self.schema = self.verity_config.DATABASE_SCHEMA
self.database = self.verity_config.DATABASE
self.default_data = self.verity_config.DEFAULT_DATA

def execute_sql(self, sql_statement: str, return_id: bool = False) -> (bool, int):
def execute_sql(
self, sql_statement: str, params: tuple = (), return_id: bool = False, seed: bool = False
) -> (bool, int):
"send the query here, returns true if successful, false if fail"
logging.debug(f"received request to execute {sql_statement}")
logger.debug(f"received request to execute {sql_statement} with params {params}")
new_id: int = 0
is_success: bool = False
try:
connection = sqlite3.connect(
database=self.database,
timeout=10, # seconds i hope
)
logging.debug("opened connection to database")
logger.info("opened connection to database")
cursor = connection.cursor()
cursor.execute(sql_statement, {})
cursor.execute("PRAGMA foreign_keys = ON;")
if seed:
cursor.execute("PRAGMA foreign_keys = OFF;")
cursor.execute(sql_statement, params)
connection.commit()
logger.debug(f"executed {sql_statement} with params: {params}")
logger.info("executed sql command")
if return_id:
new_id = cursor.lastrowid
logger.debug(f"New id created {new_id}")
is_success = True
except Exception as e: # TODO: better Exception handling
logging.error(e)
logger.error(e)
is_success = False
finally:
cursor.execute("PRAGMA foreign_keys = ON;")
connection.close()
logger.info("closed connection to database")
if return_id:
return (is_success, new_id)
else:
return is_success

def read_database(self, sql_statement: str):
def read_database(self, sql_statement: str, params: tuple = ()) -> list:
"reads the database query and returns the results"
logging.debug(f"received request to read {sql_statement}")
results = 0
logger.debug(f"received request to read {sql_statement} with params {params}")
results = []
try:
connection = sqlite3.connect(self.database)
logging.debug("opened connection to database")
cursor = connection.cursor()
results = cursor.execute(sql_statement, {})
results = cursor.execute(sql_statement, params)
results = results.fetchall()
logging.debug(f"query returned: {results}")
logger.debug(f"query returned: {results}")
except Exception as e:
logging.error(f"Read error occured: {e}")
logger.error(f"Read error occurred: {e}")
finally:
connection.close()
return results

@staticmethod
def _build_column(column: dict) -> str:
logging.debug(
f"building column {column}"
)
logging.debug(f"building column {column}")
name = column["column_name"]
is_pk = column["is_pk"]
is_fk = column.get("is_fk")
Expand All @@ -78,7 +86,6 @@ def _build_column(column: dict) -> str:
column_string += " NOT NULL"
return column_string


def _add_table_to_db(self, table: dict) -> bool:
"Creates the table in the verity database, based on the schema yaml"
sql = f"""CREATE TABLE IF NOT EXISTS {table["table_name"]} (
Expand Down Expand Up @@ -133,9 +140,7 @@ def print_table_schema(self, table_name):
# Print the schema
logger.debug(f"Schema for table: {table_name}")
for row in cursor.fetchall():
logger.debug(
f"Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}"
)
logger.debug(f"Column Name: {row[1]}, Data Type: {row[2]}, Not Null: {row[3]}")

except Exception as e:
logger.error(f"An error occurred: {e}")
Expand All @@ -148,42 +153,51 @@ def print_table_schema(self, table_name):

def add_user_name(self, user_name: str) -> int:
"takes user name string, returns user id"
logger.debug(
f"attempting to insert values into user table {user_name}"
)
try:
connection = sqlite3.connect(self.database)
logger.debug("connection to db open")
cursor = connection.cursor()
logger.debug("cursor activated")
cursor.execute(
"""INSERT INTO user (
name
)
VALUES (?)
""",
(user_name,),
)
logger.debug("cursor executed")
connection.commit()
user_id = cursor.lastrowid
logger.debug(f"insert attempt seems successful, user id is {user_id}")

if user_id is None:
user_id = 0
except Exception as e:
logger.error(f"Failed to insert user name, error: {e}")
user_id = 0
finally:
try:
connection.close()
logger.debug("connection to db closed")
return user_id
except Exception as e:
logger.error(f"failed to close connection message: {e}")
return 0
logger.debug(f"attempting to insert values into user table {user_name}")
sql_statement = """
INSERT INTO user (name)
VALUES (?)
"""
params = (user_name,)
success, user_id = self.execute_sql(sql_statement, params, True)
if not success:
logger.error("Failed to execute sql, check the logs")
self.add_category(user_id, "internal_master_category", seed=True)
return user_id

def get_users(self) -> list:
get_user_sql = "SELECT name FROM user"
users = self.read_database(get_user_sql)
return users
"""Returns all users in the database."""
get_user_sql = "SELECT id, name FROM user"
return self.read_database(get_user_sql)

def add_category(
self, user_id: int, category_name: str, budget_value: int = 0, parent_id=None, seed=False
) -> int:
"""Inserts a new category. Returns the category id."""
logger.debug(f"attempting to insert category '{category_name}' for user {user_id}")
sql_statement = """
INSERT INTO category (user_id, name, budget_value, parent_id)
VALUES (?, ?, ?, ?)"""
if not seed:
if not parent_id:
parent_id = self.read_database(
"SELECT id FROM category WHERE user_id = ? AND name = ?",
(user_id, "internal_master_category"),
)
try:
parent_id = parent_id[0][0]
except IndexError:
parent_id = None
params = (user_id, category_name, budget_value, parent_id)

success, category_id = self.execute_sql(sql_statement, params, True, seed)
if not success:
logger.error("Failed to execute sql, check the logs")
return category_id

def get_categories(self, user_id: int) -> list:
"""Returns all categories for a given user."""
sql = (
"SELECT id, name, budget_value, parent_id FROM category WHERE user_id = ? and name != ?"
)
return self.read_database(sql_statement=sql, params=(user_id, "internal_master_category"))
Loading