From d6134e799efc4f1a883e5097d3c251f1600905c6 Mon Sep 17 00:00:00 2001 From: Scott Idem Date: Tue, 27 Jan 2026 10:49:02 -0500 Subject: [PATCH] Refactor Event models to use Vision ID string pattern Updated Event_Presentation_Base, Event_Location_Base, and Event_Abstract_Base (and Base_New/In) to use standardized string IDs mapped from random IDs via root_validator. Removed legacy integer ID fields and validators to ensure API responses comply with the V3 Vision standard. --- app/models/event_abstract_models.py | 270 ++++++++---------------- app/models/event_location_models.py | 65 +++--- app/models/event_presentation_models.py | 90 ++++---- 3 files changed, 157 insertions(+), 268 deletions(-) diff --git a/app/models/event_abstract_models.py b/app/models/event_abstract_models.py index 147851d..6d20f66 100644 --- a/app/models/event_abstract_models.py +++ b/app/models/event_abstract_models.py @@ -1,7 +1,7 @@ import datetime, pytz from typing import Dict, List, Optional, Set, Union -from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator +from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from app.db_sql import redis_lookup_id_random from app.lib_general import log, logging @@ -23,31 +23,18 @@ class Event_Abstract_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - id_random: Optional[str] = Field( - # **base_fields['event_abstract_id_random'], - alias = 'event_abstract_id_random', - ) - id: Optional[int] = Field( - alias = 'event_abstract_id' - ) + # --- Standardized Vision IDs (Strings) --- + id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) + event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) + + event_id: Optional[str] = Field(None, **base_fields['event_id_random']) + event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random']) + event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) + event_presenter_id: Optional[str] = Field(None, **base_fields['event_presenter_id_random']) + event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random']) + grant_id: Optional[str] = Field(None, **base_fields['grant_id_random']) - event_id_random: Optional[str] - event_id: Optional[int] - - event_person_id_random: Optional[str] # This is the primary person/submitter - event_person_id: Optional[int] - - event_presentation_id_random: Optional[str] - event_presentation_id: Optional[int] - - event_presenter_id_random: Optional[str] - event_presenter_id: Optional[int] - - event_session_id_random: Optional[str] - event_session_id: Optional[int] - - # event_track_id_random: Optional[str] - # event_track_id: Optional[int] + # event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random']) # poc_event_person_id_random: Optional[str] # Maybe change this to primary_event_person? # poc_event_person_id: Optional[int] # Maybe change this to primary_event_person? @@ -55,9 +42,6 @@ class Event_Abstract_Base(BaseModel): external_id: Optional[str] code: Optional[str] - grant_id_random: Optional[str] - grant_id: Optional[int] - grant_code: Optional[str] # grant_type_code: Optional[str] # grant_json: Optional[Union[Json, None]] @@ -101,67 +85,40 @@ class Event_Abstract_Base(BaseModel): _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) - @validator('id', always=True) - def event_abstract_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_abstract') - return None - - @validator('event_id', always=True) - def event_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event') - return None - - @validator('event_person_id', always=True) - def event_person_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_person_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') - return None - - @validator('event_presentation_id', always=True) - def event_presentation_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_presentation_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation') - return None - - @validator('event_presenter_id', always=True) - def event_presenter_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_presenter_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_presenter') - return None - - @validator('event_session_id', always=True) - def event_session_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_session_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_session') - return None - - @validator('grant_id', always=True) - def grant_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('grant_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='grant') - return None - - # @validator('poc_event_person_id', always=True) - # def poc_event_person_id_lookup(cls, v, values, **kwargs): - # log.setLevel(logging.WARNING) - # log.debug(locals()) - - # if values['poc_event_person_id_random']: - # return redis_lookup_id_random(record_id_random=values['poc_event_person_id_random'], table_name='poc_event_person') - # return None + @root_validator(pre=True) + def map_v3_ids(cls, values): + """ + Vision Transformer: + Map DB keys to clean API keys and strip internal integers. + """ + # 1. Map Random Strings to Clean Names + if rid := values.get('id_random') or values.get('event_abstract_id_random'): + values['id'] = rid + values['event_abstract_id'] = rid + + if e_rid := values.get('event_id_random'): + values['event_id'] = e_rid + if ep_rid := values.get('event_person_id_random'): + values['event_person_id'] = ep_rid + if epr_rid := values.get('event_presentation_id_random'): + values['event_presentation_id'] = epr_rid + if eps_rid := values.get('event_presenter_id_random'): + values['event_presenter_id'] = eps_rid + if es_rid := values.get('event_session_id_random'): + values['event_session_id'] = es_rid + if g_rid := values.get('grant_id_random'): + values['grant_id'] = g_rid + + # 2. Prevent "Collision Population" + for k in ['id', 'event_abstract_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']: + if k in values and not isinstance(values[k], str) and values[k] is not None: + del values[k] + + return values class Config: underscore_attrs_are_private = True - allow_population_by_field_name = True + allow_population_by_field_name = False fields = base_fields # ### END ### API Event Abstract Models ### Event_Abstract_Base() ### @@ -175,24 +132,16 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - id_random: Optional[str] = Field( - alias = 'event_abstract_id_random', - ) - - event_id_random: Optional[str] - event_id: Optional[int] - - event_person_id: Optional[int] - - event_session_id: Optional[int] - - event_person_id_random: Optional[str] - - event_presentation_id_random: Optional[str] - - event_presenter_id_random: Optional[str] - - event_session_id_random: Optional[str] + # --- Standardized Vision IDs (Strings) --- + id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) + event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) + + event_id: Optional[str] = Field(None, **base_fields['event_id_random']) + event_person_id: Optional[str] = Field(None, **base_fields['event_person_id_random']) + event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) + event_presenter_id: Optional[str] = Field(None, **base_fields['event_presenter_id_random']) + event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random']) + grant_id: Optional[str] = Field(None, **base_fields['grant_id_random']) # event_track_id_random: Optional[str] @@ -209,9 +158,6 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base): passcode: Optional[str] - grant_id_random: Optional[str] - grant_id: Optional[int] - grant_code: Optional[str] grant_type_code: Optional[str] grant_json: Optional[Union[Json, None]] @@ -224,23 +170,40 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base): submitter_json: Optional[Union[Json, None]] coauthors_json: Optional[Union[Json, None]] - @validator('event_person_id', always=True) - def event_person_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_person_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') - return None - - # @validator('event_session_id', always=True) - # def event_session_id_lookup(cls, v, values, **kwargs): - # if isinstance(v, int) and v > 0: return v - # elif id_random := values.get('event_session_id_random'): - # return redis_lookup_id_random(record_id_random=id_random, table_name='event_session') - # return None + @root_validator(pre=True) + def map_v3_ids(cls, values): + """ + Vision Transformer: + Map DB keys to clean API keys and strip internal integers. + """ + # 1. Map Random Strings to Clean Names + if rid := values.get('id_random') or values.get('event_abstract_id_random'): + values['id'] = rid + values['event_abstract_id'] = rid + + if e_rid := values.get('event_id_random'): + values['event_id'] = e_rid + if ep_rid := values.get('event_person_id_random'): + values['event_person_id'] = ep_rid + if epr_rid := values.get('event_presentation_id_random'): + values['event_presentation_id'] = epr_rid + if eps_rid := values.get('event_presenter_id_random'): + values['event_presenter_id'] = eps_rid + if es_rid := values.get('event_session_id_random'): + values['event_session_id'] = es_rid + if g_rid := values.get('grant_id_random'): + values['grant_id'] = g_rid + + # 2. Prevent "Collision Population" + for k in ['id', 'event_abstract_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']: + if k in values and not isinstance(values[k], str) and values[k] is not None: + del values[k] + + return values class Config: underscore_attrs_are_private = True - allow_population_by_field_name = True + allow_population_by_field_name = False fields = base_fields # ### END ### API Event Abstract Models ### Event_Abstract_Base() ### @@ -250,68 +213,11 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base): class Event_Abstract_In(Event_Abstract_Base_New): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) + + # Inherits everything from Event_Abstract_Base_New including the Vision ID pattern. + # We do NOT redefine 'id' as int here. - id: Optional[int] = Field( - alias = 'event_abstract_id' - ) - - event_id: Optional[int] - - event_person_id: Optional[int] - - # event_session_id: Optional[int] - - # grant_json: Optional[Union[str, None]] - - - @validator('id', always=True) - def event_abstract_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_abstract') - return None - - @validator('event_id', always=True) - def event_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event') - return None - - @validator('event_person_id', always=True) - def event_person_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_person_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') - return None - - # @validator('event_presentation_id', always=True) - # def event_presentation_id_lookup(cls, v, values, **kwargs): - # if isinstance(v, int) and v > 0: return v - # elif id_random := values.get('event_presentation_id_random'): - # return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation') - # return None - - # @validator('event_presenter_id', always=True) - # def event_presenter_id_lookup(cls, v, values, **kwargs): - # if isinstance(v, int) and v > 0: return v - # elif id_random := values.get('event_presenter_id_random'): - # return redis_lookup_id_random(record_id_random=id_random, table_name='event_presenter') - # return None - - # @validator('event_session_id', always=True) - # def event_session_id_lookup(cls, v, values, **kwargs): - # if isinstance(v, int) and v > 0: return v - # elif id_random := values.get('event_session_id_random'): - # return redis_lookup_id_random(record_id_random=id_random, table_name='event_session') - # return None - - @validator('grant_id', always=True) - def grant_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('grant_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='grant') - return None + pass # ### END ### API Event Abstract Models ### Event_Abstract_In() ### diff --git a/app/models/event_location_models.py b/app/models/event_location_models.py index 5f829a1..b45c193 100644 --- a/app/models/event_location_models.py +++ b/app/models/event_location_models.py @@ -1,7 +1,7 @@ import datetime, pytz from typing import Dict, List, Optional, Set, Union -from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator +from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from app.db_sql import redis_lookup_id_random from app.lib_general import log, logging @@ -15,13 +15,12 @@ class Event_Location_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - id_random: Optional[str] = Field( - # **base_fields['event_location_id_random'], - alias = 'event_location_id_random', - ) - id: Optional[int] = Field( - alias = 'event_location_id' - ) + # --- Standardized Vision IDs (Strings) --- + id: Optional[str] = Field(None, **base_fields['event_location_id_random']) + event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random']) + + event_id: Optional[str] = Field(None, **base_fields['event_id_random']) + event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random']) code: Optional[str] = Field( # alias = 'event_location_code' @@ -31,12 +30,6 @@ class Event_Location_Base(BaseModel): # alias = 'event_location_external_id' ) - event_id_random: Optional[str] - event_id: Optional[int] - - event_track_id_random: Optional[str] # Can a track be assigned to one location? - event_track_id: Optional[int] # Can a track be assigned to one location? - lu_location_type_id: Optional[int] location_type_code: Optional[str] location_type: Optional[str] @@ -104,29 +97,31 @@ class Event_Location_Base(BaseModel): _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) - @validator('id', always=True) - def event_location_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_location') - return None - - @validator('event_id', always=True) - def event_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event') - return None - - @validator('event_track_id', always=True) - def event_track_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_track_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_track') - return None + @root_validator(pre=True) + def map_v3_ids(cls, values): + """ + Vision Transformer: + Map DB keys to clean API keys and strip internal integers. + """ + # 1. Map Random Strings to Clean Names + if rid := values.get('id_random') or values.get('event_location_id_random'): + values['id'] = rid + values['event_location_id'] = rid + + if e_rid := values.get('event_id_random'): + values['event_id'] = e_rid + if et_rid := values.get('event_track_id_random'): + values['event_track_id'] = et_rid + + # 2. Prevent "Collision Population" + for k in ['id', 'event_location_id', 'event_id', 'event_track_id']: + if k in values and not isinstance(values[k], str) and values[k] is not None: + del values[k] + + return values class Config: underscore_attrs_are_private = True - allow_population_by_field_name = True + allow_population_by_field_name = False fields = base_fields # ### END ### API Event Location Models ### Event_Location_Base() ### diff --git a/app/models/event_presentation_models.py b/app/models/event_presentation_models.py index 9ba3f0d..83d3239 100644 --- a/app/models/event_presentation_models.py +++ b/app/models/event_presentation_models.py @@ -1,7 +1,7 @@ import datetime, pytz from typing import Dict, List, Optional, Set, Union -from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator +from pydantic import BaseModel, EmailStr, Field, Json, PrivateAttr, ValidationError, validator, root_validator from app.db_sql import redis_lookup_id_random from app.lib_general import log, logging @@ -18,13 +18,15 @@ class Event_Presentation_Base(BaseModel): log.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL log.debug(locals()) - id_random: Optional[str] = Field( - # **base_fields['event_presentation_id_random'], - alias = 'event_presentation_id_random', - ) - id: Optional[int] = Field( - alias = 'event_presentation_id' - ) + # --- Standardized Vision IDs (Strings) --- + id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) + event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random']) + + event_id: Optional[str] = Field(None, **base_fields['event_id_random']) + event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random']) + event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random']) + event_session_id: Optional[str] = Field(None, **base_fields['event_session_id_random']) + event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random']) external_id: Optional[str] = Field( # alias = 'event_presentation_external_id' @@ -32,21 +34,6 @@ class Event_Presentation_Base(BaseModel): code: Optional[str] - event_id_random: Optional[str] - event_id: Optional[int] - - event_abstract_id_random: Optional[str] - event_abstract_id: Optional[int] - - event_location_id_random: Optional[str] - event_location_id: Optional[int] - - event_session_id_random: Optional[str] - event_session_id: Optional[int] - - event_track_id_random: Optional[str] - event_track_id: Optional[int] - poc_event_person: Optional[Event_Person_Base] poc_person: Optional[Person_Base] @@ -111,36 +98,37 @@ class Event_Presentation_Base(BaseModel): _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now) - @validator('id', always=True) - def event_presentation_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation') - return None - - @validator('event_id', always=True) - def event_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event') - return None - - @validator('event_abstract_id', always=True) - def event_abstract_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_abstract_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_abstract') - return None - - @validator('event_session_id', always=True) - def event_session_id_lookup(cls, v, values, **kwargs): - if isinstance(v, int) and v > 0: return v - elif id_random := values.get('event_session_id_random'): - return redis_lookup_id_random(record_id_random=id_random, table_name='event_session') - return None + @root_validator(pre=True) + def map_v3_ids(cls, values): + """ + Vision Transformer: + Map DB keys to clean API keys and strip internal integers. + """ + # 1. Map Random Strings to Clean Names + if rid := values.get('id_random') or values.get('event_presentation_id_random'): + values['id'] = rid + values['event_presentation_id'] = rid + + if e_rid := values.get('event_id_random'): + values['event_id'] = e_rid + if ea_rid := values.get('event_abstract_id_random'): + values['event_abstract_id'] = ea_rid + if el_rid := values.get('event_location_id_random'): + values['event_location_id'] = el_rid + if es_rid := values.get('event_session_id_random'): + values['event_session_id'] = es_rid + if et_rid := values.get('event_track_id_random'): + values['event_track_id'] = et_rid + + # 2. Prevent "Collision Population" + for k in ['id', 'event_presentation_id', 'event_id', 'event_abstract_id', 'event_location_id', 'event_session_id', 'event_track_id']: + if k in values and not isinstance(values[k], str) and values[k] is not None: + del values[k] + + return values class Config: underscore_attrs_are_private = True - allow_population_by_field_name = True + allow_population_by_field_name = False fields = base_fields # ### END ### API Event Presentation Models ### Event_Presentation_Base() ###