databao-context-engine 0.1.1__py3-none-any.whl → 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. databao_context_engine/__init__.py +32 -7
  2. databao_context_engine/build_sources/__init__.py +4 -0
  3. databao_context_engine/build_sources/{internal/build_runner.py → build_runner.py} +31 -27
  4. databao_context_engine/build_sources/build_service.py +53 -0
  5. databao_context_engine/build_sources/build_wiring.py +82 -0
  6. databao_context_engine/build_sources/export_results.py +41 -0
  7. databao_context_engine/build_sources/{internal/plugin_execution.py → plugin_execution.py} +11 -18
  8. databao_context_engine/cli/add_datasource_config.py +49 -44
  9. databao_context_engine/cli/commands.py +40 -55
  10. databao_context_engine/cli/info.py +3 -2
  11. databao_context_engine/databao_context_engine.py +127 -0
  12. databao_context_engine/databao_context_project_manager.py +147 -30
  13. databao_context_engine/{datasource_config → datasources}/check_config.py +31 -23
  14. databao_context_engine/datasources/datasource_context.py +90 -0
  15. databao_context_engine/datasources/datasource_discovery.py +143 -0
  16. databao_context_engine/datasources/types.py +194 -0
  17. databao_context_engine/generate_configs_schemas.py +4 -5
  18. databao_context_engine/init_project.py +25 -3
  19. databao_context_engine/introspection/property_extract.py +76 -57
  20. databao_context_engine/llm/__init__.py +10 -0
  21. databao_context_engine/llm/api.py +57 -0
  22. databao_context_engine/llm/descriptions/ollama.py +1 -3
  23. databao_context_engine/llm/errors.py +2 -8
  24. databao_context_engine/llm/factory.py +5 -2
  25. databao_context_engine/llm/install.py +26 -30
  26. databao_context_engine/llm/runtime.py +3 -5
  27. databao_context_engine/llm/service.py +1 -3
  28. databao_context_engine/mcp/mcp_runner.py +4 -2
  29. databao_context_engine/mcp/mcp_server.py +9 -11
  30. databao_context_engine/plugin_loader.py +110 -0
  31. databao_context_engine/pluginlib/build_plugin.py +12 -29
  32. databao_context_engine/pluginlib/config.py +16 -2
  33. databao_context_engine/plugins/{athena_db_plugin.py → databases/athena/athena_db_plugin.py} +3 -3
  34. databao_context_engine/plugins/databases/athena/athena_introspector.py +161 -0
  35. databao_context_engine/plugins/{base_db_plugin.py → databases/base_db_plugin.py} +6 -5
  36. databao_context_engine/plugins/databases/base_introspector.py +11 -12
  37. databao_context_engine/plugins/{clickhouse_db_plugin.py → databases/clickhouse/clickhouse_db_plugin.py} +3 -3
  38. databao_context_engine/plugins/databases/{clickhouse_introspector.py → clickhouse/clickhouse_introspector.py} +24 -16
  39. databao_context_engine/plugins/databases/duckdb/duckdb_db_plugin.py +12 -0
  40. databao_context_engine/plugins/databases/{duckdb_introspector.py → duckdb/duckdb_introspector.py} +7 -12
  41. databao_context_engine/plugins/databases/introspection_model_builder.py +1 -1
  42. databao_context_engine/plugins/databases/introspection_scope.py +11 -9
  43. databao_context_engine/plugins/databases/introspection_scope_matcher.py +2 -5
  44. databao_context_engine/plugins/{mssql_db_plugin.py → databases/mssql/mssql_db_plugin.py} +3 -3
  45. databao_context_engine/plugins/databases/{mssql_introspector.py → mssql/mssql_introspector.py} +29 -21
  46. databao_context_engine/plugins/{mysql_db_plugin.py → databases/mysql/mysql_db_plugin.py} +3 -3
  47. databao_context_engine/plugins/databases/{mysql_introspector.py → mysql/mysql_introspector.py} +26 -15
  48. databao_context_engine/plugins/databases/postgresql/__init__.py +0 -0
  49. databao_context_engine/plugins/databases/postgresql/postgresql_db_plugin.py +15 -0
  50. databao_context_engine/plugins/databases/{postgresql_introspector.py → postgresql/postgresql_introspector.py} +11 -18
  51. databao_context_engine/plugins/databases/snowflake/__init__.py +0 -0
  52. databao_context_engine/plugins/databases/snowflake/snowflake_db_plugin.py +15 -0
  53. databao_context_engine/plugins/databases/{snowflake_introspector.py → snowflake/snowflake_introspector.py} +49 -17
  54. databao_context_engine/plugins/databases/sqlite/__init__.py +0 -0
  55. databao_context_engine/plugins/databases/sqlite/sqlite_db_plugin.py +12 -0
  56. databao_context_engine/plugins/databases/sqlite/sqlite_introspector.py +241 -0
  57. databao_context_engine/plugins/duckdb_tools.py +18 -0
  58. databao_context_engine/plugins/files/__init__.py +0 -0
  59. databao_context_engine/plugins/{unstructured_files_plugin.py → files/unstructured_files_plugin.py} +1 -1
  60. databao_context_engine/plugins/plugin_loader.py +58 -52
  61. databao_context_engine/plugins/resources/parquet_introspector.py +8 -20
  62. databao_context_engine/plugins/{parquet_plugin.py → resources/parquet_plugin.py} +1 -3
  63. databao_context_engine/project/info.py +34 -2
  64. databao_context_engine/project/init_project.py +16 -7
  65. databao_context_engine/project/layout.py +14 -15
  66. databao_context_engine/retrieve_embeddings/__init__.py +3 -0
  67. databao_context_engine/retrieve_embeddings/retrieve_runner.py +17 -0
  68. databao_context_engine/retrieve_embeddings/{internal/retrieve_service.py → retrieve_service.py} +12 -19
  69. databao_context_engine/retrieve_embeddings/retrieve_wiring.py +46 -0
  70. databao_context_engine/serialization/__init__.py +0 -0
  71. databao_context_engine/{serialisation → serialization}/yaml.py +6 -6
  72. databao_context_engine/services/chunk_embedding_service.py +23 -11
  73. databao_context_engine/services/factories.py +1 -46
  74. databao_context_engine/services/persistence_service.py +11 -11
  75. databao_context_engine/storage/connection.py +11 -7
  76. databao_context_engine/storage/exceptions/exceptions.py +2 -2
  77. databao_context_engine/storage/migrate.py +3 -5
  78. databao_context_engine/storage/migrations/V01__init.sql +6 -31
  79. databao_context_engine/storage/models.py +2 -23
  80. databao_context_engine/storage/repositories/chunk_repository.py +16 -12
  81. databao_context_engine/storage/repositories/factories.py +1 -12
  82. databao_context_engine/storage/repositories/vector_search_repository.py +23 -16
  83. databao_context_engine/system/properties.py +4 -2
  84. databao_context_engine-0.1.5.dist-info/METADATA +228 -0
  85. databao_context_engine-0.1.5.dist-info/RECORD +135 -0
  86. {databao_context_engine-0.1.1.dist-info → databao_context_engine-0.1.5.dist-info}/WHEEL +1 -1
  87. databao_context_engine/build_sources/internal/build_service.py +0 -77
  88. databao_context_engine/build_sources/internal/build_wiring.py +0 -52
  89. databao_context_engine/build_sources/internal/export_results.py +0 -43
  90. databao_context_engine/build_sources/public/api.py +0 -4
  91. databao_context_engine/databao_engine.py +0 -85
  92. databao_context_engine/datasource_config/add_config.py +0 -50
  93. databao_context_engine/datasource_config/datasource_context.py +0 -60
  94. databao_context_engine/mcp/all_results_tool.py +0 -5
  95. databao_context_engine/mcp/retrieve_tool.py +0 -22
  96. databao_context_engine/plugins/databases/athena_introspector.py +0 -101
  97. databao_context_engine/plugins/duckdb_db_plugin.py +0 -12
  98. databao_context_engine/plugins/postgresql_db_plugin.py +0 -12
  99. databao_context_engine/plugins/snowflake_db_plugin.py +0 -12
  100. databao_context_engine/project/datasource_discovery.py +0 -141
  101. databao_context_engine/project/runs.py +0 -39
  102. databao_context_engine/project/types.py +0 -134
  103. databao_context_engine/retrieve_embeddings/internal/export_results.py +0 -12
  104. databao_context_engine/retrieve_embeddings/internal/retrieve_runner.py +0 -34
  105. databao_context_engine/retrieve_embeddings/internal/retrieve_wiring.py +0 -29
  106. databao_context_engine/retrieve_embeddings/public/api.py +0 -3
  107. databao_context_engine/services/run_name_policy.py +0 -8
  108. databao_context_engine/storage/repositories/datasource_run_repository.py +0 -136
  109. databao_context_engine/storage/repositories/run_repository.py +0 -157
  110. databao_context_engine-0.1.1.dist-info/METADATA +0 -186
  111. databao_context_engine-0.1.1.dist-info/RECORD +0 -135
  112. /databao_context_engine/{build_sources/internal → datasources}/__init__.py +0 -0
  113. /databao_context_engine/{build_sources/public → plugins/databases/athena}/__init__.py +0 -0
  114. /databao_context_engine/{datasource_config → plugins/databases/clickhouse}/__init__.py +0 -0
  115. /databao_context_engine/{retrieve_embeddings/internal → plugins/databases/duckdb}/__init__.py +0 -0
  116. /databao_context_engine/{retrieve_embeddings/public → plugins/databases/mssql}/__init__.py +0 -0
  117. /databao_context_engine/{serialisation → plugins/databases/mysql}/__init__.py +0 -0
  118. {databao_context_engine-0.1.1.dist-info → databao_context_engine-0.1.5.dist-info}/entry_points.txt +0 -0
@@ -6,10 +6,11 @@ from pydantic import BaseModel, ConfigDict, field_validator, model_validator
6
6
 
7
7
 
8
8
  class ScopeIncludeRule(BaseModel):
9
- """
10
- Allowlist selector.
11
- - catalog: optional glob pattern
12
- - schemas: optional list of glob patterns (string also accepted and normalized to a list)
9
+ """Allowlist selector.
10
+
11
+ Attributes:
12
+ catalog: optional glob pattern
13
+ schemas: optional list of glob patterns (string also accepted and normalized to a list)
13
14
 
14
15
  A rule must specify at least one of: catalog, schemas.
15
16
  """
@@ -36,11 +37,12 @@ class ScopeIncludeRule(BaseModel):
36
37
 
37
38
 
38
39
  class ScopeExcludeRule(BaseModel):
39
- """
40
- Denylist selector.
41
- - catalog: optional glob pattern
42
- - schemas: optional list of glob patterns (string also accepted)
43
- - except_schemas: optional list of glob patterns (string also accepted)
40
+ """Denylist selector.
41
+
42
+ Attributes:
43
+ catalog: optional glob pattern
44
+ schemas: optional list of glob patterns (string also accepted)
45
+ except_schemas: optional list of glob patterns (string also accepted)
44
46
 
45
47
  If a target matches the rule but also matches except_schemas, it is NOT excluded by this rule.
46
48
  """
@@ -10,17 +10,14 @@ from databao_context_engine.plugins.databases.introspection_scope import (
10
10
 
11
11
  @dataclass(frozen=True)
12
12
  class ScopeSelection:
13
- """
14
- The final catalog+schema scope to introspect.
15
- """
13
+ """The final catalog+schema scope to introspect."""
16
14
 
17
15
  catalogs: list[str]
18
16
  schemas_per_catalog: dict[str, list[str]]
19
17
 
20
18
 
21
19
  class IntrospectionScopeMatcher:
22
- """
23
- Applies include/exclude rules (glob matching, case-insensitive) to a discovered set of catalogs/schemas.
20
+ """Applies include/exclude rules (glob matching, case-insensitive) to a discovered set of catalogs/schemas.
24
21
 
25
22
  Semantics:
26
23
  - If include is empty => start from "everything"
@@ -1,11 +1,11 @@
1
- from databao_context_engine.plugins.base_db_plugin import BaseDatabasePlugin
2
- from databao_context_engine.plugins.databases.mssql_introspector import MSSQLConfigFile, MSSQLIntrospector
1
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabasePlugin
2
+ from databao_context_engine.plugins.databases.mssql.mssql_introspector import MSSQLConfigFile, MSSQLIntrospector
3
3
 
4
4
 
5
5
  class MSSQLDbPlugin(BaseDatabasePlugin[MSSQLConfigFile]):
6
6
  id = "jetbrains/mssql"
7
7
  name = "MSSQL DB Plugin"
8
- supported = {"databases/mssql"}
8
+ supported = {"mssql"}
9
9
  config_file_type = MSSQLConfigFile
10
10
 
11
11
  def __init__(self):
@@ -1,21 +1,36 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Mapping
3
+ from typing import Annotated, Any, Mapping
4
4
 
5
5
  from mssql_python import connect # type: ignore[import-untyped]
6
- from pydantic import Field
6
+ from pydantic import BaseModel, Field
7
7
 
8
- from databao_context_engine.plugins.base_db_plugin import BaseDatabaseConfigFile
8
+ from databao_context_engine.pluginlib.config import ConfigPropertyAnnotation
9
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabaseConfigFile
9
10
  from databao_context_engine.plugins.databases.base_introspector import BaseIntrospector, SQLQuery
10
11
  from databao_context_engine.plugins.databases.databases_types import DatabaseSchema, DatabaseTable
11
12
  from databao_context_engine.plugins.databases.introspection_model_builder import IntrospectionModelBuilder
12
13
 
13
14
 
15
+ class MSSQLConnectionProperties(BaseModel):
16
+ host: Annotated[str, ConfigPropertyAnnotation(default_value="localhost", required=True)]
17
+ port: int | None = None
18
+ instance_name: str | None = None
19
+ database: str | None = None
20
+ user: str | None = None
21
+ password: Annotated[str, ConfigPropertyAnnotation(secret=True)]
22
+ encrypt: str | None = None
23
+ additional_properties: dict[str, Any] = {}
24
+
25
+ def to_mssql_kwargs(self) -> dict[str, Any]:
26
+ kwargs = self.model_dump(exclude={"additional_properties"}, exclude_none=True)
27
+ kwargs.update(self.additional_properties)
28
+ return kwargs
29
+
30
+
14
31
  class MSSQLConfigFile(BaseDatabaseConfigFile):
15
- type: str = Field(default="databases/mssql")
16
- connection: dict[str, Any] = Field(
17
- description="Connection parameters for the Microsoft Server SQL database. It can contain any of the keys supported by the Microsoft Server connection library"
18
- )
32
+ type: str = Field(default="mssql")
33
+ connection: MSSQLConnectionProperties
19
34
 
20
35
 
21
36
  class MSSQLIntrospector(BaseIntrospector[MSSQLConfigFile]):
@@ -40,24 +55,18 @@ class MSSQLIntrospector(BaseIntrospector[MSSQLConfigFile]):
40
55
  )
41
56
  supports_catalogs = True
42
57
 
43
- def _connect(self, file_config: MSSQLConfigFile):
58
+ def _connect(self, file_config: MSSQLConfigFile, *, catalog: str | None = None):
44
59
  connection = file_config.connection
45
- if not isinstance(connection, Mapping):
46
- raise ValueError("Invalid YAML config: 'connection' must be a mapping of connection parameters")
47
-
48
- connection_string = self._create_connection_string_for_config(connection)
49
- return connect(connection_string)
50
60
 
51
- def _connect_to_catalog(self, file_config: MSSQLConfigFile, catalog: str):
52
- base_cfg = file_config.connection or {}
53
- cfg_for_db: dict[str, Any] = dict(base_cfg)
54
- cfg_for_db["database"] = catalog
61
+ connection_kwargs = connection.to_mssql_kwargs()
62
+ if catalog:
63
+ connection_kwargs["database"] = catalog
55
64
 
56
- connection_string = self._create_connection_string_for_config(cfg_for_db)
65
+ connection_string = self._create_connection_string_for_config(connection_kwargs)
57
66
  return connect(connection_string)
58
67
 
59
68
  def _get_catalogs(self, connection, file_config: MSSQLConfigFile) -> list[str]:
60
- database = file_config.connection.get("database")
69
+ database = file_config.connection.database
61
70
  if isinstance(database, str) and database:
62
71
  return [database]
63
72
 
@@ -413,8 +422,7 @@ class MSSQLIntrospector(BaseIntrospector[MSSQLConfigFile]):
413
422
  "trust_server_certificate": "yes" if file_config.get("trust_server_certificate") else None,
414
423
  }
415
424
 
416
- connection_string = ";".join(f"{k}={v}" for k, v in connection_parts.items() if v is not None)
417
- return connection_string
425
+ return ";".join(f"{k}={v}" for k, v in connection_parts.items() if v is not None)
418
426
 
419
427
  def _fetchall_dicts(self, connection, sql: str, params) -> list[dict]:
420
428
  with connection.cursor() as cursor:
@@ -1,11 +1,11 @@
1
- from databao_context_engine.plugins.base_db_plugin import BaseDatabasePlugin
2
- from databao_context_engine.plugins.databases.mysql_introspector import MySQLConfigFile, MySQLIntrospector
1
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabasePlugin
2
+ from databao_context_engine.plugins.databases.mysql.mysql_introspector import MySQLConfigFile, MySQLIntrospector
3
3
 
4
4
 
5
5
  class MySQLDbPlugin(BaseDatabasePlugin[MySQLConfigFile]):
6
6
  id = "jetbrains/mysql"
7
7
  name = "MySQL DB Plugin"
8
- supported = {"databases/mysql"}
8
+ supported = {"mysql"}
9
9
  config_file_type = MySQLConfigFile
10
10
 
11
11
  def __init__(self):
@@ -1,18 +1,33 @@
1
- from typing import Any, Mapping
1
+ from typing import Annotated, Any
2
2
 
3
3
  import pymysql
4
- from pydantic import Field
4
+ from pydantic import BaseModel, Field
5
5
  from pymysql.constants import CLIENT
6
6
 
7
- from databao_context_engine.plugins.base_db_plugin import BaseDatabaseConfigFile
7
+ from databao_context_engine.pluginlib.config import ConfigPropertyAnnotation
8
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabaseConfigFile
8
9
  from databao_context_engine.plugins.databases.base_introspector import BaseIntrospector, SQLQuery
9
10
  from databao_context_engine.plugins.databases.databases_types import DatabaseSchema, DatabaseTable
10
11
  from databao_context_engine.plugins.databases.introspection_model_builder import IntrospectionModelBuilder
11
12
 
12
13
 
14
+ class MySQLConnectionProperties(BaseModel):
15
+ host: Annotated[str, ConfigPropertyAnnotation(default_value="localhost", required=True)]
16
+ port: int | None = None
17
+ database: str | None = None
18
+ user: str | None = None
19
+ password: Annotated[str, ConfigPropertyAnnotation(secret=True)]
20
+ additional_properties: dict[str, Any] = {}
21
+
22
+ def to_pymysql_kwargs(self) -> dict[str, Any]:
23
+ kwargs = self.model_dump(exclude={"additional_properties"}, exclude_none=True)
24
+ kwargs.update(self.additional_properties)
25
+ return kwargs
26
+
27
+
13
28
  class MySQLConfigFile(BaseDatabaseConfigFile):
14
- connection: dict[str, Any]
15
- type: str = Field(default="databases/mysql")
29
+ connection: MySQLConnectionProperties
30
+ type: str = Field(default="mysql")
16
31
 
17
32
 
18
33
  class MySQLIntrospector(BaseIntrospector[MySQLConfigFile]):
@@ -20,22 +35,18 @@ class MySQLIntrospector(BaseIntrospector[MySQLConfigFile]):
20
35
 
21
36
  supports_catalogs = True
22
37
 
23
- def _connect(self, file_config: MySQLConfigFile):
24
- connection = file_config.connection
25
- if not isinstance(connection, Mapping):
26
- raise ValueError("Invalid YAML config: 'connection' must be a mapping of connection parameters")
38
+ def _connect(self, file_config: MySQLConfigFile, *, catalog: str | None = None):
39
+ connection_kwargs = file_config.connection.to_pymysql_kwargs()
40
+
41
+ if catalog:
42
+ connection_kwargs["database"] = catalog
27
43
 
28
44
  return pymysql.connect(
29
- **connection,
45
+ **connection_kwargs,
30
46
  cursorclass=pymysql.cursors.DictCursor,
31
47
  client_flag=CLIENT.MULTI_STATEMENTS | CLIENT.MULTI_RESULTS,
32
48
  )
33
49
 
34
- def _connect_to_catalog(self, file_config: MySQLConfigFile, catalog: str):
35
- cfg = dict(file_config.connection or {})
36
- cfg["database"] = catalog
37
- return self._connect(MySQLConfigFile(connection=cfg))
38
-
39
50
  def _get_catalogs(self, connection, file_config: MySQLConfigFile) -> list[str]:
40
51
  with connection.cursor() as cur:
41
52
  cur.execute(
@@ -0,0 +1,15 @@
1
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabasePlugin
2
+ from databao_context_engine.plugins.databases.postgresql.postgresql_introspector import (
3
+ PostgresConfigFile,
4
+ PostgresqlIntrospector,
5
+ )
6
+
7
+
8
+ class PostgresqlDbPlugin(BaseDatabasePlugin[PostgresConfigFile]):
9
+ id = "jetbrains/postgres"
10
+ name = "PostgreSQL DB Plugin"
11
+ supported = {"postgres"}
12
+ config_file_type = PostgresConfigFile
13
+
14
+ def __init__(self):
15
+ super().__init__(PostgresqlIntrospector())
@@ -5,7 +5,7 @@ import asyncpg
5
5
  from pydantic import BaseModel, Field
6
6
 
7
7
  from databao_context_engine.pluginlib.config import ConfigPropertyAnnotation
8
- from databao_context_engine.plugins.base_db_plugin import BaseDatabaseConfigFile
8
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabaseConfigFile
9
9
  from databao_context_engine.plugins.databases.base_introspector import BaseIntrospector, SQLQuery
10
10
  from databao_context_engine.plugins.databases.databases_types import DatabaseSchema
11
11
  from databao_context_engine.plugins.databases.introspection_model_builder import IntrospectionModelBuilder
@@ -16,12 +16,12 @@ class PostgresConnectionProperties(BaseModel):
16
16
  port: int | None = None
17
17
  database: str | None = None
18
18
  user: str | None = None
19
- password: str | None = None
19
+ password: Annotated[str, ConfigPropertyAnnotation(secret=True)]
20
20
  additional_properties: dict[str, Any] = {}
21
21
 
22
22
 
23
23
  class PostgresConfigFile(BaseDatabaseConfigFile):
24
- type: str = Field(default="databases/postgres")
24
+ type: str = Field(default="postgres")
25
25
  connection: PostgresConnectionProperties
26
26
 
27
27
 
@@ -81,12 +81,14 @@ class PostgresqlIntrospector(BaseIntrospector[PostgresConfigFile]):
81
81
  if self.supports_catalogs:
82
82
  sql = "SELECT catalog_name, schema_name FROM information_schema.schemata WHERE catalog_name = ANY($1)"
83
83
  return SQLQuery(sql, (catalogs,))
84
- else:
85
- sql = "SELECT schema_name FROM information_schema.schemata"
86
- return SQLQuery(sql, None)
87
84
 
88
- def _connect(self, file_config: PostgresConfigFile):
85
+ sql = "SELECT schema_name FROM information_schema.schemata"
86
+ return SQLQuery(sql, None)
87
+
88
+ def _connect(self, file_config: PostgresConfigFile, *, catalog: str | None = None):
89
89
  kwargs = self._create_connection_kwargs(file_config.connection)
90
+ if catalog:
91
+ kwargs["database"] = catalog
90
92
  return _SyncAsyncpgConnection(kwargs)
91
93
 
92
94
  def _fetchall_dicts(self, connection: _SyncAsyncpgConnection, sql: str, params) -> list[dict]:
@@ -97,13 +99,7 @@ class PostgresqlIntrospector(BaseIntrospector[PostgresConfigFile]):
97
99
  if database is not None:
98
100
  return [database]
99
101
 
100
- rows = connection.fetch_scalar_values("SELECT datname FROM pg_catalog.pg_database WHERE datistemplate = false")
101
- return rows
102
-
103
- def _connect_to_catalog(self, file_config: PostgresConfigFile, catalog: str):
104
- cfg = file_config.model_copy(deep=True)
105
- cfg.connection.database = catalog
106
- return self._connect(cfg)
102
+ return connection.fetch_scalar_values("SELECT datname FROM pg_catalog.pg_database WHERE datistemplate = false")
107
103
 
108
104
  def collect_catalog_model(
109
105
  self, connection: _SyncAsyncpgConnection, catalog: str, schemas: list[str]
@@ -408,10 +404,7 @@ class PostgresqlIntrospector(BaseIntrospector[PostgresConfigFile]):
408
404
  }
409
405
  connection_parts.update(connection_config.additional_properties)
410
406
 
411
- connection_string = " ".join(
412
- f"{k}={_escape_pg_value(str(v))}" for k, v in connection_parts.items() if v is not None
413
- )
414
- return connection_string
407
+ return " ".join(f"{k}={_escape_pg_value(str(v))}" for k, v in connection_parts.items() if v is not None)
415
408
 
416
409
  def _create_connection_kwargs(self, connection_config: PostgresConnectionProperties) -> dict[str, Any]:
417
410
  kwargs: dict[str, Any] = {
@@ -0,0 +1,15 @@
1
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabasePlugin
2
+ from databao_context_engine.plugins.databases.snowflake.snowflake_introspector import (
3
+ SnowflakeConfigFile,
4
+ SnowflakeIntrospector,
5
+ )
6
+
7
+
8
+ class SnowflakeDbPlugin(BaseDatabasePlugin[SnowflakeConfigFile]):
9
+ id = "jetbrains/snowflake"
10
+ name = "Snowflake DB Plugin"
11
+ supported = {"snowflake"}
12
+ config_file_type = SnowflakeConfigFile
13
+
14
+ def __init__(self):
15
+ super().__init__(SnowflakeIntrospector())
@@ -1,22 +1,57 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Any, Dict, List, Mapping
3
+ from typing import Annotated, Any, Dict, List
4
4
 
5
5
  import snowflake.connector
6
- from pydantic import Field
6
+ from pydantic import BaseModel, Field
7
7
  from snowflake.connector import DictCursor
8
8
 
9
- from databao_context_engine.plugins.base_db_plugin import BaseDatabaseConfigFile
9
+ from databao_context_engine.pluginlib.config import ConfigPropertyAnnotation
10
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabaseConfigFile
10
11
  from databao_context_engine.plugins.databases.base_introspector import BaseIntrospector, SQLQuery
11
12
  from databao_context_engine.plugins.databases.databases_types import DatabaseSchema
12
13
  from databao_context_engine.plugins.databases.introspection_model_builder import IntrospectionModelBuilder
13
14
 
14
15
 
16
+ class SnowflakePasswordAuth(BaseModel):
17
+ password: Annotated[str, ConfigPropertyAnnotation(secret=True)]
18
+
19
+
20
+ class SnowflakeKeyPairAuth(BaseModel):
21
+ private_key_file: str | None = None
22
+ private_key_file_pwd: str | None = None
23
+ private_key: Annotated[str | None, ConfigPropertyAnnotation(secret=True)] = None
24
+
25
+
26
+ class SnowflakeSSOAuth(BaseModel):
27
+ authenticator: str = Field(description='e.g. "externalbrowser"')
28
+
29
+
30
+ class SnowflakeConnectionProperties(BaseModel):
31
+ account: Annotated[str, ConfigPropertyAnnotation(required=True)]
32
+ warehouse: str | None = None
33
+ database: str | None = None
34
+ user: str | None = None
35
+ role: str | None = None
36
+ auth: SnowflakePasswordAuth | SnowflakeKeyPairAuth | SnowflakeSSOAuth
37
+ additional_properties: dict[str, Any] = {}
38
+
39
+ def to_snowflake_kwargs(self) -> dict[str, Any]:
40
+ kwargs = self.model_dump(
41
+ exclude={
42
+ "additional_properties": True,
43
+ },
44
+ exclude_none=True,
45
+ )
46
+ auth_fields = kwargs.pop("auth", {})
47
+ kwargs.update(auth_fields)
48
+ kwargs.update(self.additional_properties)
49
+ return kwargs
50
+
51
+
15
52
  class SnowflakeConfigFile(BaseDatabaseConfigFile):
16
- type: str = Field(default="databases/snowflake")
17
- connection: dict[str, Any] = Field(
18
- description="Connection parameters for Snowflake. It can contain any of the keys supported by the Snowflake connection library"
19
- )
53
+ type: str = Field(default="snowflake")
54
+ connection: SnowflakeConnectionProperties
20
55
 
21
56
 
22
57
  class SnowflakeIntrospector(BaseIntrospector[SnowflakeConfigFile]):
@@ -26,22 +61,19 @@ class SnowflakeIntrospector(BaseIntrospector[SnowflakeConfigFile]):
26
61
  _IGNORED_CATALOGS = {"STREAMLIT_APPS"}
27
62
  supports_catalogs = True
28
63
 
29
- def _connect(self, file_config: SnowflakeConfigFile):
64
+ def _connect(self, file_config: SnowflakeConfigFile, *, catalog: str | None = None):
30
65
  connection = file_config.connection
31
- if not isinstance(connection, Mapping):
32
- raise ValueError("Invalid YAML config: 'connection' must be a mapping of connection parameters")
33
66
  snowflake.connector.paramstyle = "qmark"
67
+ connection_kwargs = connection.to_snowflake_kwargs()
68
+ if catalog:
69
+ connection_kwargs["database"] = catalog
70
+
34
71
  return snowflake.connector.connect(
35
- **connection,
72
+ **connection_kwargs,
36
73
  )
37
74
 
38
- def _connect_to_catalog(self, file_config: SnowflakeConfigFile, catalog: str):
39
- cfg = dict(file_config.connection or {})
40
- cfg["database"] = catalog
41
- return snowflake.connector.connect(**cfg)
42
-
43
75
  def _get_catalogs(self, connection, file_config: SnowflakeConfigFile) -> list[str]:
44
- database = file_config.connection.get("database")
76
+ database = file_config.connection.database
45
77
  if database:
46
78
  return [database]
47
79
 
@@ -0,0 +1,12 @@
1
+ from databao_context_engine.plugins.databases.base_db_plugin import BaseDatabasePlugin
2
+ from databao_context_engine.plugins.databases.sqlite.sqlite_introspector import SQLiteConfigFile, SQLiteIntrospector
3
+
4
+
5
+ class SQLiteDbPlugin(BaseDatabasePlugin[SQLiteConfigFile]):
6
+ id = "jetbrains/sqlite"
7
+ name = "SQLite Plugin"
8
+ supported = {"sqlite"}
9
+ config_file_type = SQLiteConfigFile
10
+
11
+ def __init__(self):
12
+ super().__init__(SQLiteIntrospector())