diff --git a/.gitignore b/.gitignore index 982311e..38493ae 100644 --- a/.gitignore +++ b/.gitignore @@ -128,4 +128,5 @@ dmypy.json # Pyre type checker .pyre/ main.py -test.py \ No newline at end of file +test.py +pyproject_backup.toml \ No newline at end of file diff --git a/README.md b/README.md index 412fdee..1e98bce 100644 --- a/README.md +++ b/README.md @@ -16,15 +16,6 @@ $ pip install postgres-dynamic ## Parameter Format: -- connection_string: dict - ```Python - connection_string = { - 'PG_HOST': 'YOUR_CONNETION_HOST_ADDRESS', - 'PG_DATABASE': 'YOUR_CONNECTION_DATABASE_NAME', - 'PG_USER': 'YOUR_CONNECTION_USERNAME', - 'PG_PASSWORD': 'YOUR_CONNECTION_PASSWORD', - } - ``` - connection_object: Callable ```Python connection_object = psycopg2.connect(host,port,database,user,password) #object created from psycopg2.connect() @@ -118,7 +109,6 @@ Example DB Parameters: ``` - connection_string #required main_table #required where #required join_table #optional (if omitted it won't join to any table) @@ -133,12 +123,6 @@ Example DB import asyncio query_result = PGDGet.get_one( - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - }, main_table={'table': 'employees'}, where=[ {'column_name': 'id', 'value': '1'}, @@ -156,12 +140,6 @@ Example DB # with join table salaries query_result = PGDGet.get_one( - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - }, main_table={'table': 'employees', 'alias': 'emp'}, join_table=[ {'table': 'salaries', 'alias': 'sal', 'join_method': 'INNER', 'on': 'emp.id = sal.employee_id'} @@ -185,7 +163,6 @@ Example DB Show more... ``` - connection_string #required main_table #required where #optional (if omitted no condition will be passed) join_table #optional (if omitted it won't join to any table) @@ -206,12 +183,6 @@ Example DB import asyncio query_result = PGDGet.get_all( - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - }, main_table={'table': 'employees'}, limit=3, offset=2 @@ -231,7 +202,6 @@ Example DB Show more... ``` - connection_string #required main_table #required where #optional (if omitted no condition will be passed) join_table #optional (if omitted it won't join to any table) @@ -243,12 +213,6 @@ Example DB import asyncio query_result = PGDGet.get_count( - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - }, main_table={'table': 'employees'}, where=[{'column_name': 'first_name', 'value': 'Alex'}] ) @@ -270,7 +234,6 @@ Example DB Parameters: ``` - connection_object #required main_table #required column_and_value #required commit #optional (if omitted, default value will be False which will not saving any changes to database) @@ -283,9 +246,7 @@ Example DB from postgres_dynamic import PGDTransaction import asyncio - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.insert( - connection_object=connection_object, main_table='employees', column_and_value={'id': 6, 'first_name': 'Harrison', 'last_name': 'Ford'}, commit=True @@ -301,9 +262,7 @@ Example DB ```Python # without auto commit - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.insert( - connection_object=connection_object, main_table='salaries', column_and_value={'employee_id': 6, 'salary': 250000}, ) @@ -330,7 +289,6 @@ Example DB Parameters: ``` - connection_object #required main_table #required column_and_value #required where #required @@ -344,9 +302,7 @@ Example DB from postgres_dynamic import PGDTransaction import asyncio - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.update( - connection_object=connection_object, main_table='employees', column_and_value={'first_name': 'Tyler', 'last_name': 'Oakley'}, where=[ @@ -365,9 +321,7 @@ Example DB ```Python # without auto commit - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.update( - connection_object=connection_object, main_table='salaries', column_and_value={'salary': 450000}, where=[ @@ -398,7 +352,6 @@ Example DB Parameters: ``` - connection_object #required main_table #required where #required commit #optional (if omitted, default value will be False which will not saving any changes to database) @@ -411,9 +364,7 @@ Example DB from postgres_dynamic import PGDTransaction import asyncio - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.delete( - connection_object=connection_object, main_table='salaries', where=[ {'column_name': 'employee_id', 'value': '6'}, @@ -431,9 +382,7 @@ Example DB ```Python # without auto commit - connection_object = psycopg2.connect(database='postgres', host='localhost', port=5432, user='postgres', password='password') query_result = PGDTransaction.delete( - connection_object=connection_object, main_table='employees', where=[ {'column_name': 'id', 'value': '6'}, diff --git a/pyproject.toml b/pyproject.toml index 9744fcf..585f408 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,15 +4,12 @@ build-backend = "setuptools.build_meta" [project] name = "postgres-dynamic" -version = "0.0.6" +version = "0.0.11" authors = [ { name="Bayu Satria Gemilang", email="bayu.code.lab@gmail.com" }, ] -description = "Fast API Google Cloud Storage" +description = "Postgres Dynamic Query" readme = "README.md" -dependencies = [ - "psycopg2>=2.9.3" -] requires-python = ">=3.7" classifiers = [ "Programming Language :: Python :: 3", diff --git a/src/postgres_dynamic/pgd_connection.py b/src/postgres_dynamic/pgd_connection.py deleted file mode 100644 index 83fce41..0000000 --- a/src/postgres_dynamic/pgd_connection.py +++ /dev/null @@ -1,21 +0,0 @@ -import psycopg2 - -class PGDConnection: - def __init__(self, connection_string: dict, query: str, values: tuple) -> None: - self.query = query - self.values = values - self.connection = psycopg2.connect( - host = connection_string['PG_HOST'], - database = connection_string['PG_DATABASE'], - user = connection_string['PG_USER'], - password = connection_string['PG_PASSWORD'] - ) - self.cursor = self.connection.cursor() - - def __enter__(self): - self.cursor.execute(self.query, self.values) - return self.cursor - - def __exit__(self, exc_type, exc_value, exc_traceback): - self.connection.close() - self.cursor.close \ No newline at end of file diff --git a/src/postgres_dynamic/pgd_get.py b/src/postgres_dynamic/pgd_get.py index 4509be2..986f624 100644 --- a/src/postgres_dynamic/pgd_get.py +++ b/src/postgres_dynamic/pgd_get.py @@ -1,22 +1,13 @@ from typing import Awaitable, Optional -from datetime import datetime, timedelta -from postgres_dynamic.pgd_connection import PGDConnection class PGDGet: @classmethod - async def get_one(cls, connection_string: dict, main_table: dict, where: list, join_table:list = [], column_name: list = None) -> Awaitable[dict]: + async def get_one(cls, main_table: dict, where: list, join_table:list = [], column_name: list = None) -> Awaitable[dict]: """Get one always return a single value from the query, based on fetchone in psycopg2 and returning a dictionary with {column_name: value} of the tables. Please refer to documentation for thorough guide. Example parameters: - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - } - main_table={'table': 'employees', 'alias': 'emp'} #alias can be omitted join_table=[ @@ -32,7 +23,6 @@ async def get_one(cls, connection_string: dict, main_table: dict, where: list, j column_name=['first_name'] #can be omitted, when omitted it equals as `select * from blabla` """ try: - result = {} column_name = ','.join(column_name) if column_name else '*' query = """ SELECT {column_name} FROM {main_table} {main_table_alias} {join_table} WHERE {where_query} @@ -45,36 +35,23 @@ async def get_one(cls, connection_string: dict, main_table: dict, where: list, j join_query = '' for i in join_table: - join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' + join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' if i['join_method'] == 'RIGHT' else ' FULL JOIN' if i['join_method'] == 'FULL' else ' JOIN' join_query += f' {i["table"]} {i["alias"]} ON {i["on"]}' query = query.format(column_name=column_name, main_table=main_table['table'], main_table_alias=main_table['alias'] if main_table.get('alias') else '', join_table=join_query, where_query=where_query) - where_values = tuple(wv['value'] for wv in where) - values = where_values - with PGDConnection(connection_string, query, values) as cursor: - column_name = [i[0] for i in cursor.description] - data = cursor.fetchone() - if data: - for a, b in zip(column_name, data): - result[a] = str(b + timedelta(hours=7)) if type(b) is datetime else b - return result + where_value = tuple(wv['value'] for wv in where) + value = where_value + return query, value except Exception as e: raise e @classmethod - async def get_all(cls, connection_string: dict, main_table: dict, where: list = [], join_table:list = [], order: dict = {}, column_name: list = None, limit: Optional[int] = None, offset: Optional[int] = None) -> Awaitable[dict]: + async def get_all(cls, main_table: dict, where: list = [], join_table:list = [], order: dict = {}, column_name: list = None, limit: Optional[int] = None, offset: Optional[int] = None) -> Awaitable[dict]: """Get all always return a dict with key data, based on fetchall in psycopg2 and returning a list of dictionary with {column_name: value} of the tables. Please refer to documentation for thorough guide. Example parameters: - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - } - main_table={'table': 'employees', 'alias': 'emp'} #alias can be omitted join_table=[ @@ -96,7 +73,6 @@ async def get_all(cls, connection_string: dict, main_table: dict, where: list = offset=1 #optional """ try: - result = [] column_name = ','.join(column_name) if column_name else '*' query = """ SELECT {column_name} FROM {main_table} {main_table_alias} {join_table} {where_query} {order_query} LIMIT %s OFFSET %s @@ -115,38 +91,23 @@ async def get_all(cls, connection_string: dict, main_table: dict, where: list = join_query = '' for i in join_table: - join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' + join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' if i['join_method'] == 'RIGHT' else ' FULL JOIN' if i['join_method'] == 'FULL' else ' JOIN' join_query += f' {i["table"]} {i["alias"]} ON {i["on"]}' query = query.format(column_name=column_name, main_table=main_table['table'], main_table_alias=main_table['alias'] if main_table.get('alias') else '', join_table=join_query, where_query=where_query, order_query=order_query) - where_values = tuple(wv['value'] for wv in where) + where_value = tuple(wv['value'] for wv in where) offset_value = (limit*(offset-1)) if offset else None - values = where_values + (limit, offset_value) - with PGDConnection(connection_string, query, values) as cursor: - column_name = [i[0] for i in cursor.description] - for i in cursor.fetchall(): - data = {} - for a, b in zip(column_name, i): - data[a] = str(b + timedelta(hours=7)) if type(b) is datetime else b - result.append(data) - return {'data': result} + value = where_value + (limit, offset_value) + return query, value except Exception as e: raise e @classmethod - async def get_count(cls, connection_string: dict, main_table: dict, where: list = [], join_table:list = []) -> Awaitable[dict]: + async def get_count(cls, main_table: dict, where: list = [], join_table:list = []) -> Awaitable[dict]: """Get count always return a dict with key total_data, based on select count(*) in SQL and returning a dictionary with {total_data: value} of the query. Please refer to documentation for thorough guide. Example parameters: - - connection_string={ - 'PG_HOST': 'localhost', #using default port 5432 - 'PG_DATABASE': 'postgres', - 'PG_USER': 'postgres', - 'PG_PASSWORD': 'password' - } - main_table={'table': 'employees', 'alias': 'emp'} #alias can be omitted join_table=[ @@ -160,7 +121,6 @@ async def get_count(cls, connection_string: dict, main_table: dict, where: list #conjunction only required when providing more than one dictionary """ try: - result = [] query = """ SELECT COUNT(*) FROM {main_table} {main_table_alias} {join_table} {where_query} """ @@ -174,14 +134,12 @@ async def get_count(cls, connection_string: dict, main_table: dict, where: list join_query = '' for i in join_table: - join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' + join_query += ' INNER JOIN' if i['join_method'] == 'INNER' else ' LEFT JOIN' if i['join_method'] == 'LEFT' else ' RIGHT JOIN' if i['join_method'] == 'RIGHT' else ' FULL JOIN' if i['join_method'] == 'FULL' else ' JOIN' join_query += f' {i["table"]} {i["alias"]} ON {i["on"]}' query = query.format(main_table=main_table['table'], main_table_alias=main_table['alias'] if main_table.get('alias') else '', join_table=join_query, where_query=where_query) - where_values = tuple(wv['value'] for wv in where) - values = where_values - with PGDConnection(connection_string, query, values) as cursor: - result = cursor.fetchone()[0] - return {'total_data': result} + where_value = tuple(wv['value'] for wv in where) + value = where_value + return query, value except Exception as e: raise e \ No newline at end of file diff --git a/src/postgres_dynamic/pgd_transaction.py b/src/postgres_dynamic/pgd_transaction.py index 8827ea8..d12c682 100644 --- a/src/postgres_dynamic/pgd_transaction.py +++ b/src/postgres_dynamic/pgd_transaction.py @@ -1,13 +1,12 @@ from typing import Awaitable class PGDTransaction: @classmethod - async def insert(cls, connection_object: any, main_table: str, column_and_value: dict, commit: bool = False) -> Awaitable[None]: + async def insert(cls, main_table: str, column_and_value: dict, commit: bool = False) -> Awaitable[None]: """Dynamic query to insert certain table that can target several columns Params supplied for column_and_values are dict that contains key, value pair Example parameters: - connection_object = psycopg2.connect(database='postgres', host='localhost', user='postgres', password='password') main_table='employees', @@ -22,20 +21,15 @@ async def insert(cls, connection_object: any, main_table: str, column_and_value: """ query = query_template.format(main_table=main_table, column_keys=column_keys, column_values=', '.join(['%s']*(len(column_and_value)))) value = tuple([value for value in column_and_value.values()]) - connection_object.cursor().execute(query, value) - if commit: - connection_object.commit() - return + return query, value except Exception as e: - connection_object.rollback() raise e @classmethod - async def update(cls, connection_object: any, main_table: str, column_and_value: dict, where: list, commit: bool = False) -> Awaitable[None]: + async def update(cls, main_table: str, column_and_value: dict, where: list, commit: bool = False) -> Awaitable[None]: """Dynamic query to update certain table that can takes multiple conditions and target several columns Example parameters: - connection_object = psycopg2.connect(database='postgres', host='localhost', user='postgres', password='password') main_table='employees', @@ -62,20 +56,15 @@ async def update(cls, connection_object: any, main_table: str, column_and_value: update_values = tuple(value for value in column_and_value.values()) where_values = tuple(wv['value'] for wv in where) value = update_values + where_values - connection_object.cursor().execute(query, value) - if commit: - connection_object.commit() - return + return query, value except Exception as e: - connection_object.rollback() raise e @classmethod - async def delete(cls, connection_object: any, main_table: str, where: list, commit: bool = False) -> Awaitable[None]: + async def delete(cls, main_table: str, where: list, commit: bool = False) -> Awaitable[None]: """Dynamic query to delete data from certain table that can takes several conditions Example parameters: - connection_object = psycopg2.connect(database='postgres', host='localhost', user='postgres', password='password') main_table='employees', @@ -97,10 +86,6 @@ async def delete(cls, connection_object: any, main_table: str, where: list, comm """ query = query_template.format(main_table=main_table, where_query=where_query) value = tuple(wv['value'] for wv in where) - connection_object.cursor().execute(query, value) - if commit: - connection_object.commit() - return + return query, value except Exception as e: - connection_object.rollback() raise e \ No newline at end of file