sunholo 0.123.0__py3-none-any.whl → 0.123.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sunholo/database/alloydb_client.py +173 -119
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/METADATA +1 -1
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/RECORD +7 -7
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/WHEEL +0 -0
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/entry_points.txt +0 -0
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/licenses/LICENSE.txt +0 -0
- {sunholo-0.123.0.dist-info → sunholo-0.123.2.dist-info}/top_level.txt +0 -0
@@ -531,128 +531,182 @@ class AlloyDBClient:
|
|
531
531
|
|
532
532
|
return await self.engine._afetch(query=sql_statement)
|
533
533
|
|
534
|
-
async def
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
Args:
|
539
|
-
table_name (str): Name of the table to create
|
540
|
-
schema_data (dict): Data structure that matches the expected schema
|
541
|
-
users (list, optional): List of users to grant permissions to
|
534
|
+
async def check_connection(self):
|
535
|
+
"""
|
536
|
+
Checks if the database connection is still valid.
|
542
537
|
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
# For arrays, store as JSONB
|
554
|
-
columns.append(f'"{key}" JSONB')
|
555
|
-
elif isinstance(value, int):
|
556
|
-
columns.append(f'"{key}" INTEGER')
|
557
|
-
elif isinstance(value, float):
|
558
|
-
columns.append(f'"{key}" NUMERIC')
|
559
|
-
elif isinstance(value, bool):
|
560
|
-
columns.append(f'"{key}" BOOLEAN')
|
561
|
-
else:
|
562
|
-
# Default to TEXT for strings and other types
|
563
|
-
columns.append(f'"{key}" TEXT')
|
564
|
-
|
565
|
-
# Add metadata columns
|
566
|
-
columns.extend([
|
567
|
-
'"source" TEXT',
|
568
|
-
'"extraction_date" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP',
|
569
|
-
'"extraction_backend" TEXT',
|
570
|
-
'"extraction_model" TEXT'
|
571
|
-
])
|
572
|
-
|
573
|
-
# Create SQL statement for table creation
|
574
|
-
columns_sql = ", ".join(columns)
|
575
|
-
sql = f'''
|
576
|
-
CREATE TABLE IF NOT EXISTS "{table_name}" (
|
577
|
-
id SERIAL PRIMARY KEY,
|
578
|
-
{columns_sql}
|
579
|
-
)
|
580
|
-
'''
|
581
|
-
|
582
|
-
# Execute SQL to create table
|
583
|
-
result = await self.execute_sql_async(sql)
|
584
|
-
log.info(f"Created or ensured table {table_name} exists")
|
585
|
-
|
586
|
-
# Grant permissions if users are provided
|
587
|
-
if users:
|
588
|
-
for user in users:
|
589
|
-
await self.execute_sql_async(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";')
|
590
|
-
|
591
|
-
return result
|
538
|
+
Returns:
|
539
|
+
bool: True if connection is valid, False otherwise
|
540
|
+
"""
|
541
|
+
try:
|
542
|
+
# Simple query to check connection
|
543
|
+
result = await self.execute_sql_async("SELECT 1")
|
544
|
+
return True
|
545
|
+
except Exception as e:
|
546
|
+
log.warning(f"Database connection check failed: {e}")
|
547
|
+
return False
|
592
548
|
|
593
|
-
async def
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
Args:
|
598
|
-
table_name (str): Name of the table
|
599
|
-
data (dict): Data to write to the table
|
600
|
-
metadata (dict, optional): Additional metadata to include
|
549
|
+
async def ensure_connected(self):
|
550
|
+
"""
|
551
|
+
Ensures the database connection is valid, attempting to reconnect if necessary.
|
601
552
|
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
placeholders.append("%s")
|
623
|
-
|
624
|
-
# Create SQL statement for insertion
|
625
|
-
columns_str = ", ".join(columns)
|
626
|
-
placeholders_str = ", ".join(placeholders)
|
627
|
-
|
628
|
-
sql = f'''
|
629
|
-
INSERT INTO "{table_name}" ({columns_str})
|
630
|
-
VALUES ({placeholders_str})
|
631
|
-
RETURNING id
|
632
|
-
'''
|
633
|
-
|
634
|
-
# Execute SQL to insert data
|
635
|
-
result = await self.execute_sql_async(sql, values)
|
636
|
-
log.info(f"Inserted data into table {table_name}")
|
637
|
-
|
638
|
-
return result
|
553
|
+
Returns:
|
554
|
+
bool: True if connection is valid or reconnection successful, False otherwise
|
555
|
+
"""
|
556
|
+
if await self.check_connection():
|
557
|
+
return True
|
558
|
+
|
559
|
+
try:
|
560
|
+
# Attempt to reconnect - implementation depends on your database driver
|
561
|
+
if self.engine_type == "pg8000":
|
562
|
+
# Re-create the engine
|
563
|
+
self.engine = self._create_engine_from_pg8000(self.user, self.password, self.database)
|
564
|
+
elif self.engine_type == "langchain":
|
565
|
+
# Re-create the engine
|
566
|
+
self.engine = self._create_engine()
|
567
|
+
|
568
|
+
log.info(f"Successfully reconnected to AlloyDB")
|
569
|
+
return True
|
570
|
+
except Exception as e:
|
571
|
+
log.error(f"Failed to reconnect to AlloyDB: {e}")
|
572
|
+
return False
|
639
573
|
|
640
|
-
async def
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
|
645
|
-
|
646
|
-
|
574
|
+
async def close(self):
|
575
|
+
"""
|
576
|
+
Properly close the database connection.
|
577
|
+
"""
|
578
|
+
try:
|
579
|
+
if self.engine_type == "pg8000":
|
580
|
+
# Close engine or connector
|
581
|
+
if hasattr(self, 'connector'):
|
582
|
+
await self.connector.close()
|
583
|
+
# For langchain engine, additional cleanup might be needed
|
584
|
+
log.info("Closed AlloyDB connection")
|
585
|
+
except Exception as e:
|
586
|
+
log.warning(f"Error closing AlloyDB connection: {e}")
|
587
|
+
|
588
|
+
async def create_table_from_schema(self, table_name: str, schema_data: dict, users: list = None):
|
589
|
+
"""
|
590
|
+
Creates or ensures a table exists based on the structure of the provided schema data.
|
647
591
|
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
592
|
+
Args:
|
593
|
+
table_name (str): Name of the table to create
|
594
|
+
schema_data (dict): Data structure that matches the expected schema
|
595
|
+
users (list, optional): List of users to grant permissions to
|
596
|
+
|
597
|
+
Returns:
|
598
|
+
Result of SQL execution
|
599
|
+
"""
|
600
|
+
# Generate column definitions from schema data
|
601
|
+
columns = []
|
602
|
+
for key, value in schema_data.items():
|
603
|
+
if isinstance(value, dict):
|
604
|
+
# For nested objects, store as JSONB
|
605
|
+
columns.append(f'"{key}" JSONB')
|
606
|
+
elif isinstance(value, list):
|
607
|
+
# For arrays, store as JSONB
|
608
|
+
columns.append(f'"{key}" JSONB')
|
609
|
+
elif isinstance(value, int):
|
610
|
+
columns.append(f'"{key}" INTEGER')
|
611
|
+
elif isinstance(value, float):
|
612
|
+
columns.append(f'"{key}" NUMERIC')
|
613
|
+
elif isinstance(value, bool):
|
614
|
+
columns.append(f'"{key}" BOOLEAN')
|
615
|
+
else:
|
616
|
+
# Default to TEXT for strings and other types
|
617
|
+
columns.append(f'"{key}" TEXT')
|
618
|
+
|
619
|
+
# Add metadata columns
|
620
|
+
columns.extend([
|
621
|
+
'"source" TEXT',
|
622
|
+
'"extraction_date" TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP',
|
623
|
+
'"extraction_backend" TEXT',
|
624
|
+
'"extraction_model" TEXT'
|
625
|
+
])
|
626
|
+
|
627
|
+
# Create SQL statement for table creation
|
628
|
+
columns_sql = ", ".join(columns)
|
629
|
+
sql = f'''
|
630
|
+
CREATE TABLE IF NOT EXISTS "{table_name}" (
|
631
|
+
id SERIAL PRIMARY KEY,
|
632
|
+
{columns_sql}
|
633
|
+
)
|
634
|
+
'''
|
635
|
+
|
636
|
+
# Execute SQL to create table
|
637
|
+
result = await self.execute_sql_async(sql)
|
638
|
+
log.info(f"Created or ensured table {table_name} exists")
|
639
|
+
|
640
|
+
# Grant permissions if users are provided
|
641
|
+
if users:
|
642
|
+
for user in users:
|
643
|
+
await self.execute_sql_async(f'GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE "{table_name}" TO "{user}";')
|
644
|
+
|
645
|
+
return result
|
646
|
+
|
647
|
+
async def write_data_to_table(self, table_name: str, data: dict, metadata: dict = None):
|
648
|
+
"""
|
649
|
+
Writes data to the specified table.
|
650
|
+
|
651
|
+
Args:
|
652
|
+
table_name (str): Name of the table
|
653
|
+
data (dict): Data to write to the table
|
654
|
+
metadata (dict, optional): Additional metadata to include
|
655
|
+
|
656
|
+
Returns:
|
657
|
+
Result of SQL execution
|
658
|
+
"""
|
659
|
+
# Create copies to avoid modifying the original data
|
660
|
+
insert_data = dict(data)
|
661
|
+
|
662
|
+
# Add metadata if provided
|
663
|
+
if metadata:
|
664
|
+
insert_data["source"] = metadata.get("objectId", metadata.get("source", "unknown"))
|
665
|
+
insert_data["extraction_backend"] = metadata.get("extraction_backend", "unknown")
|
666
|
+
insert_data["extraction_model"] = metadata.get("extraction_model", "unknown")
|
667
|
+
|
668
|
+
# Prepare column names and placeholders for values
|
669
|
+
columns = [f'"{key}"' for key in insert_data.keys()]
|
670
|
+
placeholders = []
|
671
|
+
values = []
|
672
|
+
|
673
|
+
# Process values and create properly formatted placeholders
|
674
|
+
for key, value in insert_data.items():
|
675
|
+
values.append(json.dumps(value) if isinstance(value, (dict, list)) else value)
|
676
|
+
placeholders.append("%s")
|
677
|
+
|
678
|
+
# Create SQL statement for insertion
|
679
|
+
columns_str = ", ".join(columns)
|
680
|
+
placeholders_str = ", ".join(placeholders)
|
681
|
+
|
682
|
+
sql = f'''
|
683
|
+
INSERT INTO "{table_name}" ({columns_str})
|
684
|
+
VALUES ({placeholders_str})
|
685
|
+
RETURNING id
|
686
|
+
'''
|
687
|
+
|
688
|
+
# Execute SQL to insert data
|
689
|
+
result = await self.execute_sql_async(sql, values)
|
690
|
+
log.info(f"Inserted data into table {table_name}")
|
691
|
+
|
692
|
+
return result
|
693
|
+
|
694
|
+
async def execute_sql_async(self, sql_statement, values=None):
|
695
|
+
"""
|
696
|
+
Executes a given SQL statement asynchronously with optional parameter values.
|
697
|
+
|
698
|
+
Args:
|
699
|
+
sql_statement (str): The SQL statement to execute
|
700
|
+
values (list, optional): Values for parameterized query
|
701
|
+
|
702
|
+
Returns:
|
703
|
+
Result of SQL execution
|
704
|
+
"""
|
705
|
+
log.info(f"Executing async SQL statement: {sql_statement}")
|
706
|
+
if self.engine_type == "pg8000":
|
707
|
+
result = await self._execute_sql_async_pg8000(sql_statement, values)
|
708
|
+
elif self.engine_type == "langchain":
|
709
|
+
result = await self._execute_sql_async_langchain(sql_statement, values)
|
710
|
+
|
711
|
+
return result
|
658
712
|
|
@@ -60,7 +60,7 @@ sunholo/components/retriever.py,sha256=Wmchv3huAM4w7DIS-a5Lp9Hi7M8pE6vZdxgseiT9S
|
|
60
60
|
sunholo/components/vectorstore.py,sha256=k7GS1Y5c6ZGXSDAJvyCes6dTjhDAi0fjGbVLqpyfzBc,5918
|
61
61
|
sunholo/database/__init__.py,sha256=bpB5Nk21kwqYj-qdVnvNgXjLsbflnH4g-San7OHMqR4,283
|
62
62
|
sunholo/database/alloydb.py,sha256=x1zUMB-EVWbE2Zvp4nAs2Z-tB_kOZmS45H2lwVHdYnk,11678
|
63
|
-
sunholo/database/alloydb_client.py,sha256=
|
63
|
+
sunholo/database/alloydb_client.py,sha256=uPRcdfrE1YXCUoDbaKopjlKXXP5deceEn08bJKUeWI4,27596
|
64
64
|
sunholo/database/database.py,sha256=VqhZdkXUNdvWn8sUcUV3YNby1JDVf7IykPVXWBtxo9U,7361
|
65
65
|
sunholo/database/lancedb.py,sha256=DyfZntiFKBlVPaFooNN1Z6Pl-LAs4nxWKKuq8GBqN58,715
|
66
66
|
sunholo/database/static_dbs.py,sha256=8cvcMwUK6c32AS2e_WguKXWMkFf5iN3g9WHzsh0C07Q,442
|
@@ -168,9 +168,9 @@ sunholo/vertex/init.py,sha256=1OQwcPBKZYBTDPdyU7IM4X4OmiXLdsNV30C-fee2scQ,2875
|
|
168
168
|
sunholo/vertex/memory_tools.py,sha256=tBZxqVZ4InTmdBvLlOYwoSEWu4-kGquc-gxDwZCC4FA,7667
|
169
169
|
sunholo/vertex/safety.py,sha256=S9PgQT1O_BQAkcqauWncRJaydiP8Q_Jzmu9gxYfy1VA,2482
|
170
170
|
sunholo/vertex/type_dict_to_json.py,sha256=uTzL4o9tJRao4u-gJOFcACgWGkBOtqACmb6ihvCErL8,4694
|
171
|
-
sunholo-0.123.
|
172
|
-
sunholo-0.123.
|
173
|
-
sunholo-0.123.
|
174
|
-
sunholo-0.123.
|
175
|
-
sunholo-0.123.
|
176
|
-
sunholo-0.123.
|
171
|
+
sunholo-0.123.2.dist-info/licenses/LICENSE.txt,sha256=SdE3QjnD3GEmqqg9EX3TM9f7WmtOzqS1KJve8rhbYmU,11345
|
172
|
+
sunholo-0.123.2.dist-info/METADATA,sha256=0w8jC9b0-_LEB8VnRcKIIbSlHCIJRFPyiuqwfTnbsm8,10001
|
173
|
+
sunholo-0.123.2.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
174
|
+
sunholo-0.123.2.dist-info/entry_points.txt,sha256=bZuN5AIHingMPt4Ro1b_T-FnQvZ3teBes-3OyO0asl4,49
|
175
|
+
sunholo-0.123.2.dist-info/top_level.txt,sha256=wt5tadn5--5JrZsjJz2LceoUvcrIvxjHJe-RxuudxAk,8
|
176
|
+
sunholo-0.123.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|