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.
This commit is contained in:
Scott Idem
2026-01-27 10:49:02 -05:00
parent 48e0a31cf5
commit d6134e799e
3 changed files with 157 additions and 268 deletions

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union 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.db_sql import redis_lookup_id_random
from app.lib_general import log, logging 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.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_abstract_id_random'], id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
alias = 'event_abstract_id_random', event_abstract_id: Optional[str] = Field(None, **base_fields['event_abstract_id_random'])
)
id: Optional[int] = Field(
alias = 'event_abstract_id'
)
event_id_random: Optional[str] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_id: Optional[int] 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_person_id_random: Optional[str] # This is the primary person/submitter # event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
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]
# poc_event_person_id_random: Optional[str] # Maybe change this to primary_event_person? # 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? # 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] external_id: Optional[str]
code: Optional[str] code: Optional[str]
grant_id_random: Optional[str]
grant_id: Optional[int]
grant_code: Optional[str] grant_code: Optional[str]
# grant_type_code: Optional[str] # grant_type_code: Optional[str]
# grant_json: Optional[Union[Json, None]] # 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) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True) @root_validator(pre=True)
def event_abstract_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_abstract') Map DB keys to clean API keys and strip internal integers.
return None """
# 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
@validator('event_id', always=True) if e_rid := values.get('event_id_random'):
def event_id_lookup(cls, v, values, **kwargs): values['event_id'] = e_rid
if isinstance(v, int) and v > 0: return v if ep_rid := values.get('event_person_id_random'):
elif id_random := values.get('event_id_random'): values['event_person_id'] = ep_rid
return redis_lookup_id_random(record_id_random=id_random, table_name='event') if epr_rid := values.get('event_presentation_id_random'):
return None 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
@validator('event_person_id', always=True) # 2. Prevent "Collision Population"
def event_person_id_lookup(cls, v, values, **kwargs): for k in ['id', 'event_abstract_id', 'event_id', 'event_person_id', 'event_presentation_id', 'event_presenter_id', 'event_session_id', 'grant_id']:
if isinstance(v, int) and v > 0: return v if k in values and not isinstance(values[k], str) and values[k] is not None:
elif id_random := values.get('event_person_id_random'): del values[k]
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person')
return None
@validator('event_presentation_id', always=True) return values
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
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Abstract Models ### Event_Abstract_Base() ### # ### 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.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
alias = 'event_abstract_id_random', 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_random: Optional[str] event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
event_id: Optional[int] 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_person_id: Optional[int] 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'])
event_session_id: Optional[int] grant_id: Optional[str] = Field(None, **base_fields['grant_id_random'])
event_person_id_random: Optional[str]
event_presentation_id_random: Optional[str]
event_presenter_id_random: Optional[str]
event_session_id_random: Optional[str]
# event_track_id_random: Optional[str] # event_track_id_random: Optional[str]
@@ -209,9 +158,6 @@ class Event_Abstract_Base_New(Core_Std_Obj_Base):
passcode: Optional[str] passcode: Optional[str]
grant_id_random: Optional[str]
grant_id: Optional[int]
grant_code: Optional[str] grant_code: Optional[str]
grant_type_code: Optional[str] grant_type_code: Optional[str]
grant_json: Optional[Union[Json, None]] 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]] submitter_json: Optional[Union[Json, None]]
coauthors_json: Optional[Union[Json, None]] coauthors_json: Optional[Union[Json, None]]
@validator('event_person_id', always=True) @root_validator(pre=True)
def event_person_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('event_person_id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_person') Map DB keys to clean API keys and strip internal integers.
return None """
# 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
# @validator('event_session_id', always=True) if e_rid := values.get('event_id_random'):
# def event_session_id_lookup(cls, v, values, **kwargs): values['event_id'] = e_rid
# if isinstance(v, int) and v > 0: return v if ep_rid := values.get('event_person_id_random'):
# elif id_random := values.get('event_session_id_random'): values['event_person_id'] = ep_rid
# return redis_lookup_id_random(record_id_random=id_random, table_name='event_session') if epr_rid := values.get('event_presentation_id_random'):
# return None 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: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Abstract Models ### Event_Abstract_Base() ### # ### END ### API Event Abstract Models ### Event_Abstract_Base() ###
@@ -251,67 +214,10 @@ class Event_Abstract_In(Event_Abstract_Base_New):
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())
id: Optional[int] = Field( # Inherits everything from Event_Abstract_Base_New including the Vision ID pattern.
alias = 'event_abstract_id' # We do NOT redefine 'id' as int here.
)
event_id: Optional[int] pass
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
# ### END ### API Event Abstract Models ### Event_Abstract_In() ### # ### END ### API Event Abstract Models ### Event_Abstract_In() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union 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.db_sql import redis_lookup_id_random
from app.lib_general import log, logging 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.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_location_id_random'], id: Optional[str] = Field(None, **base_fields['event_location_id_random'])
alias = 'event_location_id_random', event_location_id: Optional[str] = Field(None, **base_fields['event_location_id_random'])
)
id: Optional[int] = Field( event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
alias = 'event_location_id' event_track_id: Optional[str] = Field(None, **base_fields['event_track_id_random'])
)
code: Optional[str] = Field( code: Optional[str] = Field(
# alias = 'event_location_code' # alias = 'event_location_code'
@@ -31,12 +30,6 @@ class Event_Location_Base(BaseModel):
# alias = 'event_location_external_id' # 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] lu_location_type_id: Optional[int]
location_type_code: Optional[str] location_type_code: Optional[str]
location_type: 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) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True) @root_validator(pre=True)
def event_location_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_location') Map DB keys to clean API keys and strip internal integers.
return None """
# 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
@validator('event_id', always=True) if e_rid := values.get('event_id_random'):
def event_id_lookup(cls, v, values, **kwargs): values['event_id'] = e_rid
if isinstance(v, int) and v > 0: return v if et_rid := values.get('event_track_id_random'):
elif id_random := values.get('event_id_random'): values['event_track_id'] = et_rid
return redis_lookup_id_random(record_id_random=id_random, table_name='event')
return None
@validator('event_track_id', always=True) # 2. Prevent "Collision Population"
def event_track_id_lookup(cls, v, values, **kwargs): for k in ['id', 'event_location_id', 'event_id', 'event_track_id']:
if isinstance(v, int) and v > 0: return v if k in values and not isinstance(values[k], str) and values[k] is not None:
elif id_random := values.get('event_track_id_random'): del values[k]
return redis_lookup_id_random(record_id_random=id_random, table_name='event_track')
return None return values
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Location Models ### Event_Location_Base() ### # ### END ### API Event Location Models ### Event_Location_Base() ###

View File

@@ -1,7 +1,7 @@
import datetime, pytz import datetime, pytz
from typing import Dict, List, Optional, Set, Union 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.db_sql import redis_lookup_id_random
from app.lib_general import log, logging 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.setLevel(logging.WARNING) # DEBUG, INFO, WARNING, ERROR, EXCEPTION, CRITICAL
log.debug(locals()) log.debug(locals())
id_random: Optional[str] = Field( # --- Standardized Vision IDs (Strings) ---
# **base_fields['event_presentation_id_random'], id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
alias = 'event_presentation_id_random', event_presentation_id: Optional[str] = Field(None, **base_fields['event_presentation_id_random'])
)
id: Optional[int] = Field( event_id: Optional[str] = Field(None, **base_fields['event_id_random'])
alias = 'event_presentation_id' 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( external_id: Optional[str] = Field(
# alias = 'event_presentation_external_id' # alias = 'event_presentation_external_id'
@@ -32,21 +34,6 @@ class Event_Presentation_Base(BaseModel):
code: Optional[str] 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_event_person: Optional[Event_Person_Base]
poc_person: Optional[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) _processed_at: datetime.datetime = PrivateAttr(default_factory=datetime.datetime.now)
@validator('id', always=True) @root_validator(pre=True)
def event_presentation_id_lookup(cls, v, values, **kwargs): def map_v3_ids(cls, values):
if isinstance(v, int) and v > 0: return v """
elif id_random := values.get('id_random'): Vision Transformer:
return redis_lookup_id_random(record_id_random=id_random, table_name='event_presentation') Map DB keys to clean API keys and strip internal integers.
return None """
# 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
@validator('event_id', always=True) if e_rid := values.get('event_id_random'):
def event_id_lookup(cls, v, values, **kwargs): values['event_id'] = e_rid
if isinstance(v, int) and v > 0: return v if ea_rid := values.get('event_abstract_id_random'):
elif id_random := values.get('event_id_random'): values['event_abstract_id'] = ea_rid
return redis_lookup_id_random(record_id_random=id_random, table_name='event') if el_rid := values.get('event_location_id_random'):
return None 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
@validator('event_abstract_id', always=True) # 2. Prevent "Collision Population"
def event_abstract_id_lookup(cls, v, values, **kwargs): for k in ['id', 'event_presentation_id', 'event_id', 'event_abstract_id', 'event_location_id', 'event_session_id', 'event_track_id']:
if isinstance(v, int) and v > 0: return v if k in values and not isinstance(values[k], str) and values[k] is not None:
elif id_random := values.get('event_abstract_id_random'): del values[k]
return redis_lookup_id_random(record_id_random=id_random, table_name='event_abstract')
return None
@validator('event_session_id', always=True) return values
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
class Config: class Config:
underscore_attrs_are_private = True underscore_attrs_are_private = True
allow_population_by_field_name = True allow_population_by_field_name = False
fields = base_fields fields = base_fields
# ### END ### API Event Presentation Models ### Event_Presentation_Base() ### # ### END ### API Event Presentation Models ### Event_Presentation_Base() ###