databao 0.3.3.dev2__tar.gz → 0.3.3.dev3__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.
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/PKG-INFO +1 -1
- databao-0.3.3.dev3/e2e-tests/src/databases/duckdb_utils.py +118 -0
- databao-0.3.3.dev3/e2e-tests/src/databases/mysql_utils.py +168 -0
- databao-0.3.3.dev3/e2e-tests/src/databases/postgres_utils.py +209 -0
- databao-0.3.3.dev3/e2e-tests/src/databases/sqlite_utils.py +99 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_duckdb.py +3 -2
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_mysql.py +3 -2
- databao-0.3.3.dev3/e2e-tests/tests/domains/test_postgres.py +48 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_sqlite.py +3 -2
- databao-0.3.3.dev3/e2e-tests/tests/resources/postgres_partitioned_tables_introspections.yaml +402 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/pyproject.toml +1 -1
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/src/databao_snowflake_demo/app.py +4 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/uv.lock +4 -4
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/__main__.py +18 -1
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/app.py +2 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/app.py +39 -1
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/cli.py +6 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/chat.py +178 -17
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/datasource_manager.py +2 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/results.py +40 -23
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/context_settings.py +2 -6
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/welcome.py +31 -26
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/__init__.py +2 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/query_executor.py +94 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/suggestions.py +36 -0
- databao-0.3.3.dev3/tests/test_app.py +45 -0
- databao-0.3.3.dev3/tests/test_query_executor.py +396 -0
- databao-0.3.3.dev3/tests/test_query_executor_race_conditions.py +545 -0
- databao-0.3.3.dev2/e2e-tests/src/databases/duckdb_utils.py +0 -116
- databao-0.3.3.dev2/e2e-tests/src/databases/mysql_utils.py +0 -165
- databao-0.3.3.dev2/e2e-tests/src/databases/postgres_utils.py +0 -168
- databao-0.3.3.dev2/e2e-tests/src/databases/sqlite_utils.py +0 -97
- databao-0.3.3.dev2/e2e-tests/tests/domains/test_postgres.py +0 -28
- databao-0.3.3.dev2/tests/test_app.py +0 -12
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.cursor/rules/python-style.mdc +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/actions/setup-project/action.yml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/e2e-tests.yml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/publish-dev.yml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/publish.yml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/python-package.yml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.gitignore +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.pre-commit-config.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.python-version +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/CONTRIBUTING.md +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/LICENSE +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/Makefile +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/README.md +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/.gitignore +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/pytest.ini +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/bigquery_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/snowflake_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/project_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/path_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/pexpect_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/yaml_compare.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/conftest.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_bigquery.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_snowflake.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/bigquery_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/duckdb_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/mysql_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/postgres_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/snowflake_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/sqlite_introspections.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/README.md +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/dce.ini +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/examples/src/databases/example_postgres.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/examples/src/files/documentation.md +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/examples/src/files/notes.txt +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/src/snowflake.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/setup.sql +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/src/databao_snowflake_demo/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/pyproject.toml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/scripts/generate_licenses.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/ask.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/build.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/context_engine_cli.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/add_datasource_config.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/check_datasource_connection.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/init.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/mcp.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/status.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/executor_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/llm_errors.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/logging.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/server.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/agent_factory.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/tool.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/project/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/project/layout.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/assets/bao.png +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/datasource_form.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/icons.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/sidebar.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/status.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/chat_session.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/settings.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/agent_settings.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/chat.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/general_settings.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/project_utils.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/build_service.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/chat_persistence.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/chat_title.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/dce_operations.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/llm_models.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/settings_persistence.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/storage.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/streaming.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_check_datasource.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_project/databao/domains/root/dce.ini +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_project/databao/domains/root/src/myduck.yaml +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/conftest.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/get_loaded_plugins.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/test_plugins.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_add_datasource.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_ask.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_build.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_init.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_mcp.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_status.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/utils/__init__.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/utils/project.py +0 -0
- {databao-0.3.3.dev2 → databao-0.3.3.dev3}/uv.lock +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import duckdb
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class DuckdbDB:
|
|
9
|
+
datasource_name: str | None = "test duckdb conn"
|
|
10
|
+
datasource_type: str = "duckdb"
|
|
11
|
+
database_path: Path | None = None
|
|
12
|
+
check_connection: bool = False
|
|
13
|
+
check_connection_succeed: bool = True
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def get_database(cls, db_file: Path):
|
|
17
|
+
return cls(database_path=db_file, check_connection=True)
|
|
18
|
+
|
|
19
|
+
def add_table(self, create_table_sql: str, fill_table_sql: str):
|
|
20
|
+
conn = duckdb.connect(database=str(self.database_path))
|
|
21
|
+
try:
|
|
22
|
+
with conn:
|
|
23
|
+
conn.execute(create_table_sql)
|
|
24
|
+
conn.execute(fill_table_sql)
|
|
25
|
+
finally:
|
|
26
|
+
conn.close()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
CREATE_DUCKDB_TABLE_SQL = """
|
|
30
|
+
CREATE TABLE all_types_demo
|
|
31
|
+
(
|
|
32
|
+
-- Integer types
|
|
33
|
+
id INTEGER PRIMARY KEY,
|
|
34
|
+
tinyint_col TINYINT,
|
|
35
|
+
smallint_col SMALLINT,
|
|
36
|
+
int_col INTEGER,
|
|
37
|
+
bigint_col BIGINT,
|
|
38
|
+
hugeint_col HUGEINT,
|
|
39
|
+
|
|
40
|
+
-- Unsigned integers
|
|
41
|
+
utinyint_col UTINYINT,
|
|
42
|
+
usmallint_col USMALLINT,
|
|
43
|
+
uinteger_col UINTEGER,
|
|
44
|
+
ubigint_col UBIGINT,
|
|
45
|
+
|
|
46
|
+
-- Floating point
|
|
47
|
+
real_col REAL,
|
|
48
|
+
double_col DOUBLE,
|
|
49
|
+
|
|
50
|
+
-- Decimal
|
|
51
|
+
decimal_col DECIMAL(10, 2),
|
|
52
|
+
|
|
53
|
+
-- Boolean
|
|
54
|
+
boolean_col BOOLEAN,
|
|
55
|
+
|
|
56
|
+
-- Character / string
|
|
57
|
+
char_col CHAR(5),
|
|
58
|
+
varchar_col VARCHAR,
|
|
59
|
+
text_col TEXT,
|
|
60
|
+
|
|
61
|
+
-- Binary
|
|
62
|
+
blob_col BLOB,
|
|
63
|
+
|
|
64
|
+
-- Date & time
|
|
65
|
+
date_col DATE,
|
|
66
|
+
time_col TIME,
|
|
67
|
+
timestamp_col TIMESTAMP,
|
|
68
|
+
timestamptz_col TIMESTAMPTZ,
|
|
69
|
+
interval_col INTERVAL,
|
|
70
|
+
|
|
71
|
+
-- UUID
|
|
72
|
+
uuid_col UUID,
|
|
73
|
+
|
|
74
|
+
-- JSON
|
|
75
|
+
json_col JSON,
|
|
76
|
+
|
|
77
|
+
-- Arrays (LIST)
|
|
78
|
+
int_array_col INTEGER[],
|
|
79
|
+
varchar_array_col VARCHAR[],
|
|
80
|
+
|
|
81
|
+
-- Struct
|
|
82
|
+
struct_col STRUCT(name VARCHAR, age INTEGER),
|
|
83
|
+
|
|
84
|
+
-- Map
|
|
85
|
+
map_col MAP(VARCHAR, INTEGER)
|
|
86
|
+
);"""
|
|
87
|
+
|
|
88
|
+
FILL_DUCKDB_TABLE_SQL = """
|
|
89
|
+
INSERT INTO all_types_demo
|
|
90
|
+
VALUES (1,
|
|
91
|
+
10,
|
|
92
|
+
100,
|
|
93
|
+
1000,
|
|
94
|
+
10000000000,
|
|
95
|
+
123456789012345678901234567890::HUGEINT,
|
|
96
|
+
255,
|
|
97
|
+
65535,
|
|
98
|
+
4000000000,
|
|
99
|
+
10000000000000000000,
|
|
100
|
+
3.14,
|
|
101
|
+
3.1415926535,
|
|
102
|
+
12345.67,
|
|
103
|
+
TRUE,
|
|
104
|
+
'ABCDE',
|
|
105
|
+
'Hello DuckDB',
|
|
106
|
+
'This is a text column',
|
|
107
|
+
'DEADBEEF'::BLOB,
|
|
108
|
+
DATE '2025-01-01',
|
|
109
|
+
TIME '12:30:00',
|
|
110
|
+
TIMESTAMP '2025-01-01 12:30:00',
|
|
111
|
+
TIMESTAMPTZ '2025-01-01 12:30:00+02',
|
|
112
|
+
INTERVAL '2 days',
|
|
113
|
+
'550e8400-e29b-41d4-a716-446655440000'::UUID,
|
|
114
|
+
'{"key": "value"}'::JSON,
|
|
115
|
+
[1, 2, 3],
|
|
116
|
+
['a', 'b', 'c'],
|
|
117
|
+
{'name' : 'Alice', 'age': 30},
|
|
118
|
+
MAP(['a', 'b'], [1, 2]));"""
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import pymysql
|
|
4
|
+
from testcontainers.mysql import MySqlContainer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class MysqlDB:
|
|
9
|
+
datasource_name: str | None = "test_mysql_conn"
|
|
10
|
+
datasource_type: str = "mysql"
|
|
11
|
+
host: str | None = None
|
|
12
|
+
port: int | None = None
|
|
13
|
+
database: str | None = None
|
|
14
|
+
user: str | None = None
|
|
15
|
+
password: str | None = None
|
|
16
|
+
check_connection: bool = False
|
|
17
|
+
check_connection_succeed: bool = True
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_database(cls, container: MySqlContainer):
|
|
21
|
+
return cls(
|
|
22
|
+
host=container.get_container_host_ip(),
|
|
23
|
+
port=int(container.get_exposed_port(container.port)),
|
|
24
|
+
database=container.dbname,
|
|
25
|
+
user=container.username,
|
|
26
|
+
password=container.password,
|
|
27
|
+
check_connection=True,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def add_table(self, create_table_sql: str, fill_table_sql: str):
|
|
31
|
+
conn = pymysql.connect(
|
|
32
|
+
host=self.host,
|
|
33
|
+
port=self.port,
|
|
34
|
+
user=self.user,
|
|
35
|
+
password=self.password,
|
|
36
|
+
database=self.database,
|
|
37
|
+
cursorclass=pymysql.cursors.DictCursor,
|
|
38
|
+
autocommit=True,
|
|
39
|
+
)
|
|
40
|
+
try:
|
|
41
|
+
with conn.cursor() as cur:
|
|
42
|
+
cur.execute(create_table_sql)
|
|
43
|
+
cur.execute(fill_table_sql)
|
|
44
|
+
finally:
|
|
45
|
+
conn.close()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
CREATE_MYSQL_TABLE_SQL = """
|
|
49
|
+
CREATE TABLE all_types_demo
|
|
50
|
+
(
|
|
51
|
+
-- Numeric types
|
|
52
|
+
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
53
|
+
tinyint_col TINYINT,
|
|
54
|
+
smallint_col SMALLINT,
|
|
55
|
+
mediumint_col MEDIUMINT,
|
|
56
|
+
int_col INT,
|
|
57
|
+
bigint_col BIGINT,
|
|
58
|
+
decimal_col DECIMAL(10, 2),
|
|
59
|
+
float_col FLOAT,
|
|
60
|
+
double_col DOUBLE,
|
|
61
|
+
bit_col BIT(4),
|
|
62
|
+
boolean_col BOOLEAN,
|
|
63
|
+
|
|
64
|
+
-- Date and time types
|
|
65
|
+
date_col DATE,
|
|
66
|
+
time_col TIME,
|
|
67
|
+
datetime_col DATETIME,
|
|
68
|
+
timestamp_col TIMESTAMP NULL,
|
|
69
|
+
year_col YEAR,
|
|
70
|
+
|
|
71
|
+
-- String types
|
|
72
|
+
char_col CHAR(5),
|
|
73
|
+
varchar_col VARCHAR(50),
|
|
74
|
+
binary_col BINARY(4),
|
|
75
|
+
varbinary_col VARBINARY(10),
|
|
76
|
+
|
|
77
|
+
-- Text types
|
|
78
|
+
tinytext_col TINYTEXT,
|
|
79
|
+
text_col TEXT,
|
|
80
|
+
mediumtext_col MEDIUMTEXT,
|
|
81
|
+
longtext_col LONGTEXT,
|
|
82
|
+
|
|
83
|
+
-- Blob types
|
|
84
|
+
tinyblob_col TINYBLOB,
|
|
85
|
+
blob_col BLOB,
|
|
86
|
+
mediumblob_col MEDIUMBLOB,
|
|
87
|
+
longblob_col LONGBLOB,
|
|
88
|
+
|
|
89
|
+
-- Enum and Set
|
|
90
|
+
enum_col ENUM('active','inactive','pending'),
|
|
91
|
+
set_col SET('a','b','c'),
|
|
92
|
+
|
|
93
|
+
-- JSON
|
|
94
|
+
json_col JSON,
|
|
95
|
+
|
|
96
|
+
-- Spatial types
|
|
97
|
+
point_col POINT,
|
|
98
|
+
linestring_col LINESTRING,
|
|
99
|
+
polygon_col POLYGON
|
|
100
|
+
);"""
|
|
101
|
+
|
|
102
|
+
FILL_MYSQL_TABLE_SQL = """
|
|
103
|
+
INSERT INTO all_types_demo (tinyint_col,
|
|
104
|
+
smallint_col,
|
|
105
|
+
mediumint_col,
|
|
106
|
+
int_col,
|
|
107
|
+
bigint_col,
|
|
108
|
+
decimal_col,
|
|
109
|
+
float_col,
|
|
110
|
+
double_col,
|
|
111
|
+
bit_col,
|
|
112
|
+
boolean_col,
|
|
113
|
+
date_col,
|
|
114
|
+
time_col,
|
|
115
|
+
datetime_col,
|
|
116
|
+
timestamp_col,
|
|
117
|
+
year_col,
|
|
118
|
+
char_col,
|
|
119
|
+
varchar_col,
|
|
120
|
+
binary_col,
|
|
121
|
+
varbinary_col,
|
|
122
|
+
tinytext_col,
|
|
123
|
+
text_col,
|
|
124
|
+
mediumtext_col,
|
|
125
|
+
longtext_col,
|
|
126
|
+
tinyblob_col,
|
|
127
|
+
blob_col,
|
|
128
|
+
mediumblob_col,
|
|
129
|
+
longblob_col,
|
|
130
|
+
enum_col,
|
|
131
|
+
set_col,
|
|
132
|
+
json_col,
|
|
133
|
+
point_col,
|
|
134
|
+
linestring_col,
|
|
135
|
+
polygon_col)
|
|
136
|
+
VALUES (1,
|
|
137
|
+
100,
|
|
138
|
+
1000,
|
|
139
|
+
10000,
|
|
140
|
+
10000000000,
|
|
141
|
+
12345.67,
|
|
142
|
+
3.14,
|
|
143
|
+
3.1415926535,
|
|
144
|
+
b'1010',
|
|
145
|
+
TRUE,
|
|
146
|
+
'2025-01-01',
|
|
147
|
+
'12:30:00',
|
|
148
|
+
'2025-01-01 12:30:00',
|
|
149
|
+
'2026-02-26 15:12:55',
|
|
150
|
+
2025,
|
|
151
|
+
'ABCDE',
|
|
152
|
+
'Hello MySQL',
|
|
153
|
+
'ABCD',
|
|
154
|
+
'varbin',
|
|
155
|
+
'tiny text',
|
|
156
|
+
'regular text column',
|
|
157
|
+
'medium text column',
|
|
158
|
+
'long text column',
|
|
159
|
+
UNHEX('AA'),
|
|
160
|
+
UNHEX('DEADBEEF'),
|
|
161
|
+
UNHEX('DEADBEEFDEADBEEF'),
|
|
162
|
+
UNHEX('DEADBEEFDEADBEEFDEADBEEF'),
|
|
163
|
+
'active',
|
|
164
|
+
'a,b',
|
|
165
|
+
JSON_OBJECT('key', 'value'),
|
|
166
|
+
ST_GeomFromText('POINT(1 2)'),
|
|
167
|
+
ST_GeomFromText('LINESTRING(0 0, 1 1, 2 2)'),
|
|
168
|
+
ST_GeomFromText('POLYGON((0 0, 0 5, 5 5, 5 0, 0 0))'));"""
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import psycopg2
|
|
4
|
+
from testcontainers.postgres import PostgresContainer
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
@dataclass(frozen=True)
|
|
8
|
+
class PostgresDB:
|
|
9
|
+
datasource_name: str
|
|
10
|
+
datasource_type = "postgres"
|
|
11
|
+
host: str | None = None
|
|
12
|
+
port: int | None = None
|
|
13
|
+
database: str | None = None
|
|
14
|
+
user: str | None = None
|
|
15
|
+
password: str | None = None
|
|
16
|
+
check_connection: bool = False
|
|
17
|
+
check_connection_succeed: bool = True
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def get_database(cls, container: PostgresContainer):
|
|
21
|
+
return cls(
|
|
22
|
+
datasource_name="my_postgres",
|
|
23
|
+
host=container.get_container_host_ip(),
|
|
24
|
+
port=int(container.get_exposed_port(container.port)),
|
|
25
|
+
database=container.dbname,
|
|
26
|
+
user=container.username,
|
|
27
|
+
password=container.password,
|
|
28
|
+
check_connection=True,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
def add_table(self, create_table_sql: str, fill_table_sql: str):
|
|
32
|
+
conn = psycopg2.connect(host=self.host, port=self.port, user=self.user, password=self.password, dbname=self.database)
|
|
33
|
+
try:
|
|
34
|
+
with conn.cursor() as cur:
|
|
35
|
+
cur.execute(create_table_sql)
|
|
36
|
+
cur.execute(fill_table_sql)
|
|
37
|
+
conn.commit()
|
|
38
|
+
finally:
|
|
39
|
+
conn.close()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
CREATE_POSTGRES_TABLE_SQL = """
|
|
43
|
+
CREATE TABLE all_types_demo
|
|
44
|
+
(
|
|
45
|
+
-- Numeric types
|
|
46
|
+
id SERIAL PRIMARY KEY,
|
|
47
|
+
small_int_col SMALLINT,
|
|
48
|
+
int_col INTEGER,
|
|
49
|
+
big_int_col BIGINT,
|
|
50
|
+
numeric_col NUMERIC(10, 2),
|
|
51
|
+
real_col REAL,
|
|
52
|
+
double_col DOUBLE PRECISION,
|
|
53
|
+
money_col MONEY,
|
|
54
|
+
|
|
55
|
+
-- Character types
|
|
56
|
+
char_col CHAR(5),
|
|
57
|
+
varchar_col VARCHAR(50),
|
|
58
|
+
text_col TEXT,
|
|
59
|
+
|
|
60
|
+
-- Boolean
|
|
61
|
+
boolean_col BOOLEAN,
|
|
62
|
+
|
|
63
|
+
-- Date & time
|
|
64
|
+
date_col DATE,
|
|
65
|
+
time_col TIME,
|
|
66
|
+
timetz_col TIME WITH TIME ZONE,
|
|
67
|
+
timestamp_col TIMESTAMP,
|
|
68
|
+
timestamptz_col TIMESTAMP WITH TIME ZONE,
|
|
69
|
+
interval_col INTERVAL,
|
|
70
|
+
|
|
71
|
+
-- JSON
|
|
72
|
+
json_col JSON,
|
|
73
|
+
jsonb_col JSONB,
|
|
74
|
+
|
|
75
|
+
-- Arrays
|
|
76
|
+
int_array_col INTEGER[],
|
|
77
|
+
text_array_col TEXT[],
|
|
78
|
+
|
|
79
|
+
-- Binary
|
|
80
|
+
bytea_col BYTEA,
|
|
81
|
+
|
|
82
|
+
-- Enum
|
|
83
|
+
status_col TEXT CHECK (status_col IN ('active', 'inactive', 'pending')),
|
|
84
|
+
|
|
85
|
+
-- Network
|
|
86
|
+
inet_col INET,
|
|
87
|
+
cidr_col CIDR,
|
|
88
|
+
macaddr_col MACADDR,
|
|
89
|
+
|
|
90
|
+
-- Geometric
|
|
91
|
+
point_col POINT,
|
|
92
|
+
circle_col CIRCLE,
|
|
93
|
+
|
|
94
|
+
-- Bit string
|
|
95
|
+
bit_col BIT(4),
|
|
96
|
+
bitvarying_col BIT VARYING(8),
|
|
97
|
+
|
|
98
|
+
-- XML
|
|
99
|
+
xml_col XML
|
|
100
|
+
);"""
|
|
101
|
+
|
|
102
|
+
FILL_POSTGRES_TABLE_SQL = """
|
|
103
|
+
INSERT INTO all_types_demo (small_int_col,
|
|
104
|
+
int_col,
|
|
105
|
+
big_int_col,
|
|
106
|
+
numeric_col,
|
|
107
|
+
real_col,
|
|
108
|
+
double_col,
|
|
109
|
+
money_col,
|
|
110
|
+
char_col,
|
|
111
|
+
varchar_col,
|
|
112
|
+
text_col,
|
|
113
|
+
boolean_col,
|
|
114
|
+
date_col,
|
|
115
|
+
time_col,
|
|
116
|
+
timetz_col,
|
|
117
|
+
timestamp_col,
|
|
118
|
+
timestamptz_col,
|
|
119
|
+
interval_col,
|
|
120
|
+
json_col,
|
|
121
|
+
jsonb_col,
|
|
122
|
+
int_array_col,
|
|
123
|
+
text_array_col,
|
|
124
|
+
bytea_col,
|
|
125
|
+
status_col,
|
|
126
|
+
inet_col,
|
|
127
|
+
cidr_col,
|
|
128
|
+
macaddr_col,
|
|
129
|
+
point_col,
|
|
130
|
+
circle_col,
|
|
131
|
+
bit_col,
|
|
132
|
+
bitvarying_col,
|
|
133
|
+
xml_col)
|
|
134
|
+
VALUES (10,
|
|
135
|
+
1000,
|
|
136
|
+
10000000000,
|
|
137
|
+
12345.67,
|
|
138
|
+
3.14,
|
|
139
|
+
3.1415926535,
|
|
140
|
+
99.99,
|
|
141
|
+
'ABCDE',
|
|
142
|
+
'Hello PostgreSQL',
|
|
143
|
+
'This is a long text column',
|
|
144
|
+
TRUE,
|
|
145
|
+
'2025-01-01',
|
|
146
|
+
'12:30:00',
|
|
147
|
+
'12:30:00+02',
|
|
148
|
+
'2025-01-01 12:30:00',
|
|
149
|
+
'2025-01-01 12:30:00+02',
|
|
150
|
+
'2 days 3 hours',
|
|
151
|
+
'{"key": "value"}',
|
|
152
|
+
'{"key": "value"}',
|
|
153
|
+
ARRAY[1, 2, 3],
|
|
154
|
+
ARRAY['a', 'b', 'c'],
|
|
155
|
+
decode('DEADBEEF', 'hex'),
|
|
156
|
+
'active',
|
|
157
|
+
'192.168.1.1',
|
|
158
|
+
'192.168.0.0/24',
|
|
159
|
+
'08:00:2b:01:02:03',
|
|
160
|
+
POINT(1, 2),
|
|
161
|
+
CIRCLE(POINT(1, 2), 5),
|
|
162
|
+
B'1010',
|
|
163
|
+
B'101010',
|
|
164
|
+
'<root><child>value</child></root>');"""
|
|
165
|
+
|
|
166
|
+
CREATE_POSTGRES_PARTITIONED_TABLE_SQL = """
|
|
167
|
+
CREATE TABLE sales
|
|
168
|
+
(
|
|
169
|
+
id SERIAL,
|
|
170
|
+
sale_date DATE NOT NULL,
|
|
171
|
+
amount NUMERIC(10, 2),
|
|
172
|
+
product_name VARCHAR(100),
|
|
173
|
+
region VARCHAR(50)
|
|
174
|
+
) PARTITION BY RANGE (sale_date);
|
|
175
|
+
|
|
176
|
+
CREATE TABLE sales_2024_q1 PARTITION OF sales
|
|
177
|
+
FOR VALUES FROM
|
|
178
|
+
(
|
|
179
|
+
'2024-01-01'
|
|
180
|
+
) TO
|
|
181
|
+
(
|
|
182
|
+
'2024-04-01'
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
CREATE TABLE sales_2024_q2 PARTITION OF sales
|
|
186
|
+
FOR VALUES FROM
|
|
187
|
+
(
|
|
188
|
+
'2024-04-01'
|
|
189
|
+
) TO
|
|
190
|
+
(
|
|
191
|
+
'2024-07-01'
|
|
192
|
+
);
|
|
193
|
+
|
|
194
|
+
CREATE TABLE sales_2024_q3 PARTITION OF sales
|
|
195
|
+
FOR VALUES FROM
|
|
196
|
+
(
|
|
197
|
+
'2024-07-01'
|
|
198
|
+
) TO
|
|
199
|
+
(
|
|
200
|
+
'2024-10-01'
|
|
201
|
+
);
|
|
202
|
+
"""
|
|
203
|
+
|
|
204
|
+
FILL_POSTGRES_PARTITIONED_TABLE_SQL = """
|
|
205
|
+
INSERT INTO sales (sale_date, amount, product_name, region)
|
|
206
|
+
VALUES ('2024-01-15', 150.00, 'Product A', 'North'),
|
|
207
|
+
('2024-05-20', 250.50, 'Product B', 'South'),
|
|
208
|
+
('2024-08-10', 175.75, 'Product C', 'East');
|
|
209
|
+
"""
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import sqlite3
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
@dataclass(frozen=True)
|
|
7
|
+
class SqliteDB:
|
|
8
|
+
datasource_name: str | None = "test sqlite conn"
|
|
9
|
+
datasource_type: str = "sqlite"
|
|
10
|
+
database_path: Path | None = None
|
|
11
|
+
check_connection: bool = False
|
|
12
|
+
check_connection_succeed: bool = True
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def get_database(cls, db_file: Path):
|
|
16
|
+
return cls(database_path=db_file, check_connection=True)
|
|
17
|
+
|
|
18
|
+
def add_table(self, create_table_sql: str, fill_table_sql: str):
|
|
19
|
+
conn = sqlite3.connect(database=str(self.database_path))
|
|
20
|
+
try:
|
|
21
|
+
with conn:
|
|
22
|
+
conn.execute(create_table_sql)
|
|
23
|
+
conn.execute(fill_table_sql)
|
|
24
|
+
finally:
|
|
25
|
+
conn.close()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
CREATE_SQLITE_TABLE_SQL = """
|
|
29
|
+
CREATE TABLE all_types_demo
|
|
30
|
+
(
|
|
31
|
+
-- Primary key
|
|
32
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
33
|
+
|
|
34
|
+
-- INTEGER affinity
|
|
35
|
+
int_col INTEGER,
|
|
36
|
+
bigint_col BIGINT,
|
|
37
|
+
smallint_col SMALLINT,
|
|
38
|
+
tinyint_col TINYINT,
|
|
39
|
+
boolean_col BOOLEAN,
|
|
40
|
+
|
|
41
|
+
-- REAL affinity
|
|
42
|
+
real_col REAL,
|
|
43
|
+
double_col DOUBLE,
|
|
44
|
+
float_col FLOAT,
|
|
45
|
+
numeric_col NUMERIC,
|
|
46
|
+
decimal_col DECIMAL(10, 2),
|
|
47
|
+
|
|
48
|
+
-- TEXT affinity
|
|
49
|
+
char_col CHAR(5),
|
|
50
|
+
varchar_col VARCHAR(50),
|
|
51
|
+
text_col TEXT,
|
|
52
|
+
clob_col CLOB,
|
|
53
|
+
date_col DATE,
|
|
54
|
+
datetime_col DATETIME,
|
|
55
|
+
|
|
56
|
+
-- BLOB affinity
|
|
57
|
+
blob_col BLOB,
|
|
58
|
+
|
|
59
|
+
-- No type (NONE affinity)
|
|
60
|
+
no_type_col
|
|
61
|
+
);"""
|
|
62
|
+
|
|
63
|
+
FILL_SQLITE_TABLE_SQL = """
|
|
64
|
+
INSERT INTO all_types_demo (int_col,
|
|
65
|
+
bigint_col,
|
|
66
|
+
smallint_col,
|
|
67
|
+
tinyint_col,
|
|
68
|
+
boolean_col,
|
|
69
|
+
real_col,
|
|
70
|
+
double_col,
|
|
71
|
+
float_col,
|
|
72
|
+
numeric_col,
|
|
73
|
+
decimal_col,
|
|
74
|
+
char_col,
|
|
75
|
+
varchar_col,
|
|
76
|
+
text_col,
|
|
77
|
+
clob_col,
|
|
78
|
+
date_col,
|
|
79
|
+
datetime_col,
|
|
80
|
+
blob_col,
|
|
81
|
+
no_type_col)
|
|
82
|
+
VALUES (42,
|
|
83
|
+
1234567890123,
|
|
84
|
+
123,
|
|
85
|
+
1,
|
|
86
|
+
1, -- SQLite stores boolean as INTEGER
|
|
87
|
+
3.14,
|
|
88
|
+
3.1415926535,
|
|
89
|
+
2.718,
|
|
90
|
+
999.99,
|
|
91
|
+
12345.67,
|
|
92
|
+
'ABCDE',
|
|
93
|
+
'Hello SQLite',
|
|
94
|
+
'This is a text column',
|
|
95
|
+
'This is a CLOB column',
|
|
96
|
+
'2025-01-01',
|
|
97
|
+
'2025-01-01 12:30:00',
|
|
98
|
+
X'DEADBEEF', -- BLOB value
|
|
99
|
+
'No declared type value');"""
|
|
@@ -2,7 +2,7 @@ from pathlib import Path
|
|
|
2
2
|
|
|
3
3
|
import allure
|
|
4
4
|
import pytest
|
|
5
|
-
from databases.duckdb_utils import DuckdbDB
|
|
5
|
+
from databases.duckdb_utils import CREATE_DUCKDB_TABLE_SQL, FILL_DUCKDB_TABLE_SQL, DuckdbDB
|
|
6
6
|
from project_utils import execute_build, execute_init
|
|
7
7
|
from utils.path_utils import get_datasource_result
|
|
8
8
|
from utils.yaml_compare import assert_introspections_equal
|
|
@@ -17,7 +17,8 @@ def temp_duckdb_file(tmp_path: Path):
|
|
|
17
17
|
@allure.title("Test databao build with DuckDB")
|
|
18
18
|
@allure.description("Initialize a project with DuckDB and build it, then compare results with expected introspection.")
|
|
19
19
|
def test_databao_build_duckdb(project_folder: Path, temp_duckdb_file: Path):
|
|
20
|
-
db = DuckdbDB.
|
|
20
|
+
db = DuckdbDB.get_database(temp_duckdb_file)
|
|
21
|
+
db.add_table(CREATE_DUCKDB_TABLE_SQL, FILL_DUCKDB_TABLE_SQL)
|
|
21
22
|
execute_init(project_folder, db)
|
|
22
23
|
execute_build(project_folder)
|
|
23
24
|
assert_introspections_equal(get_datasource_result(project_folder, db.datasource_name), "duckdb_introspections.yaml")
|
|
@@ -2,7 +2,7 @@ from pathlib import Path
|
|
|
2
2
|
|
|
3
3
|
import allure
|
|
4
4
|
import pytest
|
|
5
|
-
from databases.mysql_utils import MysqlDB
|
|
5
|
+
from databases.mysql_utils import CREATE_MYSQL_TABLE_SQL, FILL_MYSQL_TABLE_SQL, MysqlDB
|
|
6
6
|
from project_utils import execute_build, execute_init
|
|
7
7
|
from testcontainers.mysql import MySqlContainer
|
|
8
8
|
from utils.path_utils import get_datasource_result
|
|
@@ -20,7 +20,8 @@ def mysql_container():
|
|
|
20
20
|
@allure.title("Test databao build with MySQL")
|
|
21
21
|
@allure.description("Initialize a project with MySQL and build it, then compare results with expected introspection.")
|
|
22
22
|
def test_databao_build_mysql(project_folder: Path, mysql_container: MySqlContainer):
|
|
23
|
-
db = MysqlDB.
|
|
23
|
+
db = MysqlDB.get_database(mysql_container)
|
|
24
|
+
db.add_table(CREATE_MYSQL_TABLE_SQL, FILL_MYSQL_TABLE_SQL)
|
|
24
25
|
execute_init(project_folder, db)
|
|
25
26
|
execute_build(project_folder)
|
|
26
27
|
assert_introspections_equal(get_datasource_result(project_folder, db.datasource_name), "mysql_introspections.yaml")
|