
    i                     $   d dl Z d dlZd dlZd dl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  e         ee      Z G d d      Z G d	 d
      Z e       ZddZd Zedk(  r[ ed       	 ej-                  d      Zer6ed    d   dk(  r+ ed        edej0                   dej2                          y ed       yy# e$ rKZ ed ee               ed        ed        ed        ed        ed        ed       Y dZ[ydZ[ww xY w)    N)contextmanager)ListDictAny)load_dotenv   )
get_loggerc                   :    e Zd ZdZd
dedefdZd Zd Zd Z	d Z
y	)ConnectionPoolzv
    Thread-safe connection pool for pyodbc.
    Reuses connections to avoid connect/teardown overhead per query.
    connection_string	pool_sizec                     || _         || _        t        j                  |      | _        t        j                         | _        d| _        y )N)maxsizer   )	r   r   queueQueue_pool	threadingLock_lock_created)selfr   r   s      A/var/www/html/userprofiledev.eatanceapp.com/core/db_connection.py__init__zConnectionPool.__init__   s6    !2""'++i"@
^^%
    c                 @    t        j                  | j                        S N)pyodbcconnectr   )r   s    r   _create_connectionz!ConnectionPool._create_connection   s    ~~d4455r   c                    d}	 |j                         }|j                  d       ||	 |j                          S S # t        $ r Y S w xY w# t        $ rW 	 |j                          n# t        $ r Y nw xY w| j	                         cY |!	 |j                          S # t        $ r Y S w xY wS w xY w# |!	 |j                          w # t        $ r Y w w xY ww xY w)z^Verify connection is alive; replace with new one if not. Cursor is closed to avoid idle state.NSELECT 1)cursorexecuteclose	Exceptionr   )r   conncurs      r   _check_connection_alivez&ConnectionPool._check_connection_alive   s    	++-CKK
# IIK  !   	-

 **,,IIK   	- IIK   s   "A
 ;	AA
	B*A%$B*%	A1.B*0A11B*B- B	B%$B%)B**B- -C1CC	CCCCc                 8   	 | j                   j                         }| j                  |      S # t        j                  $ r Y nw xY wd}| j
                  5  | j                  | j                  k  r| xj                  dz  c_        d}d d d        n# 1 sw Y   nxY w|rU	 | j                         S # t        $ r8 | j
                  5  | xj                  dz  c_        d d d         # 1 sw Y    xY ww xY w| j                   j                         }| j                  |      S )NFr   T)r   
get_nowaitr(   r   Emptyr   r   r   r   r%   get)r   r&   should_creates      r   get_connectionzConnectionPool.get_connection2   s    	::((*D//55{{ 		ZZ}}t~~-" $ ZZ ..00 ZZMMQ&M    
 zz~~++D11s?   *- AA1BBB- -C.C!	C.!C*	&C.c                    |y 	 | j                   j                  |       y # t        j                  $ rJ |j	                          | j
                  5  | xj                  dz  c_        d d d        Y y # 1 sw Y   Y y xY ww xY w)Nr   )r   
put_nowaitr   Fullr$   r   r   r   r&   s     r   return_connectionz ConnectionPool.return_connectionH   s\    <	#JJ!!$'zz 	#JJL" 	#s'   ! /A>A0&A>0A:	5A>:A>N)   )__name__
__module____qualname____doc__strintr   r   r(   r.   r3    r   r   r   r      s.    
# # 6(2,#r   r   c            
       b     e Zd ZdZdZ fdZd Zed        Zd
de	de
deee	ef      fd	Z xZS )DatabaseConnectoraD  
    Centralized MS SQL Database Connector with connection pooling.
    Uses pyodbc; connections are taken from and returned to a pool for reuse.

    Requires ``DB_USER`` and ``DB_PASSWORD`` (no defaults). Optional:
    ``DB_TRUST_SERVER_CERTIFICATE=true`` to set ``TrustServerCertificate=yes`` (dev/self-signed only).
    Nc                     | j                   )t        t        |   |       | _         d| j                   _        | j                   S )NF)	_instancesuperr=   __new___initialized)cls	__class__s    r   rA   zDatabaseConnector.__new__^   s7    == !"3SA#FCM).CMM&}}r   c                 F   | j                   ry t        j                  dd      | _        t        j                  dd      | _        t        j                  dd      | _        t        t        j                  dd            }t        j                  d	      }t        j                  d
      }|t        |      j                         st        d      |t        d      t        |      j                         | _
        || _        t        j                  dd      j                         j                         }|dv }d| j
                   d| j                   d| j                   d| j                   d| j                   d| _        t        | j                  |      | _        d| _         y )N	DB_SERVER	localhostDB_NAMEprofiling_db	DB_DRIVERz{ODBC Driver 18 for SQL Server}DB_POOL_SIZE7DB_USERDB_PASSWORDzeDB_USER must be set to a non-empty value (no default credentials). Set it in the environment or .env.zHDB_PASSWORD must be set (no default). Set it in the environment or .env.DB_TRUST_SERVER_CERTIFICATE )1trueyesonzDRIVER=z;SERVER=z
;DATABASE=z;UID=z;PWD=z;TrustServerCertificate=yes;)r   T)rB   osgetenvserverdatabasedriverr:   r9   strip
ValueErrorusernamepasswordlowerr   r   r   )r   r   raw_userraw_password	trust_raw
trust_certs         r   r   zDatabaseConnector.__init__d   su   ii[9		)^<ii-NO		.#67	99Y'yy/3x=#6#6#85  Z  H++-$II;R@FFHNNP	"<<
 dkk] #kk] # '==/ "==/ "*	+ 	 $D$:$:iP
 r   c              #   B  K   | j                   j                         }	 | 	 |j                          | j                   j	                  |       y # t        $ r Y 'w xY w# 	 |j                          n# t        $ r Y nw xY w| j                   j	                  |       w xY wwr   )r   r.   rollbackr%   r3   r2   s     r   r.   z DatabaseConnector.get_connection   s     zz((*	/J JJ((.   JJ((.s\   BA A B	ABABB A10B1	A=:B<A==BBqueryparamsreturnc           
         |j                         }|r#|j                  dd      d   j                         nd}t        j	                  d|t        |             | j                         5 }|j                         }	 |j                  ||       |j                  r|j                  D cg c]  }|d   	 }}g }	|j                         D ]&  }
|	j                  t        t        ||
                   ( t        j                  dt        |	             |	|j                          cddd       S |j!                          t        j	                  d       g |j                          cddd       S c c}w # |j                          w xY w# 1 sw Y   yxY w)zz
        Executes a query and returns results as a list of dictionaries.
        Uses a connection from the pool.
        Nr   r   ?z(SQL execute: statement=%s param_count=%szFetched %s rowsz;Query executed (no results returned), connection committed.)rZ   splitupperloggerdebuglenr.   r"   r#   descriptionfetchallappenddictzipinfor$   commit)r   re   rf   _q_stmtr&   r"   columncolumnsresultsrows              r   r#   zDatabaseConnector.execute   s@    [[]02q!!$**,?FT  "d[[]Fuf- %%7=7I7IJ7IVvay7IGJ G%0tC,='>?  1 KK 13w<@ # - #"$ KKMLL!^_- #" K - #"sC   (F:,E.&E)2AE.F)&E.F)E..F  FF)r;   )r5   r6   r7   r8   r?   rA   r   r   r.   r9   tupler   r   r   r#   __classcell__)rD   s   @r   r=   r=   S   sU     I$!L 	/ 	/ S  %  d38n9M  r   r=   c                  L   t         j                  d      } | r| d   j                  d      dk7  rt        d      ddlm} ddlm}  |       j                         5 }|j                   |d            j                         }d	d	d	       dk7  rt        d
      y	# 1 sw Y   xY w)z
    Ensures both the pyodbc pool (orchestrator / raw SQL) and the SQLAlchemy engine
    (profiling tables) can reach the database. Raises on failure so the process can exit
    during application startup.
    zSELECT 1 AS connectivity_checkr   connectivity_checkr   zGDatabase connectivity check failed (pyodbc): unexpected SELECT 1 result)text)
get_enginer!   NzKDatabase connectivity check failed (SQLAlchemy): unexpected SELECT 1 result)

db_sessionr#   r,   RuntimeError
sqlalchemyr   storage.db_repor   r   
scalar_one)rz   r   r   r&   ones        r   verify_database_connectivityr      s       !ABGgajnn%9:a?U
 	
  *				4ll4
+,779 
 
axY
 	
  
 	s   &BB#c                      t         S )z2Returns the centralized database session provider.)r   r;   r   r   get_db_sessionr      s    r   __main__z$Testing DB Connection (with pool)...zSELECT 1 AS testtestu   ✅ Connection Successful!zConnected to: z on u)   ❌ Connection failed (Unexpected result)u   ❌ Connection Error: z
Possible issues:z41. DB_USER and DB_PASSWORD must be set (no defaults)zL2. For dev/self-signed SQL: set DB_TRUST_SERVER_CERTIFICATE=true if requiredz%3. Check DB_SERVER, DB_NAME, and .envz&4. Ensure the ODBC Driver is installedz35. Verify network/firewall access to the SQL Server)rg   N)r   rU   r   r   
contextlibr   typingr   r   r   dotenvr   logger_configr	   r5   rl   r   r=   r   r   r   printr#   rz   rX   rW   r%   er9   r;   r   r   <module>r      s5    	   % " "  % 	H	B# B#Jc cN  

.
 z	
01E$$%78wqz&)Q../N:#6#6"7tJ<M<M;NOP=>   E&s1vh/0"#DE\]5667CDDEs    ,AB? 5B? ?DAD

D