
    #j1                     x   d Z ddlZddlZddlmZ ddlmZmZmZm	Z	 ddl
mZ ddlmZ ddlmZmZmZ ddlmZ dd	lmZmZ dd
lmZ ddZ e             ej        Zej        ZdedefdZdefdZddZ dedededz  ddfdZ!dededz  ddfdZ"ddZ# ej$                    r e              dS  e#             dS )u   
Alembic environment for Hindsight.

Supports two dialects:

* PostgreSQL (sync psycopg2 driver) — default; uses ``search_path`` for
  multi-tenant schema isolation and forces read-write transactions to work
  around Supabase's read-only-by-default sessions.
* Oracle 23ai (``oracledb`` driver) — uses ``CURRENT_SCHEMA`` for tenant
  isolation; no equivalent of ``search_path`` or read-only session quirks.

Each migration file dispatches its DDL through ``alembic._dialect.run_for_dialect``
so a single revision tree serves both backends.
    N)Path)	parse_qsl	urlencodeurlsplit
urlunsplit)context)load_dotenv)
Connectionengine_from_configpool)Engine)is_oracle_urlto_libpq_url)Basereturnc                      t          j        d          rdS t          t                    j        j        j        } | dz  }|                                rt          |           dS dS )zELoad environment variables from .env (skipped if already configured).HINDSIGHT_API_DATABASE_URLNz.env)osgetenvr   __file__parentexistsr	   )root_direnv_files     a/home/rurouni/.hermes/hermes-agent/venv/lib/python3.11/site-packages/hindsight_api/alembic/env.pyload_envr      sh    	y-.. H~~$+2H& H H     urlc                    t          |           }|j                            d          s| S |j        dk    rdn|j        }|j                            d          }|j        }|j        }|rKd|vrGd|vrCd t          |d          D             }|                    d	|f           t          |          }d
}t          ||j
        |||j        f          S )u;  Coerce an Oracle URL into the SQLAlchemy form the oracledb dialect expects.

    Two issues to handle:

    1. Force the ``oracle+oracledb`` driver — bare ``oracle://`` defaults to
       cx_Oracle.
    2. Map a path-style service to ``?service_name=...``. SQLAlchemy's oracledb
       dialect treats the URL path as a *SID* (legacy), but Oracle Free /
       Autonomous DB only register a service name. Without this rewrite we get
       ``DPY-6003: SID "FREEPDB1" is not registered`` even though the listener
       is happy to accept the same name as a service.
    oraclezoracle+oracledb/zservice_name=zsid=c                     g | ]	\  }}||f
S  r#   ).0kvs      r   
<listcomp>z)_normalize_oracle_url.<locals>.<listcomp>I   s     RRRTQ1a&RRRr   T)keep_blank_valuesservice_name )r   scheme
startswithpathlstripqueryr   appendr   r   netlocfragment)r   parts
new_schemeservice	new_querynew_pathparamss          r   _normalize_oracle_urlr9   0   s     SMME<""8,, 
&+lh&>&>""ELJj$$GIzH  ?)33i8O8ORRYyD%Q%Q%QRRR~w/000f%%	z5<9enUVVVr   c                     t                               d          } | s%t          j        d          } | st	          d          t          |           rt          |           } nt          |           } t                               d|            | S )zNResolve the migration URL from Alembic config or env, normalizing per-dialect.zsqlalchemy.urlr   zuDatabase URL not found. Set HINDSIGHT_API_DATABASE_URL environment variable or pass database_url to run_migrations().)	configget_main_optionr   r   
ValueErrorr   r9   r   set_main_optiondatabase_urls    r   get_database_urlrA   Q   s    ))*:;;L y!=>> 	p  
 \"" 2,\:: $L11
+\:::r   c                     t          j        d           t                      } t          j        | t
          dddi           t          j                    5  t          j                     d d d            d S # 1 swxY w Y   d S )Nzrunning offlineT
paramstylenamed)r   target_metadataliteral_bindsdialect_opts)logginginforA   r   	configurerE   begin_transactionrun_migrationsr?   s    r   run_migrations_offlinerM   g   s    L"####%%L'"G,	    
	"	$	$ ! !   ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !s   A66A:=A:engine
connectiontarget_schemac                 J   ddl m}m} |                    | d          fd            }|                     |d                     rD|                     |d d                     |                     |d d	                     |                                 d
S )zFPG-only: ensure the session is RW (Supabase) and bind ``search_path``.r   )eventtextconnectc                     |                                  }|                    d           r2|                    d d           |                    d d           |                                 d S )N5SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITECREATE SCHEMA IF NOT EXISTS ""SET search_path TO "	", public)cursorexecuteclose)dbapi_connectionconnection_recordr[   rP   s      r   set_read_write_modez2_configure_pg_session.<locals>.set_read_write_modez   s}    !((**NOOO 	LNNK=KKKLLLNNJ-JJJKKKr   rV   rW   rX   rY   rZ   N)
sqlalchemyrR   rS   listens_forr\   commit)rN   rO   rP   rR   rS   r`   s     `   r   _configure_pg_sessionrd   v   s    &&&&&&&&
vy))    *) ttSTTUUU R44 P P P PQQRRR44 O} O O OPPQQQr   c                     ddl m} |                      |d                     |r$|                      |d| d                     dS dS )zEOracle: switch the session's default schema; tolerate DDL contention.r   )rS   z'ALTER SESSION SET DDL_LOCK_TIMEOUT = 30z$ALTER SESSION SET CURRENT_SCHEMA = "rX   N)ra   rS   r\   )rO   rP   rS   s      r   _configure_oracle_sessionrf      sz     ttEFFGGG Z44 W} W W WXXYYYYYZ Zr   c                     t                      } t                              d          }t          |           }t	          t                              t          j        i           dt          j                  }|	                                5 }|rt          ||           nt          |||           |t          d}|r|s||d<   t          j        di | t          j                    5  t          j                     d d d            n# 1 swxY w Y   |                                 d d d            d S # 1 swxY w Y   d S )NrP   zsqlalchemy.)prefix	poolclass)rO   rE   version_table_schemar#   )rA   r;   r<   r   r   get_sectionconfig_ini_sectionr   NullPoolrT   rf   rd   rE   r   rJ   rK   rL   rc   )r@   rP   	is_oracleconnectablerO   context_optss         r   run_migrations_onlinerq      s   #%%L**?;;Ml++I$64b99-  K 
				 * 	J%j-@@@@!+z=III %.
 
  	A 	A 4AL/0))L)))&(( 	% 	%"$$$	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	% 	5                 s7   AD3'D;D3D	D3D	D33D7:D7)r   N)%__doc__rH   r   pathlibr   urllib.parser   r   r   r   alembicr   dotenvr	   ra   r
   r   r   sqlalchemy.enginer   hindsight_api.db_urlr   r   hindsight_api.modelsr   r   r;   metadatarE   strr9   rA   rM   rd   rf   rq   is_offline_moder#   r   r   <module>r}      s     				       C C C C C C C C C C C C             ; ; ; ; ; ; ; ; ; ; $ $ $ $ $ $ < < < < < < < < % % % % % %	 	 	 	 	


	-Ws Ws W W W WB#    ,! ! ! !& j QTW[Q[ `d    (Z* ZS4Z ZTX Z Z Z Z% % % %P 7 r   