datus-postgresql 0.1.1__tar.gz → 0.1.4__tar.gz
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.
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/PKG-INFO +2 -2
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/datus_postgresql/__init__.py +1 -1
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/datus_postgresql/config.py +7 -2
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/datus_postgresql/connector.py +106 -26
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/pyproject.toml +3 -2
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/scripts/init_tpch_data.py +151 -15
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/conftest.py +2 -1
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/integration/conftest.py +152 -15
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/integration/test_integration.py +9 -4
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/integration/test_tpch.py +7 -1
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/unit/test_config.py +2 -1
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/unit/test_connector_unit.py +13 -7
- datus_postgresql-0.1.1/.gitignore +0 -140
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/README.md +0 -0
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/datus_postgresql/handlers.py +0 -0
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/docker-compose.yml +0 -0
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/__init__.py +0 -0
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/integration/__init__.py +0 -0
- {datus_postgresql-0.1.1 → datus_postgresql-0.1.4}/tests/unit/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datus-postgresql
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: PostgreSQL database adapter for Datus
|
|
5
5
|
Project-URL: Homepage, https://github.com/Datus-ai/datus-db-adapters
|
|
6
6
|
Project-URL: Repository, https://github.com/Datus-ai/datus-db-adapters
|
|
@@ -14,7 +14,7 @@ Classifier: License :: OSI Approved :: Apache Software License
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.12
|
|
16
16
|
Requires-Python: >=3.12
|
|
17
|
-
Requires-Dist: datus-
|
|
17
|
+
Requires-Dist: datus-db-core>=0.1.0
|
|
18
18
|
Requires-Dist: datus-sqlalchemy>=0.1.2
|
|
19
19
|
Requires-Dist: psycopg2-binary>=2.9.11
|
|
20
20
|
Requires-Dist: pydantic>=2.0.0
|
|
@@ -11,7 +11,7 @@ __all__ = ["PostgreSQLConnector", "PostgreSQLConfig", "register"]
|
|
|
11
11
|
|
|
12
12
|
def register():
|
|
13
13
|
"""Register PostgreSQL connector with Datus registry."""
|
|
14
|
-
from
|
|
14
|
+
from datus_db_core import connector_registry
|
|
15
15
|
|
|
16
16
|
from .handlers import build_postgresql_uri, resolve_postgresql_context
|
|
17
17
|
|
|
@@ -15,10 +15,15 @@ class PostgreSQLConfig(BaseModel):
|
|
|
15
15
|
host: str = Field(default="127.0.0.1", description="PostgreSQL server host")
|
|
16
16
|
port: int = Field(default=5432, description="PostgreSQL server port")
|
|
17
17
|
username: str = Field(..., description="PostgreSQL username")
|
|
18
|
-
password: str = Field(
|
|
18
|
+
password: str = Field(
|
|
19
|
+
default="",
|
|
20
|
+
description="PostgreSQL password",
|
|
21
|
+
json_schema_extra={"input_type": "password"},
|
|
22
|
+
)
|
|
19
23
|
database: Optional[str] = Field(default=None, description="Default database name")
|
|
20
24
|
schema_name: Optional[str] = Field(default="public", alias="schema", description="Default schema name")
|
|
21
25
|
sslmode: str = Field(
|
|
22
|
-
default="prefer",
|
|
26
|
+
default="prefer",
|
|
27
|
+
description="SSL mode (disable, allow, prefer, require, verify-ca, verify-full)",
|
|
23
28
|
)
|
|
24
29
|
timeout_seconds: int = Field(default=30, description="Connection timeout in seconds")
|
|
@@ -5,12 +5,18 @@
|
|
|
5
5
|
from typing import Any, Dict, List, Optional, Set, Union, override
|
|
6
6
|
from urllib.parse import quote_plus
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from datus.tools.db_tools.base import list_to_in_str
|
|
10
|
-
from datus.utils.exceptions import DatusException, ErrorCode
|
|
11
|
-
from datus.utils.loggings import get_logger
|
|
12
|
-
from datus_sqlalchemy import SQLAlchemyConnector
|
|
8
|
+
from pandas import DataFrame
|
|
13
9
|
from pydantic import BaseModel, Field
|
|
10
|
+
from sqlalchemy import create_engine, text
|
|
11
|
+
|
|
12
|
+
from datus_db_core import (
|
|
13
|
+
TABLE_TYPE,
|
|
14
|
+
DatusDbException,
|
|
15
|
+
ErrorCode,
|
|
16
|
+
get_logger,
|
|
17
|
+
list_to_in_str,
|
|
18
|
+
)
|
|
19
|
+
from datus_sqlalchemy import SQLAlchemyConnector
|
|
14
20
|
|
|
15
21
|
from .config import PostgreSQLConfig
|
|
16
22
|
|
|
@@ -42,7 +48,7 @@ METADATA_DICT: Dict[TABLE_TYPE, TableMetadataNames] = {
|
|
|
42
48
|
def _get_metadata_config(table_type: TABLE_TYPE) -> TableMetadataNames:
|
|
43
49
|
"""Get metadata configuration for given table type."""
|
|
44
50
|
if table_type not in METADATA_DICT:
|
|
45
|
-
raise
|
|
51
|
+
raise DatusDbException(ErrorCode.COMMON_FIELD_INVALID, f"Invalid table type '{table_type}'")
|
|
46
52
|
return METADATA_DICT[table_type]
|
|
47
53
|
|
|
48
54
|
|
|
@@ -79,7 +85,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
79
85
|
f"{database}?sslmode={config.sslmode}"
|
|
80
86
|
)
|
|
81
87
|
|
|
82
|
-
super().__init__(
|
|
88
|
+
super().__init__(
|
|
89
|
+
connection_string,
|
|
90
|
+
dialect="postgresql",
|
|
91
|
+
timeout_seconds=config.timeout_seconds,
|
|
92
|
+
)
|
|
83
93
|
self.database_name = database
|
|
84
94
|
self.schema_name = config.schema_name or "public"
|
|
85
95
|
|
|
@@ -93,7 +103,13 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
93
103
|
@override
|
|
94
104
|
def _sys_schemas(self) -> Set[str]:
|
|
95
105
|
"""System schemas to filter out."""
|
|
96
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
"pg_catalog",
|
|
108
|
+
"information_schema",
|
|
109
|
+
"pg_toast",
|
|
110
|
+
"pg_temp_1",
|
|
111
|
+
"pg_toast_temp_1",
|
|
112
|
+
}
|
|
97
113
|
|
|
98
114
|
# ==================== Utility Methods ====================
|
|
99
115
|
|
|
@@ -103,6 +119,33 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
103
119
|
escaped = identifier.replace('"', '""')
|
|
104
120
|
return f'"{escaped}"'
|
|
105
121
|
|
|
122
|
+
def _build_connection_string(self, database_name: str) -> str:
|
|
123
|
+
"""Build a PostgreSQL connection string for a given database."""
|
|
124
|
+
encoded_username = quote_plus(self.username) if self.username else ""
|
|
125
|
+
encoded_password = quote_plus(self.password) if self.password else ""
|
|
126
|
+
return (
|
|
127
|
+
f"postgresql+psycopg2://{encoded_username}:{encoded_password}"
|
|
128
|
+
f"@{self.host}:{self.port}/{database_name}?sslmode={self.config.sslmode}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def _execute_on_database(self, sql: str, database_name: str) -> DataFrame:
|
|
132
|
+
"""Execute a query on a specific database using a temporary connection.
|
|
133
|
+
|
|
134
|
+
Thread-safe: creates an isolated connection without mutating self.
|
|
135
|
+
"""
|
|
136
|
+
if database_name == self.database_name:
|
|
137
|
+
return self._execute_pandas(sql)
|
|
138
|
+
|
|
139
|
+
conn_str = self._build_connection_string(database_name)
|
|
140
|
+
engine = create_engine(conn_str)
|
|
141
|
+
try:
|
|
142
|
+
with engine.connect() as conn:
|
|
143
|
+
result = conn.execute(text(sql))
|
|
144
|
+
rows = [row._asdict() for row in result.fetchall()]
|
|
145
|
+
return DataFrame(rows)
|
|
146
|
+
finally:
|
|
147
|
+
engine.dispose()
|
|
148
|
+
|
|
106
149
|
# ==================== Metadata Retrieval ====================
|
|
107
150
|
|
|
108
151
|
def _get_metadata(
|
|
@@ -125,13 +168,15 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
125
168
|
List of metadata dictionaries
|
|
126
169
|
"""
|
|
127
170
|
self.connect()
|
|
171
|
+
database_name = database_name or self.database_name
|
|
128
172
|
schema_name = schema_name or self.schema_name
|
|
129
173
|
|
|
130
174
|
# Get metadata configuration
|
|
131
175
|
metadata_config = _get_metadata_config(table_type)
|
|
132
176
|
|
|
133
177
|
if table_type == "mv":
|
|
134
|
-
#
|
|
178
|
+
# pg_matviews is scoped to the current database connection.
|
|
179
|
+
# Use a temporary connection if a different database is requested (thread-safe).
|
|
135
180
|
if schema_name:
|
|
136
181
|
where = f"schemaname = '{schema_name}'"
|
|
137
182
|
else:
|
|
@@ -142,8 +187,9 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
142
187
|
FROM pg_matviews
|
|
143
188
|
WHERE {where}
|
|
144
189
|
"""
|
|
190
|
+
query_result = self._execute_on_database(query, database_name)
|
|
145
191
|
else:
|
|
146
|
-
# Tables and views use information_schema
|
|
192
|
+
# Tables and views use information_schema (supports table_catalog filter)
|
|
147
193
|
if schema_name:
|
|
148
194
|
where = f"table_schema = '{schema_name}'"
|
|
149
195
|
else:
|
|
@@ -157,10 +203,9 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
157
203
|
query = f"""
|
|
158
204
|
SELECT table_schema, table_name
|
|
159
205
|
FROM information_schema.{metadata_config.info_table}
|
|
160
|
-
WHERE {where} {type_filter}
|
|
206
|
+
WHERE table_catalog = '{database_name}' AND {where} {type_filter}
|
|
161
207
|
"""
|
|
162
|
-
|
|
163
|
-
query_result = self._execute_pandas(query)
|
|
208
|
+
query_result = self._execute_pandas(query)
|
|
164
209
|
|
|
165
210
|
# Format results
|
|
166
211
|
result = []
|
|
@@ -171,7 +216,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
171
216
|
{
|
|
172
217
|
"identifier": self.identifier(schema_name=schema, table_name=tb_name),
|
|
173
218
|
"catalog_name": "",
|
|
174
|
-
"database_name":
|
|
219
|
+
"database_name": database_name,
|
|
175
220
|
"schema_name": schema,
|
|
176
221
|
"table_name": tb_name,
|
|
177
222
|
"table_type": table_type,
|
|
@@ -310,7 +355,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
310
355
|
|
|
311
356
|
@override
|
|
312
357
|
def get_tables_with_ddl(
|
|
313
|
-
self,
|
|
358
|
+
self,
|
|
359
|
+
catalog_name: str = "",
|
|
360
|
+
database_name: str = "",
|
|
361
|
+
schema_name: str = "",
|
|
362
|
+
tables: Optional[List[str]] = None,
|
|
314
363
|
) -> List[Dict[str, str]]:
|
|
315
364
|
"""Get tables with DDL statements."""
|
|
316
365
|
return self._get_objects_with_ddl("table", tables, catalog_name, database_name, schema_name)
|
|
@@ -324,7 +373,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
324
373
|
|
|
325
374
|
@override
|
|
326
375
|
def get_schema(
|
|
327
|
-
self,
|
|
376
|
+
self,
|
|
377
|
+
catalog_name: str = "",
|
|
378
|
+
database_name: str = "",
|
|
379
|
+
schema_name: str = "",
|
|
380
|
+
table_name: str = "",
|
|
328
381
|
) -> List[Dict[str, Any]]:
|
|
329
382
|
"""
|
|
330
383
|
Get table schema using INFORMATION_SCHEMA.
|
|
@@ -341,6 +394,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
341
394
|
if not table_name:
|
|
342
395
|
return []
|
|
343
396
|
|
|
397
|
+
database_name = database_name or self.database_name
|
|
344
398
|
schema_name = schema_name or self.schema_name
|
|
345
399
|
|
|
346
400
|
# Use INFORMATION_SCHEMA to get schema with comments
|
|
@@ -367,7 +421,8 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
367
421
|
ON st.schemaname = c.table_schema AND st.relname = c.table_name
|
|
368
422
|
LEFT JOIN pg_catalog.pg_description pgd
|
|
369
423
|
ON pgd.objoid = st.relid AND pgd.objsubid = c.ordinal_position
|
|
370
|
-
WHERE c.
|
|
424
|
+
WHERE c.table_catalog = '{database_name}'
|
|
425
|
+
AND c.table_schema = '{schema_name}'
|
|
371
426
|
AND c.table_name = '{table_name}'
|
|
372
427
|
ORDER BY c.ordinal_position
|
|
373
428
|
"""
|
|
@@ -406,7 +461,8 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
406
461
|
@override
|
|
407
462
|
def get_schemas(self, catalog_name: str = "", database_name: str = "", include_sys: bool = False) -> List[str]:
|
|
408
463
|
"""Get list of schemas in the current database."""
|
|
409
|
-
|
|
464
|
+
database_name = database_name or self.database_name
|
|
465
|
+
sql = f"SELECT schema_name FROM information_schema.schemata WHERE catalog_name = '{database_name}'"
|
|
410
466
|
result = self._execute_pandas(sql)
|
|
411
467
|
schemas = result["schema_name"].tolist()
|
|
412
468
|
|
|
@@ -425,11 +481,17 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
425
481
|
|
|
426
482
|
@override
|
|
427
483
|
def do_switch_context(self, catalog_name: str = "", database_name: str = "", schema_name: str = ""):
|
|
428
|
-
"""Switch schema context
|
|
484
|
+
"""Switch database/schema context.
|
|
429
485
|
|
|
430
|
-
|
|
431
|
-
|
|
486
|
+
PostgreSQL requires reconnection to switch databases.
|
|
487
|
+
Schema switching only updates self.schema_name since all queries
|
|
488
|
+
use explicit schema qualification via full_name().
|
|
432
489
|
"""
|
|
490
|
+
if database_name and database_name != self.database_name:
|
|
491
|
+
self.connection_string = self._build_connection_string(database_name)
|
|
492
|
+
self.close()
|
|
493
|
+
self.connect()
|
|
494
|
+
self.database_name = database_name
|
|
433
495
|
if schema_name:
|
|
434
496
|
self.schema_name = schema_name
|
|
435
497
|
|
|
@@ -480,7 +542,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
480
542
|
return result
|
|
481
543
|
|
|
482
544
|
# Otherwise get metadata and query all tables
|
|
483
|
-
metadata = self._get_metadata(table_type, "",
|
|
545
|
+
metadata = self._get_metadata(table_type, "", database_name, schema_name)
|
|
484
546
|
for meta in metadata:
|
|
485
547
|
full_name = self.full_name(schema_name=meta["schema_name"], table_name=meta["table_name"])
|
|
486
548
|
sql = f"SELECT * FROM {full_name} LIMIT {top_n}"
|
|
@@ -502,28 +564,46 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
502
564
|
|
|
503
565
|
@override
|
|
504
566
|
def identifier(
|
|
505
|
-
self,
|
|
567
|
+
self,
|
|
568
|
+
catalog_name: str = "",
|
|
569
|
+
database_name: str = "",
|
|
570
|
+
schema_name: str = "",
|
|
571
|
+
table_name: str = "",
|
|
506
572
|
) -> str:
|
|
507
573
|
"""Generate a unique identifier for a table."""
|
|
574
|
+
database_name = database_name or self.database_name
|
|
508
575
|
schema_name = schema_name or self.schema_name
|
|
576
|
+
if database_name and schema_name:
|
|
577
|
+
return f"{database_name}.{schema_name}.{table_name}"
|
|
509
578
|
if schema_name:
|
|
510
579
|
return f"{schema_name}.{table_name}"
|
|
511
580
|
return table_name
|
|
512
581
|
|
|
513
582
|
@override
|
|
514
583
|
def full_name(
|
|
515
|
-
self,
|
|
584
|
+
self,
|
|
585
|
+
catalog_name: str = "",
|
|
586
|
+
database_name: str = "",
|
|
587
|
+
schema_name: str = "",
|
|
588
|
+
table_name: str = "",
|
|
516
589
|
) -> str:
|
|
517
590
|
"""Build fully-qualified table name."""
|
|
591
|
+
database_name = database_name or self.database_name
|
|
518
592
|
schema_name = schema_name or self.schema_name
|
|
593
|
+
if database_name and schema_name:
|
|
594
|
+
return f"{self._quote_identifier(database_name)}.{self._quote_identifier(schema_name)}.{self._quote_identifier(table_name)}"
|
|
519
595
|
if schema_name:
|
|
520
596
|
return f"{self._quote_identifier(schema_name)}.{self._quote_identifier(table_name)}"
|
|
521
597
|
return self._quote_identifier(table_name)
|
|
522
598
|
|
|
523
599
|
@override
|
|
524
600
|
def _reset_filter_tables(
|
|
525
|
-
self,
|
|
601
|
+
self,
|
|
602
|
+
tables: Optional[List[str]] = None,
|
|
603
|
+
catalog_name: str = "",
|
|
604
|
+
database_name: str = "",
|
|
605
|
+
schema_name: str = "",
|
|
526
606
|
) -> List[str]:
|
|
527
607
|
"""Reset filter tables with full names."""
|
|
528
608
|
schema_name = schema_name or self.schema_name
|
|
529
|
-
return super()._reset_filter_tables(tables, "",
|
|
609
|
+
return super()._reset_filter_tables(tables, "", database_name, schema_name)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "datus-postgresql"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.4"
|
|
4
4
|
description = "PostgreSQL database adapter for Datus"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.12"
|
|
@@ -18,7 +18,7 @@ classifiers = [
|
|
|
18
18
|
]
|
|
19
19
|
|
|
20
20
|
dependencies = [
|
|
21
|
-
"datus-
|
|
21
|
+
"datus-db-core>=0.1.0",
|
|
22
22
|
"datus-sqlalchemy>=0.1.2",
|
|
23
23
|
"psycopg2-binary>=2.9.11",
|
|
24
24
|
"pydantic>=2.0.0",
|
|
@@ -33,6 +33,7 @@ Issues = "https://github.com/Datus-ai/datus-db-adapters/issues"
|
|
|
33
33
|
postgresql = "datus_postgresql:register"
|
|
34
34
|
|
|
35
35
|
[tool.uv.sources]
|
|
36
|
+
datus-db-core = { workspace = true }
|
|
36
37
|
datus-sqlalchemy = { workspace = true }
|
|
37
38
|
|
|
38
39
|
[build-system]
|
|
@@ -104,7 +104,12 @@ TPCH_DATA = {
|
|
|
104
104
|
],
|
|
105
105
|
"tpch_nation": [
|
|
106
106
|
(0, "ALGERIA", 0, " haggle. carefully final deposits detect slyly agai"),
|
|
107
|
-
(
|
|
107
|
+
(
|
|
108
|
+
1,
|
|
109
|
+
"ARGENTINA",
|
|
110
|
+
1,
|
|
111
|
+
"al foxes promise slyly according to the regular accounts.",
|
|
112
|
+
),
|
|
108
113
|
(2, "BRAZIL", 1, "y alongside of the pending deposits."),
|
|
109
114
|
(3, "CANADA", 1, "eas hang ironic, silent packages."),
|
|
110
115
|
(4, "EGYPT", 4, "y above the carefully unusual theodolites."),
|
|
@@ -118,7 +123,12 @@ TPCH_DATA = {
|
|
|
118
123
|
(12, "JAPAN", 2, "ously. final, express gifts cajole a"),
|
|
119
124
|
(13, "JORDAN", 4, "ic deposits are blithely about the carefully regular pa"),
|
|
120
125
|
(14, "KENYA", 0, " pending excuses haggle furiously deposits."),
|
|
121
|
-
(
|
|
126
|
+
(
|
|
127
|
+
15,
|
|
128
|
+
"MOROCCO",
|
|
129
|
+
0,
|
|
130
|
+
"rns. blithely bold courts among the closely regular packages",
|
|
131
|
+
),
|
|
122
132
|
(16, "MOZAMBIQUE", 0, "s. ironic, unusual asymptotes wake blithely r"),
|
|
123
133
|
(17, "PERU", 1, "platelets. blithely pending dependencies use fluffily"),
|
|
124
134
|
(18, "CHINA", 2, "c dependencies. furiously express notornis sleep slyly"),
|
|
@@ -139,7 +149,15 @@ TPCH_DATA = {
|
|
|
139
149
|
5755.94,
|
|
140
150
|
"each slyly above the careful",
|
|
141
151
|
),
|
|
142
|
-
(
|
|
152
|
+
(
|
|
153
|
+
2,
|
|
154
|
+
"Supplier#000000002",
|
|
155
|
+
"89eJ5ksX3ImxJQBvxObC,",
|
|
156
|
+
5,
|
|
157
|
+
"15-679-861-2259",
|
|
158
|
+
4032.68,
|
|
159
|
+
" slyly bold instructions.",
|
|
160
|
+
),
|
|
143
161
|
(
|
|
144
162
|
3,
|
|
145
163
|
"Supplier#000000003",
|
|
@@ -158,7 +176,15 @@ TPCH_DATA = {
|
|
|
158
176
|
4641.08,
|
|
159
177
|
"riously even requests above the exp",
|
|
160
178
|
),
|
|
161
|
-
(
|
|
179
|
+
(
|
|
180
|
+
5,
|
|
181
|
+
"Supplier#000000005",
|
|
182
|
+
"Gcdm2rJRzl5qlTVzc",
|
|
183
|
+
11,
|
|
184
|
+
"21-151-690-3663",
|
|
185
|
+
-531.44,
|
|
186
|
+
". slyly regular pinto beans t",
|
|
187
|
+
),
|
|
162
188
|
],
|
|
163
189
|
"tpch_customer": [
|
|
164
190
|
(
|
|
@@ -263,7 +289,17 @@ TPCH_DATA = {
|
|
|
263
289
|
),
|
|
264
290
|
],
|
|
265
291
|
"tpch_orders": [
|
|
266
|
-
(
|
|
292
|
+
(
|
|
293
|
+
1,
|
|
294
|
+
1,
|
|
295
|
+
"O",
|
|
296
|
+
173665.47,
|
|
297
|
+
"1996-01-02",
|
|
298
|
+
"5-LOW",
|
|
299
|
+
"Clerk#000000951",
|
|
300
|
+
0,
|
|
301
|
+
"nstructions sleep furiously among",
|
|
302
|
+
),
|
|
267
303
|
(
|
|
268
304
|
2,
|
|
269
305
|
2,
|
|
@@ -275,9 +311,39 @@ TPCH_DATA = {
|
|
|
275
311
|
0,
|
|
276
312
|
" foxes. pending accounts at the pending",
|
|
277
313
|
),
|
|
278
|
-
(
|
|
279
|
-
|
|
280
|
-
|
|
314
|
+
(
|
|
315
|
+
3,
|
|
316
|
+
3,
|
|
317
|
+
"F",
|
|
318
|
+
193846.25,
|
|
319
|
+
"1993-10-14",
|
|
320
|
+
"5-LOW",
|
|
321
|
+
"Clerk#000000955",
|
|
322
|
+
0,
|
|
323
|
+
"sly final accounts boost.",
|
|
324
|
+
),
|
|
325
|
+
(
|
|
326
|
+
4,
|
|
327
|
+
4,
|
|
328
|
+
"O",
|
|
329
|
+
32151.78,
|
|
330
|
+
"1995-10-11",
|
|
331
|
+
"5-LOW",
|
|
332
|
+
"Clerk#000000124",
|
|
333
|
+
0,
|
|
334
|
+
"sits. slyly regular warthogs cajole.",
|
|
335
|
+
),
|
|
336
|
+
(
|
|
337
|
+
5,
|
|
338
|
+
5,
|
|
339
|
+
"F",
|
|
340
|
+
144659.20,
|
|
341
|
+
"1994-07-30",
|
|
342
|
+
"5-LOW",
|
|
343
|
+
"Clerk#000000925",
|
|
344
|
+
0,
|
|
345
|
+
"quickly. bold deposits sleep slyly.",
|
|
346
|
+
),
|
|
281
347
|
(
|
|
282
348
|
6,
|
|
283
349
|
6,
|
|
@@ -289,9 +355,39 @@ TPCH_DATA = {
|
|
|
289
355
|
0,
|
|
290
356
|
"ggle. special, final requests are against the furiously",
|
|
291
357
|
),
|
|
292
|
-
(
|
|
293
|
-
|
|
294
|
-
|
|
358
|
+
(
|
|
359
|
+
7,
|
|
360
|
+
7,
|
|
361
|
+
"O",
|
|
362
|
+
252004.18,
|
|
363
|
+
"1996-01-10",
|
|
364
|
+
"2-HIGH",
|
|
365
|
+
"Clerk#000000470",
|
|
366
|
+
0,
|
|
367
|
+
"ly special requests",
|
|
368
|
+
),
|
|
369
|
+
(
|
|
370
|
+
32,
|
|
371
|
+
8,
|
|
372
|
+
"O",
|
|
373
|
+
208660.75,
|
|
374
|
+
"1995-07-16",
|
|
375
|
+
"2-HIGH",
|
|
376
|
+
"Clerk#000000616",
|
|
377
|
+
0,
|
|
378
|
+
"ise blithely bold, regular requests.",
|
|
379
|
+
),
|
|
380
|
+
(
|
|
381
|
+
33,
|
|
382
|
+
9,
|
|
383
|
+
"F",
|
|
384
|
+
163243.98,
|
|
385
|
+
"1993-10-27",
|
|
386
|
+
"3-MEDIUM",
|
|
387
|
+
"Clerk#000000409",
|
|
388
|
+
0,
|
|
389
|
+
"uriously. furiously final request",
|
|
390
|
+
),
|
|
295
391
|
(
|
|
296
392
|
34,
|
|
297
393
|
10,
|
|
@@ -314,10 +410,50 @@ TPCH_DATA = {
|
|
|
314
410
|
0,
|
|
315
411
|
"zzle. carefully enticing deposits nag furio",
|
|
316
412
|
),
|
|
317
|
-
(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
413
|
+
(
|
|
414
|
+
36,
|
|
415
|
+
2,
|
|
416
|
+
"O",
|
|
417
|
+
38988.98,
|
|
418
|
+
"1995-11-03",
|
|
419
|
+
"1-URGENT",
|
|
420
|
+
"Clerk#000000358",
|
|
421
|
+
0,
|
|
422
|
+
" quick packages are blithely.",
|
|
423
|
+
),
|
|
424
|
+
(
|
|
425
|
+
37,
|
|
426
|
+
3,
|
|
427
|
+
"F",
|
|
428
|
+
131896.48,
|
|
429
|
+
"1992-06-03",
|
|
430
|
+
"3-MEDIUM",
|
|
431
|
+
"Clerk#000000456",
|
|
432
|
+
0,
|
|
433
|
+
"kly regular pinto beans.",
|
|
434
|
+
),
|
|
435
|
+
(
|
|
436
|
+
38,
|
|
437
|
+
4,
|
|
438
|
+
"O",
|
|
439
|
+
46366.56,
|
|
440
|
+
"1996-08-21",
|
|
441
|
+
"4-NOT SPECIFIED",
|
|
442
|
+
"Clerk#000000604",
|
|
443
|
+
0,
|
|
444
|
+
"haggle blithely.",
|
|
445
|
+
),
|
|
446
|
+
(
|
|
447
|
+
39,
|
|
448
|
+
5,
|
|
449
|
+
"O",
|
|
450
|
+
219707.84,
|
|
451
|
+
"1996-09-20",
|
|
452
|
+
"3-MEDIUM",
|
|
453
|
+
"Clerk#000000659",
|
|
454
|
+
0,
|
|
455
|
+
"ole express, ironic requests:",
|
|
456
|
+
),
|
|
321
457
|
],
|
|
322
458
|
}
|
|
323
459
|
|
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
def pytest_configure(config):
|
|
7
7
|
"""Configure custom markers."""
|
|
8
8
|
config.addinivalue_line(
|
|
9
|
-
"markers",
|
|
9
|
+
"markers",
|
|
10
|
+
"integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
|
|
10
11
|
)
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
from typing import Generator
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
+
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
11
12
|
# ---------------------------------------------------------------------------
|
|
@@ -83,7 +84,12 @@ TPCH_DATA = {
|
|
|
83
84
|
],
|
|
84
85
|
"tpch_nation": [
|
|
85
86
|
(0, "ALGERIA", 0, " haggle. carefully final deposits detect slyly agai"),
|
|
86
|
-
(
|
|
87
|
+
(
|
|
88
|
+
1,
|
|
89
|
+
"ARGENTINA",
|
|
90
|
+
1,
|
|
91
|
+
"al foxes promise slyly according to the regular accounts.",
|
|
92
|
+
),
|
|
87
93
|
(2, "BRAZIL", 1, "y alongside of the pending deposits."),
|
|
88
94
|
(3, "CANADA", 1, "eas hang ironic, silent packages."),
|
|
89
95
|
(4, "EGYPT", 4, "y above the carefully unusual theodolites."),
|
|
@@ -97,7 +103,12 @@ TPCH_DATA = {
|
|
|
97
103
|
(12, "JAPAN", 2, "ously. final, express gifts cajole a"),
|
|
98
104
|
(13, "JORDAN", 4, "ic deposits are blithely about the carefully regular pa"),
|
|
99
105
|
(14, "KENYA", 0, " pending excuses haggle furiously deposits."),
|
|
100
|
-
(
|
|
106
|
+
(
|
|
107
|
+
15,
|
|
108
|
+
"MOROCCO",
|
|
109
|
+
0,
|
|
110
|
+
"rns. blithely bold courts among the closely regular packages",
|
|
111
|
+
),
|
|
101
112
|
(16, "MOZAMBIQUE", 0, "s. ironic, unusual asymptotes wake blithely r"),
|
|
102
113
|
(17, "PERU", 1, "platelets. blithely pending dependencies use fluffily"),
|
|
103
114
|
(18, "CHINA", 2, "c dependencies. furiously express notornis sleep slyly"),
|
|
@@ -118,7 +129,15 @@ TPCH_DATA = {
|
|
|
118
129
|
5755.94,
|
|
119
130
|
"each slyly above the careful",
|
|
120
131
|
),
|
|
121
|
-
(
|
|
132
|
+
(
|
|
133
|
+
2,
|
|
134
|
+
"Supplier#000000002",
|
|
135
|
+
"89eJ5ksX3ImxJQBvxObC,",
|
|
136
|
+
5,
|
|
137
|
+
"15-679-861-2259",
|
|
138
|
+
4032.68,
|
|
139
|
+
" slyly bold instructions.",
|
|
140
|
+
),
|
|
122
141
|
(
|
|
123
142
|
3,
|
|
124
143
|
"Supplier#000000003",
|
|
@@ -137,7 +156,15 @@ TPCH_DATA = {
|
|
|
137
156
|
4641.08,
|
|
138
157
|
"riously even requests above the exp",
|
|
139
158
|
),
|
|
140
|
-
(
|
|
159
|
+
(
|
|
160
|
+
5,
|
|
161
|
+
"Supplier#000000005",
|
|
162
|
+
"Gcdm2rJRzl5qlTVzc",
|
|
163
|
+
11,
|
|
164
|
+
"21-151-690-3663",
|
|
165
|
+
-531.44,
|
|
166
|
+
". slyly regular pinto beans t",
|
|
167
|
+
),
|
|
141
168
|
],
|
|
142
169
|
"tpch_customer": [
|
|
143
170
|
(
|
|
@@ -242,7 +269,17 @@ TPCH_DATA = {
|
|
|
242
269
|
),
|
|
243
270
|
],
|
|
244
271
|
"tpch_orders": [
|
|
245
|
-
(
|
|
272
|
+
(
|
|
273
|
+
1,
|
|
274
|
+
1,
|
|
275
|
+
"O",
|
|
276
|
+
173665.47,
|
|
277
|
+
"1996-01-02",
|
|
278
|
+
"5-LOW",
|
|
279
|
+
"Clerk#000000951",
|
|
280
|
+
0,
|
|
281
|
+
"nstructions sleep furiously among",
|
|
282
|
+
),
|
|
246
283
|
(
|
|
247
284
|
2,
|
|
248
285
|
2,
|
|
@@ -254,9 +291,39 @@ TPCH_DATA = {
|
|
|
254
291
|
0,
|
|
255
292
|
" foxes. pending accounts at the pending",
|
|
256
293
|
),
|
|
257
|
-
(
|
|
258
|
-
|
|
259
|
-
|
|
294
|
+
(
|
|
295
|
+
3,
|
|
296
|
+
3,
|
|
297
|
+
"F",
|
|
298
|
+
193846.25,
|
|
299
|
+
"1993-10-14",
|
|
300
|
+
"5-LOW",
|
|
301
|
+
"Clerk#000000955",
|
|
302
|
+
0,
|
|
303
|
+
"sly final accounts boost.",
|
|
304
|
+
),
|
|
305
|
+
(
|
|
306
|
+
4,
|
|
307
|
+
4,
|
|
308
|
+
"O",
|
|
309
|
+
32151.78,
|
|
310
|
+
"1995-10-11",
|
|
311
|
+
"5-LOW",
|
|
312
|
+
"Clerk#000000124",
|
|
313
|
+
0,
|
|
314
|
+
"sits. slyly regular warthogs cajole.",
|
|
315
|
+
),
|
|
316
|
+
(
|
|
317
|
+
5,
|
|
318
|
+
5,
|
|
319
|
+
"F",
|
|
320
|
+
144659.20,
|
|
321
|
+
"1994-07-30",
|
|
322
|
+
"5-LOW",
|
|
323
|
+
"Clerk#000000925",
|
|
324
|
+
0,
|
|
325
|
+
"quickly. bold deposits sleep slyly.",
|
|
326
|
+
),
|
|
260
327
|
(
|
|
261
328
|
6,
|
|
262
329
|
6,
|
|
@@ -268,9 +335,39 @@ TPCH_DATA = {
|
|
|
268
335
|
0,
|
|
269
336
|
"ggle. special, final requests are against the furiously",
|
|
270
337
|
),
|
|
271
|
-
(
|
|
272
|
-
|
|
273
|
-
|
|
338
|
+
(
|
|
339
|
+
7,
|
|
340
|
+
7,
|
|
341
|
+
"O",
|
|
342
|
+
252004.18,
|
|
343
|
+
"1996-01-10",
|
|
344
|
+
"2-HIGH",
|
|
345
|
+
"Clerk#000000470",
|
|
346
|
+
0,
|
|
347
|
+
"ly special requests",
|
|
348
|
+
),
|
|
349
|
+
(
|
|
350
|
+
32,
|
|
351
|
+
8,
|
|
352
|
+
"O",
|
|
353
|
+
208660.75,
|
|
354
|
+
"1995-07-16",
|
|
355
|
+
"2-HIGH",
|
|
356
|
+
"Clerk#000000616",
|
|
357
|
+
0,
|
|
358
|
+
"ise blithely bold, regular requests.",
|
|
359
|
+
),
|
|
360
|
+
(
|
|
361
|
+
33,
|
|
362
|
+
9,
|
|
363
|
+
"F",
|
|
364
|
+
163243.98,
|
|
365
|
+
"1993-10-27",
|
|
366
|
+
"3-MEDIUM",
|
|
367
|
+
"Clerk#000000409",
|
|
368
|
+
0,
|
|
369
|
+
"uriously. furiously final request",
|
|
370
|
+
),
|
|
274
371
|
(
|
|
275
372
|
34,
|
|
276
373
|
10,
|
|
@@ -293,10 +390,50 @@ TPCH_DATA = {
|
|
|
293
390
|
0,
|
|
294
391
|
"zzle. carefully enticing deposits nag furio",
|
|
295
392
|
),
|
|
296
|
-
(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
393
|
+
(
|
|
394
|
+
36,
|
|
395
|
+
2,
|
|
396
|
+
"O",
|
|
397
|
+
38988.98,
|
|
398
|
+
"1995-11-03",
|
|
399
|
+
"1-URGENT",
|
|
400
|
+
"Clerk#000000358",
|
|
401
|
+
0,
|
|
402
|
+
" quick packages are blithely.",
|
|
403
|
+
),
|
|
404
|
+
(
|
|
405
|
+
37,
|
|
406
|
+
3,
|
|
407
|
+
"F",
|
|
408
|
+
131896.48,
|
|
409
|
+
"1992-06-03",
|
|
410
|
+
"3-MEDIUM",
|
|
411
|
+
"Clerk#000000456",
|
|
412
|
+
0,
|
|
413
|
+
"kly regular pinto beans.",
|
|
414
|
+
),
|
|
415
|
+
(
|
|
416
|
+
38,
|
|
417
|
+
4,
|
|
418
|
+
"O",
|
|
419
|
+
46366.56,
|
|
420
|
+
"1996-08-21",
|
|
421
|
+
"4-NOT SPECIFIED",
|
|
422
|
+
"Clerk#000000604",
|
|
423
|
+
0,
|
|
424
|
+
"haggle blithely.",
|
|
425
|
+
),
|
|
426
|
+
(
|
|
427
|
+
39,
|
|
428
|
+
5,
|
|
429
|
+
"O",
|
|
430
|
+
219707.84,
|
|
431
|
+
"1996-09-20",
|
|
432
|
+
"3-MEDIUM",
|
|
433
|
+
"Clerk#000000659",
|
|
434
|
+
0,
|
|
435
|
+
"ole express, ironic requests:",
|
|
436
|
+
),
|
|
300
437
|
],
|
|
301
438
|
}
|
|
302
439
|
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
import uuid
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
+
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
11
12
|
# ==================== Connection Tests ====================
|
|
@@ -307,7 +308,8 @@ def test_execute_insert(connector: PostgreSQLConnector, config: PostgreSQLConfig
|
|
|
307
308
|
|
|
308
309
|
# Verify
|
|
309
310
|
query_result = connector.execute(
|
|
310
|
-
{"sql_query": f"SELECT id, name FROM {table_name} ORDER BY id"},
|
|
311
|
+
{"sql_query": f"SELECT id, name FROM {table_name} ORDER BY id"},
|
|
312
|
+
result_format="list",
|
|
311
313
|
)
|
|
312
314
|
assert len(query_result.sql_return) == 2
|
|
313
315
|
assert query_result.sql_return[0]["name"] == "Alice"
|
|
@@ -342,7 +344,8 @@ def test_execute_update(connector: PostgreSQLConnector, config: PostgreSQLConfig
|
|
|
342
344
|
|
|
343
345
|
# Verify
|
|
344
346
|
query_result = connector.execute(
|
|
345
|
-
{"sql_query": f"SELECT name FROM {table_name} WHERE id = 1"},
|
|
347
|
+
{"sql_query": f"SELECT name FROM {table_name} WHERE id = 1"},
|
|
348
|
+
result_format="list",
|
|
346
349
|
)
|
|
347
350
|
assert query_result.sql_return == [{"name": "Alice Updated"}]
|
|
348
351
|
finally:
|
|
@@ -404,8 +407,9 @@ def test_exception_on_nonexistent_table(connector: PostgreSQLConnector):
|
|
|
404
407
|
@pytest.mark.integration
|
|
405
408
|
def test_full_name_with_schema(connector: PostgreSQLConnector):
|
|
406
409
|
"""Test full_name with schema."""
|
|
410
|
+
db = connector.database_name
|
|
407
411
|
full_name = connector.full_name(schema_name="myschema", table_name="mytable")
|
|
408
|
-
assert full_name == '"myschema"."mytable"'
|
|
412
|
+
assert full_name == f'"{db}"."myschema"."mytable"'
|
|
409
413
|
|
|
410
414
|
|
|
411
415
|
@pytest.mark.integration
|
|
@@ -419,5 +423,6 @@ def test_full_name_with_default_schema(connector: PostgreSQLConnector):
|
|
|
419
423
|
@pytest.mark.integration
|
|
420
424
|
def test_identifier(connector: PostgreSQLConnector):
|
|
421
425
|
"""Test identifier generation."""
|
|
426
|
+
db = connector.database_name
|
|
422
427
|
identifier = connector.identifier(schema_name="myschema", table_name="mytable")
|
|
423
|
-
assert identifier == "myschema.mytable"
|
|
428
|
+
assert identifier == f"{db}.myschema.mytable"
|
|
@@ -131,7 +131,13 @@ class TestTpchMetadata:
|
|
|
131
131
|
"""get_tables() should return TPC-H tables."""
|
|
132
132
|
tables = tpch_setup.get_tables(schema_name="public")
|
|
133
133
|
tpch_tables = {t for t in tables if t.startswith("tpch_")}
|
|
134
|
-
expected = {
|
|
134
|
+
expected = {
|
|
135
|
+
"tpch_region",
|
|
136
|
+
"tpch_nation",
|
|
137
|
+
"tpch_supplier",
|
|
138
|
+
"tpch_customer",
|
|
139
|
+
"tpch_orders",
|
|
140
|
+
}
|
|
135
141
|
assert expected.issubset(tpch_tables)
|
|
136
142
|
|
|
137
143
|
def test_get_schema_columns(self, tpch_setup):
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
# See http://www.apache.org/licenses/LICENSE-2.0 for details.
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
-
from datus_postgresql import PostgreSQLConfig
|
|
7
6
|
from pydantic import ValidationError
|
|
8
7
|
|
|
8
|
+
from datus_postgresql import PostgreSQLConfig
|
|
9
|
+
|
|
9
10
|
|
|
10
11
|
@pytest.mark.acceptance
|
|
11
12
|
def test_config_with_all_required_fields():
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
from unittest.mock import patch
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
|
-
|
|
8
|
+
|
|
9
|
+
from datus_db_core import DatusDbException
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
11
12
|
|
|
@@ -223,10 +224,11 @@ def test_full_name_with_schema():
|
|
|
223
224
|
|
|
224
225
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
225
226
|
connector = PostgreSQLConnector(config)
|
|
227
|
+
connector.database_name = "postgres"
|
|
226
228
|
connector.schema_name = "public"
|
|
227
229
|
full_name = connector.full_name(schema_name="myschema", table_name="mytable")
|
|
228
230
|
|
|
229
|
-
assert full_name == '"myschema"."mytable"'
|
|
231
|
+
assert full_name == '"postgres"."myschema"."mytable"'
|
|
230
232
|
|
|
231
233
|
|
|
232
234
|
def test_full_name_with_default_schema():
|
|
@@ -235,10 +237,11 @@ def test_full_name_with_default_schema():
|
|
|
235
237
|
|
|
236
238
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
237
239
|
connector = PostgreSQLConnector(config)
|
|
240
|
+
connector.database_name = "postgres"
|
|
238
241
|
connector.schema_name = "public"
|
|
239
242
|
full_name = connector.full_name(table_name="mytable")
|
|
240
243
|
|
|
241
|
-
assert full_name == '"public"."mytable"'
|
|
244
|
+
assert full_name == '"postgres"."public"."mytable"'
|
|
242
245
|
|
|
243
246
|
|
|
244
247
|
def test_full_name_with_special_characters():
|
|
@@ -247,10 +250,11 @@ def test_full_name_with_special_characters():
|
|
|
247
250
|
|
|
248
251
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
249
252
|
connector = PostgreSQLConnector(config)
|
|
253
|
+
connector.database_name = "postgres"
|
|
250
254
|
connector.schema_name = "public"
|
|
251
255
|
full_name = connector.full_name(schema_name='my"schema', table_name='my"table')
|
|
252
256
|
|
|
253
|
-
assert full_name == '"my""schema"."my""table"'
|
|
257
|
+
assert full_name == '"postgres"."my""schema"."my""table"'
|
|
254
258
|
|
|
255
259
|
|
|
256
260
|
def test_identifier_with_schema():
|
|
@@ -259,10 +263,11 @@ def test_identifier_with_schema():
|
|
|
259
263
|
|
|
260
264
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
261
265
|
connector = PostgreSQLConnector(config)
|
|
266
|
+
connector.database_name = "postgres"
|
|
262
267
|
connector.schema_name = "public"
|
|
263
268
|
identifier = connector.identifier(schema_name="myschema", table_name="mytable")
|
|
264
269
|
|
|
265
|
-
assert identifier == "myschema.mytable"
|
|
270
|
+
assert identifier == "postgres.myschema.mytable"
|
|
266
271
|
|
|
267
272
|
|
|
268
273
|
def test_identifier_with_default_schema():
|
|
@@ -271,10 +276,11 @@ def test_identifier_with_default_schema():
|
|
|
271
276
|
|
|
272
277
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
273
278
|
connector = PostgreSQLConnector(config)
|
|
279
|
+
connector.database_name = "postgres"
|
|
274
280
|
connector.schema_name = "public"
|
|
275
281
|
identifier = connector.identifier(table_name="mytable")
|
|
276
282
|
|
|
277
|
-
assert identifier == "public.mytable"
|
|
283
|
+
assert identifier == "postgres.public.mytable"
|
|
278
284
|
|
|
279
285
|
|
|
280
286
|
@pytest.mark.acceptance
|
|
@@ -308,7 +314,7 @@ def test_get_metadata_config_invalid_type():
|
|
|
308
314
|
"""Test _get_metadata_config with invalid table type."""
|
|
309
315
|
from datus_postgresql.connector import _get_metadata_config
|
|
310
316
|
|
|
311
|
-
with pytest.raises(
|
|
317
|
+
with pytest.raises(DatusDbException, match="Invalid table type"):
|
|
312
318
|
_get_metadata_config("invalid_type")
|
|
313
319
|
|
|
314
320
|
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
|
|
6
|
-
# C extensions
|
|
7
|
-
*.so
|
|
8
|
-
|
|
9
|
-
# Distribution / packaging
|
|
10
|
-
.Python
|
|
11
|
-
build/
|
|
12
|
-
develop-eggs/
|
|
13
|
-
dist/
|
|
14
|
-
downloads/
|
|
15
|
-
eggs/
|
|
16
|
-
.eggs/
|
|
17
|
-
lib/
|
|
18
|
-
lib64/
|
|
19
|
-
parts/
|
|
20
|
-
sdist/
|
|
21
|
-
var/
|
|
22
|
-
wheels/
|
|
23
|
-
pip-wheel-metadata/
|
|
24
|
-
share/python-wheels/
|
|
25
|
-
*.egg-info/
|
|
26
|
-
.installed.cfg
|
|
27
|
-
*.egg
|
|
28
|
-
MANIFEST
|
|
29
|
-
|
|
30
|
-
# PyInstaller
|
|
31
|
-
*.manifest
|
|
32
|
-
*.spec
|
|
33
|
-
|
|
34
|
-
# Installer logs
|
|
35
|
-
pip-log.txt
|
|
36
|
-
pip-delete-this-directory.txt
|
|
37
|
-
|
|
38
|
-
# Unit test / coverage reports
|
|
39
|
-
htmlcov/
|
|
40
|
-
.tox/
|
|
41
|
-
.nox/
|
|
42
|
-
.coverage
|
|
43
|
-
.coverage.*
|
|
44
|
-
.cache
|
|
45
|
-
nosetests.xml
|
|
46
|
-
coverage.xml
|
|
47
|
-
*.cover
|
|
48
|
-
*.py,cover
|
|
49
|
-
.hypothesis/
|
|
50
|
-
.pytest_cache/
|
|
51
|
-
|
|
52
|
-
# Translations
|
|
53
|
-
*.mo
|
|
54
|
-
*.pot
|
|
55
|
-
|
|
56
|
-
# Django stuff:
|
|
57
|
-
*.log
|
|
58
|
-
local_settings.py
|
|
59
|
-
db.sqlite3
|
|
60
|
-
db.sqlite3-journal
|
|
61
|
-
|
|
62
|
-
# Flask stuff:
|
|
63
|
-
instance/
|
|
64
|
-
.webassets-cache
|
|
65
|
-
|
|
66
|
-
# Scrapy stuff:
|
|
67
|
-
.scrapy
|
|
68
|
-
|
|
69
|
-
# Sphinx documentation
|
|
70
|
-
docs/_build/
|
|
71
|
-
|
|
72
|
-
# PyBuilder
|
|
73
|
-
target/
|
|
74
|
-
|
|
75
|
-
# Jupyter Notebook
|
|
76
|
-
.ipynb_checkpoints
|
|
77
|
-
|
|
78
|
-
# IPython
|
|
79
|
-
profile_default/
|
|
80
|
-
ipython_config.py
|
|
81
|
-
|
|
82
|
-
# pyenv
|
|
83
|
-
.python-version
|
|
84
|
-
|
|
85
|
-
# pipenv
|
|
86
|
-
Pipfile.lock
|
|
87
|
-
|
|
88
|
-
# uv
|
|
89
|
-
uv.lock
|
|
90
|
-
|
|
91
|
-
# PEP 582
|
|
92
|
-
__pypackages__/
|
|
93
|
-
|
|
94
|
-
# Celery stuff
|
|
95
|
-
celerybeat-schedule
|
|
96
|
-
celerybeat.pid
|
|
97
|
-
|
|
98
|
-
# SageMath parsed files
|
|
99
|
-
*.sage.py
|
|
100
|
-
|
|
101
|
-
# Environments
|
|
102
|
-
.env
|
|
103
|
-
.venv
|
|
104
|
-
env/
|
|
105
|
-
venv/
|
|
106
|
-
ENV/
|
|
107
|
-
env.bak/
|
|
108
|
-
venv.bak/
|
|
109
|
-
|
|
110
|
-
# Spyder project settings
|
|
111
|
-
.spyderproject
|
|
112
|
-
.spyproject
|
|
113
|
-
|
|
114
|
-
# Rope project settings
|
|
115
|
-
.ropeproject
|
|
116
|
-
|
|
117
|
-
# mkdocs documentation
|
|
118
|
-
/site
|
|
119
|
-
|
|
120
|
-
# mypy
|
|
121
|
-
.mypy_cache/
|
|
122
|
-
.dmypy.json
|
|
123
|
-
dmypy.json
|
|
124
|
-
|
|
125
|
-
# Pyre type checker
|
|
126
|
-
.pyre/
|
|
127
|
-
|
|
128
|
-
# IDEs
|
|
129
|
-
.vscode/
|
|
130
|
-
.idea/
|
|
131
|
-
*.swp
|
|
132
|
-
*.swo
|
|
133
|
-
*~
|
|
134
|
-
|
|
135
|
-
# OS
|
|
136
|
-
.DS_Store
|
|
137
|
-
Thumbs.db
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.omc
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|