codegraph-engine 3.0.0__2-py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. codegraph/__init__.py +37 -0
  2. codegraph/agent.py +26 -0
  3. codegraph/agent_brain.py +2212 -0
  4. codegraph/agent_capabilities.py +4058 -0
  5. codegraph/agent_rules.py +531 -0
  6. codegraph/api_drift.py +455 -0
  7. codegraph/architecture.py +371 -0
  8. codegraph/async_queue/__init__.py +50 -0
  9. codegraph/async_queue/detectors/__init__.py +48 -0
  10. codegraph/async_queue/detectors/celery.py +160 -0
  11. codegraph/async_queue/detectors/kafka.py +168 -0
  12. codegraph/async_queue/detectors/rabbitmq.py +116 -0
  13. codegraph/async_queue/detectors/redis.py +130 -0
  14. codegraph/async_queue/detectors/sqs.py +135 -0
  15. codegraph/async_queue/models.py +161 -0
  16. codegraph/async_queue/otel_models.py +74 -0
  17. codegraph/async_queue/otel_parser.py +337 -0
  18. codegraph/async_queue/reconciler.py +427 -0
  19. codegraph/async_queue/scanner.py +291 -0
  20. codegraph/async_queue/traversal.py +447 -0
  21. codegraph/audit.py +106 -0
  22. codegraph/binding_resolver.py +616 -0
  23. codegraph/branch_comparison.py +197 -0
  24. codegraph/cache.py +95 -0
  25. codegraph/change_impact.py +547 -0
  26. codegraph/cli.py +2436 -0
  27. codegraph/cli_output.py +205 -0
  28. codegraph/config.py +45 -0
  29. codegraph/constraints.py +238 -0
  30. codegraph/context.py +2182 -0
  31. codegraph/context_freshness.py +351 -0
  32. codegraph/database/__init__.py +72 -0
  33. codegraph/database/extractor.py +3651 -0
  34. codegraph/database/interrogation.py +1494 -0
  35. codegraph/database/models.py +310 -0
  36. codegraph/database/schema_drift.py +862 -0
  37. codegraph/epistemic.py +200 -0
  38. codegraph/errors.py +282 -0
  39. codegraph/evidence/__init__.py +15 -0
  40. codegraph/evidence/citations.py +418 -0
  41. codegraph/evidence_contract.py +486 -0
  42. codegraph/frameworks.py +960 -0
  43. codegraph/frameworks_nestjs.py +502 -0
  44. codegraph/frameworks_nextjs.py +337 -0
  45. codegraph/frameworks_react.py +457 -0
  46. codegraph/freshness.py +335 -0
  47. codegraph/frontend_html.py +109 -0
  48. codegraph/git.py +362 -0
  49. codegraph/git_state.py +545 -0
  50. codegraph/graph/__init__.py +46 -0
  51. codegraph/graph/models.py +56 -0
  52. codegraph/graph/traversal.py +1993 -0
  53. codegraph/indexing/__init__.py +24 -0
  54. codegraph/indexing/classifier.py +564 -0
  55. codegraph/indexing/indexer.py +2578 -0
  56. codegraph/indexing/models.py +427 -0
  57. codegraph/indexing/parser.py +3404 -0
  58. codegraph/indexing/pool.py +136 -0
  59. codegraph/indexing/scanner.py +211 -0
  60. codegraph/indexing/telemetry.py +326 -0
  61. codegraph/indexing/templates.py +418 -0
  62. codegraph/indexing/test_framework.py +116 -0
  63. codegraph/installer.py +1702 -0
  64. codegraph/interrogation.py +2355 -0
  65. codegraph/llm/__init__.py +3 -0
  66. codegraph/llm/base.py +15 -0
  67. codegraph/llm/context.py +20 -0
  68. codegraph/mcp/__init__.py +3 -0
  69. codegraph/mcp/server.py +1476 -0
  70. codegraph/mcp_diagnostics.py +882 -0
  71. codegraph/memory/__init__.py +3 -0
  72. codegraph/memory/store.py +46 -0
  73. codegraph/models.py +310 -0
  74. codegraph/monorepo.py +925 -0
  75. codegraph/observability.py +262 -0
  76. codegraph/optimizer.py +1014 -0
  77. codegraph/planner.py +417 -0
  78. codegraph/process_lifecycle.py +1153 -0
  79. codegraph/py.typed +1 -0
  80. codegraph/query_expansion.py +199 -0
  81. codegraph/ranking.py +408 -0
  82. codegraph/refactor/__init__.py +36 -0
  83. codegraph/refactor/models.py +114 -0
  84. codegraph/refactor/renamer.py +844 -0
  85. codegraph/refactor/transactions.py +414 -0
  86. codegraph/resolver.py +3968 -0
  87. codegraph/resources/__init__.py +46 -0
  88. codegraph/resources/cache.py +117 -0
  89. codegraph/resources/coalescer.py +83 -0
  90. codegraph/resources/debouncer.py +98 -0
  91. codegraph/resources/governor.py +219 -0
  92. codegraph/resources/monitor.py +102 -0
  93. codegraph/resources/policy.py +123 -0
  94. codegraph/retrieval_policy.py +320 -0
  95. codegraph/roblox.py +2174 -0
  96. codegraph/route_composer.py +363 -0
  97. codegraph/route_topology.py +172 -0
  98. codegraph/runtime/__init__.py +51 -0
  99. codegraph/runtime/collector.py +155 -0
  100. codegraph/runtime/db_watcher.py +191 -0
  101. codegraph/runtime/ingestor.py +692 -0
  102. codegraph/runtime/models.py +130 -0
  103. codegraph/runtime/port_inspector.py +304 -0
  104. codegraph/runtime/reconciliation.py +492 -0
  105. codegraph/runtime/runner.py +353 -0
  106. codegraph/runtime/trace_linker.py +175 -0
  107. codegraph/search/__init__.py +25 -0
  108. codegraph/search/hybrid.py +846 -0
  109. codegraph/search/semantic.py +28 -0
  110. codegraph/security/__init__.py +51 -0
  111. codegraph/security/paths.py +189 -0
  112. codegraph/security/redaction.py +633 -0
  113. codegraph/semantic_conflicts.py +270 -0
  114. codegraph/semantic_decorators.py +372 -0
  115. codegraph/structural_diff.py +542 -0
  116. codegraph/styles.py +144 -0
  117. codegraph/symbol_history.py +277 -0
  118. codegraph/target_resolver.py +348 -0
  119. codegraph/task.py +637 -0
  120. codegraph/tool_selection_eval.py +1158 -0
  121. codegraph/tsconfig.py +236 -0
  122. codegraph/ui/__init__.py +6 -0
  123. codegraph/ui/server.py +755 -0
  124. codegraph/watcher.py +323 -0
  125. codegraph_engine-3.0.0.dist-info/METADATA +868 -0
  126. codegraph_engine-3.0.0.dist-info/RECORD +130 -0
  127. codegraph_engine-3.0.0.dist-info/WHEEL +6 -0
  128. codegraph_engine-3.0.0.dist-info/entry_points.txt +2 -0
  129. codegraph_engine-3.0.0.dist-info/licenses/LICENSE +21 -0
  130. codegraph_engine-3.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,351 @@
1
+ """Context Freshness Validation Engine.
2
+
3
+ Validates whether a previously compiled ContextPacket remains valid against
4
+ the current repository state or whether it has become STALE or PARTIALLY_STALE.
5
+
6
+ CRITICAL INVARIANT:
7
+ Do NOT invalidate context merely because an unrelated file changed!
8
+ A context containing files A/B must remain VALID when an unrelated file Z changes.
9
+ """
10
+ from __future__ import annotations
11
+
12
+ import re
13
+ import sqlite3
14
+ import subprocess
15
+ from dataclasses import dataclass, field
16
+ from enum import StrEnum
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ from codegraph.git_state import GitStateReport, get_git_state
21
+
22
+
23
+ class ContextFreshnessStatus(StrEnum):
24
+ VALID = "VALID" # None of the files/symbols in the context were modified
25
+ PARTIALLY_STALE = "PARTIALLY_STALE" # Secondary files/tests in context changed, primary target unaffected
26
+ STALE = "STALE" # Primary targets or core symbols in context were modified or removed
27
+ UNKNOWN = "UNKNOWN" # Cannot verify (e.g. no git history or commit not found)
28
+
29
+
30
+ @dataclass
31
+ class ContextFreshnessReport:
32
+ status: ContextFreshnessStatus
33
+ base_commit: str | None
34
+ current_head: str | None
35
+ repository_dirty: bool
36
+ context_files: list[str]
37
+ changed_relevant_files: list[str] = field(default_factory=list)
38
+ unrelated_changed_files: list[str] = field(default_factory=list)
39
+ invalidated_symbols: list[str] = field(default_factory=list)
40
+ reason: str = ""
41
+ recommended_action: str = "NONE" # "NONE" | "RECOMPILE_CONTEXT" | "REFRESH_PERIPHERAL"
42
+
43
+ @property
44
+ def is_valid(self) -> bool:
45
+ return self.status == ContextFreshnessStatus.VALID
46
+
47
+ def as_dict(self) -> dict[str, Any]:
48
+ return {
49
+ "status": self.status.value,
50
+ "base_commit": self.base_commit,
51
+ "current_head": self.current_head,
52
+ "repository_dirty": self.repository_dirty,
53
+ "context_files": self.context_files,
54
+ "changed_relevant_files": self.changed_relevant_files,
55
+ "unrelated_changed_files": self.unrelated_changed_files,
56
+ "invalidated_symbols": self.invalidated_symbols,
57
+ "reason": self.reason,
58
+ "recommended_action": self.recommended_action,
59
+ }
60
+
61
+
62
+ def _run_git(repository: Path, *args: str, timeout: int = 10) -> str | None:
63
+ for arg in args:
64
+ if any(c in arg for c in (";", "|", "&", "`", "$", "\n", "\r")):
65
+ return None
66
+ try:
67
+ res = subprocess.run(
68
+ ["git", *args],
69
+ cwd=str(repository),
70
+ capture_output=True,
71
+ text=True,
72
+ encoding="utf-8",
73
+ errors="replace",
74
+ timeout=timeout,
75
+ )
76
+ return res.stdout if res.returncode == 0 else None
77
+ except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
78
+ return None
79
+
80
+
81
+ _REF_PATTERN = re.compile(r"^[A-Za-z0-9_.~^/-]{1,100}$")
82
+
83
+ _COMMIT_DIFF_FILES_CACHE: dict[tuple[str, str, str], tuple[str, ...]] = {}
84
+
85
+
86
+ def _get_cached_commit_diff_files(repository: Path, base: str, head: str) -> tuple[str, ...] | None:
87
+ """Cache immutable diff between two commits to avoid repeated subprocess invocations."""
88
+ cache_key = (str(repository), base, head)
89
+ if cache_key in _COMMIT_DIFF_FILES_CACHE:
90
+ return _COMMIT_DIFF_FILES_CACHE[cache_key]
91
+ diff_raw = _run_git(repository, "diff", "--name-only", base, head)
92
+ if diff_raw is None:
93
+ return None
94
+ files = tuple(line.strip() for line in diff_raw.splitlines() if line.strip())
95
+ if len(_COMMIT_DIFF_FILES_CACHE) > 500:
96
+ _COMMIT_DIFF_FILES_CACHE.clear()
97
+ _COMMIT_DIFF_FILES_CACHE[cache_key] = files
98
+ return files
99
+
100
+
101
+ def check_context_freshness(
102
+ context_packet: dict[str, Any] | Any,
103
+ repository: Path,
104
+ con: sqlite3.Connection | None = None,
105
+ state: GitStateReport | None = None,
106
+ ) -> ContextFreshnessReport:
107
+ """Evaluate whether previously generated ContextPacket is still valid against repository state.
108
+
109
+ Guarantees:
110
+ - Context remains VALID when changes occur only in unrelated files.
111
+ - Becomes PARTIALLY_STALE if secondary files (e.g. related tests) changed.
112
+ - Becomes STALE if primary target symbols or core files changed.
113
+ """
114
+ # 1. Normalize packet data
115
+ packet_dict: dict[str, Any]
116
+ if hasattr(context_packet, "model_dump"):
117
+ packet_dict = context_packet.model_dump()
118
+ elif hasattr(context_packet, "as_dict"):
119
+ packet_dict = context_packet.as_dict()
120
+ elif isinstance(context_packet, dict):
121
+ packet_dict = context_packet
122
+ else:
123
+ return ContextFreshnessReport(
124
+ status=ContextFreshnessStatus.UNKNOWN,
125
+ base_commit=None,
126
+ current_head=None,
127
+ repository_dirty=False,
128
+ context_files=[],
129
+ reason="Invalid context packet data type.",
130
+ recommended_action="RECOMPILE_CONTEXT",
131
+ )
132
+
133
+ # 2. Extract base commit from packet
134
+ meta = packet_dict.get("metadata", {}) if isinstance(packet_dict.get("metadata"), dict) else {}
135
+ base_commit = (
136
+ packet_dict.get("current_commit")
137
+ or packet_dict.get("indexed_commit")
138
+ or meta.get("indexed_commit")
139
+ or meta.get("current_commit")
140
+ )
141
+ if isinstance(base_commit, str):
142
+ base_commit = base_commit.strip()
143
+
144
+ # 3. Collect all files and symbols mentioned in context
145
+ context_files: set[str] = set()
146
+ core_files: set[str] = set()
147
+ peripheral_files: set[str] = set()
148
+ context_symbols: set[str] = set()
149
+ primary_targets: set[str] = set()
150
+
151
+ # Files section
152
+ for f_obj in packet_dict.get("files", []):
153
+ f_path: str | None = None
154
+ if isinstance(f_obj, str):
155
+ f_path = f_obj
156
+ elif isinstance(f_obj, dict):
157
+ val = f_obj.get("file") or f_obj.get("path")
158
+ f_path = str(val) if val else None
159
+ else:
160
+ val = getattr(f_obj, "file", getattr(f_obj, "path", None))
161
+ f_path = str(val) if val else None
162
+ if f_path:
163
+ context_files.add(f_path)
164
+ core_files.add(f_path)
165
+
166
+ # Symbols section
167
+ for s_obj in packet_dict.get("symbols", []):
168
+ s_file = s_obj.get("file") if isinstance(s_obj, dict) else getattr(s_obj, "file", None)
169
+ s_name = s_obj.get("symbol") if isinstance(s_obj, dict) else getattr(s_obj, "symbol", None)
170
+ if s_file:
171
+ context_files.add(str(s_file))
172
+ core_files.add(str(s_file))
173
+ if s_name:
174
+ context_symbols.add(str(s_name))
175
+
176
+ # Evidence section
177
+ for e_obj in packet_dict.get("evidence", []):
178
+ e_file = e_obj.get("file") if isinstance(e_obj, dict) else getattr(e_obj, "file", None)
179
+ if e_file:
180
+ context_files.add(str(e_file))
181
+
182
+ # Tests section (treated as peripheral)
183
+ for t_obj in packet_dict.get("tests", []):
184
+ t_file = t_obj.get("file") if isinstance(t_obj, dict) else getattr(t_obj, "file", None)
185
+ if t_file:
186
+ context_files.add(str(t_file))
187
+ if str(t_file) not in core_files:
188
+ peripheral_files.add(str(t_file))
189
+
190
+ # Target info
191
+ target_obj = packet_dict.get("target")
192
+ if isinstance(target_obj, dict):
193
+ t_file = target_obj.get("file")
194
+ if t_file:
195
+ context_files.add(str(t_file))
196
+ core_files.add(str(t_file))
197
+ t_sym = target_obj.get("symbol")
198
+ if t_sym:
199
+ primary_targets.add(str(t_sym))
200
+
201
+ # 4. Check Git state
202
+ git_state = state if state is not None else get_git_state(repository, con=con)
203
+ if not git_state.is_git:
204
+ return ContextFreshnessReport(
205
+ status=ContextFreshnessStatus.UNKNOWN,
206
+ base_commit=base_commit,
207
+ current_head=None,
208
+ repository_dirty=False,
209
+ context_files=sorted(context_files),
210
+ reason="Not a git repository.",
211
+ recommended_action="NONE",
212
+ )
213
+
214
+ current_head = git_state.current_head
215
+ state = git_state
216
+
217
+ # 5. Determine which files changed since base_commit (including working tree)
218
+ all_changed_files: set[str] = set()
219
+
220
+ is_at_head = (
221
+ not base_commit
222
+ or base_commit == "HEAD"
223
+ or (current_head and (base_commit == current_head or current_head.startswith(base_commit)))
224
+ )
225
+
226
+ if is_at_head:
227
+ # Fast path: context was generated at current HEAD.
228
+ # Only working tree uncommitted changes can invalidate it.
229
+ wt = state.working_tree
230
+ if not wt.is_dirty:
231
+ # Absolute zero changes anywhere in repository!
232
+ return ContextFreshnessReport(
233
+ status=ContextFreshnessStatus.VALID,
234
+ base_commit=base_commit,
235
+ current_head=current_head,
236
+ repository_dirty=False,
237
+ context_files=sorted(context_files),
238
+ changed_relevant_files=[],
239
+ unrelated_changed_files=[],
240
+ invalidated_symbols=[],
241
+ reason="Context is completely fresh. Repository state is unchanged.",
242
+ recommended_action="NONE",
243
+ )
244
+ all_changed_files.update(wt.modified_files)
245
+ all_changed_files.update(wt.staged_files)
246
+ all_changed_files.update(wt.deleted_files)
247
+ all_changed_files.update(wt.untracked_files)
248
+ elif base_commit and _REF_PATTERN.match(base_commit):
249
+ # Diff base_commit against current HEAD using cached immutable diff, then add working tree
250
+ head_ref = current_head or "HEAD"
251
+ commit_diff = _get_cached_commit_diff_files(repository, base_commit, head_ref)
252
+ if commit_diff is not None:
253
+ all_changed_files.update(commit_diff)
254
+ wt = state.working_tree
255
+ all_changed_files.update(wt.modified_files)
256
+ all_changed_files.update(wt.staged_files)
257
+ all_changed_files.update(wt.deleted_files)
258
+ all_changed_files.update(wt.untracked_files)
259
+ else:
260
+ # Fallback direct diff
261
+ diff_raw = _run_git(repository, "diff", "--name-only", base_commit)
262
+ if diff_raw is not None:
263
+ for line in diff_raw.splitlines():
264
+ if line.strip():
265
+ all_changed_files.add(line.strip())
266
+ all_changed_files.update(state.working_tree.untracked_files)
267
+ else:
268
+ return ContextFreshnessReport(
269
+ status=ContextFreshnessStatus.UNKNOWN,
270
+ base_commit=base_commit,
271
+ current_head=current_head,
272
+ repository_dirty=state.working_tree.is_dirty,
273
+ context_files=sorted(context_files),
274
+ reason=f"Base commit {base_commit} not reachable in git repository.",
275
+ recommended_action="RECOMPILE_CONTEXT",
276
+ )
277
+ else:
278
+ wt = state.working_tree
279
+ all_changed_files.update(wt.modified_files)
280
+ all_changed_files.update(wt.staged_files)
281
+ all_changed_files.update(wt.deleted_files)
282
+ all_changed_files.update(wt.untracked_files)
283
+
284
+ # 6. Intersect changed files with context files
285
+ changed_relevant = sorted(all_changed_files.intersection(context_files))
286
+ unrelated_changed = sorted(all_changed_files - context_files)
287
+
288
+ # 7. Evaluate Freshness
289
+ if not changed_relevant:
290
+ # None of the files in context were modified!
291
+ if unrelated_changed:
292
+ reason = f"Context remains VALID. {len(unrelated_changed)} unrelated file(s) changed in repository, but none belong to this context packet."
293
+ else:
294
+ reason = "Context is completely fresh. Repository state is unchanged."
295
+ return ContextFreshnessReport(
296
+ status=ContextFreshnessStatus.VALID,
297
+ base_commit=base_commit,
298
+ current_head=current_head,
299
+ repository_dirty=state.working_tree.is_dirty,
300
+ context_files=sorted(context_files),
301
+ changed_relevant_files=[],
302
+ unrelated_changed_files=unrelated_changed,
303
+ invalidated_symbols=[],
304
+ reason=reason,
305
+ recommended_action="NONE",
306
+ )
307
+
308
+ # Some relevant files did change! Check if they are core or peripheral
309
+ invalidated_symbols: list[str] = []
310
+ core_hit = False
311
+
312
+ for crf in changed_relevant:
313
+ if crf in core_files or crf not in peripheral_files:
314
+ core_hit = True
315
+
316
+ # Find which symbols were in this file
317
+ for s_obj in packet_dict.get("symbols", []):
318
+ s_file = s_obj.get("file") if isinstance(s_obj, dict) else getattr(s_obj, "file", None)
319
+ s_name = s_obj.get("symbol") if isinstance(s_obj, dict) else getattr(s_obj, "symbol", None)
320
+ if s_file == crf and s_name:
321
+ invalidated_symbols.append(str(s_name))
322
+
323
+ # Check if primary targets were hit
324
+ primary_hit = any(t in invalidated_symbols for t in primary_targets)
325
+
326
+ if core_hit or primary_hit:
327
+ return ContextFreshnessReport(
328
+ status=ContextFreshnessStatus.STALE,
329
+ base_commit=base_commit,
330
+ current_head=current_head,
331
+ repository_dirty=state.working_tree.is_dirty,
332
+ context_files=sorted(context_files),
333
+ changed_relevant_files=changed_relevant,
334
+ unrelated_changed_files=unrelated_changed,
335
+ invalidated_symbols=sorted(set(invalidated_symbols)),
336
+ reason=f"Context is STALE. Core file(s) ({', '.join(changed_relevant[:3])}) were modified or deleted.",
337
+ recommended_action="RECOMPILE_CONTEXT",
338
+ )
339
+ else:
340
+ return ContextFreshnessReport(
341
+ status=ContextFreshnessStatus.PARTIALLY_STALE,
342
+ base_commit=base_commit,
343
+ current_head=current_head,
344
+ repository_dirty=state.working_tree.is_dirty,
345
+ context_files=sorted(context_files),
346
+ changed_relevant_files=changed_relevant,
347
+ unrelated_changed_files=unrelated_changed,
348
+ invalidated_symbols=sorted(set(invalidated_symbols)),
349
+ reason=f"Context is PARTIALLY_STALE. Secondary file(s) ({', '.join(changed_relevant[:3])}) were modified, but primary targets remain valid.",
350
+ recommended_action="REFRESH_PERIPHERAL",
351
+ )
@@ -0,0 +1,72 @@
1
+ """Database Deep Intelligence package for CodeGraph."""
2
+ from .extractor import (
3
+ DatabaseExtractionResult,
4
+ detect_file_dialects,
5
+ extract_database_from_file,
6
+ has_potential_database_activity,
7
+ has_potential_orm_models,
8
+ parse_sql_statement,
9
+ )
10
+ from .interrogation import (
11
+ find_db_callers,
12
+ find_db_columns,
13
+ find_db_models,
14
+ find_db_queries,
15
+ find_db_readers,
16
+ find_db_relationships,
17
+ find_db_tables,
18
+ find_db_writers,
19
+ get_db_impact,
20
+ get_db_schema,
21
+ get_db_table,
22
+ get_route_db_lineage,
23
+ )
24
+ from .models import (
25
+ DatabaseEntity,
26
+ DatabaseEntityKind,
27
+ DatabaseQueryFact,
28
+ MigrationFact,
29
+ build_db_canonical_id,
30
+ normalize_dialect,
31
+ normalize_schema_name,
32
+ )
33
+ from .schema_drift import (
34
+ DriftSeverity,
35
+ DriftType,
36
+ SchemaDriftIssue,
37
+ SchemaFieldSpec,
38
+ detect_schema_drift,
39
+ )
40
+
41
+ __all__ = [
42
+ "DatabaseEntity",
43
+ "DatabaseEntityKind",
44
+ "DatabaseExtractionResult",
45
+ "DatabaseQueryFact",
46
+ "DriftSeverity",
47
+ "DriftType",
48
+ "MigrationFact",
49
+ "SchemaDriftIssue",
50
+ "SchemaFieldSpec",
51
+ "build_db_canonical_id",
52
+ "detect_file_dialects",
53
+ "detect_schema_drift",
54
+ "extract_database_from_file",
55
+ "find_db_callers",
56
+ "find_db_columns",
57
+ "find_db_models",
58
+ "find_db_queries",
59
+ "find_db_readers",
60
+ "find_db_relationships",
61
+ "find_db_tables",
62
+ "find_db_writers",
63
+ "get_db_impact",
64
+ "get_db_schema",
65
+ "get_db_table",
66
+ "get_route_db_lineage",
67
+ "has_potential_database_activity",
68
+ "has_potential_orm_models",
69
+ "normalize_dialect",
70
+ "normalize_schema_name",
71
+ "parse_sql_statement",
72
+ ]