This commit is contained in:
Pongsatorn 2025-08-29 00:57:32 +07:00
parent 85b49ddf0f
commit 39394caa8e
3 changed files with 249 additions and 15 deletions

View file

@ -80,37 +80,50 @@ class DatabaseManager:
try:
cur = self.connection.cursor()
# Build the UPDATE query dynamically
# Build the INSERT and UPDATE query dynamically
insert_placeholders = []
insert_values = [key_value] # Start with key_value
set_clauses = []
values = []
update_values = []
for field, value in fields.items():
if value == "NOW()":
# Special handling for NOW()
insert_placeholders.append("NOW()")
set_clauses.append(f"{field} = NOW()")
else:
insert_placeholders.append("%s")
insert_values.append(value)
set_clauses.append(f"{field} = %s")
values.append(value)
update_values.append(value)
# Add schema prefix if table doesn't already have it
full_table_name = table if '.' in table else f"gas_station_1.{table}"
# Build the complete query
query = f"""
INSERT INTO {full_table_name} ({key_field}, {', '.join(fields.keys())})
VALUES (%s, {', '.join(['%s'] * len(fields))})
VALUES (%s, {', '.join(insert_placeholders)})
ON CONFLICT ({key_field})
DO UPDATE SET {', '.join(set_clauses)}
"""
# Add key_value to the beginning of values list
all_values = [key_value] + list(fields.values()) + values
# Combine values for the query: insert_values + update_values
all_values = insert_values + update_values
logger.debug(f"SQL Query: {query}")
logger.debug(f"Values: {all_values}")
cur.execute(query, all_values)
self.connection.commit()
cur.close()
logger.info(f"Updated {table} for {key_field}={key_value}")
logger.info(f"Updated {table} for {key_field}={key_value} with fields: {fields}")
return True
except Exception as e:
logger.error(f"Failed to execute update on {table}: {e}")
logger.error(f"❌ Failed to execute update on {table}: {e}")
logger.debug(f"Query: {query if 'query' in locals() else 'Query not built'}")
logger.debug(f"Values: {all_values if 'all_values' in locals() else 'Values not prepared'}")
if self.connection:
self.connection.rollback()
return False

View file

@ -453,6 +453,7 @@ def execute_postgresql_update_combined(node, action, detection_result, branch_re
key_value = key_value_template.format(**action_context)
logger.info(f"Executing database update: table={table}, {key_field}={key_value}")
logger.debug(f"Available branch results: {list(branch_results.keys())}")
# Process field mappings
mapped_fields = {}
@ -461,26 +462,38 @@ def execute_postgresql_update_combined(node, action, detection_result, branch_re
mapped_value = resolve_field_mapping(value_template, branch_results, action_context)
if mapped_value is not None:
mapped_fields[db_field] = mapped_value
logger.debug(f"Mapped field: {db_field} = {mapped_value}")
logger.info(f"Mapped field: {db_field} = {mapped_value}")
else:
logger.warning(f"Could not resolve field mapping for {db_field}: {value_template}")
logger.debug(f"Available branch results: {branch_results}")
except Exception as e:
logger.error(f"Error mapping field {db_field} with template '{value_template}': {e}")
import traceback
logger.debug(f"Field mapping error traceback: {traceback.format_exc()}")
if not mapped_fields:
logger.warning("No fields mapped successfully, skipping database update")
logger.debug(f"Branch results available: {branch_results}")
logger.debug(f"Field templates: {fields}")
return
# Add updated_at field automatically
mapped_fields["updated_at"] = "NOW()"
# Execute the database update
logger.info(f"Attempting database update with fields: {mapped_fields}")
success = node["db_manager"].execute_update(table, key_field, key_value, mapped_fields)
if success:
logger.info(f"Successfully updated database: {table} with {len(mapped_fields)} fields")
logger.info(f"✅ Successfully updated database: {table} with {len(mapped_fields)} fields")
logger.info(f"Updated fields: {mapped_fields}")
else:
logger.error(f"Failed to update database: {table}")
logger.error(f"❌ Failed to update database: {table}")
logger.error(f"Attempted update with: {key_field}={key_value}, fields={mapped_fields}")
except KeyError as e:
logger.error(f"Missing required field in postgresql_update_combined action: {e}")
logger.debug(f"Action config: {action}")
except Exception as e:
logger.error(f"Error in postgresql_update_combined action: {e}")
import traceback
@ -489,28 +502,68 @@ def execute_postgresql_update_combined(node, action, detection_result, branch_re
def resolve_field_mapping(value_template, branch_results, action_context):
"""Resolve field mapping templates like {car_brand_cls_v1.brand}."""
try:
logger.debug(f"Resolving field mapping: '{value_template}'")
logger.debug(f"Available branch results: {list(branch_results.keys())}")
# Handle simple context variables first (non-branch references)
if not '.' in value_template:
return value_template.format(**action_context)
result = value_template.format(**action_context)
logger.debug(f"Simple template resolved: '{value_template}' -> '{result}'")
return result
# Handle branch result references like {model_id.field}
import re
branch_refs = re.findall(r'\{([^}]+\.[^}]+)\}', value_template)
logger.debug(f"Found branch references: {branch_refs}")
resolved_template = value_template
for ref in branch_refs:
try:
model_id, field_name = ref.split('.', 1)
logger.debug(f"Processing branch reference: model_id='{model_id}', field_name='{field_name}'")
if model_id in branch_results:
branch_data = branch_results[model_id]
logger.debug(f"Branch '{model_id}' data: {branch_data}")
if field_name in branch_data:
field_value = branch_data[field_name]
resolved_template = resolved_template.replace(f'{{{ref}}}', str(field_value))
logger.debug(f"Resolved {ref} to {field_value}")
logger.info(f"Resolved {ref} to '{field_value}'")
else:
logger.warning(f"Field '{field_name}' not found in branch '{model_id}' results. Available fields: {list(branch_data.keys())}")
return None
logger.warning(f"Field '{field_name}' not found in branch '{model_id}' results.")
logger.debug(f"Available fields in '{model_id}': {list(branch_data.keys())}")
# Try alternative field names based on the class result and model type
if isinstance(branch_data, dict):
fallback_value = None
# First, try the exact field name
if field_name in branch_data:
fallback_value = branch_data[field_name]
# Then try 'class' field as fallback
elif 'class' in branch_data:
fallback_value = branch_data['class']
logger.info(f"Using 'class' field as fallback for '{field_name}': '{fallback_value}'")
# For brand models, also check if the class name exists as a key
elif field_name == 'brand' and branch_data.get('class') in branch_data:
fallback_value = branch_data[branch_data['class']]
logger.info(f"Found brand value using class name as key: '{fallback_value}'")
# For body_type models, also check if the class name exists as a key
elif field_name == 'body_type' and branch_data.get('class') in branch_data:
fallback_value = branch_data[branch_data['class']]
logger.info(f"Found body_type value using class name as key: '{fallback_value}'")
if fallback_value is not None:
resolved_template = resolved_template.replace(f'{{{ref}}}', str(fallback_value))
logger.info(f"✅ Resolved {ref} to '{fallback_value}' (using fallback)")
else:
logger.error(f"No suitable field found for '{field_name}' in branch '{model_id}'")
logger.debug(f"Branch data structure: {branch_data}")
return None
else:
logger.error(f"Branch data for '{model_id}' is not a dictionary: {type(branch_data)}")
return None
else:
logger.warning(f"Branch '{model_id}' not found in results. Available branches: {list(branch_results.keys())}")
return None
@ -521,6 +574,7 @@ def resolve_field_mapping(value_template, branch_results, action_context):
# Format any remaining simple variables
try:
final_value = resolved_template.format(**action_context)
logger.debug(f"Final resolved value: '{final_value}'")
return final_value
except KeyError as e:
logger.warning(f"Could not resolve context variable in template: {e}")
@ -528,6 +582,8 @@ def resolve_field_mapping(value_template, branch_results, action_context):
except Exception as e:
logger.error(f"Error resolving field mapping '{value_template}': {e}")
import traceback
logger.debug(f"Field mapping error traceback: {traceback.format_exc()}")
return None
def run_detection_with_tracking(frame, node, context=None):
@ -1720,6 +1776,12 @@ def run_pipeline(frame, node: dict, return_bbox: bool=False, context=None):
if result:
branch_results[br["modelId"]] = result
logger.info(f"Branch {br['modelId']} completed: {result}")
# Collect nested branch results if they exist
if "branch_results" in result:
for nested_id, nested_result in result["branch_results"].items():
branch_results[nested_id] = nested_result
logger.info(f"Collected nested branch result: {nested_id} = {nested_result}")
except Exception as e:
logger.error(f"Branch {br['modelId']} failed: {e}")
else:
@ -1760,6 +1822,12 @@ def run_pipeline(frame, node: dict, return_bbox: bool=False, context=None):
if result:
branch_results[br["modelId"]] = result
logger.info(f"Branch {br['modelId']} completed: {result}")
# Collect nested branch results if they exist
if "branch_results" in result:
for nested_id, nested_result in result["branch_results"].items():
branch_results[nested_id] = nested_result
logger.info(f"Collected nested branch result: {nested_id} = {nested_result}")
else:
logger.warning(f"Branch {br['modelId']} returned no result")
except Exception as e: