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.
Files changed (141) hide show
  1. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/PKG-INFO +1 -1
  2. databao-0.3.3.dev3/e2e-tests/src/databases/duckdb_utils.py +118 -0
  3. databao-0.3.3.dev3/e2e-tests/src/databases/mysql_utils.py +168 -0
  4. databao-0.3.3.dev3/e2e-tests/src/databases/postgres_utils.py +209 -0
  5. databao-0.3.3.dev3/e2e-tests/src/databases/sqlite_utils.py +99 -0
  6. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_duckdb.py +3 -2
  7. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_mysql.py +3 -2
  8. databao-0.3.3.dev3/e2e-tests/tests/domains/test_postgres.py +48 -0
  9. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_sqlite.py +3 -2
  10. databao-0.3.3.dev3/e2e-tests/tests/resources/postgres_partitioned_tables_introspections.yaml +402 -0
  11. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/pyproject.toml +1 -1
  12. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/src/databao_snowflake_demo/app.py +4 -0
  13. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/uv.lock +4 -4
  14. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/__main__.py +18 -1
  15. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/app.py +2 -0
  16. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/app.py +39 -1
  17. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/cli.py +6 -0
  18. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/chat.py +178 -17
  19. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/datasource_manager.py +2 -0
  20. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/results.py +40 -23
  21. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/context_settings.py +2 -6
  22. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/welcome.py +31 -26
  23. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/__init__.py +2 -0
  24. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/query_executor.py +94 -0
  25. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/suggestions.py +36 -0
  26. databao-0.3.3.dev3/tests/test_app.py +45 -0
  27. databao-0.3.3.dev3/tests/test_query_executor.py +396 -0
  28. databao-0.3.3.dev3/tests/test_query_executor_race_conditions.py +545 -0
  29. databao-0.3.3.dev2/e2e-tests/src/databases/duckdb_utils.py +0 -116
  30. databao-0.3.3.dev2/e2e-tests/src/databases/mysql_utils.py +0 -165
  31. databao-0.3.3.dev2/e2e-tests/src/databases/postgres_utils.py +0 -168
  32. databao-0.3.3.dev2/e2e-tests/src/databases/sqlite_utils.py +0 -97
  33. databao-0.3.3.dev2/e2e-tests/tests/domains/test_postgres.py +0 -28
  34. databao-0.3.3.dev2/tests/test_app.py +0 -12
  35. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.cursor/rules/python-style.mdc +0 -0
  36. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/actions/setup-project/action.yml +0 -0
  37. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/e2e-tests.yml +0 -0
  38. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/publish-dev.yml +0 -0
  39. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/publish.yml +0 -0
  40. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.github/workflows/python-package.yml +0 -0
  41. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.gitignore +0 -0
  42. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.pre-commit-config.yaml +0 -0
  43. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/.python-version +0 -0
  44. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/CONTRIBUTING.md +0 -0
  45. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/LICENSE +0 -0
  46. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/Makefile +0 -0
  47. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/README.md +0 -0
  48. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/.gitignore +0 -0
  49. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/pytest.ini +0 -0
  50. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/__init__.py +0 -0
  51. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/__init__.py +0 -0
  52. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/bigquery_utils.py +0 -0
  53. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/databases/snowflake_utils.py +0 -0
  54. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/project_utils.py +0 -0
  55. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/__init__.py +0 -0
  56. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/path_utils.py +0 -0
  57. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/pexpect_utils.py +0 -0
  58. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/src/utils/yaml_compare.py +0 -0
  59. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/conftest.py +0 -0
  60. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_bigquery.py +0 -0
  61. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/domains/test_snowflake.py +0 -0
  62. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/bigquery_introspections.yaml +0 -0
  63. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/duckdb_introspections.yaml +0 -0
  64. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/mysql_introspections.yaml +0 -0
  65. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/postgres_introspections.yaml +0 -0
  66. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/snowflake_introspections.yaml +0 -0
  67. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/e2e-tests/tests/resources/sqlite_introspections.yaml +0 -0
  68. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/README.md +0 -0
  69. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/dce.ini +0 -0
  70. {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
  71. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/examples/src/files/documentation.md +0 -0
  72. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/examples/src/files/notes.txt +0 -0
  73. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/databao/domains/root/src/snowflake.yaml +0 -0
  74. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/setup.sql +0 -0
  75. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/examples/demo-snowflake-project/src/databao_snowflake_demo/__init__.py +0 -0
  76. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/pyproject.toml +0 -0
  77. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/scripts/generate_licenses.py +0 -0
  78. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/__init__.py +0 -0
  79. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/__init__.py +0 -0
  80. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/ask.py +0 -0
  81. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/build.py +0 -0
  82. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/context_engine_cli.py +0 -0
  83. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/__init__.py +0 -0
  84. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/add_datasource_config.py +0 -0
  85. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/datasource/check_datasource_connection.py +0 -0
  86. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/init.py +0 -0
  87. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/mcp.py +0 -0
  88. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/commands/status.py +0 -0
  89. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/executor_utils.py +0 -0
  90. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/__init__.py +0 -0
  91. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/llm_errors.py +0 -0
  92. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/log/logging.py +0 -0
  93. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/__init__.py +0 -0
  94. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/server.py +0 -0
  95. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/__init__.py +0 -0
  96. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/__init__.py +0 -0
  97. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/agent_factory.py +0 -0
  98. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/mcp/tools/databao_ask/tool.py +0 -0
  99. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/project/__init__.py +0 -0
  100. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/project/layout.py +0 -0
  101. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/__init__.py +0 -0
  102. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/assets/bao.png +0 -0
  103. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/__init__.py +0 -0
  104. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/datasource_form.py +0 -0
  105. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/icons.py +0 -0
  106. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/sidebar.py +0 -0
  107. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/components/status.py +0 -0
  108. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/__init__.py +0 -0
  109. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/chat_session.py +0 -0
  110. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/models/settings.py +0 -0
  111. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/__init__.py +0 -0
  112. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/agent_settings.py +0 -0
  113. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/chat.py +0 -0
  114. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/pages/general_settings.py +0 -0
  115. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/project_utils.py +0 -0
  116. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/build_service.py +0 -0
  117. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/chat_persistence.py +0 -0
  118. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/chat_title.py +0 -0
  119. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/dce_operations.py +0 -0
  120. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/llm_models.py +0 -0
  121. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/settings_persistence.py +0 -0
  122. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/services/storage.py +0 -0
  123. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/src/databao_cli/ui/streaming.py +0 -0
  124. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/__init__.py +0 -0
  125. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/__init__.py +0 -0
  126. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_check_datasource.py +0 -0
  127. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_project/databao/domains/root/dce.ini +0 -0
  128. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/check_datasource/test_project/databao/domains/root/src/myduck.yaml +0 -0
  129. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/conftest.py +0 -0
  130. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/__init__.py +0 -0
  131. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/get_loaded_plugins.py +0 -0
  132. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/plugins/test_plugins.py +0 -0
  133. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_add_datasource.py +0 -0
  134. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_ask.py +0 -0
  135. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_build.py +0 -0
  136. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_init.py +0 -0
  137. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_mcp.py +0 -0
  138. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/test_status.py +0 -0
  139. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/utils/__init__.py +0 -0
  140. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/tests/utils/project.py +0 -0
  141. {databao-0.3.3.dev2 → databao-0.3.3.dev3}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: databao
3
- Version: 0.3.3.dev2
3
+ Version: 0.3.3.dev3
4
4
  License-File: LICENSE
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: adbc-driver-manager>=1.10.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.prepare_database(temp_duckdb_file)
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.prepare_database(mysql_container)
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")