4242COMPETENCY_USER = os .environ .get ('COMPETENCY_USER' )
4343COMPETENCY_HOST = os .environ .get ('COMPETENCY_HOST' , 'localhost:5432' )
4444
45+ COMPETENCY_SCHEMA_VERSION_KEY = 'schema_version'
46+ COMPETENCY_SCHEMA_STATE_KEY = 'competency-schema-version'
47+ COMPETENCY_SCHEMA_VERSION = '1.1'
48+
4549if not COMPETENCY_USER :
4650 print ('Competency queries are unavailable because COMPETENCY_USER is not set' )
4751
52+ #===============================================================================
53+
54+ async def table_exists (connection : asyncpg .Connection , table_name : str ) -> bool :
55+ #===========================================================================
56+ reg_class = await connection .fetchval ('SELECT to_regclass($1)' , table_name )
57+ return reg_class is not None
58+
59+ async def schema_version (connection : asyncpg .Connection ) -> str | None :
60+ #===================================================================
61+ if not await table_exists (connection , 'metadata' ):
62+ return None
63+ row = await connection .fetchrow (
64+ 'SELECT value FROM metadata WHERE name=$1' ,
65+ COMPETENCY_SCHEMA_VERSION_KEY ,
66+ )
67+ return row [0 ] if row is not None else None
68+
69+ def schema_mismatch_error (expected : str , actual : str | None , query_id : str | None = None ) -> str :
70+ #=============================================================================
71+ found = actual if actual is not None else 'missing metadata/schema_version'
72+ query = f' (query { query_id } )' if query_id is not None else ''
73+ return (
74+ f'Competency schema version mismatch{ query } : '
75+ f'expected `{ expected } ` but found `{ found } `. '
76+ 'Some queries may fail until the database schema and query definitions are aligned.'
77+ )
78+
4879#===============================================================================
4980#===============================================================================
5081
@@ -76,6 +107,8 @@ async def competency_connection_context(app: Litestar) -> AsyncGenerator[None, N
76107 timeout = 5
77108 )
78109 app .state ['competency-pool' ] = competency_pool
110+ async with competency_pool .acquire () as connection :
111+ app .state [COMPETENCY_SCHEMA_STATE_KEY ] = await schema_version (connection )
79112 except Exception as err :
80113 # log (where?)
81114 print (f'Unable to connect to competency database: { COMPETENCY_HOST } /{ COMPETENCY_DATABASE } ' )
@@ -91,6 +124,23 @@ def get_competency_pool(app: Litestar) -> Optional[asyncpg.Pool]:
91124#================================================================
92125 return getattr (app .state , 'competency-pool' , None )
93126
127+ def get_competency_schema_version (app : Litestar ) -> str | None :
128+ #==============================================================
129+ return getattr (app .state , COMPETENCY_SCHEMA_STATE_KEY , None )
130+
131+ async def get_competency_schema_info (app : Litestar ) -> dict [str , str | None ]:
132+ #======================================================================
133+ if (get_competency_pool (app )) is None :
134+ return {
135+ 'version' : None ,
136+ 'expected' : COMPETENCY_SCHEMA_VERSION ,
137+ 'error' : 'Backend cannot connect to Competency database' ,
138+ }
139+ return {
140+ 'version' : get_competency_schema_version (app ),
141+ 'expected' : COMPETENCY_SCHEMA_VERSION ,
142+ }
143+
94144#===============================================================================
95145#===============================================================================
96146
@@ -118,6 +168,7 @@ async def query(data: QueryRequest, request: Request) -> QueryResults|QueryError
118168 return {'error' : f'Error building query: { err } ' }
119169 if (pool := get_competency_pool (request .app )) is None :
120170 return {'error' : 'Backend cannot connect to Competency database' }
171+ db_schema = get_competency_schema_version (request .app )
121172 try :
122173 async with pool .acquire () as connection :
123174 records = await connection .fetch (sql , * params )
@@ -133,6 +184,9 @@ async def query(data: QueryRequest, request: Request) -> QueryResults|QueryError
133184 }
134185 }
135186 except Exception as err :
136- return {'error' : f'Error executing query: { err } ' }
187+ error_msg = f'Error executing query: { err } .'
188+ if db_schema != COMPETENCY_SCHEMA_VERSION :
189+ error_msg += f' { schema_mismatch_error (COMPETENCY_SCHEMA_VERSION , db_schema , data ["query_id" ])} '
190+ return {'error' : error_msg }
137191
138192#===============================================================================
0 commit comments