
    sU%h3                     L    d dl Z d dlmZ d dlmZmZmZmZmZm	Z	  G d d      Z
y)    N)asynccontextmanager)ListDictAnyTupleOptionalUnionc                      e Zd ZdefdZed        Zd Zdedeeef   de	fdZ
ded	eeef   dee   fd
Z	 ddedeeef   deeeef      de	fdZ	 	 	 ddedeeeef      dee   dee   dee   f
dZdedeeef   deeef   de	fdZdedeeef   de	fdZdedeeef   de	fdZddedeeeef      defdZddededee   fdZy)DatabaseManagerdb_namec                     || _         y N)r   )selfr   s     MC:\Users\james\Desktop\root\other\Misc\Work\ledger\server\database\handler.py__init__zDatabaseManager.__init__   s	        c                T  K   t        j                  | j                        4 d{   }t         j                  |_        	 | |j                          d{    ddd      d{    y7 H7 # |j                          d{  7   w xY w7 '# 1 d{  7  sw Y   yxY ww)z/Async context manager for database connections.N)	aiosqliteconnectr   Rowrow_factorycloser   conns     r   get_connectionzDatabaseManager.get_connection	   s      $$T\\2 	# 	#d(}}D#
jjl""	# 	# 	#
 #djjl""	# 	# 	# 	#sz   $B(A/B(BA3BA1BB()B*B(1B3BB

BBB(B%BB%!B(c                   K   | j                         4 d{   }|j                  d       d{    |j                  d       d{    |j                  d       d{    |j                  d       d{    |j                          d{    ddd      d{    y7 7 z7 c7 L7 57 7 # 1 d{  7  sw Y   yxY ww)z7Create database and initial tables if they don't exist.Nan  
                CREATE TABLE IF NOT EXISTS visitors (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    ip TEXT DEFAULT NULL,
                    phrase TEXT DEFAULT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            a]  
                CREATE TABLE IF NOT EXISTS api_keys (
                    key_id INTEGER PRIMARY KEY AUTOINCREMENT,
                    ip TEXT NOT NULL,
                    api_key VARCHAR(64) UNIQUE,
                    active BOOLEAN DEFAULT TRUE,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                )
            z
                CREATE TABLE IF NOT EXISTS config (
                    id INTEGER PRIMARY KEY CHECK (id = 1),
                    enabled INTEGER DEFAULT TRUE
                )
            z
                INSERT OR IGNORE INTO config (rowid, enabled) 
                SELECT 1, 1 WHERE NOT EXISTS (SELECT 1 FROM config)
            )r   executecommitr   s     r   initialize_databasez#DatabaseManager.initialize_database   s     &&( 	  	 D,,      ,,      ,,      ,,      ++-;	  	  	   ;	  	  	  	 s   CB)CB7B+B7	B-
B7"B/#B7;B1<B7B3B7C#B5$C+B7-B7/B71B73B75C7C	=C >C	C
table_namecolumnsreturnc           
        K   	 | j                         4 d{   }dj                  |j                         D cg c]  \  }}| d|  c}}      }d| d| d}|j                  |       d{    |j	                          d{    	 ddd      d{    y7 c c}}w 7 67  7 # 1 d{  7  sw Y   yxY w# t
        j                  $ r}t        d|        Y d}~y	d}~ww xY ww)
z*Create a new table with specified columns.N,  zCREATE TABLE IF NOT EXISTS  ()TzError creating table: F)r   joinitemsr   r   r   Errorprint)	r   r    r!   r   coldtypecolumns_defqueryes	            r   create_tablezDatabaseManager.create_table4   s     		**,  "iiGMMO(\jc5C5%)9(\]5j\K=PQRll5)))kkm##  (\)#	     	*1#./	s   C1C B C B.B"%B.1B(2B.	B*
B.C B,C C1 C "B.*B.,C .C 4B75C <C ?C1 C C.C)$C1)C..C1search_valuec                   K   	 | j                         4 d{   }|j                  d| d       d{   }|2 cg c3 d{   }|d   7 67 7 6 nc c}w }}|j                          d{  7   |sg cddd      d{  7   S t        |t              r(|D cg c]  }| d	 nc c}w }}|gt        |      z  }	n1|D cg c]  }| d	 nc c}w }}|D 
cg c]  }
d| d
 nc c}
w }	}
dj                  |      }d	| d
| }|j                  ||	       d{  7  }|2 cg c3 d{  7  }t        |      6 nc c}w }}|j                          d{  7   |cddd      d{  7   S # 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d|        g cY d}~S d}~ww xY ww)a/  
        Search all columns in a table for a given value (string or int).
        
        Args:
            table_name: The table to search
            search_value: The value to look for in any column

        Returns:
            List of rows (as dicts) where the value appears in any column
        NzPRAGMA table_info(r'       = ?z LIKE ?%z OR SELECT * FROM  WHERE zError searching table: )r   r   r   
isinstanceintlenr(   dictr   r*   r+   )r   r    r2   r   cursorrowr!   r,   
conditionsparams_where_clauser/   rowsr0   s                  r   search_tablezDatabaseManager.search_tableA   s    	**,  #||.@A,NOO39::C3q6O::::lln$$   lC0:A!B3SE,!B!BJ!B*^c'l:F=D!EcSE/!E!EJ!E;BCa,q1CCFC%{{:6(GL>J#||E6:::39::CS	:::lln$$+    .  	+A3/0I	sH  GF AF E<AE<A AAAAF E<AAE<1A42E<:F B	F GE<!B.-E<	CE<!C/.6E<$D'%	E<.E0E4D75E9EE<"E%#E<)F 5E86F ;G<FFF
F GF F>$F93F>4G9F>>GNdata	conditionc                   K   	 | j                         4 d{   }|r(dj                  |j                         D cg c]  }| d	 c}      }t        |j	                               }d| d| }|j                  ||       d{   }	|	j                          d{   }
|
d   dkD  }|rdj                  |j                         D cg c]  }| d	 c}      }t        |j	                               |z   }d	| d
| d| }|j                  ||       d{    |j                          d{    	 ddd      d{    ydj                  |j                               }dj                  |D cg c]  }d c}      }t        |j	                               }d| d| d| d}|j                  ||       d{    |j                          d{    	 ddd      d{    y7 c c}w 7 q7 \c c}w 7 7 7 c c}w 7 L7 67 '# 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d|        Y d}~yd}~ww xY ww)a  
        Universal insert/update function. If the record matching the condition exists,
        it will be updated; otherwise, a new record will be inserted.
        
        Args:
            table_name: The table to operate on
            data: The data to insert or update
            condition: Key-value pairs to identify existing records. 
                      If None, will always insert.
        
        Returns:
            bool: Success or failure
        N AND r5   SELECT COUNT(*) as count FROM r8   countr   r$   UPDATE  SET T?zINSERT INTO r&   z
) VALUES (r'   zError in upsert operation: F)r   r(   keystuplevaluesr   fetchoner   r   r*   r+   )r   r    rE   rF   r   krB   where_valuesr/   r=   resultrecord_existsr,   
set_clauseupdate_valuesr!   rA   placeholdersrP   r0   s                       r   upsertzDatabaseManager.upserth   s*    	**,  #*<<Y^^EU0VA3d0V#WL#()9)9);#<L<ZLP\~^E#'<<|#DDF#)??#44F$*7Oa$7M$%)YY		/T3%t/T%U
(-dkkm(<|(K")*U:,gl^ \"ll5-@@@"kkm++#!  $ ))DIIK0#yyt)<!#)<=t{{}-&zl"WIZ~UVWll5&111kkm##1  0V E4 0U A+& *= 2#/   4  	/s34	s4  IH( G/H( !HG2
	=HG7HG:+H
G=
AHHH1H2H7H( HH( I.H6	H
?AH HHHHH( )H*H( .I/H( 2H:H=HHH( HHH( H%HH%!H( $I%H( (I;I	IIIorder_bylimitc                   K   	 | j                         4 d{   }d| }d}|rQdj                  |j                         D cg c]  }| d	 c}      }	t        |j	                               }|d|	 z  }|r|d| z  }|r|d| z  }|j                  ||       d{   }
|
2 cg c3 d{   }t        |      7 c c}w 7 &7 6 nc c}w }}|
j                          d{  7   |cddd      d{  7   S # 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d	|        g cY d}~S d}~ww xY ww)
a  
        Retrieve rows from the specified table based on conditions.
        
        Args:
            table_name: The table to query
            condition: Key-value pairs for WHERE clause
            order_by: Optional ORDER BY clause (e.g., "id DESC")
            limit: Optional limit for number of returned rows
            
        Returns:
            List of dictionaries representing rows
        Nr7    rH   r5   r8   z
 ORDER BY z LIMIT zError retrieving rows: )r   r(   rN   rO   rP   r   r<   r   r   r*   r+   )r   r    rF   rZ   r[   r   r/   r@   rR   rB   r=   r>   rC   r0   s                 r   get_rowszDatabaseManager.get_rows   sC     	**,  (5#*<<Y^^EU0VA3d0V#WL"9#3#3#56Fw|n55Ez(44Ewug..E#||E6::39::CS	!
 1W ;::::lln$$%    (  	+A3/0I	s   ED C D 'DC
AD C!D)C+C/C	0C3C D D	CCD'C*(D.D :C=;D  EDD
DD ED E)D>8E9E>EEc                   K   	 | j                         4 d{   }dj                  |j                         D cg c]  }| d	 c}      }dj                  |j                         D cg c]  }| d	 c}      }t        |j	                               t        |j	                               z   }	d| d| d| }
|j                  |
|	       d{    |j                          d{    	 ddd      d{    y7 c c}w c c}w 7 :7 $7 # 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d	|        Y d}~y
d}~ww xY ww)a6  
        Update rows in the specified table based on condition.
        
        Args:
            table_name: The table to update
            data: Key-value pairs of fields to update
            condition: Key-value pairs for WHERE clause
            
        Returns:
            Success or failure
        Nr$   r5   rH   rK   rL   r8   TzError updating rows: F
r   r(   rN   rO   rP   r   r   r   r*   r+   )r   r    rE   rF   r   r,   rV   rR   rB   rP   r/   r0   s               r   update_rowszDatabaseManager.update_rows   s+    	**, 	 	!YY		'L3%t'LM
&||AQ,RAs$Z,RSt{{}-i6F6F6H0II!*U:,gl^Tll5&111kkm##	 	 	'L,R
 2#	 	 	 	  	)!-.	s   ED& C?D& DD
$D*D
6ADDD(D)D.D& 9D:D& >E?D& DDD& D#DD#D& "E#D& &E9EEEEc                   K   	 | j                         4 d{   }dj                  |j                         D cg c]  }| d	 c}      }t        |j	                               }d| d| }|j                  ||       d{    |j                          d{    	 ddd      d{    y7 c c}w 7 57 7 # 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d|        Y d}~yd}~ww xY ww)	a  
        Delete rows from the specified table based on condition.
        
        Args:
            table_name: The table to delete from
            condition: Key-value pairs for WHERE clause
            
        Returns:
            Success or failure
        NrH   r5   zDELETE FROM r8   TzError deleting rows: Fr`   )	r   r    rF   r   rR   rB   r@   r/   r0   s	            r   delete_rowszDatabaseManager.delete_rows   s     	**,  &||AQ,RAs$Z,RSy//12&zl',Hll5&111kkm##  ,R 2#     	)!-.	s   DC B2C B?B4
=B?B9B?B;B?!C ,B=-C 1D2C 4B?;B?=C ?CCCC DC C?'C:5D:C??Dc                 J  K   	 | j                         4 d{   }dj                  |j                         D cg c]  }| d	 c}      }t        |j	                               }d| d| }|j                  ||       d{   }|j                          d{   }	|j                          d{    |	d   dkD  cddd      d{    S 7 c c}w 7 T7 >7 (7 # 1 d{  7  sw Y   yxY w# t        j                  $ r}
t        d|
        Y d}
~
y	d}
~
ww xY ww)
a	  
        Check if a record exists based on condition.
        
        Args:
            table_name: The table to check
            condition: Key-value pairs for WHERE clause
            
        Returns:
            True if record exists, False otherwise
        NrH   r5   rI   r8   rJ   r   zError checking existence: Fr   r(   rN   rO   rP   r   rQ   r   r   r*   r+   )r   r    rF   r   rR   rB   r@   r/   r=   rT   r0   s              r   existszDatabaseManager.exists   s    	**, 	+ 	+&||AQ,RAs$Z,RSy//128GL>Z#||E6::%00lln$$g*	+ 	+ 	+,R ;0$	+ 	+ 	+ 	+  	.qc23	s   D#C5 CC5 C C
=C CC CC 3C4C ?C5 CC5 D#C5 C C C C5  C2&C)'C2.C5 1D#2C5 5D DD#D  D#c                 V  K   	 | j                         4 d{   }d| }d}|rQdj                  |j                         D cg c]  }| d	 c}      }t        |j	                               }|d| z  }|j                  ||       d{   }|j                          d{   }	|j                          d{    |	d   cddd      d{    S 7 c c}w 7 Q7 ;7 %7 # 1 d{  7  sw Y   yxY w# t        j                  $ r}
t        d|
        Y d}
~
y	d}
~
ww xY ww)
z
        Count records based on condition.
        
        Args:
            table_name: The table to count from
            condition: Key-value pairs for WHERE clause
            
        Returns:
            Number of matching records
        NrI   r]   rH   r5   r8   rJ   zError counting records: r   re   )r   r    rF   r   r/   r@   rR   rB   r=   rT   r0   s              r   rJ   zDatabaseManager.count  s    	**, ' '8E#*<<Y^^EU0VA3d0V#WL"9#3#3#56Fw|n55E#||E6::%00lln$$g' ' '
 1W ;0$' ' ' '  	,QC01	s   D)C; CC; 'C&C
=C&CC&$C %C&<C"=C&C; C$C; D)C; C& C&"C&$C; &C8,C/-C84C; 7D)8C; ;D&D!D)!D&&D)r/   r@   c                 b  K   	 | j                         4 d{   }|j                  ||       d{   }|j                         j                         j	                  d      r|2 cg c3 d{   }t        |      |j                          d{    g cddd      d{    S 7 7 y7 ?6 nc c}w }}|j                          d{  7   |cddd      d{  7   S 7 S7 C# 1 d{  7  sw Y   yxY w# t        j                  $ r}t        d|        g cY d}~S d}~ww xY ww)z
        Execute a custom query with parameters.
        
        Args:
            query: SQL query to execute
            params: Parameters for the query
            
        Returns:
            Results of the query
        NSELECTzError executing query: )r   r   stripupper
startswithr<   r   r   r   r*   r+   )r   r/   r@   r   r=   r>   rC   r0   s           r   execute_queryzDatabaseManager.execute_query/  s    	**, 	 	#||E6::;;=&&(33H=7=>>DI ++-''	 	 	: ?>>D> ,,.((	 	 	 (	 	 	 	  	+A3/0I	s  D/C? B*C? C*B,5C*(B2*B0.B./B02B2?C*C&C*C? $C(%C? )D/*C? ,C*.B00B21C*CC*C? C" C? %D/&C*(C? *C<0C31C<8C? ;D/<C? ?D,D'!D,"D/'D,,D/r   )NNN)r]   )__name__
__module____qualname__strr   r   r   r   r   boolr1   r	   r:   r   rD   r   r   rY   r^   ra   rc   rf   rJ   r   rm   r]   r   r   r   r      s     # # BS 4S> d %S %c3h %TXY]T^ %P ;?,s ,$sCx. ,'S#X7,CG,^ =A04-1' '!)$sCx.!9' (' &c]' 7;4j'RC tCH~ $(cN7;:C DcN t 2s tCH~ $ 6c htCH~6N Z] > e T$Z r   r   )r   
contextlibr   typingr   r   r   r   r   r	   r   r]   r   r   <module>ru      s     * : :C Cr   