From fa068befe5e6b5b279643378c8304b5f2ef67593 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Mon, 16 Sep 2024 13:00:50 +0300 Subject: [PATCH 01/10] first commit of class tag --- DB/NEW_KT_DB/DataAccess/DBManager.py | 151 +++++++------ DB/NEW_KT_DB/DataAccess/ObjectManager.py | 89 ++++---- Storage/ELTS/GenreSalseDailyELT.py | 204 ++++++++++++++++++ .../Controller/TagObjectController.py | 29 +++ .../DataAccess/ObjectManager.py | 4 +- .../DataAccess/TagObjectManager.py | 35 +++ .../NEW_KT_Storage/Models/TagObjectModel.py | 23 ++ .../Service/Classes/TagObjectService.py | 28 +++ 8 files changed, 439 insertions(+), 124 deletions(-) create mode 100644 Storage/ELTS/GenreSalseDailyELT.py create mode 100644 Storage/NEW_KT_Storage/Controller/TagObjectController.py create mode 100644 Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py create mode 100644 Storage/NEW_KT_Storage/Models/TagObjectModel.py create mode 100644 Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py diff --git a/DB/NEW_KT_DB/DataAccess/DBManager.py b/DB/NEW_KT_DB/DataAccess/DBManager.py index dd0dde58..89c1cb90 100644 --- a/DB/NEW_KT_DB/DataAccess/DBManager.py +++ b/DB/NEW_KT_DB/DataAccess/DBManager.py @@ -3,34 +3,32 @@ import json from sqlite3 import OperationalError + class DBManager: def __init__(self, db_file: str): - '''Initialize the database connection and create tables if they do not exist.''' + """Initialize the database connection and create tables if they do not exist.""" self.connection = sqlite3.connect(db_file) - # rachel-8511, ShaniStrassProg def close(self): - '''Close the database connection.''' - self.connection.close() - + """Close the database connection.""" + self.connection.close() # saraNoigershel def execute_query_with_multiple_results(self, query: str) -> Optional[List[Tuple]]: - '''Execute a given query and return the results.''' - try: - c = self.connection.cursor() - c.execute(query) - results = c.fetchall() - # self.connection.commit() ??? - return results if results else None - except OperationalError as e: - raise Exception(f'Error executing query {query}: {e}') - - - # ShaniStrassProg + """Execute a given query and return the results.""" + try: + c = self.connection.cursor() + c.execute(query) + results = c.fetchall() + # self.connection.commit() ??? + return results if results else None + except OperationalError as e: + raise Exception(f"Error executing query {query}: {e}") + + # ShaniStrassProg def execute_query_with_single_result(self, query: str) -> Optional[Tuple]: - '''Execute a given query and return a single result.''' + """Execute a given query and return a single result.""" try: c = self.connection.cursor() c.execute(query) @@ -38,94 +36,97 @@ def execute_query_with_single_result(self, query: str) -> Optional[Tuple]: # self.connection.commit() ??? return result if result else None except OperationalError as e: - raise Exception(f'Error executing query {query}: {e}') - + raise Exception(f"Error executing query {query}: {e}") # Riki7649255 def execute_query_without_results(self, query: str): - '''Execute a given query without waiting for any result.''' + """Execute a given query without waiting for any result.""" try: c = self.connection.cursor() c.execute(query) self.connection.commit() except OperationalError as e: - raise Exception(f'Error executing query {query}: {e}') - + raise Exception(f"Error executing query {query}: {e}") # Yael, Riki7649255 def create_table(self, table_name, table_structure): - '''create a table in a given db by given table_structure''' - create_statement = f'''CREATE TABLE IF NOT EXISTS {table_name} ({table_structure})''' - execute_query_without_results(create_statement) - + """create a table in a given db by given table_structure""" + create_statement = ( + f"""CREATE TABLE IF NOT EXISTS {table_name} ({table_structure})""" + ) + self.execute_query_without_results(create_statement) - # Riki7649255 based on rachel-8511, ShaniStrassProg + # Riki7649255 based on rachel-8511, ShaniStrassProg def insert_data_into_table(self, table_name, data): - insert_statement = f'''INSERT INTO {table_name} VALUES {data}''' - execute_query_without_results(insert_statement) + insert_statement = f"""INSERT INTO {table_name} VALUES {data}""" + self.execute_query_without_results(insert_statement) + def get_all_data_from_table(self, table_name): + get_all_data_query = f"""SELECT * FROM {table_name} """ + return self.execute_query_with_multiple_results(get_all_data_query) + # Riki7649255 based on rachel-8511, Shani - def update_records_in_table(self, table_name: str, updates: Dict[str, Any], criteria: str) -> None: - '''Update records in the specified table based on criteria.''' - - # add documentation here - set_clause = ', '.join([f'{k} = ?' for k in updates.keys()]) - values = list(updates.values()) - - update_statement = f''' - UPDATE {table_name} - SET {set_clause} - WHERE {criteria} - ''' - - execute_query_without_results(update_statement) + def update_records_in_table( + self, table_name: str, updates: Dict[str, Any], criteria: str + ) -> None: + """Update records in the specified table based on criteria.""" + + # add documentation here + set_clause = ", ".join([f"{k} = ?" for k in updates.keys()]) + values = list(updates.values()) + update_statement = f""" + UPDATE {table_name} + SET {set_clause} + WHERE {criteria} + """ + + self.execute_query_without_results(update_statement) # Riki7649255 based on rachel-8511 def delete_data_from_table(self, table_name: str, criteria: str) -> None: - '''Delete a record from the specified table based on criteria.''' - - delete_statement = f''' - DELETE FROM {table_name} - WHERE {criteria} - ''') - - execute_query_without_results(delete_statement) + """Delete a record from the specified table based on criteria.""" + + delete_statement = f""" + DELETE FROM {table_name} + WHERE {criteria} + """ + self.execute_query_without_results(delete_statement) # rachel-8511, Riki7649255 - def select_and_return_records_from_table(self, table_name: str, columns: List[str] = ['*'], criteria: str = '') -> Dict[int, Dict[str, Any]]: - '''Select records from the specified table based on criteria. + def select_and_return_records_from_table( + self, table_name: str, columns: List[str] = ["*"], criteria: str = "" + ) -> Dict[int, Dict[str, Any]]: + """Select records from the specified table based on criteria. Args: table_name (str): The name of the table. columns (List[str]): The columns to select. Default is all columns ('*'). criteria (str): SQL condition for filtering records. Default is no filter. Returns: Dict[int, Dict[str, Any]]: A dictionary where keys are object_ids and values are metadata. - ''' - columns_clause = ', '.join(columns) - query = f'SELECT {columns_clause} FROM {table_name}' + """ + columns_clause = ", ".join(columns) + query = f"SELECT {columns_clause} FROM {table_name}" if criteria: - query += f' WHERE {criteria}' + query += f" WHERE {criteria}" try: - results = execute_query_with_multiple_results(query) + results = self.execute_query_with_multiple_results(query) return {result[0]: dict(zip(columns, result[1:])) for result in results} except OperationalError as e: - raise Exception(f'Error selecting from {table_name}: {e}') - + raise Exception(f"Error selecting from {table_name}: {e}") # rachel-8511, ShaniStrassProg, Riki7649255 def describe_table(self, table_name: str) -> Dict[str, str]: - '''Describe table structure.''' + """Describe table structure.""" try: - desc_statement = f'PRAGMA table_info({table_name})' - columns = execute_query_with_multiple_results(desc_statement) + desc_statement = f"PRAGMA table_info({table_name})" + columns = self.execute_query_with_multiple_results(desc_statement) return {col[1]: col[2] for col in columns} except OperationalError as e: - raise Exception(f'Error describing table {table_name}: {e}') - - + raise Exception(f"Error describing table {table_name}: {e}") + # ShaniStrassProg # should be in ObjectManager and send the query to one of the execute_query functions # def is_json_column_contains_key_and_value(self, table_name: str, key: str, value: str) -> bool: @@ -144,7 +145,6 @@ def describe_table(self, table_name: str) -> Dict[str, str]: # print(f'Error: {e}') # return False - # Yael, ShaniStrassProg # should be in ObjectManager and send the query to one of the execute_query functions # def is_identifier_exist(self, table_name: str, value: str) -> bool: @@ -158,14 +158,13 @@ def describe_table(self, table_name: str) -> Dict[str, str]: # return c.fetchone()[0] > 0 # except sqlite3.OperationalError as e: # print(f'Error: {e}') - # sara-lea # should be in ObjectManager and send the query to one of the execute_query functions # def update_metadata(self, table_name: str, user_id: int, key: str, value: Any, action: str = 'set') -> None: # """ # Generic function to update a specific part of the metadata for a given user. - + # Parameters: # - table_name: The name of the table containing the metadata. # - user_id: The ID of the user whose metadata needs to be updated. @@ -173,7 +172,7 @@ def describe_table(self, table_name: str) -> Dict[str, str]: # - value: The value to update, append, or delete (could be a new policy, role, password, etc.). # - action: The type of update to perform ('set' for replacing, 'append' for adding to lists, 'update' for dicts, 'delete' for removing). # """ - + # # Step 1: Retrieve the current metadata for the user # query = f"SELECT metadata FROM {table_name} WHERE user_id = ?" # try: @@ -186,11 +185,11 @@ def describe_table(self, table_name: str) -> Dict[str, str]: # raise Exception(f"User with id {user_id} not found.") # except OperationalError as e: # raise Exception(f'Error fetching metadata: {e}') - + # # Step 2: Modify the relevant part of the metadata # if key not in metadata: # raise KeyError(f"Key '{key}' not found in metadata.") - + # if action == 'set': # # Replace the value of the key directly # metadata[key] = value @@ -217,11 +216,11 @@ def describe_table(self, table_name: str) -> Dict[str, str]: # raise ValueError(f"Action 'delete' is not supported for the data type of key '{key}'.") # else: # raise ValueError(f"Invalid action '{action}' or incompatible data type for key '{key}'.") - + # # Step 3: Serialize metadata back to JSON string # updated_metadata = json.dumps(metadata) - + # # Step 4: Use your update function to write the new metadata back to the database # updates = {"metadata": updated_metadata} # criteria = f"user_id = {user_id}" - # self.update(table_name, updates, criteria) \ No newline at end of file + # self.update(table_name, updates, criteria) diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index 56c6948f..a8a0739f 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -3,104 +3,101 @@ import sqlite3 from DBManager import DBManager + class ObjectManager: def __init__(self, db_file: str): - '''Initialize ObjectManager with the database connection.''' + """Initialize ObjectManager with the database connection.""" self.db_manager = DBManager(db_file) - # for internal use only: - - # Riki7649255 based on rachel-8511 - def create_management_table(self, table_name, table_structure='object_id INTEGER PRIMARY KEY AUTOINCREMENT,type_object TEXT NOT NULL,metadata TEXT NOT NULL') + def create_management_table( + self, + table_name, + table_structure: str = "object_id INTEGER PRIMARY KEY AUTOINCREMENT,type_object TEXT NOT NULL,metadata TEXT NOT NULL", + ): self.db_manager.create_table(table_name, table_structure) - # Riki7649255 based on saraNoigershel def insert_object_to_management_table(self, table_name, object): self.db_manager.insert_data_into_table(table_name, object) - # Riki7649255 based on rachel-8511 - def update_object_in_management_table_by_criteria(self, table_name, updates, criteria): + def update_object_in_management_table_by_criteria( + self, table_name, updates, criteria + ): self.db_manager.update_records_in_table(table_name, updates, criteria) - # rachel-8511, Riki7649255 def get_object_from_management_table(self, object_id: int) -> Dict[str, Any]: - '''Retrieve an object from the database.''' - result = self.db_manager.select_and_return_records_from_table(self.table_name, ['type_object', 'metadata'], f'object_id = {object_id}') + """Retrieve an object from the database.""" + result = self.db_manager.select_and_return_records_from_table( + self.table_name, ["type_object", "metadata"], f"object_id = {object_id}" + ) if result: return result[object_id] else: - raise FileNotFoundError(f'Object with ID {object_id} not found.') - + raise FileNotFoundError(f"Object with ID {object_id} not found.") # rachel-8511, ShaniStrassProg, Riki7649255 def delete_object_from_management_table(self, table_name, criteria) -> None: - '''Delete an object from the database.''' + """Delete an object from the database.""" self.db_manager.delete_data_from_table(table_name, criteria) - # rachel-8511, ShaniStrassProg is it needed? # def get_all_objects(self) -> Dict[int, Dict[str, Any]]: # '''Retrieve all objects from the database.''' # return self.db_manager.select(self.table_name, ['object_id', 'type_object', 'metadata']) - # rachel-8511 is it needed? # def describe_table(self) -> Dict[str, str]: # '''Describe the schema of the table.''' # return self.db_manager.describe(self.table_name) - def convert_object_name_to_management_table_name(object_name): - return f'mng_{object_name}s' - + return f"mng_{object_name}s" def is_management_table_exist(table_name): # check if table exists using single result query - return db_manager.execute_query_with_single_result(f'desc table {table_name}') - + return self.db_manager.execute_query_with_single_result( + f"desc table {table_name}" + ) # for outer use: def save_in_memory(self, object): - + # insert object info into management table mng_{object_name}s # for exmple: object db_instance will be saved in table mng_db_instances - table_name = convert_object_name_to_management_table_name(self.object_name) + table_name = self.convert_object_name_to_management_table_name(self.object_name) - if not is_management_table_exist(table_name): - create_management_table(table_name) - - insert_object_to_management_table(table_name, object) + if not self.is_management_table_exist(table_name): + self.create_management_table(table_name) - - def delete_from_memory(self,criteria='default'): - - # if criteria not sent- use PK for deletion - if criteria == 'default': - criteria = f'{self.pk_column} = {self.pk_value}' - - table_name = convert_object_name_to_management_table_name(self.object_name) - - delete_data_from_table(table_name, criteria) + self.insert_object_to_management_table(table_name, object) + def delete_from_memory(self, criteria="default"): - def update_in_memory(self, updates, criteria='default'): - # if criteria not sent- use PK for deletion - if criteria == 'default': - criteria = f'{self.pk_column} = {self.pk_value}' + if criteria == "default": + criteria = f"{self.pk_column} = {self.pk_value}" - table_name = convert_object_name_to_management_table_name(self.object_name) + table_name = self.convert_object_name_to_management_table_name(self.object_name) - update_object_in_management_table_by_criteria(table_name, updates, criteria) + self.delete_data_from_table(table_name, criteria) + def update_in_memory(self, updates, criteria="default"): - def get_from_memory(self): - get_object_from_management_table(self.object_id) + # if criteria not sent- use PK for deletion + if criteria == "default": + criteria = f"{self.pk_column} = {self.pk_value}" + + table_name = self.convert_object_name_to_management_table_name(self.object_name) + self.update_object_in_management_table_by_criteria( + table_name, updates, criteria + ) + + def get_from_memory(self): + self.get_object_from_management_table(self.object_id) def convert_object_attributes_to_dictionary(**kwargs): @@ -108,5 +105,5 @@ def convert_object_attributes_to_dictionary(**kwargs): for key, value in kwargs.items(): dict[key] = value - + return dict diff --git a/Storage/ELTS/GenreSalseDailyELT.py b/Storage/ELTS/GenreSalseDailyELT.py new file mode 100644 index 00000000..494e3b6f --- /dev/null +++ b/Storage/ELTS/GenreSalseDailyELT.py @@ -0,0 +1,204 @@ +from pyspark.sql import SparkSession +import sqlite3 # Assuming you're using sqlite3 +import pandas as pd +from datetime import datetime +import os + +BASE_URL = "C:/Users/jimmy/Desktop/תמר לימודים יד/bootcamp/db_files" + + + + # create_table_time_query = """ + # CREATE TABLE IF NOT EXISTS tableTime AS + # SELECT ci.CustomerId, ci.created_at + # FROM customer_invoice_avg_elt ci + # WHERE EXISTS ( + # SELECT 1 + # FROM Customers_ELT ce + # JOIN Invoices_ELT i ON ce.CustomerId = i.CustomerId + # WHERE ((i.InvoiceDate > ? OR ce.created_at > ?) + # AND ci.customerId = ce.customerId) + # group by ce.CustomerId + # ) + # """ + + + # print("SELECT :",conn.execute("""SELECT c.CustomerId,c.created_at,i.InvoiceDate FROM Customers_ELT c + # JOIN Invoices_ELT i ON c.CustomerId = i.CustomerId + # where i.InvoiceDate > ? or c.created_at > ? + # group by c.CustomerId """ + # ,(latest_timestamp,latest_timestamp,)).fetchall()) + # # print("SELECT :",conn.execute("""SELECT InvoiceDate FROM Invoices_ELT + # # where InvoiceDate > ? """ + # # ,(latest_timestamp,)).fetchall()) + + # conn.execute(create_table_time_query, (latest_timestamp, latest_timestamp)) + # conn.commit() + # conn.execute("""DELETE FROM customer_invoice_avg_elt + # WHERE EXISTS ( + # SELECT 1 + # FROM tableTime t + # WHERE customer_invoice_avg_elt.CustomerId = t.CustomerId + # )""") + + # conn.commit() + # print("customer_invoice_avg_after_del:", conn.execute("SELECT * FROM 'customer_invoice_avg_elt'").fetchall()) + # print("tableTime:", conn.execute("SELECT * FROM 'tableTime'").fetchall()) + + # transform_query = """ + # INSERT INTO customer_invoice_avg_elt (CustomerId,InvoiceMonth, avg_spend, created_at, updated_at, updated_by) + # SELECT c.CustomerId, strftime('%m', i.InvoiceDate) AS InvoiceMonth, + # AVG(i.Total) AS avg_spend, + # COALESCE(t.created_at, CURRENT_DATE) AS created_at, + # CURRENT_DATE AS updated_at, + # 'process:shana_levovitz_' || CURRENT_DATE AS updated_by + # FROM Customers_ELT c + # RIGHT JOIN Invoices_ELT i ON c.CustomerId = i.CustomerId + # LEFT JOIN tableTime t ON c.CustomerId = t.CustomerId + # WHERE i.InvoiceDate > ? OR c.created_at > ? + # GROUP BY c.CustomerId, InvoiceMonth + # """ + # conn.execute(transform_query, (latest_timestamp, latest_timestamp)) + + # # Commit the changes to the database + # conn.execute("""DROP TABLE IF EXISTS tableTime""") + # conn.commit() + # print("customer_invoice_avg:", conn.execute("SELECT * FROM 'customer_invoice_avg_elt'").fetchall()) + # finally: + # # Step 3: Close the SQLite connection and stop Spark session + # conn.close() # Close the SQLite connection + # spark.stop() # Stop the Spark session + + + +def load(): + conn = sqlite3.connect(os.path.join(BASE_URL,"genres_table_ELT.db")) + try: + # EXTRACT (Loading CSVs from S3 or local storage) + # ----------------------------------------------- + genres = pd.read_csv(os.path.join(BASE_URL, "Genre.csv")) + tracks = pd.read_csv(os.path.join(BASE_URL, "Track.csv")) + invoice_lines = pd.read_csv(os.path.join(BASE_URL, "InvoiceLine.csv")) + # LOAD (Save the raw data into SQLite without transformation) + # ----------------------------------------------------------------------- + # Load raw data into SQLite + genres.to_sql("Genres", conn, if_exists="replace", index=False) + tracks.to_sql("Tracks", conn, if_exists="replace", index=False) + invoice_lines.to_sql("InvoiceLines", conn, if_exists="replace", index=False) + # TRANSFORM (Perform transformations with SQL queries using KT_DB functions) + # ------------------------------------------------------------------------- + last_update_date = """Select max(updated_at) from genre_sales_popularity_elt""" + latest_timestamp = conn.execute(last_update_date).fetchone()[0] + + # Handle case where no data exists yet (initial load) + if latest_timestamp is None: + latest_timestamp = '1900-01-01 00:00:00' + print("latest_timestamp:", latest_timestamp) + + transform_query = f""" + CREATE TABLE IF NOT EXISTS genre_sales_popularity_elt AS + SELECT + G.GenreId, + G.Name, + SUM(IL.UnitPrice * IL.Quantity) AS TotalSales, + AVG(IL.UnitPrice) AS AverageSalesPrice, + '{datetime.now()}' AS created_at, + '{datetime.now()}' AS updated_at, + 'Tamar Gavrielov' AS updated_by + FROM + Genres G + LEFT JOIN Tracks T ON G.GenreId = T.GenreId + LEFT JOIN InvoiceLines IL ON T.TrackId = IL.TrackId + WHERE G.Update_at > ? OR T.Update_at > ? + GROUP BY + G.GenreId, G.Name; + """ + # Execute the transformation query + conn.execute(transform_query) + # Commit the changes to the database + conn.commit() + finally: + # Close the SQLite connection and stop Spark session + conn.close() # Close the SQLite connection + + +def after_load_check_answers(): + conn = sqlite3.connect(os.path.join(BASE_URL,"genres_table_ELT.db")) + query = "SELECT * FROM genre_sales_popularity_elt" + result = pd.read_sql( + query, conn + ) # Use pandas to read the SQL result into a DataFrame + print(result.head()) + conn.close() + + +if __name__ == "__main__": + load() + after_load_check_answers() +from pyspark.sql import SparkSession +import sqlite3 # Assuming you're using sqlite3 +import pandas as pd +from datetime import datetime +import os + +BASE_URL = "C:/Users/jimmy/Desktop/תמר לימודים יד/bootcamp/db_files" + + +def load(): + conn = sqlite3.connect(os.path.join(BASE_URL,"genres_table_ELT.db")) + try: + # EXTRACT (Loading CSVs from S3 or local storage) + # ----------------------------------------------- + genres = pd.read_csv(os.path.join(BASE_URL, "Genre.csv")) + tracks = pd.read_csv(os.path.join(BASE_URL, "Track.csv")) + invoice_lines = pd.read_csv(os.path.join(BASE_URL, "InvoiceLine.csv")) + # LOAD (Save the raw data into SQLite without transformation) + # ----------------------------------------------------------------------- + # Load raw data into SQLite + genres.to_sql("Genres", conn, if_exists="replace", index=False) + tracks.to_sql("Tracks", conn, if_exists="replace", index=False) + invoice_lines.to_sql("InvoiceLines", conn, if_exists="replace", index=False) + # TRANSFORM (Perform transformations with SQL queries using KT_DB functions) + # ------------------------------------------------------------------------- + drop_query = """DROP TABLE IF EXISTS genre_sales_popularity_elt""" + conn.execute(drop_query) + conn.commit() + transform_query = f""" + CREATE TABLE genre_sales_popularity_elt AS + SELECT + G.GenreId, + G.Name, + SUM(IL.UnitPrice * IL.Quantity) AS TotalSales, + AVG(IL.UnitPrice) AS AverageSalesPrice, + '{datetime.now()}' AS created_at, + '{datetime.now()}' AS updated_at, + 'Tamar Gavrielov' AS updated_by + FROM + Genres G + LEFT JOIN Tracks T ON G.GenreId = T.GenreId + LEFT JOIN InvoiceLines IL ON T.TrackId = IL.TrackId + GROUP BY + G.GenreId, G.Name; + """ + # Execute the transformation query + conn.execute(transform_query) + # Commit the changes to the database + conn.commit() + finally: + # Close the SQLite connection and stop Spark session + conn.close() # Close the SQLite connection + + +def after_load_check_answers(): + conn = sqlite3.connect(os.path.join(BASE_URL,"genres_table_ELT.db")) + query = "SELECT * FROM genre_sales_popularity_elt" + result = pd.read_sql( + query, conn + ) # Use pandas to read the SQL result into a DataFrame + print(result.head()) + conn.close() + + +if __name__ == "__main__": + load() + after_load_check_answers() diff --git a/Storage/NEW_KT_Storage/Controller/TagObjectController.py b/Storage/NEW_KT_Storage/Controller/TagObjectController.py new file mode 100644 index 00000000..6f47430b --- /dev/null +++ b/Storage/NEW_KT_Storage/Controller/TagObjectController.py @@ -0,0 +1,29 @@ +from typing import Optional +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from Models import TagObjectModel +from Service.Classes import TagObjectService + + +class TagObjctController: + def __init__(self): + self.tag_service = TagObjectService() + + def create_tag(self, key, value,version_id): + return self.tag_service.create(key, value) + + def get_tag(self, ): + return self.tag_service.get(pk_value, pk_column) + + def delete_tag(self, pk_value, pk_column): + return self.tag_service.delete(pk_value, pk_column) + + def modify_tag(self): + return self.tag_service.modify() + + def describe_tag(self): + return self.tag_service.describe() diff --git a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py index 49d2b234..827dd7b8 100644 --- a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py @@ -46,8 +46,8 @@ def update_in_memory(self, updates, criteria='default'): self.object_manager.update_object_in_management_table_by_criteria(table_name, updates, criteria) - def get_from_memory(self): - self.object_manager.get_object_from_management_table(self.object_id) + def get_from_memory(self,object): + self.object_manager.get_object_from_management_table(object.id) def convert_object_attributes_to_dictionary(**kwargs): diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py new file mode 100644 index 00000000..7ccc9786 --- /dev/null +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -0,0 +1,35 @@ +from typing import Dict, Any +import json +import sqlite3 +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from Models.TagObjectModel import TagObject +from DataAccess.ObjectManager import ObjectManager + + +class TagObjectManager: + def __init__(self, db_file: str): + """Initialize ObjectManager with the database connection.""" + self.object_manager = ObjectManager(db_file) + self.object_manager.create_table() + + def createInMemoryTagObject(self, tag: TagObject): + return self.object_manager.save_in_memory(tag) + + def deleteInMemoryTagObject(self, tag: TagObject): + return self.object_manager.delete_from_memory(tag) + + def describeTagObject(self, tag: TagObject): + return self.object_manager.get_from_memory(tag) + + def putTagObject(self, tag: TagObject): + return self.object_manager.update_in_memory(tag) + + def get_tag_object_from_memory(self, tag:TagObject): + return self.object_manager.get_from_memory(tag) + + diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py new file mode 100644 index 00000000..4cbd71a3 --- /dev/null +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -0,0 +1,23 @@ +from typing import Dict +from DataAccess import ObjectManager +import uuid + + +class TagObject: + def __init__(self, key: str, value: str, pk_value): + self.id = str(uuid.uuid1()) + self.key = key + self.value = value + self.pk_column = "id" + self.pk_value = self.id + + def to_dict(self) -> Dict: + """Retrieve the data of the DB cluster as a dictionary.""" + + # send relevant attributes in this syntax: + return ObjectManager.convert_object_attributes_to_dictionary( + key=self.key, + value=self.value, + pk_column=self.pk_column, + pk_value=self.pk_value, + ) diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py new file mode 100644 index 00000000..36692ade --- /dev/null +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -0,0 +1,28 @@ +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from DataAccess.TagObjectManager import TagObjectManager +from Models.TagObjectModel import TagObject + + +class TagObjectService: + def __init__(self) -> None: + self.tag_dal = TagObjectManager() + + def create(self, key, value): + tag = TagObject(key, value) + return self.tag_dal.createInMemoryTagObject(tag) + + # def get(self, tag: TagObject): + # return self.tag_dal.get(tag) + + def delete(self, tag: TagObject): + return self.tag_dal.deleteInMemoryTagObject(tag) + + def modify(self, tag: TagObject): + return self.tag_dal.putTagObject(tag) + + def describe(self, tag: TagObject): + return self.tag_dal.describeTagObject(tag) From cedff0fe9bc4973846f7b2e88aa084483c776f95 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Tue, 17 Sep 2024 12:42:44 +0300 Subject: [PATCH 02/10] a few chenches I need it for pulling the main --- DB/NEW_KT_DB/DataAccess/DBManager.py | 238 ++++-------------- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 184 +++++++------- .../DataAccess/ObjectManager.py | 77 +++--- .../DataAccess/TagObjectManager.py | 8 +- .../NEW_KT_Storage/Models/TagObjectModel.py | 10 +- .../Service/Classes/TagObjectService.py | 5 + tag | Bin 0 -> 12288 bytes 7 files changed, 193 insertions(+), 329 deletions(-) create mode 100644 tag diff --git a/DB/NEW_KT_DB/DataAccess/DBManager.py b/DB/NEW_KT_DB/DataAccess/DBManager.py index d4547c94..01ba7efe 100644 --- a/DB/NEW_KT_DB/DataAccess/DBManager.py +++ b/DB/NEW_KT_DB/DataAccess/DBManager.py @@ -3,19 +3,11 @@ import json from sqlite3 import OperationalError - class DBManager: def __init__(self, db_file: str): - """Initialize the database connection and create tables if they do not exist.""" + '''Initialize the database connection and create tables if they do not exist.''' self.connection = sqlite3.connect(db_file) - - # rachel-8511, ShaniStrassProg - def close(self): - '''Close the database connection.''' - self.connection.close() - - # saraNoigershel def execute_query_with_multiple_results(self, query: str, params:Tuple = ()) -> Optional[List[Tuple]]: '''Execute a given query and return the results.''' @@ -23,77 +15,49 @@ def execute_query_with_multiple_results(self, query: str, params:Tuple = ()) -> c = self.connection.cursor() c.execute(query, params) results = c.fetchall() - self.connection.commit() + self.connection.commit() return results if results else None except OperationalError as e: raise Exception(f'Error executing query {query}: {e}') - def execute_query_with_multiple_results(self, query: str) -> Optional[List[Tuple]]: - """Execute a given query and return the results.""" - try: - c = self.connection.cursor() - c.execute(query) - results = c.fetchall() - # self.connection.commit() ??? - return results if results else None - except OperationalError as e: - raise Exception(f"Error executing query {query}: {e}") - # ShaniStrassProg + # ShaniStrassProg def execute_query_with_single_result(self, query: str, params:Tuple = ()) -> Optional[Tuple]: '''Execute a given query and return a single result.''' - # ShaniStrassProg - def execute_query_with_single_result(self, query: str) -> Optional[Tuple]: - """Execute a given query and return a single result.""" try: c = self.connection.cursor() c.execute(query, params) result = c.fetchone() - self.connection.commit() + self.connection.commit() return result if result else None - + except OperationalError as e: - raise Exception(f"Error executing query {query}: {e}") + raise Exception(f'Error executing query {query}: {e}') + # Riki7649255 def execute_query_without_results(self, query: str, params:Tuple = ()): '''Execute a given query without waiting for any result.''' - def execute_query_without_results(self, query: str): - """Execute a given query without waiting for any result.""" try: c = self.connection.cursor() c.execute(query, params) self.connection.commit() except OperationalError as e: - raise Exception(f"Error executing query {query}: {e}") + raise Exception(f'Error executing query {query}: {e}') + + # Yael, Riki7649255 def create_table(self, table_name, table_structure): '''create a table in a given db by given table_structure''' create_statement = f'''CREATE TABLE IF NOT EXISTS {table_name} ({table_structure})''' self.execute_query_without_results(create_statement) - """create a table in a given db by given table_structure""" - create_statement = ( - f"""CREATE TABLE IF NOT EXISTS {table_name} ({table_structure})""" - ) - self.execute_query_without_results(create_statement) - # Riki7649255 based on rachel-8511, ShaniStrassProg - def insert_data_into_table(self, table_name, columns, data): - column_names = ', '.join(columns) - placeholders = ', '.join(['?' for _ in range(len(columns))]) - insert_query = f"INSERT INTO {table_name} ({column_names}) VALUES ({placeholders})" - self.execute_query_without_results(insert_query, data) - # Riki7649255 based on rachel-8511, ShaniStrassProg def insert_data_into_table(self, table_name, data): - insert_statement = f"""INSERT INTO {table_name} VALUES {data}""" + insert_statement = f'''INSERT INTO {table_name} VALUES {data}''' self.execute_query_without_results(insert_statement) - def get_all_data_from_table(self, table_name): - get_all_data_query = f"""SELECT * FROM {table_name} """ - return self.execute_query_with_multiple_results(get_all_data_query) - # Riki7649255 based on rachel-8511, Shani def update_records_in_table(self, table_name: str, updates: Dict[str, Any], criteria: Optional[str]) -> None: @@ -101,8 +65,8 @@ def update_records_in_table(self, table_name: str, updates: Dict[str, Any], crit # add documentation here set_clause = ', '.join([f'{k} = ?' for k in updates.keys()]) - values = list(updates.values()) - + values = tuple(updates.values()) + update_statement = f''' UPDATE {table_name} SET {set_clause} @@ -112,22 +76,6 @@ def update_records_in_table(self, table_name: str, updates: Dict[str, Any], crit self.execute_query_without_results(update_statement, values) - def update_records_in_table( - self, table_name: str, updates: Dict[str, Any], criteria: str - ) -> None: - """Update records in the specified table based on criteria.""" - - # add documentation here - set_clause = ", ".join([f"{k} = ?" for k in updates.keys()]) - values = list(updates.values()) - - update_statement = f""" - UPDATE {table_name} - SET {set_clause} - WHERE {criteria} - """ - - self.execute_query_without_results(update_statement) # Riki7649255 based on rachel-8511 def delete_data_from_table(self, table_name: str, criteria: str) -> None: @@ -140,160 +88,68 @@ def delete_data_from_table(self, table_name: str, criteria: str) -> None: self.execute_query_without_results(delete_statement) - """Delete a record from the specified table based on criteria.""" - - delete_statement = f""" - DELETE FROM {table_name} - WHERE {criteria} - """ + # Tem-M + def get_columns_from_table(self, table_name): + '''Get the columns from the specified table.''' + try: + get_columns_query = f"""PRAGMA table_info({table_name});""" + cols = self.execute_query_with_multiple_results(get_columns_query) + return [col[1] for col in cols] + except Exception as e: + print(f"Error occurred while fetching columns from table {table_name}: {e}") + return [] - self.execute_query_without_results(delete_statement) + def get_all_data_from_table(self, table_name): + try: + get_all_data_query = f"""SELECT * FROM {table_name}""" + return self.execute_query_with_multiple_results(get_all_data_query) + except Exception as e: + print(f"Error occurred while fetching data from table {table_name}: {e}") + return [] # rachel-8511, Riki7649255 def select_and_return_records_from_table(self, table_name: str, columns: List[str] = ['*'], criteria: Optional[str] = None) -> Dict[int, Dict[str, Any]]: '''Select records from the specified table based on criteria. - def select_and_return_records_from_table( - self, table_name: str, columns: List[str] = ["*"], criteria: str = "" - ) -> Dict[int, Dict[str, Any]]: - """Select records from the specified table based on criteria. Args: table_name (str): The name of the table. columns (List[str]): The columns to select. Default is all columns ('*'). criteria (str): SQL condition for filtering records. Default is no filter. Returns: Dict[int, Dict[str, Any]]: A dictionary where keys are object_ids and values are metadata. - """ - columns_clause = ", ".join(columns) - query = f"SELECT {columns_clause} FROM {table_name}" + ''' + cols = columns + if cols == ['*']: + cols = self.get_columns_from_table(table_name) + + columns_clause = ', '.join(cols) + query = f'SELECT {columns_clause} FROM {table_name}' if criteria: - query += f" WHERE {criteria}" + query += f' WHERE {criteria};' + try: results = self.execute_query_with_multiple_results(query) - results = self.execute_query_with_multiple_results(query) - return {result[0]: dict(zip(columns, result[1:])) for result in results} + return {result[0]: dict(zip(cols if columns != ['*'] else cols[1:], result[1:])) for result in results} except OperationalError as e: raise Exception(f'Error selecting from {table_name}: {e}') - + except TypeError as e: + raise Exception(f'Error selecting from {table_name}: {e}') + def is_exists_in_table(self, table_name:str, criteria:str): """check if rows exists in table""" return self.select_and_return_records_from_table(table_name, criteria=criteria) != {} - - raise Exception(f"Error selecting from {table_name}: {e}") + # rachel-8511, ShaniStrassProg, Riki7649255 def describe_table(self, table_name: str) -> Dict[str, str]: - """Describe table structure.""" + '''Describe table structure.''' try: desc_statement = f'PRAGMA table_info({table_name})' columns = self.execute_query_with_multiple_results(desc_statement) - desc_statement = f"PRAGMA table_info({table_name})" - columns = self.execute_query_with_multiple_results(desc_statement) return {col[1]: col[2] for col in columns} except OperationalError as e: raise Exception(f'Error describing table {table_name}: {e}') - + # rachel-8511, ShaniStrassProg def close(self): '''Close the database connection.''' - self.connection.close() - - - raise Exception(f"Error describing table {table_name}: {e}") - - # ShaniStrassProg - # should be in ObjectManager and send the query to one of the execute_query functions - # def is_json_column_contains_key_and_value(self, table_name: str, key: str, value: str) -> bool: - # '''Check if a specific key-value pair exists within a JSON column in the given table.''' - # try: - # c = self.connection.cursor() - # # Properly format the LIKE clause with escaped quotes for key and value - # c.execute(f''' - # SELECT COUNT(*) FROM {table_name} - # WHERE metadata LIKE ? - # LIMIT 1 - # ''', (f'%"{key}": "{value}"%',)) - # # Check if the count is greater than 0, indicating the key-value pair exists - # return c.fetchone()[0] > 0 - # except sqlite3.OperationalError as e: - # print(f'Error: {e}') - # return False - - # Yael, ShaniStrassProg - # should be in ObjectManager and send the query to one of the execute_query functions - # def is_identifier_exist(self, table_name: str, value: str) -> bool: - # '''Check if a specific value exists within a column in the given table.''' - # try: - # c = self.connection.cursor() - # c.execute(f''' - # SELECT COUNT(*) FROM {table_name} - # WHERE id LIKE ? - # ''', (value,)) - # return c.fetchone()[0] > 0 - # except sqlite3.OperationalError as e: - # print(f'Error: {e}') - - # sara-lea - # should be in ObjectManager and send the query to one of the execute_query functions - # def update_metadata(self, table_name: str, user_id: int, key: str, value: Any, action: str = 'set') -> None: - # """ - # Generic function to update a specific part of the metadata for a given user. - - # Parameters: - # - table_name: The name of the table containing the metadata. - # - user_id: The ID of the user whose metadata needs to be updated. - # - key: The specific part of the metadata to update (e.g., 'password', 'roles', 'policies', 'quotas'). - # - value: The value to update, append, or delete (could be a new policy, role, password, etc.). - # - action: The type of update to perform ('set' for replacing, 'append' for adding to lists, 'update' for dicts, 'delete' for removing). - # """ - - # # Step 1: Retrieve the current metadata for the user - # query = f"SELECT metadata FROM {table_name} WHERE user_id = ?" - # try: - # c = self.connection.cursor() - # c.execute(query, (user_id,)) - # row = c.fetchone() - # if row: - # metadata = json.loads(row[0]) # Assuming metadata is stored as a JSON string - # else: - # raise Exception(f"User with id {user_id} not found.") - # except OperationalError as e: - # raise Exception(f'Error fetching metadata: {e}') - - # # Step 2: Modify the relevant part of the metadata - # if key not in metadata: - # raise KeyError(f"Key '{key}' not found in metadata.") - - # if action == 'set': - # # Replace the value of the key directly - # metadata[key] = value - # elif action == 'append' and isinstance(metadata[key], list): - # # Append to the list (for roles, policies, etc.) - # metadata[key].append(value) - # elif action == 'update' and isinstance(metadata[key], dict): - # # Update a dictionary (for quotas or nested data) - # metadata[key].update(value) - # elif action == 'delete': - # if isinstance(metadata[key], list): - # # Remove an item from a list - # if value in metadata[key]: - # metadata[key].remove(value) - # else: - # raise ValueError(f"Value '{value}' not found in list '{key}'.") - # elif isinstance(metadata[key], dict): - # # Remove a key from a dictionary - # if value in metadata[key]: - # del metadata[key][value] - # else: - # raise ValueError(f"Key '{value}' not found in dictionary '{key}'.") - # else: - # raise ValueError(f"Action 'delete' is not supported for the data type of key '{key}'.") - # else: - # raise ValueError(f"Invalid action '{action}' or incompatible data type for key '{key}'.") - - # # Step 3: Serialize metadata back to JSON string - # updated_metadata = json.dumps(metadata) - - # # Step 4: Use your update function to write the new metadata back to the database - # updates = {"metadata": updated_metadata} - # criteria = f"user_id = {user_id}" - # self.update(table_name, updates, criteria) + self.connection.close() \ No newline at end of file diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index 8b0b07eb..69e1a2d5 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,174 +1,157 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DBManager import DBManager - +from DB.NEW_KT_DB.DataAccess.DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): - """Initialize ObjectManager with the database connection.""" + '''Initialize ObjectManager with the database connection.''' self.db_manager = DBManager(db_file) + # for internal use only: # Riki7649255 based on rachel-8511 - def create_management_table( - self, - table_name, - table_structure="object_id INTEGER PRIMARY KEY AUTOINCREMENT,type_object TEXT NOT NULL,metadata TEXT NOT NULL", - ): + def create_management_table(self, table_name, table_structure='object_id INTEGER PRIMARY KEY AUTOINCREMENT,type_object TEXT NOT NULL,metadata TEXT NOT NULL'): self.db_manager.create_table(table_name, table_structure) - def create_management_table_with_str_id( - self, - table_name, - table_structure="object_id TEXT NOT NULL PRIMARY KEY ,metadata TEXT NOT NULL", - ): + def create_management_table_with_str_id(self, table_name, table_structure='object_id TEXT NOT NULL PRIMARY KEY ,metadata TEXT NOT NULL'): self.db_manager.create_table(table_name, table_structure) - # Riki7649255 based on saraNoigershel - def insert_object_to_management_table(self, table_name, object_metadata): - self.db_manager.insert_data_into_table( - table_name, ["metadata"], (object_metadata) - ) - def insert_object_to_management_table_with_str_id(self, table_name, id, metadata): - self.db_manager.insert_data_into_table( - table_name, ["object_id", "metadata"], (id, metadata) - ) + def insert_object_to_management_table(self, table_name, object): + self.db_manager.insert_data_into_table(table_name, object) + + # def insert_object_to_management_table_with_str_id(self, table_name, id, metadata): + # # self.db_manager.insert_data_into_table(table_name, ['object_id','metadata'],(id, metadata)) + + # def insert_object_to_management_table_with_str_id(self, table_name, id, metadata): + # self.db_manager.insert_data_into_table(table_name, ['object_id','metadata'],(id, metadata)) + def update_object_in_management_table_by_id(self, table_name, object_id, updates): + self.db_manager.update_records_in_table(table_name, updates, f'object_id = {object_id}') # Riki7649255 based on rachel-8511 - def update_object_in_management_table_by_criteria( - self, table_name, updates, criteria - ): + def update_object_in_management_table_by_criteria(self, table_name, updates, criteria): self.db_manager.update_records_in_table(table_name, updates, criteria) - def update_object_in_management_table_by_id(self, table_name, object_id, updates): - self.db_manager.update_records_in_table( - table_name, updates, f"object_id = {object_id}" - ) + # def update_object_in_management_table_by_id(self, table_name, object_id, updates): + # self.db_manager.update_records_in_table(table_name, updates, f'object_id = {object_id}') + # rachel-8511, Riki7649255 - def get_object_from_management_table( - self, table_name, object_id: int, columns=["*"] - ) -> Dict[str, Any]: - """Retrieve an object from the database.""" - result = self.db_manager.select_and_return_records_from_table( - table_name, columns, criteria=f"object_id = {object_id}" - ) + def get_object_from_management_table(self, table_name, object_id: int, columns = ["*"]) -> Dict[str, Any]: + '''Retrieve an object from the database.''' + result = self.db_manager.select_and_return_records_from_table(table_name, columns, criteria= f'object_id = {object_id}') if result: return result[object_id] else: - raise FileNotFoundError(f"Object with ID {object_id} not found.") - - def get_objects_from_management_table_by_criteria( - self, object_id: int, columns=["*"], criteria: Optional[str] = None - ) -> Dict: - """Retrieve an object from the database.""" - result = self.db_manager.select_and_return_records_from_table( - self.table_name, columns, criteria - ) + raise FileNotFoundError(f'Object with ID {object_id} not found.') + + def get_objects_from_management_table_by_criteria(self, object_id: int, columns = ["*"], criteria:Optional[str] = None) -> Dict: + '''Retrieve an object from the database.''' + result = self.db_manager.select_and_return_records_from_table(self.table_name, columns, criteria) if result: return result else: - raise FileNotFoundError(f"Objects with criteria {criteria} not found.") + raise FileNotFoundError(f'Objects with criteria {criteria} not found.') + # rachel-8511, ShaniStrassProg, Riki7649255 def delete_object_from_management_table(self, table_name, criteria) -> None: - """Delete an object from the database.""" + '''Delete an object from the database.''' self.db_manager.delete_data_from_table(table_name, criteria) def delete_object_from_management_table_by_id(self, table_name, object_id) -> None: - """Delete an object from the database.""" - self.db_manager.delete_data_from_table( - table_name, criteria=f"object_id = {object_id}" - ) + '''Delete an object from the database.''' + self.db_manager.delete_data_from_table(table_name, criteria= f'object_id = {object_id}') + # rachel-8511, ShaniStrassProg is it needed? # def get_all_objects(self) -> Dict[int, Dict[str, Any]]: # '''Retrieve all objects from the database.''' # return self.db_manager.select(self.table_name, ['object_id', 'type_object', 'metadata']) + # rachel-8511 is it needed? # def describe_table(self) -> Dict[str, str]: # '''Describe the schema of the table.''' # return self.db_manager.describe(self.table_name) - def convert_object_name_to_management_table_name(object_name): - return f"mng_{object_name}s" + + def convert_object_name_to_management_table_name(self,object_name): + return f'mng_{object_name}s' + def is_management_table_exist(self, table_name): # Check if table exists by querying the sqlite_master table - query = ( - f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'" - ) + query = f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'" return self.db_manager.execute_query_with_single_result(query) - # for outer use: - def save_in_memory( - self, object_name: str, metadata: Dict[str:Any], object_id: Optional[str] = None - ): - - # insert object info into management table mng_{object_name}s - # for exmple: object db_instance will be saved in table mng_db_instances - table_name = self.convert_object_name_to_management_table_name(object_name) - if not self.is_management_table_exist(table_name): - self.create_management_table(table_name) - - if object_id: - self.insert_object_to_management_table_with_str_id( - table_name, object_id, metadata - ) + # for outer use: + # def save_in_memory(self, object_name:str, metadata:Dict[str:Any], object_id:Optional[str] = None): + # + # # insert object info into management table mng_{object_name}s + # # for exmple: object db_instance will be saved in table mng_db_instances + # table_name = self.convert_object_name_to_management_table_name(object_name) + # + # if not self.is_management_table_exist(table_name): + # self.create_management_table(table_name) + # + # if object_id: + # self.insert_object_to_management_table_with_str_id(table_name, object_id, metadata) + # + # else: + # self.insert_object_to_management_table(table_name, metadata) + + + def save_in_memory(self, object): + # insert object info into management table mng_{object_name}s + # for exmple: object db_instance will be saved in table mng_db_instances + table_name = str(object.__class__.__name__) + if not self.object_manager.is_management_table_exist(table_name): + self.object_manager.create_management_table(table_name) + self.object_manager.insert_object_to_management_table(table_name, object.to_sql()) - else: - self.insert_object_to_management_table(table_name, metadata) + def is_management_table_exist(self, table_name): + query = f"SELECT name FROM sqlite_master WHERE type='table' AND name='{table_name}'" + result = self.db_manager.execute_query_with_single_result(query) + return result is not None - def delete_from_memory( - self, object_name: str, criteria="default", object_id: Optional[str] = None - ): + def delete_from_memory(self,object_name:str, criteria='default', object_id:Optional[str] = None): # if criteria not sent- use PK for deletion - if criteria == "default": + if criteria == 'default': if not object_id: - raise ValueError("must be or criteria or object id") - criteria = f"object_id = {object_id}" + raise ValueError('must be or criteria or object id') + criteria = f'object_id = {object_id}' table_name = self.convert_object_name_to_management_table_name(object_name) self.delete_object_from_management_table(table_name, criteria) - table_name = self.convert_object_name_to_management_table_name(self.object_name) - - self.delete_data_from_table(table_name, criteria) - def update_in_memory( - self, object_name, updates, criteria="default", object_id: Optional[str] = None - ): + def update_in_memory(self, object_name, updates, criteria='default', object_id:Optional[str] = None): # if criteria not sent- use PK for deletion - if criteria == "default": + if criteria == 'default': if not object_id: - raise ValueError("must be or criteria or object id") - criteria = f"object_id = {object_id}" + raise ValueError('must be or criteria or object id') + criteria = f'object_id = {object_id}' table_name = self.convert_object_name_to_management_table_name(object_name) - self.update_object_in_management_table_by_criteria( - table_name, updates, criteria - ) + self.update_object_in_management_table_by_criteria(table_name, updates, criteria) - def get_from_memory( - self, object_name, columns=["*"], object_id=None, criteria=None - ): + + def get_from_memory(self, object_name, columns = ["*"], object_id = None, criteria = None): """get records from memory by criteria or id""" table_name = self.convert_object_name_to_management_table_name(object_name) if object_id: - criteria = f"object_id = {object_id}" - self.get_objects_from_management_table_by_criteria( - table_name, columns, criteria - ) + criteria = f'object_id = {object_id}' + self.get_objects_from_management_table_by_criteria(table_name, columns, criteria) + - def convert_object_attributes_to_dictionary(**kwargs): + def convert_object_attributes_to_dictionary(self, **kwargs): dict = {} @@ -176,3 +159,6 @@ def convert_object_attributes_to_dictionary(**kwargs): dict[key] = value return dict + + def get_all_data_from_table(self, table_name): + self.db_manager.get_all_data_from_table(table_name) \ No newline at end of file diff --git a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py index cd936c7f..184f4941 100644 --- a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py @@ -1,66 +1,83 @@ from typing import Dict, Any import json import sqlite3 -from DB.NEW_KT_DB.DataAccess.ObjectManager import ObjectManager -from StorageManager import StorageManager +import os +import sys + +sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) +) + +from DB.NEW_KT_DB.DataAccess.ObjectManager import ObjectManager as DB_ObjectManager + +# from StorageManager import StorageManager + class ObjectManager: - def __init__(self, db_file: str,type, storage_path=None): + def __init__(self, db_file: str, type, storage_path=None): """Initialize ObjectManager with the database connection.""" - self.object_manager = ObjectManager(db_file) - self.storage_manager = StorageManager(storage_path) + self.object_manager = DB_ObjectManager(db_file) + # self.storage_manager = StorageManager(storage_path) self.object_name = type # for outer use: def save_in_memory(self, object): - + # insert object info into management table mng_{object_name}s # for exmple: object db_instance will be saved in table mng_db_instances - table_name = self.object_manager.convert_object_name_to_management_table_name(self.object_name) - + table_name = self.object_manager.convert_object_name_to_management_table_name( + self.object_name + ) if not self.object_manager.is_management_table_exist(table_name): self.object_manager.create_management_table(table_name) - + self.object_manager.insert_object_to_management_table(table_name, object) - - def delete_from_memory(self,object, criteria='default'): - + def delete_from_memory(self, object, criteria="default"): + # if criteria not sent- use PK for deletion - if criteria == 'default': - criteria = f'{object.pk_column} = {object.pk_value}' - - table_name = self.object_manager.convert_object_name_to_management_table_name(self.object_name) - + if criteria == "default": + criteria = f"{object.pk_column} = {object.pk_value}" + + table_name = self.object_manager.convert_object_name_to_management_table_name( + self.object_name + ) + self.object_manager.delete_data_from_table(table_name, criteria) + def update_in_memory(self, object, updates, criteria="default"): - def update_in_memory(self,object, updates, criteria='default'): - # if criteria not sent- use PK for deletion - if criteria == 'default': - - criteria = f'{object.pk_column} = {object.pk_value}' + if criteria == "default": - table_name = self.object_manager.convert_object_name_to_management_table_name(self.object_name) + criteria = f"{object.pk_column} = {object.pk_value}" - self.object_manager.update_object_in_management_table_by_criteria(table_name, updates, criteria) + table_name = self.object_manager.convert_object_name_to_management_table_name( + self.object_name + ) - def get_from_memory(self, object_id): - table_name = self.object_manager.convert_object_name_to_management_table_name(self.object_name) - self.object_manager.get_object_from_management_table(table_name,object_id) + self.object_manager.update_object_in_management_table_by_criteria( + table_name, updates, criteria + ) + def get_from_memory(self, object_id): + table_name = self.object_manager.convert_object_name_to_management_table_name( + self.object_name + ) + self.object_manager.get_object_from_management_table(table_name, object_id) def get_data_from_memory_db(self): - table_name = self.object_manager.convert_object_name_to_management_table_name(self.object_name) + table_name = self.object_manager.convert_object_name_to_management_table_name( + self.object_name + ) self.object_manager.get_data_from_memory(table_name=table_name) - + def convert_object_attributes_to_dictionary(**kwargs): dict = {} for key, value in kwargs.items(): dict[key] = value - + return dict diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py index 7ccc9786..5d67d348 100644 --- a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -4,7 +4,7 @@ import sys import os -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) +# sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from Models.TagObjectModel import TagObject @@ -12,10 +12,10 @@ class TagObjectManager: - def __init__(self, db_file: str): + def __init__(self, db_file: str = "tag"): """Initialize ObjectManager with the database connection.""" - self.object_manager = ObjectManager(db_file) - self.object_manager.create_table() + self.object_manager = ObjectManager("tag",db_file) + # self.object_manager.create_table() def createInMemoryTagObject(self, tag: TagObject): return self.object_manager.save_in_memory(tag) diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py index 4cbd71a3..f30a7c40 100644 --- a/Storage/NEW_KT_Storage/Models/TagObjectModel.py +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -1,15 +1,15 @@ from typing import Dict -from DataAccess import ObjectManager import uuid +from DataAccess import ObjectManager class TagObject: - def __init__(self, key: str, value: str, pk_value): - self.id = str(uuid.uuid1()) + def __init__(self, key: str, value: str): + self.tag_id = str(uuid.uuid1()) self.key = key self.value = value - self.pk_column = "id" - self.pk_value = self.id + self.pk_column = "TagId" + self.pk_value = self.tag_id def to_dict(self) -> Dict: """Retrieve the data of the DB cluster as a dictionary.""" diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py index 36692ade..bd639b38 100644 --- a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -2,6 +2,7 @@ import os sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..",'..'))) from DataAccess.TagObjectManager import TagObjectManager from Models.TagObjectModel import TagObject @@ -26,3 +27,7 @@ def modify(self, tag: TagObject): def describe(self, tag: TagObject): return self.tag_dal.describeTagObject(tag) + +if __name__ == '__main__': + tagObjectService = TagObjectService() + tagObjectService.create("a","a") \ No newline at end of file diff --git a/tag b/tag new file mode 100644 index 0000000000000000000000000000000000000000..4d7617def2a343274fe61b478a9f2bbdd73430ee GIT binary patch literal 12288 zcmeI#!AiqG5C-7gRP-d(Q$Z-qv8BO_FJP2Kf@xag7R)JZ+ij^NsWsb!$G)yl;Y7`$ zy?B-K4@{O>b{6)_X`Y{=m9w;1zZb^Qjkpj}id!Nfgyd{-Hc{6nO~Gqj{}obPFFw!t zl-Irz?VLXd2tWV=5P$##AOHafKmY;|fWW^J7<;Fk!9b?YOmkapavqbj%5Ju{oE?^} z`$Pp=kq+)6MF(elr75h>o&DXVJnMA3a<~1yvnZFDGs~)3y}etSUFxl;uXg6L)ttgu zs|S_PI0=VAlG39}DVXR{7<21T#oBitZ#MgBAgx|B#Usv16#0d9W^SC>-|pA5IS>5^ z2tWV=5P$##AOHafKmY;|fB*!JSOD|?5&v8~4FV8=00bZa0SG_<0uX=z1R(G$@C8Yb BQ^NoN literal 0 HcmV?d00001 From 68f1822c30d68b933aa6f95288e708881e674056 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Wed, 18 Sep 2024 12:54:22 +0300 Subject: [PATCH 03/10] TagsObject work in all layers --- DB/NEW_KT_DB/DataAccess/DBManager.py | 3 +- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 11 +-- .../Controller/TagObjectController.py | 18 ++--- .../DataAccess/ObjectManager.py | 5 ++ .../DataAccess/TagObjectManager.py | 55 +++++++++----- .../NEW_KT_Storage/Models/TagObjectModel.py | 44 +++++++++--- .../Service/Classes/TagObjectService.py | 38 +++++++--- Storage/NEW_KT_Storage/Test/TagObject_test.py | 67 ++++++++++++++++++ tag | Bin 12288 -> 0 bytes 9 files changed, 185 insertions(+), 56 deletions(-) create mode 100644 Storage/NEW_KT_Storage/Test/TagObject_test.py delete mode 100644 tag diff --git a/DB/NEW_KT_DB/DataAccess/DBManager.py b/DB/NEW_KT_DB/DataAccess/DBManager.py index 46c7f863..bbd45fff 100644 --- a/DB/NEW_KT_DB/DataAccess/DBManager.py +++ b/DB/NEW_KT_DB/DataAccess/DBManager.py @@ -143,6 +143,7 @@ def get_column_names_of_table(self, table_name): print(f"Error occurred while fetching columns from table {table_name}: {e}") return [] + def get_all_data_from_table(self, table_name): try: get_all_data_query = f"""SELECT * FROM {table_name}""" @@ -203,4 +204,4 @@ def describe_table(self, table_name: str) -> Dict[str, str]: else: raise Exception(f'table {table_name} not found') except OperationalError as e: - raise Exception(f'Error describing table {table_name}: {e}') + raise Exception(f'Error describing table {table_name}: {e}') \ No newline at end of file diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index c397c3cb..0a0d00a7 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,7 +1,7 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DBManager import DBManager +from DB.NEW_KT_DB.DataAccess.DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): @@ -26,14 +26,10 @@ def _insert_object_to_management_table(self, table_name, object_info, columns_to else: self.db_manager.insert_data_into_table(table_name, object_info, columns_to_populate) - # def insert_object_to_management_table_with_str_id(self, table_name, id, metadata): - # # self.db_manager.insert_data_into_table(table_name, ['object_id','metadata'],(id, metadata)) def _update_object_in_management_table_by_criteria(self, table_name, updates, criteria): self.db_manager.update_records_in_table(table_name, updates, criteria) - # def update_object_in_management_table_by_id(self, table_name, object_id, updates): - # self.db_manager.update_records_in_table(table_name, updates, f'object_id = {object_id}') def _delete_object_from_management_table(self, table_name, criteria) -> None: '''Delete an object from the database.''' @@ -111,7 +107,4 @@ def convert_object_attributes_to_dictionary(self, **kwargs): for key, value in kwargs.items(): dict[key] = value - return dict - - def get_all_data_from_table(self, table_name): - self.db_manager.get_all_data_from_table(table_name) \ No newline at end of file + return dict \ No newline at end of file diff --git a/Storage/NEW_KT_Storage/Controller/TagObjectController.py b/Storage/NEW_KT_Storage/Controller/TagObjectController.py index 6f47430b..82b72998 100644 --- a/Storage/NEW_KT_Storage/Controller/TagObjectController.py +++ b/Storage/NEW_KT_Storage/Controller/TagObjectController.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Dict import sys import os @@ -6,24 +6,24 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from Models import TagObjectModel -from Service.Classes import TagObjectService +from Service.Classes.TagObjectService import TagObjectService class TagObjctController: def __init__(self): self.tag_service = TagObjectService() - def create_tag(self, key, value,version_id): + def create_tag(self, key, value): return self.tag_service.create(key, value) - def get_tag(self, ): - return self.tag_service.get(pk_value, pk_column) + def get_tag(self, key:str)->TagObjectModel: + return self.tag_service.get(key) - def delete_tag(self, pk_value, pk_column): - return self.tag_service.delete(pk_value, pk_column) + def delete_tag(self, key: str): + return self.tag_service.delete(key) - def modify_tag(self): - return self.tag_service.modify() + def modify_tag(self, key: str, changes: Dict): + return self.tag_service.modify(key, changes) def describe_tag(self): return self.tag_service.describe() diff --git a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py index a3165bde..2409720e 100644 --- a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py @@ -1,3 +1,8 @@ +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..",'..','..'))) + from DB.NEW_KT_DB.DataAccess.ObjectManager import ObjectManager as ObjectManagerDB from Storage.NEW_KT_Storage.DataAccess.StorageManager import StorageManager diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py index 5d67d348..b7df736a 100644 --- a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -12,24 +12,43 @@ class TagObjectManager: - def __init__(self, db_file: str = "tag"): + def __init__(self, db_file: str = "Tags.db"): """Initialize ObjectManager with the database connection.""" - self.object_manager = ObjectManager("tag",db_file) - # self.object_manager.create_table() + self.object_manager = ObjectManager(db_file) + self.create_table() - def createInMemoryTagObject(self, tag: TagObject): - return self.object_manager.save_in_memory(tag) - - def deleteInMemoryTagObject(self, tag: TagObject): - return self.object_manager.delete_from_memory(tag) - - def describeTagObject(self, tag: TagObject): - return self.object_manager.get_from_memory(tag) + def create_table(self): + table_columns = "Key TEXT PRIMARY KEY", "Value TEXT" + columns_str = ", ".join(table_columns) + self.object_manager.object_manager.db_manager.create_table( + "mng_Tags", columns_str + ) - def putTagObject(self, tag: TagObject): - return self.object_manager.update_in_memory(tag) - - def get_tag_object_from_memory(self, tag:TagObject): - return self.object_manager.get_from_memory(tag) - - + def createInMemoryTagObject(self, tag: TagObject): + return self.object_manager.save_in_memory( + object_name=TagObject.OBJECT_NAME, object_info=tag.to_sql() + ) + + def deleteInMemoryTagObject(self, key: str): + return self.object_manager.delete_from_memory_by_pk( + object_name=TagObject.OBJECT_NAME, pk_column=TagObject.PK_COULMN, pk_value=key + ) + + def describeTagObject(self): + return self.object_manager.get_from_memory(object_name=TagObject.OBJECT_NAME) + + def putTagObject(self, last_key: str, updates: str = None): + print(updates) + if not updates: + raise ValueError("No fields to update") + + return self.object_manager.update_in_memory( + object_name=TagObject.OBJECT_NAME, + updates=updates, + criteria=f""" {TagObject.PK_COULMN}='{last_key}' """, + ) + + def get_tag_object_from_memory(self, key: str): + return self.object_manager.get_from_memory( + object_name=TagObject.OBJECT_NAME, criteria=f""" {TagObject.PK_COULMN}='{key}' """ + ) diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py index f30a7c40..95c70993 100644 --- a/Storage/NEW_KT_Storage/Models/TagObjectModel.py +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -1,23 +1,51 @@ from typing import Dict import uuid -from DataAccess import ObjectManager +from DataAccess.ObjectManager import ObjectManager +import json +from datetime import datetime class TagObject: + PK_COULMN = "Key" + OBJECT_NAME = "Tag" def __init__(self, key: str, value: str): - self.tag_id = str(uuid.uuid1()) self.key = key self.value = value - self.pk_column = "TagId" - self.pk_value = self.tag_id def to_dict(self) -> Dict: """Retrieve the data of the DB cluster as a dictionary.""" - # send relevant attributes in this syntax: - return ObjectManager.convert_object_attributes_to_dictionary( + om = ObjectManager("Tags.db") + return om.convert_object_attributes_to_dictionary( key=self.key, value=self.value, - pk_column=self.pk_column, - pk_value=self.pk_value, ) + + def to_sql(self) -> str: + """Convert the TagObject instance to a SQL-friendly format.""" + data_dict = self.to_dict() + try: + values = ( + "(" + + ", ".join( + ( + f"'{json.dumps(v)}'" + if isinstance(v, dict) or isinstance(v, list) + else f"'{v}'" if isinstance(v, str) else f"'{str(v)}'" + ) + for v in data_dict.values() + ) + + ")" + ) + return values + except Exception as e: + print(f"Error converting to SQL format: {e}") + return None + + def __str__(self) -> str: + """Convert the TagObject instance to a JSON string.""" + try: + return json.dumps(self.to_dict(), indent=4) + except Exception as e: + print(f"Error converting to JSON string: {e}") + return None diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py index bd639b38..ca280ac1 100644 --- a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -2,7 +2,7 @@ import os sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..",'..'))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from DataAccess.TagObjectManager import TagObjectManager from Models.TagObjectModel import TagObject @@ -16,18 +16,34 @@ def create(self, key, value): tag = TagObject(key, value) return self.tag_dal.createInMemoryTagObject(tag) - # def get(self, tag: TagObject): - # return self.tag_dal.get(tag) + def get(self, key: str): + return self.tag_dal.get_tag_object_from_memory(key) - def delete(self, tag: TagObject): - return self.tag_dal.deleteInMemoryTagObject(tag) + def delete(self, key: str): + return self.tag_dal.deleteInMemoryTagObject(key) - def modify(self, tag: TagObject): - return self.tag_dal.putTagObject(tag) + def modify(self, last_key: str, key: str = None, value: str=None): + update_fields = "" - def describe(self, tag: TagObject): - return self.tag_dal.describeTagObject(tag) + if key is not None: + update_fields += f'''Key = '{key}' ''' -if __name__ == '__main__': + if value is not None: + if update_fields: + update_fields += ", " + update_fields += f'''Value = '{value}' ''' + + return self.tag_dal.putTagObject( last_key=last_key, updates = update_fields) + + def describe(self): + return self.tag_dal.describeTagObject() + + +if __name__ == "__main__": tagObjectService = TagObjectService() - tagObjectService.create("a","a") \ No newline at end of file + tagObjectService.create("hh","b") + print(tagObjectService.get("hh")) + tagObjectService.modify("hh","n","f") + print(tagObjectService.get("n")) + tagObjectService.delete("n") + print(tagObjectService.describe()) diff --git a/Storage/NEW_KT_Storage/Test/TagObject_test.py b/Storage/NEW_KT_Storage/Test/TagObject_test.py new file mode 100644 index 00000000..73cf6dce --- /dev/null +++ b/Storage/NEW_KT_Storage/Test/TagObject_test.py @@ -0,0 +1,67 @@ +import pytest +import sys +import os + +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..",".."))) + +from NEW_KT_Storage.Service.Classes.TagObjectService import TagObjectService +from Models.TagObjectModel import TagObject + + +@pytest.fixture +def tag_service(): + """Create a fixture for the TagObjectService.""" + return TagObjectService() + + +def test_create_tag(tag_service): + """Test that creating a TagObject works correctly.""" + key = "TestKey" + value = "TestValue" + result = tag_service.create(key, value) + + assert result is not None + assert isinstance(result, TagObject) + assert result.key == key + assert result.value == value + + +def test_modify_tag(tag_service): + """Test that modifying a TagObject works correctly.""" + key = "TestKey" + value = "TestValue" + tag = tag_service.create(key, value) + + # Modify the tag object + new_value = "NewTestValue" + tag.value = new_value + modified_tag = tag_service.modify(tag) + + assert modified_tag is not None + assert modified_tag.value == new_value + + +def test_delete_tag(tag_service): + """Test that deleting a TagObject works correctly.""" + key = "DeleteKey" + value = "DeleteValue" + tag = tag_service.create(key, value) + + # Test delete functionality + delete_result = tag_service.delete(tag) + + assert delete_result is True + + +def test_describe_tag(tag_service): + """Test that describing a TagObject works correctly.""" + key = "DescribeKey" + value = "DescribeValue" + tag = tag_service.create(key, value) + + # Test describe functionality + description = tag_service.describe(tag) + + assert description is not None + assert description["key"] == key + assert description["value"] == value diff --git a/tag b/tag deleted file mode 100644 index 4d7617def2a343274fe61b478a9f2bbdd73430ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI#!AiqG5C-7gRP-d(Q$Z-qv8BO_FJP2Kf@xag7R)JZ+ij^NsWsb!$G)yl;Y7`$ zy?B-K4@{O>b{6)_X`Y{=m9w;1zZb^Qjkpj}id!Nfgyd{-Hc{6nO~Gqj{}obPFFw!t zl-Irz?VLXd2tWV=5P$##AOHafKmY;|fWW^J7<;Fk!9b?YOmkapavqbj%5Ju{oE?^} z`$Pp=kq+)6MF(elr75h>o&DXVJnMA3a<~1yvnZFDGs~)3y}etSUFxl;uXg6L)ttgu zs|S_PI0=VAlG39}DVXR{7<21T#oBitZ#MgBAgx|B#Usv16#0d9W^SC>-|pA5IS>5^ z2tWV=5P$##AOHafKmY;|fB*!JSOD|?5&v8~4FV8=00bZa0SG_<0uX=z1R(G$@C8Yb BQ^NoN From 2cd9c907d3b501e9da0a276aaef213b7a447613e Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Wed, 18 Sep 2024 13:02:43 +0300 Subject: [PATCH 04/10] change the convert_object_attributes_to_dictionary to the static function --- Storage/NEW_KT_Storage/Models/TagObjectModel.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py index 95c70993..2d08b16e 100644 --- a/Storage/NEW_KT_Storage/Models/TagObjectModel.py +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -15,8 +15,7 @@ def __init__(self, key: str, value: str): def to_dict(self) -> Dict: """Retrieve the data of the DB cluster as a dictionary.""" - om = ObjectManager("Tags.db") - return om.convert_object_attributes_to_dictionary( + return ObjectManager.convert_object_attributes_to_dictionary( key=self.key, value=self.value, ) From 6c46f665d7697fe8d8676c97ebcbf8e17725f679 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Wed, 18 Sep 2024 14:07:00 +0300 Subject: [PATCH 05/10] fix all mistakes --- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 2 +- Storage/NEW_KT_Storage/DataAccess/ObjectManager.py | 8 +------- Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py | 7 +------ .../NEW_KT_Storage/Service/Classes/TagObjectService.py | 10 ---------- Storage/NEW_KT_Storage/Test/TagObject_test.py | 4 ++-- 5 files changed, 5 insertions(+), 26 deletions(-) diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index 66902742..f9cc64fd 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,7 +1,7 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DB.NEW_KT_DB.DataAccess.DBManager import DBManager +from DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): diff --git a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py index c39fb494..1a35507e 100644 --- a/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/ObjectManager.py @@ -1,8 +1,3 @@ -import sys -import os - -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..",'..','..'))) - from DB.NEW_KT_DB.DataAccess.ObjectManager import ObjectManager as ObjectManagerDB from Storage.NEW_KT_Storage.DataAccess.StorageManager import StorageManager @@ -54,5 +49,4 @@ def convert_object_attributes_to_dictionary(**kwargs): def get_all_objects_from_memory(self, object_name): - return self.object_manager.get_all_objects_from_memory(object_name) - + return self.object_manager.get_all_objects_from_memory(object_name) \ No newline at end of file diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py index b7df736a..2aea1c37 100644 --- a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -15,14 +15,10 @@ class TagObjectManager: def __init__(self, db_file: str = "Tags.db"): """Initialize ObjectManager with the database connection.""" self.object_manager = ObjectManager(db_file) - self.create_table() - def create_table(self): table_columns = "Key TEXT PRIMARY KEY", "Value TEXT" columns_str = ", ".join(table_columns) - self.object_manager.object_manager.db_manager.create_table( - "mng_Tags", columns_str - ) + self.object_manager.object_manager.db_manager.create_table("mng_Tags", columns_str) def createInMemoryTagObject(self, tag: TagObject): return self.object_manager.save_in_memory( @@ -38,7 +34,6 @@ def describeTagObject(self): return self.object_manager.get_from_memory(object_name=TagObject.OBJECT_NAME) def putTagObject(self, last_key: str, updates: str = None): - print(updates) if not updates: raise ValueError("No fields to update") diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py index ca280ac1..206598f7 100644 --- a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -37,13 +37,3 @@ def modify(self, last_key: str, key: str = None, value: str=None): def describe(self): return self.tag_dal.describeTagObject() - - -if __name__ == "__main__": - tagObjectService = TagObjectService() - tagObjectService.create("hh","b") - print(tagObjectService.get("hh")) - tagObjectService.modify("hh","n","f") - print(tagObjectService.get("n")) - tagObjectService.delete("n") - print(tagObjectService.describe()) diff --git a/Storage/NEW_KT_Storage/Test/TagObject_test.py b/Storage/NEW_KT_Storage/Test/TagObject_test.py index 73cf6dce..3d0194eb 100644 --- a/Storage/NEW_KT_Storage/Test/TagObject_test.py +++ b/Storage/NEW_KT_Storage/Test/TagObject_test.py @@ -2,9 +2,9 @@ import sys import os -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..",".."))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))) -from NEW_KT_Storage.Service.Classes.TagObjectService import TagObjectService +from Storage.NEW_KT_Storage.Service.Classes.TagObjectService import TagObjectService from Models.TagObjectModel import TagObject From 59e8c23ea2290865bbfe27f7015935c0355ed9a4 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Wed, 18 Sep 2024 15:16:18 +0300 Subject: [PATCH 06/10] fix again and change the convert_object_attributes_to_dictionary to static mathod --- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 3 +- .../DataAccess/TagObjectManager.py | 17 +++++---- .../NEW_KT_Storage/Models/TagObjectModel.py | 1 - .../Service/Classes/TagObjectService.py | 36 ++++++++++++++++--- 4 files changed, 40 insertions(+), 17 deletions(-) diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index f9cc64fd..63728d1b 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,14 +1,13 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DBManager import DBManager +from DataAccess.DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): '''Initialize ObjectManager with the database connection.''' self.db_manager = DBManager(db_file) - def create_management_table(self, object_name, table_structure='default', pk_column_data_type='INTEGER'): table_name = self._convert_object_name_to_management_table_name(object_name) diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py index 2aea1c37..a9273596 100644 --- a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -1,40 +1,38 @@ from typing import Dict, Any -import json -import sqlite3 import sys import os -# sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from Models.TagObjectModel import TagObject from DataAccess.ObjectManager import ObjectManager - class TagObjectManager: def __init__(self, db_file: str = "Tags.db"): """Initialize ObjectManager with the database connection.""" self.object_manager = ObjectManager(db_file) - - table_columns = "Key TEXT PRIMARY KEY", "Value TEXT" - columns_str = ", ".join(table_columns) - self.object_manager.object_manager.db_manager.create_table("mng_Tags", columns_str) + self.table_structure = ", ".join(["Key TEXT PRIMARY KEY", "Value TEXT"]) + self.object_manager.object_manager.db_manager.create_table("mng_Tags", self.table_structure) def createInMemoryTagObject(self, tag: TagObject): + """Save a TagObject instance in memory.""" return self.object_manager.save_in_memory( object_name=TagObject.OBJECT_NAME, object_info=tag.to_sql() ) def deleteInMemoryTagObject(self, key: str): + """Delete a TagObject from memory based on its primary key (key).""" return self.object_manager.delete_from_memory_by_pk( object_name=TagObject.OBJECT_NAME, pk_column=TagObject.PK_COULMN, pk_value=key ) def describeTagObject(self): + """Retrieve a list of TagObjects from memory.""" return self.object_manager.get_from_memory(object_name=TagObject.OBJECT_NAME) def putTagObject(self, last_key: str, updates: str = None): - if not updates: + """Update a TagObject in memory based on its primary key.""" + if not updates: raise ValueError("No fields to update") return self.object_manager.update_in_memory( @@ -44,6 +42,7 @@ def putTagObject(self, last_key: str, updates: str = None): ) def get_tag_object_from_memory(self, key: str): + """Retrieve a TagObject from memory based on its primary key (key).""" return self.object_manager.get_from_memory( object_name=TagObject.OBJECT_NAME, criteria=f""" {TagObject.PK_COULMN}='{key}' """ ) diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py index 2d08b16e..89426a49 100644 --- a/Storage/NEW_KT_Storage/Models/TagObjectModel.py +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -14,7 +14,6 @@ def __init__(self, key: str, value: str): def to_dict(self) -> Dict: """Retrieve the data of the DB cluster as a dictionary.""" - return ObjectManager.convert_object_attributes_to_dictionary( key=self.key, value=self.value, diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py index 206598f7..10c6292c 100644 --- a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -10,19 +10,43 @@ class TagObjectService: def __init__(self) -> None: + """Initialize the TagObjectService with a TagObjectManager instance.""" self.tag_dal = TagObjectManager() - def create(self, key, value): + def create(self, key, value)->None: + """Create a new TagObject and save it in memory. + + Args: + key (str): The key for the TagObject. + value (str): The value for the TagObject. + """ tag = TagObject(key, value) return self.tag_dal.createInMemoryTagObject(tag) - def get(self, key: str): + def get(self, key: str)->TagObject: + """Retrieve a TagObject from memory by its key. + + Args: + key (str): The key of the TagObject to retrieve. + """ return self.tag_dal.get_tag_object_from_memory(key) def delete(self, key: str): + """Delete a TagObject from memory by its key. + + Args: + key (str): The key of the TagObject to delete. + """ return self.tag_dal.deleteInMemoryTagObject(key) - def modify(self, last_key: str, key: str = None, value: str=None): + def modify(self, last_key: str, key: str = None, value: str = None): + """Modify an existing TagObject's key and/or value. + + Args: + last_key (str): The original key of the TagObject to modify. + key (str, optional): The new key to set. Defaults to None. + value (str, optional): The new value to set. Defaults to None. + """ update_fields = "" if key is not None: @@ -33,7 +57,9 @@ def modify(self, last_key: str, key: str = None, value: str=None): update_fields += ", " update_fields += f'''Value = '{value}' ''' - return self.tag_dal.putTagObject( last_key=last_key, updates = update_fields) - + return self.tag_dal.putTagObject(last_key=last_key, updates=update_fields) + def describe(self): + """Retrieve a list of all TagObjects from memory. + """ return self.tag_dal.describeTagObject() From 3a4b8cb3284809dd9aa946f41819410c88e897dc Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Wed, 18 Sep 2024 15:29:49 +0300 Subject: [PATCH 07/10] one more finish --- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index 63728d1b..cba10773 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,7 +1,7 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DataAccess.DBManager import DBManager +from DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): From 3c5f10601caf8750d68c3b6ec7e3ae7d6c92cef8 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <37325928810@mby.co.il> Date: Thu, 19 Sep 2024 14:01:16 +0300 Subject: [PATCH 08/10] Tag model fith tests and validation --- .../DataAccess/TagObjectManager.py | 59 +++- .../NEW_KT_Storage/Models/TagObjectModel.py | 2 + .../Service/Classes/TagObjectService.py | 83 ++++- Storage/NEW_KT_Storage/Test/TagObject_test.py | 304 +++++++++++++++--- .../Validation/TagValidation.py | 13 + 5 files changed, 398 insertions(+), 63 deletions(-) create mode 100644 Storage/NEW_KT_Storage/Validation/TagValidation.py diff --git a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py index a9273596..3c7f7257 100644 --- a/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py +++ b/Storage/NEW_KT_Storage/DataAccess/TagObjectManager.py @@ -7,12 +7,12 @@ from Models.TagObjectModel import TagObject from DataAccess.ObjectManager import ObjectManager + class TagObjectManager: def __init__(self, db_file: str = "Tags.db"): """Initialize ObjectManager with the database connection.""" self.object_manager = ObjectManager(db_file) - self.table_structure = ", ".join(["Key TEXT PRIMARY KEY", "Value TEXT"]) - self.object_manager.object_manager.db_manager.create_table("mng_Tags", self.table_structure) + self.object_manager.object_manager.db_manager.create_table("mng_Tags", TagObject.TABLE_STRUCTURE) def createInMemoryTagObject(self, tag: TagObject): """Save a TagObject instance in memory.""" @@ -26,11 +26,30 @@ def deleteInMemoryTagObject(self, key: str): object_name=TagObject.OBJECT_NAME, pk_column=TagObject.PK_COULMN, pk_value=key ) - def describeTagObject(self): - """Retrieve a list of TagObjects from memory.""" - return self.object_manager.get_from_memory(object_name=TagObject.OBJECT_NAME) - def putTagObject(self, last_key: str, updates: str = None): + + def describeTagObject(self) -> list[TagObject]: + """Retrieve a list of TagObjects from memory. + + Returns: + list: A list of TagObject instances. + + Raises: + NoTagObjectsFoundError: If no TagObjects are found in memory. + """ + # Retrieve the list of tuples (key, value) from memory + results = self.object_manager.get_from_memory(object_name=TagObject.OBJECT_NAME) + + if results == []: + return [] + + # Create a list of TagObject instances from the results + tag_objects = [TagObject(key=res[0], value=res[1]) for res in results] + + return tag_objects + + + def putTagObject(self, old_key: str, updates: str = None): """Update a TagObject in memory based on its primary key.""" if not updates: raise ValueError("No fields to update") @@ -38,11 +57,29 @@ def putTagObject(self, last_key: str, updates: str = None): return self.object_manager.update_in_memory( object_name=TagObject.OBJECT_NAME, updates=updates, - criteria=f""" {TagObject.PK_COULMN}='{last_key}' """, + criteria=f""" {TagObject.PK_COULMN}='{old_key}' """, ) - def get_tag_object_from_memory(self, key: str): - """Retrieve a TagObject from memory based on its primary key (key).""" - return self.object_manager.get_from_memory( - object_name=TagObject.OBJECT_NAME, criteria=f""" {TagObject.PK_COULMN}='{key}' """ + def get_tag_object_from_memory(self, key: str) -> TagObject: + """Retrieve a TagObject from memory based on its primary key (key). + + Args: + key (str): The primary key of the TagObject to retrieve. + + Returns: + TagObject: The retrieved TagObject instance, or None if not found. + """ + # Retrieve data from memory based on the primary key + result = self.object_manager.get_from_memory( + object_name=TagObject.OBJECT_NAME, + criteria=f"{TagObject.PK_COULMN}='{key}'" ) + + if not result or not result[0]: + raise KeyError("No TagObject.") + + # Create a TagObject from the retrieved data + key, value = result[0] # Unpack key and value from the result + tag_object = TagObject(key=key, value=value) + + return tag_object diff --git a/Storage/NEW_KT_Storage/Models/TagObjectModel.py b/Storage/NEW_KT_Storage/Models/TagObjectModel.py index 89426a49..8d18adde 100644 --- a/Storage/NEW_KT_Storage/Models/TagObjectModel.py +++ b/Storage/NEW_KT_Storage/Models/TagObjectModel.py @@ -8,6 +8,8 @@ class TagObject: PK_COULMN = "Key" OBJECT_NAME = "Tag" + TABLE_STRUCTURE = ", ".join(["Key TEXT PRIMARY KEY", "Value TEXT"]) + def __init__(self, key: str, value: str): self.key = key self.value = value diff --git a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py index 10c6292c..d74bd81d 100644 --- a/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py +++ b/Storage/NEW_KT_Storage/Service/Classes/TagObjectService.py @@ -5,30 +5,63 @@ sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from DataAccess.TagObjectManager import TagObjectManager +from DataAccess.StorageManager import StorageManager from Models.TagObjectModel import TagObject +from Validation import TagValidation as validation class TagObjectService: - def __init__(self) -> None: + def __init__( + self, db_file: str = "Tags.db", storage_file: str = "local_storage" + ) -> None: """Initialize the TagObjectService with a TagObjectManager instance.""" - self.tag_dal = TagObjectManager() - - def create(self, key, value)->None: + self.tag_dal = TagObjectManager(db_file) + self.tags = [] + self.load_tags() + + def load_tags(self): + self.tags = self.tag_dal.describeTagObject() + + def validation_for_key(self, key): + if not validation.check_required_params(key): + raise ValueError("key is required") + if not validation.is_valid_key_name(key): + raise ValueError("Incorrect key name") + + def validation_for_value(self, value): + if not validation.is_valid_key_name(value): + raise ValueError("Incorrect key name") + + def create(self, key, value) -> None: """Create a new TagObject and save it in memory. Args: key (str): The key for the TagObject. value (str): The value for the TagObject. """ + self.validation_for_key(key=key) + + self.validation_for_value(value=value) + + if validation.key_exists(tags=self.tags, key=key): + raise KeyError("Duplicate key") + tag = TagObject(key, value) - return self.tag_dal.createInMemoryTagObject(tag) + create_result = self.tag_dal.createInMemoryTagObject(tag) + self.load_tags() + return create_result - def get(self, key: str)->TagObject: + def get(self, key: str) -> TagObject: """Retrieve a TagObject from memory by its key. Args: key (str): The key of the TagObject to retrieve. """ + self.validation_for_key(key=key) + + if not validation.key_exists(tags=self.tags, key=key): + raise KeyError("no such key") + return self.tag_dal.get_tag_object_from_memory(key) def delete(self, key: str): @@ -37,29 +70,51 @@ def delete(self, key: str): Args: key (str): The key of the TagObject to delete. """ - return self.tag_dal.deleteInMemoryTagObject(key) + self.validation_for_key(key=key) + + if not validation.key_exists(tags=self.tags, key=key): + raise KeyError("no such key") + + delete_result = self.tag_dal.deleteInMemoryTagObject(key) + self.load_tags() + return delete_result - def modify(self, last_key: str, key: str = None, value: str = None): + def modify(self, old_key: str, key: str = None, value: str = None): """Modify an existing TagObject's key and/or value. Args: - last_key (str): The original key of the TagObject to modify. + old_key (str): The original key of the TagObject to modify. key (str, optional): The new key to set. Defaults to None. value (str, optional): The new value to set. Defaults to None. """ + self.validation_for_key(key=old_key) + + if not validation.key_exists(tags=self.tags, key=old_key): + raise KeyError("no such key") + update_fields = "" if key is not None: - update_fields += f'''Key = '{key}' ''' + self.validation_for_key(key=key) + if validation.key_exists(tags=self.tags, key=key): + raise ValueError("Douplicate key") + update_fields += f"""Key = '{key}' """ if value is not None: + self.validation_for_value(value=value) + if update_fields: update_fields += ", " - update_fields += f'''Value = '{value}' ''' + update_fields += f"""Value = '{value}' """ - return self.tag_dal.putTagObject(last_key=last_key, updates=update_fields) + put_tag_result = self.tag_dal.putTagObject( + old_key=old_key, updates=update_fields + ) + self.load_tags() + return put_tag_result def describe(self): - """Retrieve a list of all TagObjects from memory. - """ + """Retrieve a list of all TagObjects from memory.""" return self.tag_dal.describeTagObject() + + diff --git a/Storage/NEW_KT_Storage/Test/TagObject_test.py b/Storage/NEW_KT_Storage/Test/TagObject_test.py index 3d0194eb..ce74c006 100644 --- a/Storage/NEW_KT_Storage/Test/TagObject_test.py +++ b/Storage/NEW_KT_Storage/Test/TagObject_test.py @@ -1,67 +1,295 @@ import pytest -import sys import os +import sys -sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..'))) +sys.path.append( + os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")) +) from Storage.NEW_KT_Storage.Service.Classes.TagObjectService import TagObjectService from Models.TagObjectModel import TagObject -@pytest.fixture +@pytest.fixture(scope="function") def tag_service(): - """Create a fixture for the TagObjectService.""" - return TagObjectService() + tag_service = TagObjectService(db_file=":memory:") + return tag_service def test_create_tag(tag_service): - """Test that creating a TagObject works correctly.""" - key = "TestKey" - value = "TestValue" - result = tag_service.create(key, value) + """Test the creation of a new tag.""" + key = "test_key" + value = "test_value" + tag_service.create(key, value) + + # Assert that the tag is created and exists in memory + tag = tag_service.get(key) + assert tag is not None + assert tag.key == key + assert tag.value == value + - assert result is not None - assert isinstance(result, TagObject) - assert result.key == key - assert result.value == value +def test_get_tag(tag_service): + """Test retrieving a tag by key.""" + key = "get_test_key" + value = "get_test_value" + tag_service.create(key, value) + + # Retrieve the tag and verify its correctness + tag = tag_service.get(key) + assert tag is not None + assert tag.key == key + assert tag.value == value + + +def test_raise_KeyError_where_get_not_exist_tag(tag_service): + key_that_not_exist = "key_that_not_exist" + with pytest.raises(KeyError): + tag_service.get(key_that_not_exist) def test_modify_tag(tag_service): - """Test that modifying a TagObject works correctly.""" - key = "TestKey" - value = "TestValue" - tag = tag_service.create(key, value) + """Test modifying an existing tag.""" + key = "modify_test_key" + value = "modify_test_value" + new_key = "new_test_key" + new_value = "new_test_value" - # Modify the tag object - new_value = "NewTestValue" - tag.value = new_value - modified_tag = tag_service.modify(tag) + # Create a tag and modify it + tag_service.create(key, value) + tag_service.modify(old_key=key, key=new_key, value=new_value) + # Verify the tag was updated + modified_tag = tag_service.get(new_key) assert modified_tag is not None + assert modified_tag.key == new_key assert modified_tag.value == new_value +def test_modify_tag_key_to_existing_key(tag_service): + """Test modifying a tag's key to an already existing key.""" + key1 = "existing_key_1" + value1 = "value1" + key2 = "existing_key_2" + value2 = "value2" + tag_service.create(key1, value1) + tag_service.create(key2, value2) + + # Attempt to modify key1 to key2, which already exists + with pytest.raises(Exception): # Adjust based on how your system handles this + tag_service.modify(old_key=key1, key=key2) + + +def test_get_after_modify_key(tag_service): + """Test that the original key is no longer accessible after modifying the key.""" + key = "mod_key_test" + value = "mod_value_test" + new_key = "new_mod_key" + tag_service.create(key, value) + + # Modify the key + tag_service.modify(old_key=key, key=new_key) + + # The old key should raise a KeyError + with pytest.raises(KeyError): + tag_service.get(key) + + def test_delete_tag(tag_service): - """Test that deleting a TagObject works correctly.""" - key = "DeleteKey" - value = "DeleteValue" - tag = tag_service.create(key, value) + """Test deleting an existing tag.""" + key = "delete_test_key" + value = "delete_test_value" + tag_service.create(key, value) + + # Delete the tag and verify it's gone + tag_service.delete(key) + + with pytest.raises(KeyError): + tag_service.get(key) + + +def test_delete_non_existent_tag(tag_service): + """Test attempting to delete a non-existent tag.""" + non_existent_key = "non_existent_key" + + # Attempting to delete should not raise an error but should have no effect + with pytest.raises(KeyError): + tag_service.delete(non_existent_key) + + +def test_modify_non_existent_tag(tag_service): + """Test modifying a tag that does not exist.""" + non_existent_key = "non_existent_key" + + # Modifying a non-existent tag should raise an error + with pytest.raises(KeyError): + tag_service.modify(old_key=non_existent_key, key="new_key", value="new_value") + + +def test_create_duplicate_tag(tag_service): + """Test creating a tag with a duplicate key.""" + key = "duplicate_key" + value1 = "value1" + value2 = "value2" + + # Create the first tag + tag_service.create(key, value1) + + # Creating a second tag with the same key should raise an error or overwrite + with pytest.raises( + Exception + ): # Modify this according to how duplicates are handled + tag_service.create(key, value2) + + +def test_create_with_empty_key(tag_service): + """Test creating a tag with an empty key.""" + with pytest.raises(ValueError): # Adjust based on the actual exception + tag_service.create("", "value_with_empty_key") + + +def test_create_with_empty_value(tag_service): + """Test creating a tag with an empty value.""" + key = "empty_value_key" + tag_service.create(key, "") + + # Verify that the tag was created with an empty value + tag = tag_service.get(key) + assert tag.value == "" + + +def test_get_tag_case_sensitivity(tag_service): + """Test the case sensitivity of tag keys.""" + key_lower = "case_key" + key_upper = "CASE_KEY" + value_lower = "lower_case_value" + value_upper = "upper_case_value" + + # Create both a lowercase and uppercase key + tag_service.create(key_lower, value_lower) + tag_service.create(key_upper, value_upper) + + # Verify that both tags exist and are distinct + tag_lower = tag_service.get(key_lower) + tag_upper = tag_service.get(key_upper) + assert tag_lower.value == value_lower + assert tag_upper.value == value_upper + assert tag_lower.key != tag_upper.key + + +def test_modify_only_key(tag_service): + """Test modifying only the key of an existing tag.""" + key = "original_key" + value = "original_value" + new_key = "new_only_key" + + # Create a tag and modify only its key + tag_service.create(key, value) + tag_service.modify(old_key=key, key=new_key) + + # Verify that the key was updated and value remains the same + modified_tag = tag_service.get(new_key) + assert modified_tag.key == new_key + assert modified_tag.value == value + + +def test_modify_only_value(tag_service): + """Test modifying only the value of an existing tag.""" + key = "modify_value_key" + value = "original_value" + new_value = "new_only_value" + + # Create a tag and modify only its value + tag_service.create(key, value) + tag_service.modify(old_key=key, value=new_value) + + # Verify that the value was updated and the key remains the same + modified_tag = tag_service.get(key) + assert modified_tag.key == key + assert modified_tag.value == new_value + + +def test_describe_empty(tag_service): + """Test describing tags when no tags exist.""" + # Describe should return an empty list when no tags are present + result = tag_service.describe() + assert result == [] + + +def test_create_tag_with_special_characters(tag_service): + """Test creating a tag with special characters in the key and value.""" + key = "key_with_special_!@#$%^&*()" + value = "value_with_special_{}[]<>" + + # Verify that the tag was created with the special characters + with pytest.raises(ValueError): + tag_service.create(key, value) + + +def test_create_tag_with_long_key(tag_service): + """Test creating a tag with a very long key.""" + long_key = "k" * 256 + value = "long_key_value" + with pytest.raises(ValueError): + tag_service.create(long_key, value) + + +def test_create_tag_with_long_value(tag_service): + """Test creating a tag with a very long value.""" + key = "long_value_key" + long_value = "v" * 1024 + tag_service.create(key, long_value) + + # Verify that the tag with the long value was created + tag = tag_service.get(key) + assert tag.key == key + assert tag.value == long_value + + +def test_modify_with_invalid_old_key(tag_service): + """Test modifying a tag with an invalid original key.""" + invalid_key = "invalid_key" + with pytest.raises(KeyError): + tag_service.modify(old_key=invalid_key, key="new_key", value="new_value") + + +def test_delete_all_tags(tag_service): + """Test deleting all tags and ensuring the memory is empty.""" + # Create a few tags + tag_service.create("key1", "value1") + tag_service.create("key2", "value2") + tag_service.create("key3", "value3") + + # Delete all tags + tag_service.delete("key1") + tag_service.delete("key2") + tag_service.delete("key3") + + # Describe should return an empty list + assert tag_service.describe() == [] + + +def test_modify_tag_to_empty_key(tag_service): + """Test modifying a tag's key to an empty key, which should raise an error.""" + key = "non_empty_key" + value = "some_value" + tag_service.create(key, value) - # Test delete functionality - delete_result = tag_service.delete(tag) + with pytest.raises(ValueError): # Adjust based on your system's behavior + tag_service.modify(old_key=key, key="") - assert delete_result is True +def test_create_tag_with_whitespace_key(tag_service): + """Test creating a tag with a key containing only whitespace.""" + with pytest.raises(ValueError): # Adjust based on your system's behavior + tag_service.create(" ", "value_with_whitespace_key") -def test_describe_tag(tag_service): - """Test that describing a TagObject works correctly.""" - key = "DescribeKey" - value = "DescribeValue" - tag = tag_service.create(key, value) - # Test describe functionality - description = tag_service.describe(tag) +def test_modify_tag_to_whitespace_key(tag_service): + """Test modifying a tag's key to a key containing only whitespace.""" + key = "valid_key" + value = "some_value" + tag_service.create(key, value) - assert description is not None - assert description["key"] == key - assert description["value"] == value + with pytest.raises(ValueError): # Adjust based on your system's behavior + tag_service.modify(old_key=key, key=" ") diff --git a/Storage/NEW_KT_Storage/Validation/TagValidation.py b/Storage/NEW_KT_Storage/Validation/TagValidation.py new file mode 100644 index 00000000..135eefab --- /dev/null +++ b/Storage/NEW_KT_Storage/Validation/TagValidation.py @@ -0,0 +1,13 @@ +import re +import Storage.NEW_KT_Storage.Validation.GeneralValidations as GeneralValidations + +def check_required_params(key): + return GeneralValidations.check_required_params(["key"],{'key': key}) + +def key_exists(tags, key): + '''Check if a bucket with the given name already exists.''' + return any(tag.key == key for tag in tags) + +def is_valid_key_name(key): + return re.match(r'^[a-zA-Z0-9._-]{2,63}$', key) + From 1e4528d39745007340ea47fc9d0ab4230a484cc2 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <160516400+Tamar-Gav@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:32:28 +0300 Subject: [PATCH 09/10] Update ObjectManager.py --- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py index cba10773..58dcc4cb 100644 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ b/DB/NEW_KT_DB/DataAccess/ObjectManager.py @@ -1,13 +1,15 @@ from typing import Dict, Any, Optional import json import sqlite3 -from DBManager import DBManager + +from DB.NEW_KT_DB.DataAccess.DBManager import DBManager class ObjectManager: def __init__(self, db_file: str): '''Initialize ObjectManager with the database connection.''' self.db_manager = DBManager(db_file) + def create_management_table(self, object_name, table_structure='default', pk_column_data_type='INTEGER'): table_name = self._convert_object_name_to_management_table_name(object_name) @@ -99,11 +101,10 @@ def get_all_objects_from_memory(self, object_name): table_name = self._convert_object_name_to_management_table_name(object_name) return self.db_manager.get_all_data_from_table(table_name) + @staticmethod def convert_object_attributes_to_dictionary(**kwargs): - dict = {} for key, value in kwargs.items(): dict[key] = value - - return dict \ No newline at end of file + return dict From 94e65e8601efa3ef42f67f09194ca64f9c8b4233 Mon Sep 17 00:00:00 2001 From: Tamar-Gav <160516400+Tamar-Gav@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:33:03 +0300 Subject: [PATCH 10/10] Delete DB/NEW_KT_DB/DataAccess/ObjectManager.py --- DB/NEW_KT_DB/DataAccess/ObjectManager.py | 110 ----------------------- 1 file changed, 110 deletions(-) delete mode 100644 DB/NEW_KT_DB/DataAccess/ObjectManager.py diff --git a/DB/NEW_KT_DB/DataAccess/ObjectManager.py b/DB/NEW_KT_DB/DataAccess/ObjectManager.py deleted file mode 100644 index 58dcc4cb..00000000 --- a/DB/NEW_KT_DB/DataAccess/ObjectManager.py +++ /dev/null @@ -1,110 +0,0 @@ -from typing import Dict, Any, Optional -import json -import sqlite3 - -from DB.NEW_KT_DB.DataAccess.DBManager import DBManager - -class ObjectManager: - def __init__(self, db_file: str): - '''Initialize ObjectManager with the database connection.''' - self.db_manager = DBManager(db_file) - - - def create_management_table(self, object_name, table_structure='default', pk_column_data_type='INTEGER'): - - table_name = self._convert_object_name_to_management_table_name(object_name) - pk_constraint = ' AUTOINCREMENT' if pk_column_data_type == 'INTEGER' else '' - - if table_structure == 'default': - table_structure = f'object_id {pk_column_data_type} PRIMARY KEY {pk_constraint},type_object TEXT NOT NULL,metadata TEXT NOT NULL' - self.db_manager.create_table(table_name, table_structure) - - - def _insert_object_to_management_table(self, table_name, object_info, columns_to_populate=None): - - if columns_to_populate is None: - self.db_manager.insert_data_into_table(table_name, object_info) - else: - self.db_manager.insert_data_into_table(table_name, object_info, columns_to_populate) - - - def _update_object_in_management_table_by_criteria(self, table_name, updates, criteria): - self.db_manager.update_records_in_table(table_name, updates, criteria) - - - def _delete_object_from_management_table(self, table_name, criteria) -> None: - '''Delete an object from the database.''' - self.db_manager.delete_data_from_table(table_name, criteria) - - - def _convert_object_name_to_management_table_name(self,object_name): - return f'mng_{object_name}s' - - - def save_in_memory(self, object_name, object_info, columns=None): - # insert object info into management table mng_{object_name}s - # for exmple: object db_instance will be saved in table mng_db_instances - table_name = self._convert_object_name_to_management_table_name(object_name) - - if not self._is_management_table_exist(object_name): - self.create_management_table(object_name) - - if columns is None: - self._insert_object_to_management_table(table_name, object_info) - else: - self._insert_object_to_management_table(table_name, object_info, columns) - - - def _is_management_table_exist(self, object_name): - - table_name = self._convert_object_name_to_management_table_name(object_name) - return self.db_manager.is_table_exist(table_name) - - - def delete_from_memory_by_criteria(self, object_name:str, criteria:str): - - table_name = self._convert_object_name_to_management_table_name(object_name) - - self._delete_object_from_management_table(table_name, criteria) - - - def delete_from_memory_by_pk(self, object_name:str, pk_column:str, pk_value:str): - - criteria = f"{pk_column} = '{pk_value}'" - - table_name = self._convert_object_name_to_management_table_name(object_name) - - self._delete_object_from_management_table(table_name, criteria) - - - def update_in_memory(self, object_name, updates, criteria): - - table_name = self._convert_object_name_to_management_table_name(object_name) - self._update_object_in_management_table_by_criteria(table_name, updates, criteria) - - - def get_from_memory(self, object_name, columns=None, criteria=None): - """get records from memory by criteria or id""" - table_name = self._convert_object_name_to_management_table_name(object_name) - - if columns is None and criteria is None: - return self.db_manager.get_data_from_table(table_name) - elif columns is None: - return self.db_manager.get_data_from_table(table_name, criteria=criteria) - elif criteria is None: - return self.db_manager.get_data_from_table(table_name, columns) - else: - return self.db_manager.get_data_from_table(table_name, columns, criteria) - - - def get_all_objects_from_memory(self, object_name): - table_name = self._convert_object_name_to_management_table_name(object_name) - return self.db_manager.get_all_data_from_table(table_name) - - - @staticmethod - def convert_object_attributes_to_dictionary(**kwargs): - dict = {} - for key, value in kwargs.items(): - dict[key] = value - return dict