Working on general PATCH template function.

This commit is contained in:
Scott Idem
2021-03-09 15:27:17 -05:00
parent bc22a8c9d8
commit 291dfc8896
6 changed files with 403 additions and 22 deletions

View File

@@ -25,7 +25,7 @@ db = engine.connect()
# ### BEGIN ### Core Help CRUD ### sql_insert() ### # ### BEGIN ### Core Help CRUD ### sql_insert() ###
def sql_insert(sql:str=None, data:dict=None, table_name:str=None, id_random_length:int=8): def sql_insert(sql:str=None, data:dict=None, table_name:str=None, id_random_length:int=8):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
if sql: if sql:
@@ -81,7 +81,7 @@ def sql_insert(sql:str=None, data:dict=None, table_name:str=None, id_random_leng
return False return False
else: else:
log.debug(result_insert) log.debug(result_insert)
log.debug(result_insert.rowcount) log.debug(f'rowcount = {result_insert.rowcount}; lastrowid = {result_insert.lastrowid}')
if result_insert.rowcount == 1 and result_insert.lastrowid > 0: # insert if result_insert.rowcount == 1 and result_insert.lastrowid > 0: # insert
log.info('Insert record') log.info('Insert record')
log.debug(result_insert.lastrowid) log.debug(result_insert.lastrowid)
@@ -106,10 +106,77 @@ def sql_insert(sql:str=None, data:dict=None, table_name:str=None, id_random_leng
# ### BEGIN ### Core Help CRUD ### sql_update() ### # ### BEGIN ### Core Help CRUD ### sql_update() ###
def sql_update(sql=None, data=None, table_name=None, rm_id_random=None, id_random_length=None): def sql_update(sql:str=None, data:dict=None, table_name:str=None, record_id:int=None, record_id_random:str=None, rm_id_random=None, id_random_length:int=8):
log.setLevel(logging.ERROR) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
if sql:
sql_update = text(sql)
elif table_name and data:
#if rm_id_random:
#data = lookup_id_random_pop(obj_data=data)
if not data.get('id_random', None) and id_random_length:
data['id_random'] = secrets.token_urlsafe(id_random_length)
log.debug(data)
fields_string = []
for key, value in data.items():
if key != 'id': # Creating a special exception for the id field.
fields_string.append('`'+str(key) + '` = :' + str(key))
sql_set = ', '.join(fields_string)
if record_id:
log.info('Update record with ID')
data['id'] = record_id
sql = 'UPDATE `'+table_name+'` SET '+ sql_set + ' WHERE id = :id'
elif record_id_random:
log.info('Update record with ID random')
data['id_random'] = record_id_random
sql = 'UPDATE `'+table_name+'` SET '+ sql_set + ' WHERE id_random = :id_random'
elif 'id' in data:
log.info('Update record with ID')
sql = 'UPDATE `'+table_name+'` SET '+ sql_set + ' WHERE id = :id'
elif 'id_random' in data:
# NOTE: For now it is not possible to update the id_random when supplying the id_random as the primary key for a record.
# NOTE: In the future I can use record_id_random=True as a special case SQL UPDATE.
log.info('Update record with ID random')
sql = 'UPDATE `'+table_name+'` SET '+ sql_set + ' WHERE id_random = :id_random'
else:
return False
sql_update = text(sql)
trans = db.begin()
try:
result_update = db.execute(sql_update, data)
trans.commit()
except Exception as e:
trans.rollback()
log.exception('*** An exception happened. ***')
log.exception(repr(e))
log.exception('***')
log.exception(str(e))
log.exception('^^^ exception ^^^')
return False
else:
log.debug(result_update)
log.debug(f'rowcount = {result_update.rowcount}; lastrowid = {result_update.lastrowid}')
if result_update.rowcount == 1 and result_update.lastrowid == 0: # update with no change
log.info('Update record (with no change???)') # With SQL UPDATE this record may have actually changed
return True
elif result_update.rowcount == 2 and result_update.lastrowid > 0: # update with change
log.warning('Should we be here???')
log.info('Update record with changes')
record_id = result_update.lastrowid
return record_id
else:
log.debug(result_update)
log.debug(vars(result_update))
log.debug(dir(result_update))
log.debug(result_update.rowcount) # returns 1 on insert and 2 on update with change
log.debug(result_update.lastrowid) # returns last row ID on insert and update with a change and returns 0 if nothing changed
return False
return False return False
# ### END ### Core Help CRUD ### sql_update() ### # ### END ### Core Help CRUD ### sql_update() ###
@@ -118,7 +185,7 @@ def sql_update(sql=None, data=None, table_name=None, rm_id_random=None, id_rando
# The catch all SQL INSERT or UPDATE function - STI 2021-02-17 # The catch all SQL INSERT or UPDATE function - STI 2021-02-17
# This one does it all for SQL INSERT and UPDATE queries # This one does it all for SQL INSERT and UPDATE queries
def sql_insert_or_update(sql:str=None, data:dict=None, table_name:str=None, rm_id_random:bool=None, id_random_length:int=None): def sql_insert_or_update(sql:str=None, data:dict=None, table_name:str=None, rm_id_random:bool=None, id_random_length:int=None):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
#if sql: pass #if sql: pass
@@ -165,7 +232,7 @@ def sql_insert_or_update(sql:str=None, data:dict=None, table_name:str=None, rm_i
trans = db.begin() trans = db.begin()
try: try:
result_insert = db.execute(sql_insert_or_update, data) result_insert_or_update = db.execute(sql_insert_or_update, data)
trans.commit() trans.commit()
except Exception as e: except Exception as e:
trans.rollback() trans.rollback()
@@ -176,23 +243,25 @@ def sql_insert_or_update(sql:str=None, data:dict=None, table_name:str=None, rm_i
log.exception('^^^ exception ^^^') log.exception('^^^ exception ^^^')
return False return False
else: else:
if result_insert.rowcount == 1 and result_insert.lastrowid > 0: # insert log.debug(result_insert_or_update)
log.debug(f'rowcount = {result_insert_or_update.rowcount}; lastrowid = {result_insert_or_update.lastrowid}')
if result_insert_or_update.rowcount == 1 and result_insert_or_update.lastrowid > 0: # insert
log.info('Insert record') log.info('Insert record')
record_id = result_insert.lastrowid record_id = result_insert_or_update.lastrowid
return record_id return record_id
elif result_insert.rowcount == 1 and result_insert.lastrowid == 0: # update with no change elif result_insert_or_update.rowcount == 1 and result_insert_or_update.lastrowid == 0: # update with no change
log.info('Update record with no change') log.info('Update record with no change')
return True return True
elif result_insert.rowcount == 2 and result_insert.lastrowid > 0: # update with change elif result_insert_or_update.rowcount == 2 and result_insert_or_update.lastrowid > 0: # update with change
log.info('Update record with changes') log.info('Update record with changes')
record_id = result_insert.lastrowid record_id = result_insert_or_update.lastrowid
return record_id return record_id
else: else:
log.debug(result_insert) log.debug(result_insert_or_update)
log.debug(vars(result_insert)) log.debug(vars(result_insert_or_update))
log.debug(dir(result_insert)) log.debug(dir(result_insert_or_update))
log.debug(result_insert.rowcount) # returns 1 on insert and 2 on update with change log.debug(result_insert_or_update.rowcount) # returns 1 on insert and 2 on update with change
log.debug(result_insert.lastrowid) # returns last row ID on insert and update with a change and returns 0 if nothing changed log.debug(result_insert_or_update.lastrowid) # returns last row ID on insert and update with a change and returns 0 if nothing changed
return False return False
return False return False
# ### END ### Core Help CRUD ### sql_insert_or_update() ### # ### END ### Core Help CRUD ### sql_insert_or_update() ###
@@ -407,7 +476,7 @@ def sql_select(table_name=None, record_id=None, record_id_random=None, field_nam
# The catch all SQL DELETE function - STI 2021-02-17 # The catch all SQL DELETE function - STI 2021-02-17
# This one does it all for SQL DELETE queries # This one does it all for SQL DELETE queries
def sql_delete(table_name:str=None, record_id:int=None, record_id_random:str=None, field_name:str=None, field_value=None, sql:str=None, data:dict=None): def sql_delete(table_name:str=None, record_id:int=None, record_id_random:str=None, field_name:str=None, field_value=None, sql:str=None, data:dict=None):
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
if table_name and (record_id or record_id_random) and not (field_name or field_value or sql or data): if table_name and (record_id or record_id_random) and not (field_name or field_value or sql or data):

View File

@@ -18,7 +18,7 @@ from .lib_general import *
from .log import * from .log import *
# Import the routers here first: # Import the routers here first:
from .routers import api_crud, address, websockets # , items, journals, users from .routers import api_crud, address, contact, websockets # , items, journals, users
from .db_sql import db from .db_sql import db
@@ -61,6 +61,14 @@ app.include_router(
#dependencies=[Depends(get_account_header)], #dependencies=[Depends(get_account_header)],
#responses={404: {'description': 'Not found'}}, #responses={404: {'description': 'Not found'}},
) )
app.include_router(
contact.router,
prefix='/contact',
tags=['Contact'],
#dependencies=[Depends(get_token_header)],
#dependencies=[Depends(get_account_header)],
#responses={404: {'description': 'Not found'}},
)
app.include_router( app.include_router(
websockets.router, websockets.router,
#prefix='/websocket', #prefix='/websocket',

View File

@@ -33,7 +33,7 @@ class Contact_Base(BaseModel):
address_id: Optional[int] address_id: Optional[int]
for_type: Optional[str] for_type: Optional[str]
for_id_random: Optional[str] for_id_random: Optional[str] = None
for_id: Optional[int] for_id: Optional[int]
name: Optional[str] name: Optional[str]

View File

@@ -9,6 +9,8 @@ from ..log import *
from app.config import settings from app.config import settings
from app.db_sql import * from app.db_sql import *
from .api_crud import patch_obj_template
from ..models.address_model import Address_Base from ..models.address_model import Address_Base
from ..models.response_model import * from ..models.response_model import *
@@ -52,3 +54,66 @@ async def post_address_obj(address: Address_Base,
resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset) resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data) return mk_resp(data=resp_data)
@router.patch('/{address_id}')
async def patch_address_obj(
address_id: str,
address: Address_Base,
x_account_id: str = Header(...),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
table_name_update = 'address'
obj_id = address_id # actually id_random
obj_data_dict = address.dict(by_alias=False, exclude_unset=True)
obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=table_name_update)
obj_data_dict['id_random'] = obj_id
result = patch_obj_template(table_name_update=table_name_update,
data=obj_data_dict,
obj_id=obj_id,
return_obj=True,
by_alias=True,
exclude_unset=True
)
return result
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
table_name_update = 'address'
table_name_select = 'v_address'
obj_id = address_id
obj_data_dict = address.dict(by_alias=False, exclude_unset=True)
obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=table_name_update)
obj_data_dict['id_random'] = address_id # NOTE: Adding this in so the id_random is NOT updated
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(obj_data_dict)
obj_data = lookup_id_random_pop(obj_data_dict)
base_name = Address_Base
if sql_update_result := sql_update(table_name=table_name_update, data=obj_data):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
#obj_id = sql_update_result
obj_id = obj_data_dict['id']
else:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
return mk_resp(data=False, status_code=400)
if sql_select_result := sql_select(table_name=table_name_select, record_id=obj_id):
log.debug(sql_select_result)
resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data)
else:
log.debug(sql_select_result)
return mk_resp(data=False, status_code=404)

View File

@@ -208,6 +208,20 @@ async def get_obj(obj_type_l1: str=None,
by_alias: Optional[bool] = True, by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True, exclude_unset: Optional[bool] = True,
): ):
"""
Simple select object type with an ID:
- **obj_type_l1, obj_type_l2, obj_type_l3**:
- Examples:
- /account = account
- /user = user
- /user/role = user_role
- /event = event
- /event/exhibit = event_exhibit
- /order = order
- /order/cart = order_cart
- /order/cart/line = order_cart_line
- /lu/some_lookup = lu_some_lookup
"""
log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
@@ -250,10 +264,123 @@ async def get_obj(obj_type_l1: str=None,
table_name = obj_type_li[obj_name]['table_name'] table_name = obj_type_li[obj_name]['table_name']
# NOTE: Add a check for the object ID... assuming it is a random ID string for now. # NOTE: Add a check for the object ID... assuming it is a random ID string for now.
sql_result = sql_select(table_name=table_name, record_id_random=obj_id) if sql_result := sql_select(table_name=table_name, record_id_random=obj_id):
log.debug(sql_result)
base_name = obj_type_li[obj_name]['base_name']
resp_data = base_name(**sql_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data) #, details=debug_data)
else:
log.debug(sql_result)
return mk_resp(data=False, status_code=404)
@router.delete('/{obj_type_l1}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_id}')
@router.delete('/{obj_type_l1}/{obj_type_l2}/{obj_type_l3}/{obj_id}')
async def delete_obj(obj_type_l1: str=None,
obj_type_l2: str=None,
obj_type_l3: str=None,
obj_id: str=None,
x_account_id: str = Header(...),
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
):
"""
Simple delete object type with an ID:
- **obj_type_l1, obj_type_l2, obj_type_l3**:
- Examples:
- /account = account
- /user = user
- /user/role = user_role
- /event = event
- /event/exhibit = event_exhibit
- /order = order
- /order/cart = order_cart
- /order/cart/line = order_cart_line
- /lu/some_lookup = lu_some_lookup
"""
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
debug_data = {}
debug_data['obj_type_l1'] = obj_type_l1
debug_data['obj_type_l2'] = obj_type_l2
debug_data['obj_type_l3'] = obj_type_l3
debug_data['obj_id'] = obj_id
log.debug(debug_data)
if obj_type_l1 and obj_type_l2 and obj_type_l3:
obj_name = f'{obj_type_l1}_{obj_type_l2}_{obj_type_l3}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400)
elif obj_type_l1 and obj_type_l2:
obj_name = f'{obj_type_l1}_{obj_type_l2}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400)
elif obj_type_l1:
obj_name = f'{obj_type_l1}'
if obj_name in obj_type_li:
pass
else:
return mk_resp(data=False, status_code=400)
else:
log.warning('We should not be here')
return mk_resp(data=False, status_code=400)
table_name = obj_name # obj_type_li[obj_name]['table_name'] # NOTE: Don't try to use the view!
# NOTE: Add a check for the object ID... assuming it is a random ID string for now.
sql_result = sql_delete(table_name=table_name, record_id_random=obj_id)
log.debug(sql_result) log.debug(sql_result)
base_name = obj_type_li[obj_name]['base_name'] resp_data = True
resp_data = base_name(**sql_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data) #, details=debug_data) return mk_resp(data=resp_data) #, details=debug_data)
def patch_obj_template(table_name_update:str=None,
data:dict=None,
obj_id:str=None,
return_obj:bool=True,
by_alias:bool=True,
exclude_unset:bool=True
):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
obj_data_dict = data
#obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=table_name_update)
obj_data_dict['id_random'] = obj_id # NOTE: Adding this in so the id_random is NOT updated
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(obj_data_dict)
obj_data = lookup_id_random_pop(obj_data_dict)
table_name_select = obj_type_li[table_name_update]['table_name']
base_name = obj_type_li[table_name_update]['base_name']
if sql_update_result := sql_update(table_name=table_name_update, data=obj_data):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
#obj_id = sql_update_result
obj_id = obj_data_dict['id']
else:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
return mk_resp(data=False, status_code=400)
if sql_select_result := sql_select(table_name=table_name_select, record_id=obj_id):
log.debug(sql_select_result)
resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data)
else:
log.debug(sql_select_result)
return mk_resp(data=False, status_code=404)

112
app/routers/contact.py Normal file
View File

@@ -0,0 +1,112 @@
import datetime
#from datetime import datetime, time, timedelta
from fastapi import APIRouter, Body, Depends, Header, HTTPException, Query, status
from pydantic import BaseModel, EmailStr, Field
from typing import Dict, List, Optional, Set, Union
from ..lib_general import *
from ..log import *
from app.config import settings
from app.db_sql import *
from ..models.contact_model import Contact_Base
from ..models.response_model import *
router = APIRouter()
# Working on the contact API CRUD - STI 2021-03-08
@router.post('')
async def post_contact_obj(contact: Contact_Base,
x_account_id: str = Header(...),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
table_name_insert = 'contact'
obj_data_dict = contact.dict(by_alias=False, exclude_unset=True)
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(obj_data_dict)
obj_data = lookup_id_random_pop(obj_data_dict)
base_name = Contact_Base
if sql_insert_result := sql_insert(table_name=table_name_insert, data=obj_data):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_insert_result)
obj_id = sql_insert_result
else:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_insert_result)
return mk_resp(data=False, status_code=400)
table_name_select = 'v_contact'
sql_select_result = sql_select(table_name=table_name_select, record_id=obj_id)
log.debug(sql_select_result)
resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data)
@router.patch('/{contact_id}')
async def patch_contact_obj(contact_id: str,
contact: Contact_Base,
x_account_id: str = Header(...),
return_obj: Optional[bool] = True,
by_alias: Optional[bool] = True,
exclude_unset: Optional[bool] = True,
):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals())
table_name_update = 'contact'
obj_id = contact_id # actually id_random
obj_data_dict = contact.dict(by_alias=False, exclude_unset=True)
obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=table_name_update)
obj_data_dict['id_random'] = obj_id
result = patch_obj_template(table_name_update=table_name_update,
data=obj_data_dict,
obj_id=obj_id,
return_obj=True,
by_alias=True,
exclude_unset=True
)
return result
table_name_update = 'contact'
table_name_select = 'v_contact'
obj_id = contact_id
obj_data_dict = contact.dict(by_alias=False, exclude_unset=True)
obj_data_dict['id'] = redis_lookup_id_random(record_id_random=obj_id, table_name=table_name_update)
obj_data_dict['id_random'] = contact_id # NOTE: Adding this in so the id_random is NOT updated
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(obj_data_dict)
obj_data = lookup_id_random_pop(obj_data_dict)
base_name = Contact_Base
if sql_update_result := sql_update(table_name=table_name_update, data=obj_data):
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
#obj_id = sql_update_result
obj_id = obj_data_dict['id']
else:
log.setLevel(logging.DEBUG) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(sql_update_result)
return mk_resp(data=False, status_code=400)
if sql_select_result := sql_select(table_name=table_name_select, record_id=obj_id):
log.debug(sql_select_result)
resp_data = base_name(**sql_select_result).dict(by_alias=by_alias, exclude_unset=exclude_unset)
return mk_resp(data=resp_data)
else:
log.debug(sql_select_result)
return mk_resp(data=False, status_code=404)