From 6d1cc6c1ff68df14ff00776ed1713b988d0312cc Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Wed, 29 Nov 2023 18:24:39 -0500 Subject: [PATCH] Updated API CRUD and SQL SELECT related functions. They can now handle full text searching! --- app/db_sql.py | 32 ++++++++++++++++++++++++++++++++ app/routers/api_crud.py | 39 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/app/db_sql.py b/app/db_sql.py index 4bb374d..d51dc3e 100644 --- a/app/db_sql.py +++ b/app/db_sql.py @@ -541,6 +541,8 @@ def sql_select( field_value = None, enabled: str|None = None, # enabled, disabled, all hidden: str|None = None, # hidden, not_hidden, all + fulltext_qry_field_li: list|None = None, # ['field_name_1', 'field_name_2'] + fulltext_qry_str: str|None = None, # 'search string' order_by_li: dict|None = None, # {"the_field_name": "DESC"} limit: int = 9999999, offset: int = 0, @@ -581,6 +583,32 @@ def sql_select( sql_order_by = '' log.debug(sql_order_by) + # NOTE: Version 1 of the fulltext search + # NOTE: This version works fine, but can only do one MATCH AGAINST at a time. - STI 2023-11-29 + # sql_fulltext_match_against = '' + # log.debug(fulltext_qry_field_li) + # if fulltext_qry_field_li and isinstance(fulltext_qry_field_li, list) and fulltext_qry_str: # fulltext_qry_field_li should be a list + # fulltext_qry_field_string = ', '.join(fulltext_qry_field_li) + # sql_fulltext_match_against = f'AND MATCH( {fulltext_qry_field_string} ) AGAINST( :fulltext_qry_str IN BOOLEAN MODE )' + # else: + # sql_fulltext_match_against = '' + # log.debug(sql_fulltext_match_against) + + # NOTE: Version 2 of the fulltext search + # NOTE: This version works well and can do multiple MATCH AGAINST at a time. - STI 2023-11-29 + sql_fulltext_match_against = '' + log.debug(fulltext_qry_field_li) + if fulltext_qry_field_li and isinstance(fulltext_qry_field_li, list) and fulltext_qry_str: # fulltext_qry_field_li should be a list + log.info('Creating partial SQL string for fulltext search.') + fulltext_qry_field_li_str = [] + for value in fulltext_qry_field_li: + log.debug(value) + fulltext_qry_field_li_str.append(f'MATCH( {value} ) AGAINST( :fulltext_qry_str IN BOOLEAN MODE )') + fulltext_qry_field_string = ' OR '.join(fulltext_qry_field_li_str) + + sql_fulltext_match_against = f'AND ({fulltext_qry_field_string})' + log.debug(sql_fulltext_match_against) + log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL @@ -670,6 +698,9 @@ def sql_select( data = {} data[field_name] = field_value + if sql_fulltext_match_against: + data['fulltext_qry_str'] = fulltext_qry_str + if enabled: sql_enabled, data['enabled'] = sql_enable_part(table_name=table_name, enabled=enabled) # Reasonably safe return str else: @@ -697,6 +728,7 @@ def sql_select( SELECT * FROM `{table_name}` WHERE `{table_name}`.{field_name} = :{field_name} + {sql_fulltext_match_against} {sql_enabled} {sql_hidden} {sql_order_by} diff --git a/app/routers/api_crud.py b/app/routers/api_crud.py index 15aa2e4..5439e4d 100644 --- a/app/routers/api_crud.py +++ b/app/routers/api_crud.py @@ -82,7 +82,7 @@ obj_type_li['cont_edu_cert'] = {'table_name': 'v_cont_edu_cert', 'tbl_name_updat obj_type_li['cont_edu_cert_person'] = {'table_name': 'v_cont_edu_cert_person', 'tbl_name_update': 'cont_edu_cert_person', 'base_name': Cont_Edu_Cert_Person_Base} obj_type_li['event'] = {'table_name': 'v_event', 'table_name_alt': 'v_event_w_file_count', 'tbl_name_update': 'event', 'base_name': Event_Base, 'base_name_alt': Event_Meeting_Flat_Base} obj_type_li['event_abstract'] = {'table_name': 'v_event_abstract', 'tbl_name_update': 'event_abstract', 'base_name': Event_Abstract_In} -obj_type_li['event_badge'] = {'table_name': 'event_badge', 'tbl_name_update': 'event_badge', 'base_name': Event_Badge_Base} +obj_type_li['event_badge'] = {'table_name': 'event_badge', 'table_name_alt': 'v_event_badge', 'tbl_name_update': 'event_badge', 'base_name': Event_Badge_Base} #obj_type_li['event_badge_log'] = {'table_name': 'event_badge_log', 'tbl_name_update': 'event_badge_log', 'base_name': Event_Badge_Log_Base} #obj_type_li['event_badge_template'] = {'table_name': 'event_badge_template', 'tbl_name_update': 'event_badge_template', 'base_name': Event_Badge_Template_Base} #obj_type_li['event_device'] = {'table_name': 'event_device', 'tbl_name_update': 'event_device', 'base_name': Event_Device_Base} @@ -176,6 +176,9 @@ async def get_obj_li( use_alt_table: bool = False, # NOTE: This will use table_name_alt if they exist. -2023-11-17 use_alt_base: bool = False, # NOTE: This will use base_name_alt if they exist. -2023-11-17 + fulltext_qry_field_li: str = Header(None), # Json formatted string list of fields to search. It is not ideal that this is in the header. Need a better option, but this is currently a GET request. + fulltext_qry_str: str = Query(None, max_length=150), + hidden: str = 'not_hidden', # hidden, not_hidden, all, # order_by_li: dict = None, order_by_li: str = Header(None), # Json formatted string in a key value format. It is not ideal that this is in the header. Need a better option, but this is currently a GET request. @@ -194,6 +197,9 @@ async def get_obj_li( log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) + if fulltext_qry_field_li: + fulltext_qry_field_li = json.loads(fulltext_qry_field_li) + if order_by_li: order_by_li = json.loads(order_by_li) @@ -204,6 +210,11 @@ async def get_obj_li( #debug_data['obj_id'] = obj_id debug_data['for_obj_type'] = for_obj_type debug_data['for_obj_id'] = for_obj_id + debug_data['use_alt_table'] = use_alt_table + debug_data['use_alt_base'] = use_alt_base + debug_data['fulltext_qry_field_li'] = fulltext_qry_field_li + debug_data['fulltext_qry_str'] = fulltext_qry_str + debug_data['hidden'] = hidden debug_data['order_by_li'] = order_by_li log.debug(debug_data) @@ -243,11 +254,33 @@ async def get_obj_li( field_name = f'{for_obj_type}_id' # NOTE: The enabled and hidden parameters are new to this endpoint and the sql_select function! -2023-07-06 - sql_result = sql_select(table_name=table_name, field_name=field_name, field_value=for_obj_id, enabled=commons.enabled, hidden=hidden, order_by_li=order_by_li, limit=commons.limit, offset=commons.offset, as_list=True) + sql_result = sql_select( + table_name = table_name, + field_name = field_name, + field_value = for_obj_id, + enabled = commons.enabled, + hidden = hidden, + fulltext_qry_field_li = fulltext_qry_field_li, + fulltext_qry_str = fulltext_qry_str, + order_by_li = order_by_li, + limit = commons.limit, + offset = commons.offset, + as_list = True + ) else: # NOTE: The enabled and hidden parameters are new to this endpoint and the sql_select function! -2023-07-06 # NOTE: This call (without field_name, field_value, limit, offset) may need more testing. - sql_result = sql_select(table_name=table_name, enabled=commons.enabled, hidden=hidden, order_by_li=order_by_li, limit=commons.limit, offset=commons.offset, as_list=True) + sql_result = sql_select( + table_name = table_name, + enabled = commons.enabled, + hidden = hidden, + fulltext_qry_field_li = fulltext_qry_field_li, + fulltext_qry_str = fulltext_qry_str, + order_by_li = order_by_li, + limit = commons.limit, + offset = commons.offset, + as_list = True + ) # log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(sql_result)