truthound 1.0.8__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 (877) hide show
  1. truthound/__init__.py +162 -0
  2. truthound/adapters.py +100 -0
  3. truthound/api.py +365 -0
  4. truthound/audit/__init__.py +248 -0
  5. truthound/audit/core.py +967 -0
  6. truthound/audit/filters.py +620 -0
  7. truthound/audit/formatters.py +707 -0
  8. truthound/audit/logger.py +902 -0
  9. truthound/audit/middleware.py +571 -0
  10. truthound/audit/storage.py +1083 -0
  11. truthound/benchmark/__init__.py +123 -0
  12. truthound/benchmark/base.py +757 -0
  13. truthound/benchmark/comparison.py +635 -0
  14. truthound/benchmark/generators.py +706 -0
  15. truthound/benchmark/reporters.py +718 -0
  16. truthound/benchmark/runner.py +635 -0
  17. truthound/benchmark/scenarios.py +712 -0
  18. truthound/cache.py +252 -0
  19. truthound/checkpoint/__init__.py +136 -0
  20. truthound/checkpoint/actions/__init__.py +164 -0
  21. truthound/checkpoint/actions/base.py +324 -0
  22. truthound/checkpoint/actions/custom.py +234 -0
  23. truthound/checkpoint/actions/discord_notify.py +290 -0
  24. truthound/checkpoint/actions/email_notify.py +405 -0
  25. truthound/checkpoint/actions/github_action.py +406 -0
  26. truthound/checkpoint/actions/opsgenie.py +1499 -0
  27. truthound/checkpoint/actions/pagerduty.py +226 -0
  28. truthound/checkpoint/actions/slack_notify.py +233 -0
  29. truthound/checkpoint/actions/store_result.py +249 -0
  30. truthound/checkpoint/actions/teams_notify.py +1570 -0
  31. truthound/checkpoint/actions/telegram_notify.py +419 -0
  32. truthound/checkpoint/actions/update_docs.py +552 -0
  33. truthound/checkpoint/actions/webhook.py +293 -0
  34. truthound/checkpoint/analytics/__init__.py +147 -0
  35. truthound/checkpoint/analytics/aggregations/__init__.py +23 -0
  36. truthound/checkpoint/analytics/aggregations/rollup.py +481 -0
  37. truthound/checkpoint/analytics/aggregations/time_bucket.py +306 -0
  38. truthound/checkpoint/analytics/analyzers/__init__.py +17 -0
  39. truthound/checkpoint/analytics/analyzers/anomaly.py +386 -0
  40. truthound/checkpoint/analytics/analyzers/base.py +270 -0
  41. truthound/checkpoint/analytics/analyzers/forecast.py +421 -0
  42. truthound/checkpoint/analytics/analyzers/trend.py +314 -0
  43. truthound/checkpoint/analytics/models.py +292 -0
  44. truthound/checkpoint/analytics/protocols.py +549 -0
  45. truthound/checkpoint/analytics/service.py +718 -0
  46. truthound/checkpoint/analytics/stores/__init__.py +16 -0
  47. truthound/checkpoint/analytics/stores/base.py +306 -0
  48. truthound/checkpoint/analytics/stores/memory_store.py +353 -0
  49. truthound/checkpoint/analytics/stores/sqlite_store.py +557 -0
  50. truthound/checkpoint/analytics/stores/timescale_store.py +501 -0
  51. truthound/checkpoint/async_actions.py +794 -0
  52. truthound/checkpoint/async_base.py +708 -0
  53. truthound/checkpoint/async_checkpoint.py +617 -0
  54. truthound/checkpoint/async_runner.py +639 -0
  55. truthound/checkpoint/checkpoint.py +527 -0
  56. truthound/checkpoint/ci/__init__.py +61 -0
  57. truthound/checkpoint/ci/detector.py +355 -0
  58. truthound/checkpoint/ci/reporter.py +436 -0
  59. truthound/checkpoint/ci/templates.py +454 -0
  60. truthound/checkpoint/circuitbreaker/__init__.py +133 -0
  61. truthound/checkpoint/circuitbreaker/breaker.py +542 -0
  62. truthound/checkpoint/circuitbreaker/core.py +252 -0
  63. truthound/checkpoint/circuitbreaker/detection.py +459 -0
  64. truthound/checkpoint/circuitbreaker/middleware.py +389 -0
  65. truthound/checkpoint/circuitbreaker/registry.py +357 -0
  66. truthound/checkpoint/distributed/__init__.py +139 -0
  67. truthound/checkpoint/distributed/backends/__init__.py +35 -0
  68. truthound/checkpoint/distributed/backends/celery_backend.py +503 -0
  69. truthound/checkpoint/distributed/backends/kubernetes_backend.py +696 -0
  70. truthound/checkpoint/distributed/backends/local_backend.py +397 -0
  71. truthound/checkpoint/distributed/backends/ray_backend.py +625 -0
  72. truthound/checkpoint/distributed/base.py +774 -0
  73. truthound/checkpoint/distributed/orchestrator.py +765 -0
  74. truthound/checkpoint/distributed/protocols.py +842 -0
  75. truthound/checkpoint/distributed/registry.py +449 -0
  76. truthound/checkpoint/idempotency/__init__.py +120 -0
  77. truthound/checkpoint/idempotency/core.py +295 -0
  78. truthound/checkpoint/idempotency/fingerprint.py +454 -0
  79. truthound/checkpoint/idempotency/locking.py +604 -0
  80. truthound/checkpoint/idempotency/service.py +592 -0
  81. truthound/checkpoint/idempotency/stores.py +653 -0
  82. truthound/checkpoint/monitoring/__init__.py +134 -0
  83. truthound/checkpoint/monitoring/aggregators/__init__.py +15 -0
  84. truthound/checkpoint/monitoring/aggregators/base.py +372 -0
  85. truthound/checkpoint/monitoring/aggregators/realtime.py +300 -0
  86. truthound/checkpoint/monitoring/aggregators/window.py +493 -0
  87. truthound/checkpoint/monitoring/collectors/__init__.py +17 -0
  88. truthound/checkpoint/monitoring/collectors/base.py +257 -0
  89. truthound/checkpoint/monitoring/collectors/memory_collector.py +617 -0
  90. truthound/checkpoint/monitoring/collectors/prometheus_collector.py +451 -0
  91. truthound/checkpoint/monitoring/collectors/redis_collector.py +518 -0
  92. truthound/checkpoint/monitoring/events.py +410 -0
  93. truthound/checkpoint/monitoring/protocols.py +636 -0
  94. truthound/checkpoint/monitoring/service.py +578 -0
  95. truthound/checkpoint/monitoring/views/__init__.py +17 -0
  96. truthound/checkpoint/monitoring/views/base.py +172 -0
  97. truthound/checkpoint/monitoring/views/queue_view.py +220 -0
  98. truthound/checkpoint/monitoring/views/task_view.py +240 -0
  99. truthound/checkpoint/monitoring/views/worker_view.py +263 -0
  100. truthound/checkpoint/registry.py +337 -0
  101. truthound/checkpoint/runner.py +356 -0
  102. truthound/checkpoint/transaction/__init__.py +133 -0
  103. truthound/checkpoint/transaction/base.py +389 -0
  104. truthound/checkpoint/transaction/compensatable.py +537 -0
  105. truthound/checkpoint/transaction/coordinator.py +576 -0
  106. truthound/checkpoint/transaction/executor.py +622 -0
  107. truthound/checkpoint/transaction/idempotency.py +534 -0
  108. truthound/checkpoint/transaction/saga/__init__.py +143 -0
  109. truthound/checkpoint/transaction/saga/builder.py +584 -0
  110. truthound/checkpoint/transaction/saga/definition.py +515 -0
  111. truthound/checkpoint/transaction/saga/event_store.py +542 -0
  112. truthound/checkpoint/transaction/saga/patterns.py +833 -0
  113. truthound/checkpoint/transaction/saga/runner.py +718 -0
  114. truthound/checkpoint/transaction/saga/state_machine.py +793 -0
  115. truthound/checkpoint/transaction/saga/strategies.py +780 -0
  116. truthound/checkpoint/transaction/saga/testing.py +886 -0
  117. truthound/checkpoint/triggers/__init__.py +58 -0
  118. truthound/checkpoint/triggers/base.py +237 -0
  119. truthound/checkpoint/triggers/event.py +385 -0
  120. truthound/checkpoint/triggers/schedule.py +355 -0
  121. truthound/cli.py +2358 -0
  122. truthound/cli_modules/__init__.py +124 -0
  123. truthound/cli_modules/advanced/__init__.py +45 -0
  124. truthound/cli_modules/advanced/benchmark.py +343 -0
  125. truthound/cli_modules/advanced/docs.py +225 -0
  126. truthound/cli_modules/advanced/lineage.py +209 -0
  127. truthound/cli_modules/advanced/ml.py +320 -0
  128. truthound/cli_modules/advanced/realtime.py +196 -0
  129. truthound/cli_modules/checkpoint/__init__.py +46 -0
  130. truthound/cli_modules/checkpoint/init.py +114 -0
  131. truthound/cli_modules/checkpoint/list.py +71 -0
  132. truthound/cli_modules/checkpoint/run.py +159 -0
  133. truthound/cli_modules/checkpoint/validate.py +67 -0
  134. truthound/cli_modules/common/__init__.py +71 -0
  135. truthound/cli_modules/common/errors.py +414 -0
  136. truthound/cli_modules/common/options.py +419 -0
  137. truthound/cli_modules/common/output.py +507 -0
  138. truthound/cli_modules/common/protocol.py +552 -0
  139. truthound/cli_modules/core/__init__.py +48 -0
  140. truthound/cli_modules/core/check.py +123 -0
  141. truthound/cli_modules/core/compare.py +104 -0
  142. truthound/cli_modules/core/learn.py +57 -0
  143. truthound/cli_modules/core/mask.py +77 -0
  144. truthound/cli_modules/core/profile.py +65 -0
  145. truthound/cli_modules/core/scan.py +61 -0
  146. truthound/cli_modules/profiler/__init__.py +51 -0
  147. truthound/cli_modules/profiler/auto_profile.py +175 -0
  148. truthound/cli_modules/profiler/metadata.py +107 -0
  149. truthound/cli_modules/profiler/suite.py +283 -0
  150. truthound/cli_modules/registry.py +431 -0
  151. truthound/cli_modules/scaffolding/__init__.py +89 -0
  152. truthound/cli_modules/scaffolding/base.py +631 -0
  153. truthound/cli_modules/scaffolding/commands.py +545 -0
  154. truthound/cli_modules/scaffolding/plugins.py +1072 -0
  155. truthound/cli_modules/scaffolding/reporters.py +594 -0
  156. truthound/cli_modules/scaffolding/validators.py +1127 -0
  157. truthound/common/__init__.py +18 -0
  158. truthound/common/resilience/__init__.py +130 -0
  159. truthound/common/resilience/bulkhead.py +266 -0
  160. truthound/common/resilience/circuit_breaker.py +516 -0
  161. truthound/common/resilience/composite.py +332 -0
  162. truthound/common/resilience/config.py +292 -0
  163. truthound/common/resilience/protocols.py +217 -0
  164. truthound/common/resilience/rate_limiter.py +404 -0
  165. truthound/common/resilience/retry.py +341 -0
  166. truthound/datadocs/__init__.py +260 -0
  167. truthound/datadocs/base.py +571 -0
  168. truthound/datadocs/builder.py +761 -0
  169. truthound/datadocs/charts.py +764 -0
  170. truthound/datadocs/dashboard/__init__.py +63 -0
  171. truthound/datadocs/dashboard/app.py +576 -0
  172. truthound/datadocs/dashboard/components.py +584 -0
  173. truthound/datadocs/dashboard/state.py +240 -0
  174. truthound/datadocs/engine/__init__.py +46 -0
  175. truthound/datadocs/engine/context.py +376 -0
  176. truthound/datadocs/engine/pipeline.py +618 -0
  177. truthound/datadocs/engine/registry.py +469 -0
  178. truthound/datadocs/exporters/__init__.py +49 -0
  179. truthound/datadocs/exporters/base.py +198 -0
  180. truthound/datadocs/exporters/html.py +178 -0
  181. truthound/datadocs/exporters/json_exporter.py +253 -0
  182. truthound/datadocs/exporters/markdown.py +284 -0
  183. truthound/datadocs/exporters/pdf.py +392 -0
  184. truthound/datadocs/i18n/__init__.py +86 -0
  185. truthound/datadocs/i18n/catalog.py +960 -0
  186. truthound/datadocs/i18n/formatting.py +505 -0
  187. truthound/datadocs/i18n/loader.py +256 -0
  188. truthound/datadocs/i18n/plurals.py +378 -0
  189. truthound/datadocs/renderers/__init__.py +42 -0
  190. truthound/datadocs/renderers/base.py +401 -0
  191. truthound/datadocs/renderers/custom.py +342 -0
  192. truthound/datadocs/renderers/jinja.py +697 -0
  193. truthound/datadocs/sections.py +736 -0
  194. truthound/datadocs/styles.py +931 -0
  195. truthound/datadocs/themes/__init__.py +101 -0
  196. truthound/datadocs/themes/base.py +336 -0
  197. truthound/datadocs/themes/default.py +417 -0
  198. truthound/datadocs/themes/enterprise.py +419 -0
  199. truthound/datadocs/themes/loader.py +336 -0
  200. truthound/datadocs/themes.py +301 -0
  201. truthound/datadocs/transformers/__init__.py +57 -0
  202. truthound/datadocs/transformers/base.py +268 -0
  203. truthound/datadocs/transformers/enrichers.py +544 -0
  204. truthound/datadocs/transformers/filters.py +447 -0
  205. truthound/datadocs/transformers/i18n.py +468 -0
  206. truthound/datadocs/versioning/__init__.py +62 -0
  207. truthound/datadocs/versioning/diff.py +639 -0
  208. truthound/datadocs/versioning/storage.py +497 -0
  209. truthound/datadocs/versioning/version.py +358 -0
  210. truthound/datasources/__init__.py +223 -0
  211. truthound/datasources/_async_protocols.py +222 -0
  212. truthound/datasources/_protocols.py +159 -0
  213. truthound/datasources/adapters.py +428 -0
  214. truthound/datasources/async_base.py +599 -0
  215. truthound/datasources/async_factory.py +511 -0
  216. truthound/datasources/base.py +516 -0
  217. truthound/datasources/factory.py +433 -0
  218. truthound/datasources/nosql/__init__.py +47 -0
  219. truthound/datasources/nosql/base.py +487 -0
  220. truthound/datasources/nosql/elasticsearch.py +801 -0
  221. truthound/datasources/nosql/mongodb.py +636 -0
  222. truthound/datasources/pandas_optimized.py +582 -0
  223. truthound/datasources/pandas_source.py +216 -0
  224. truthound/datasources/polars_source.py +395 -0
  225. truthound/datasources/spark_source.py +479 -0
  226. truthound/datasources/sql/__init__.py +154 -0
  227. truthound/datasources/sql/base.py +710 -0
  228. truthound/datasources/sql/bigquery.py +410 -0
  229. truthound/datasources/sql/cloud_base.py +199 -0
  230. truthound/datasources/sql/databricks.py +471 -0
  231. truthound/datasources/sql/mysql.py +316 -0
  232. truthound/datasources/sql/oracle.py +427 -0
  233. truthound/datasources/sql/postgresql.py +321 -0
  234. truthound/datasources/sql/redshift.py +479 -0
  235. truthound/datasources/sql/snowflake.py +439 -0
  236. truthound/datasources/sql/sqlite.py +286 -0
  237. truthound/datasources/sql/sqlserver.py +437 -0
  238. truthound/datasources/streaming/__init__.py +47 -0
  239. truthound/datasources/streaming/base.py +350 -0
  240. truthound/datasources/streaming/kafka.py +670 -0
  241. truthound/decorators.py +98 -0
  242. truthound/docs/__init__.py +69 -0
  243. truthound/docs/extractor.py +971 -0
  244. truthound/docs/generator.py +601 -0
  245. truthound/docs/parser.py +1037 -0
  246. truthound/docs/renderer.py +999 -0
  247. truthound/drift/__init__.py +22 -0
  248. truthound/drift/compare.py +189 -0
  249. truthound/drift/detectors.py +464 -0
  250. truthound/drift/report.py +160 -0
  251. truthound/execution/__init__.py +65 -0
  252. truthound/execution/_protocols.py +324 -0
  253. truthound/execution/base.py +576 -0
  254. truthound/execution/distributed/__init__.py +179 -0
  255. truthound/execution/distributed/aggregations.py +731 -0
  256. truthound/execution/distributed/arrow_bridge.py +817 -0
  257. truthound/execution/distributed/base.py +550 -0
  258. truthound/execution/distributed/dask_engine.py +976 -0
  259. truthound/execution/distributed/mixins.py +766 -0
  260. truthound/execution/distributed/protocols.py +756 -0
  261. truthound/execution/distributed/ray_engine.py +1127 -0
  262. truthound/execution/distributed/registry.py +446 -0
  263. truthound/execution/distributed/spark_engine.py +1011 -0
  264. truthound/execution/distributed/validator_adapter.py +682 -0
  265. truthound/execution/pandas_engine.py +401 -0
  266. truthound/execution/polars_engine.py +497 -0
  267. truthound/execution/pushdown/__init__.py +230 -0
  268. truthound/execution/pushdown/ast.py +1550 -0
  269. truthound/execution/pushdown/builder.py +1550 -0
  270. truthound/execution/pushdown/dialects.py +1072 -0
  271. truthound/execution/pushdown/executor.py +829 -0
  272. truthound/execution/pushdown/optimizer.py +1041 -0
  273. truthound/execution/sql_engine.py +518 -0
  274. truthound/infrastructure/__init__.py +189 -0
  275. truthound/infrastructure/audit.py +1515 -0
  276. truthound/infrastructure/config.py +1133 -0
  277. truthound/infrastructure/encryption.py +1132 -0
  278. truthound/infrastructure/logging.py +1503 -0
  279. truthound/infrastructure/metrics.py +1220 -0
  280. truthound/lineage/__init__.py +89 -0
  281. truthound/lineage/base.py +746 -0
  282. truthound/lineage/impact_analysis.py +474 -0
  283. truthound/lineage/integrations/__init__.py +22 -0
  284. truthound/lineage/integrations/openlineage.py +548 -0
  285. truthound/lineage/tracker.py +512 -0
  286. truthound/lineage/visualization/__init__.py +33 -0
  287. truthound/lineage/visualization/protocols.py +145 -0
  288. truthound/lineage/visualization/renderers/__init__.py +20 -0
  289. truthound/lineage/visualization/renderers/cytoscape.py +329 -0
  290. truthound/lineage/visualization/renderers/d3.py +331 -0
  291. truthound/lineage/visualization/renderers/graphviz.py +276 -0
  292. truthound/lineage/visualization/renderers/mermaid.py +308 -0
  293. truthound/maskers.py +113 -0
  294. truthound/ml/__init__.py +124 -0
  295. truthound/ml/anomaly_models/__init__.py +31 -0
  296. truthound/ml/anomaly_models/ensemble.py +362 -0
  297. truthound/ml/anomaly_models/isolation_forest.py +444 -0
  298. truthound/ml/anomaly_models/statistical.py +392 -0
  299. truthound/ml/base.py +1178 -0
  300. truthound/ml/drift_detection/__init__.py +26 -0
  301. truthound/ml/drift_detection/concept.py +381 -0
  302. truthound/ml/drift_detection/distribution.py +361 -0
  303. truthound/ml/drift_detection/feature.py +442 -0
  304. truthound/ml/drift_detection/multivariate.py +495 -0
  305. truthound/ml/monitoring/__init__.py +88 -0
  306. truthound/ml/monitoring/alerting/__init__.py +33 -0
  307. truthound/ml/monitoring/alerting/handlers.py +427 -0
  308. truthound/ml/monitoring/alerting/rules.py +508 -0
  309. truthound/ml/monitoring/collectors/__init__.py +19 -0
  310. truthound/ml/monitoring/collectors/composite.py +105 -0
  311. truthound/ml/monitoring/collectors/drift.py +324 -0
  312. truthound/ml/monitoring/collectors/performance.py +179 -0
  313. truthound/ml/monitoring/collectors/quality.py +369 -0
  314. truthound/ml/monitoring/monitor.py +536 -0
  315. truthound/ml/monitoring/protocols.py +451 -0
  316. truthound/ml/monitoring/stores/__init__.py +15 -0
  317. truthound/ml/monitoring/stores/memory.py +201 -0
  318. truthound/ml/monitoring/stores/prometheus.py +296 -0
  319. truthound/ml/rule_learning/__init__.py +25 -0
  320. truthound/ml/rule_learning/constraint_miner.py +443 -0
  321. truthound/ml/rule_learning/pattern_learner.py +499 -0
  322. truthound/ml/rule_learning/profile_learner.py +462 -0
  323. truthound/multitenancy/__init__.py +326 -0
  324. truthound/multitenancy/core.py +852 -0
  325. truthound/multitenancy/integration.py +597 -0
  326. truthound/multitenancy/isolation.py +630 -0
  327. truthound/multitenancy/manager.py +770 -0
  328. truthound/multitenancy/middleware.py +765 -0
  329. truthound/multitenancy/quota.py +537 -0
  330. truthound/multitenancy/resolvers.py +603 -0
  331. truthound/multitenancy/storage.py +703 -0
  332. truthound/observability/__init__.py +307 -0
  333. truthound/observability/context.py +531 -0
  334. truthound/observability/instrumentation.py +611 -0
  335. truthound/observability/logging.py +887 -0
  336. truthound/observability/metrics.py +1157 -0
  337. truthound/observability/tracing/__init__.py +178 -0
  338. truthound/observability/tracing/baggage.py +310 -0
  339. truthound/observability/tracing/config.py +426 -0
  340. truthound/observability/tracing/exporter.py +787 -0
  341. truthound/observability/tracing/integration.py +1018 -0
  342. truthound/observability/tracing/otel/__init__.py +146 -0
  343. truthound/observability/tracing/otel/adapter.py +982 -0
  344. truthound/observability/tracing/otel/bridge.py +1177 -0
  345. truthound/observability/tracing/otel/compat.py +681 -0
  346. truthound/observability/tracing/otel/config.py +691 -0
  347. truthound/observability/tracing/otel/detection.py +327 -0
  348. truthound/observability/tracing/otel/protocols.py +426 -0
  349. truthound/observability/tracing/processor.py +561 -0
  350. truthound/observability/tracing/propagator.py +757 -0
  351. truthound/observability/tracing/provider.py +569 -0
  352. truthound/observability/tracing/resource.py +515 -0
  353. truthound/observability/tracing/sampler.py +487 -0
  354. truthound/observability/tracing/span.py +676 -0
  355. truthound/plugins/__init__.py +198 -0
  356. truthound/plugins/base.py +599 -0
  357. truthound/plugins/cli.py +680 -0
  358. truthound/plugins/dependencies/__init__.py +42 -0
  359. truthound/plugins/dependencies/graph.py +422 -0
  360. truthound/plugins/dependencies/resolver.py +417 -0
  361. truthound/plugins/discovery.py +379 -0
  362. truthound/plugins/docs/__init__.py +46 -0
  363. truthound/plugins/docs/extractor.py +444 -0
  364. truthound/plugins/docs/renderer.py +499 -0
  365. truthound/plugins/enterprise_manager.py +877 -0
  366. truthound/plugins/examples/__init__.py +19 -0
  367. truthound/plugins/examples/custom_validators.py +317 -0
  368. truthound/plugins/examples/slack_notifier.py +312 -0
  369. truthound/plugins/examples/xml_reporter.py +254 -0
  370. truthound/plugins/hooks.py +558 -0
  371. truthound/plugins/lifecycle/__init__.py +43 -0
  372. truthound/plugins/lifecycle/hot_reload.py +402 -0
  373. truthound/plugins/lifecycle/manager.py +371 -0
  374. truthound/plugins/manager.py +736 -0
  375. truthound/plugins/registry.py +338 -0
  376. truthound/plugins/security/__init__.py +93 -0
  377. truthound/plugins/security/exceptions.py +332 -0
  378. truthound/plugins/security/policies.py +348 -0
  379. truthound/plugins/security/protocols.py +643 -0
  380. truthound/plugins/security/sandbox/__init__.py +45 -0
  381. truthound/plugins/security/sandbox/context.py +158 -0
  382. truthound/plugins/security/sandbox/engines/__init__.py +19 -0
  383. truthound/plugins/security/sandbox/engines/container.py +379 -0
  384. truthound/plugins/security/sandbox/engines/noop.py +144 -0
  385. truthound/plugins/security/sandbox/engines/process.py +336 -0
  386. truthound/plugins/security/sandbox/factory.py +211 -0
  387. truthound/plugins/security/signing/__init__.py +57 -0
  388. truthound/plugins/security/signing/service.py +330 -0
  389. truthound/plugins/security/signing/trust_store.py +368 -0
  390. truthound/plugins/security/signing/verifier.py +459 -0
  391. truthound/plugins/versioning/__init__.py +41 -0
  392. truthound/plugins/versioning/constraints.py +297 -0
  393. truthound/plugins/versioning/resolver.py +329 -0
  394. truthound/profiler/__init__.py +1729 -0
  395. truthound/profiler/_lazy.py +452 -0
  396. truthound/profiler/ab_testing/__init__.py +80 -0
  397. truthound/profiler/ab_testing/analysis.py +449 -0
  398. truthound/profiler/ab_testing/base.py +257 -0
  399. truthound/profiler/ab_testing/experiment.py +395 -0
  400. truthound/profiler/ab_testing/tracking.py +368 -0
  401. truthound/profiler/auto_threshold.py +1170 -0
  402. truthound/profiler/base.py +579 -0
  403. truthound/profiler/cache_patterns.py +911 -0
  404. truthound/profiler/caching.py +1303 -0
  405. truthound/profiler/column_profiler.py +712 -0
  406. truthound/profiler/comparison.py +1007 -0
  407. truthound/profiler/custom_patterns.py +1170 -0
  408. truthound/profiler/dashboard/__init__.py +50 -0
  409. truthound/profiler/dashboard/app.py +476 -0
  410. truthound/profiler/dashboard/components.py +457 -0
  411. truthound/profiler/dashboard/config.py +72 -0
  412. truthound/profiler/distributed/__init__.py +83 -0
  413. truthound/profiler/distributed/base.py +281 -0
  414. truthound/profiler/distributed/dask_backend.py +498 -0
  415. truthound/profiler/distributed/local_backend.py +293 -0
  416. truthound/profiler/distributed/profiler.py +304 -0
  417. truthound/profiler/distributed/ray_backend.py +374 -0
  418. truthound/profiler/distributed/spark_backend.py +375 -0
  419. truthound/profiler/distributed.py +1366 -0
  420. truthound/profiler/enterprise_sampling.py +1065 -0
  421. truthound/profiler/errors.py +488 -0
  422. truthound/profiler/evolution/__init__.py +91 -0
  423. truthound/profiler/evolution/alerts.py +426 -0
  424. truthound/profiler/evolution/changes.py +206 -0
  425. truthound/profiler/evolution/compatibility.py +365 -0
  426. truthound/profiler/evolution/detector.py +372 -0
  427. truthound/profiler/evolution/protocols.py +121 -0
  428. truthound/profiler/generators/__init__.py +48 -0
  429. truthound/profiler/generators/base.py +384 -0
  430. truthound/profiler/generators/ml_rules.py +375 -0
  431. truthound/profiler/generators/pattern_rules.py +384 -0
  432. truthound/profiler/generators/schema_rules.py +267 -0
  433. truthound/profiler/generators/stats_rules.py +324 -0
  434. truthound/profiler/generators/suite_generator.py +857 -0
  435. truthound/profiler/i18n.py +1542 -0
  436. truthound/profiler/incremental.py +554 -0
  437. truthound/profiler/incremental_validation.py +1710 -0
  438. truthound/profiler/integration/__init__.py +73 -0
  439. truthound/profiler/integration/adapters.py +345 -0
  440. truthound/profiler/integration/context.py +371 -0
  441. truthound/profiler/integration/executor.py +527 -0
  442. truthound/profiler/integration/naming.py +75 -0
  443. truthound/profiler/integration/protocols.py +243 -0
  444. truthound/profiler/memory.py +1185 -0
  445. truthound/profiler/migration/__init__.py +60 -0
  446. truthound/profiler/migration/base.py +345 -0
  447. truthound/profiler/migration/manager.py +444 -0
  448. truthound/profiler/migration/v1_0_to_v1_1.py +484 -0
  449. truthound/profiler/ml/__init__.py +73 -0
  450. truthound/profiler/ml/base.py +244 -0
  451. truthound/profiler/ml/classifier.py +507 -0
  452. truthound/profiler/ml/feature_extraction.py +604 -0
  453. truthound/profiler/ml/pretrained.py +448 -0
  454. truthound/profiler/ml_inference.py +1276 -0
  455. truthound/profiler/native_patterns.py +815 -0
  456. truthound/profiler/observability.py +1184 -0
  457. truthound/profiler/process_timeout.py +1566 -0
  458. truthound/profiler/progress.py +568 -0
  459. truthound/profiler/progress_callbacks.py +1734 -0
  460. truthound/profiler/quality.py +1345 -0
  461. truthound/profiler/resilience.py +1180 -0
  462. truthound/profiler/sampled_matcher.py +794 -0
  463. truthound/profiler/sampling.py +1288 -0
  464. truthound/profiler/scheduling/__init__.py +82 -0
  465. truthound/profiler/scheduling/protocols.py +214 -0
  466. truthound/profiler/scheduling/scheduler.py +474 -0
  467. truthound/profiler/scheduling/storage.py +457 -0
  468. truthound/profiler/scheduling/triggers.py +449 -0
  469. truthound/profiler/schema.py +603 -0
  470. truthound/profiler/streaming.py +685 -0
  471. truthound/profiler/streaming_patterns.py +1354 -0
  472. truthound/profiler/suite_cli.py +625 -0
  473. truthound/profiler/suite_config.py +789 -0
  474. truthound/profiler/suite_export.py +1268 -0
  475. truthound/profiler/table_profiler.py +547 -0
  476. truthound/profiler/timeout.py +565 -0
  477. truthound/profiler/validation.py +1532 -0
  478. truthound/profiler/visualization/__init__.py +118 -0
  479. truthound/profiler/visualization/base.py +346 -0
  480. truthound/profiler/visualization/generator.py +1259 -0
  481. truthound/profiler/visualization/plotly_renderer.py +811 -0
  482. truthound/profiler/visualization/renderers.py +669 -0
  483. truthound/profiler/visualization/sections.py +540 -0
  484. truthound/profiler/visualization.py +2122 -0
  485. truthound/profiler/yaml_validation.py +1151 -0
  486. truthound/py.typed +0 -0
  487. truthound/ratelimit/__init__.py +248 -0
  488. truthound/ratelimit/algorithms.py +1108 -0
  489. truthound/ratelimit/core.py +573 -0
  490. truthound/ratelimit/integration.py +532 -0
  491. truthound/ratelimit/limiter.py +663 -0
  492. truthound/ratelimit/middleware.py +700 -0
  493. truthound/ratelimit/policy.py +792 -0
  494. truthound/ratelimit/storage.py +763 -0
  495. truthound/rbac/__init__.py +340 -0
  496. truthound/rbac/core.py +976 -0
  497. truthound/rbac/integration.py +760 -0
  498. truthound/rbac/manager.py +1052 -0
  499. truthound/rbac/middleware.py +842 -0
  500. truthound/rbac/policy.py +954 -0
  501. truthound/rbac/storage.py +878 -0
  502. truthound/realtime/__init__.py +141 -0
  503. truthound/realtime/adapters/__init__.py +43 -0
  504. truthound/realtime/adapters/base.py +533 -0
  505. truthound/realtime/adapters/kafka.py +487 -0
  506. truthound/realtime/adapters/kinesis.py +479 -0
  507. truthound/realtime/adapters/mock.py +243 -0
  508. truthound/realtime/base.py +553 -0
  509. truthound/realtime/factory.py +382 -0
  510. truthound/realtime/incremental.py +660 -0
  511. truthound/realtime/processing/__init__.py +67 -0
  512. truthound/realtime/processing/exactly_once.py +575 -0
  513. truthound/realtime/processing/state.py +547 -0
  514. truthound/realtime/processing/windows.py +647 -0
  515. truthound/realtime/protocols.py +569 -0
  516. truthound/realtime/streaming.py +605 -0
  517. truthound/realtime/testing/__init__.py +32 -0
  518. truthound/realtime/testing/containers.py +615 -0
  519. truthound/realtime/testing/fixtures.py +484 -0
  520. truthound/report.py +280 -0
  521. truthound/reporters/__init__.py +46 -0
  522. truthound/reporters/_protocols.py +30 -0
  523. truthound/reporters/base.py +324 -0
  524. truthound/reporters/ci/__init__.py +66 -0
  525. truthound/reporters/ci/azure.py +436 -0
  526. truthound/reporters/ci/base.py +509 -0
  527. truthound/reporters/ci/bitbucket.py +567 -0
  528. truthound/reporters/ci/circleci.py +547 -0
  529. truthound/reporters/ci/detection.py +364 -0
  530. truthound/reporters/ci/factory.py +182 -0
  531. truthound/reporters/ci/github.py +388 -0
  532. truthound/reporters/ci/gitlab.py +471 -0
  533. truthound/reporters/ci/jenkins.py +525 -0
  534. truthound/reporters/console_reporter.py +299 -0
  535. truthound/reporters/factory.py +211 -0
  536. truthound/reporters/html_reporter.py +524 -0
  537. truthound/reporters/json_reporter.py +256 -0
  538. truthound/reporters/markdown_reporter.py +280 -0
  539. truthound/reporters/sdk/__init__.py +174 -0
  540. truthound/reporters/sdk/builder.py +558 -0
  541. truthound/reporters/sdk/mixins.py +1150 -0
  542. truthound/reporters/sdk/schema.py +1493 -0
  543. truthound/reporters/sdk/templates.py +666 -0
  544. truthound/reporters/sdk/testing.py +968 -0
  545. truthound/scanners.py +170 -0
  546. truthound/scheduling/__init__.py +122 -0
  547. truthound/scheduling/cron.py +1136 -0
  548. truthound/scheduling/presets.py +212 -0
  549. truthound/schema.py +275 -0
  550. truthound/secrets/__init__.py +173 -0
  551. truthound/secrets/base.py +618 -0
  552. truthound/secrets/cloud.py +682 -0
  553. truthound/secrets/integration.py +507 -0
  554. truthound/secrets/manager.py +633 -0
  555. truthound/secrets/oidc/__init__.py +172 -0
  556. truthound/secrets/oidc/base.py +902 -0
  557. truthound/secrets/oidc/credential_provider.py +623 -0
  558. truthound/secrets/oidc/exchangers.py +1001 -0
  559. truthound/secrets/oidc/github/__init__.py +110 -0
  560. truthound/secrets/oidc/github/claims.py +718 -0
  561. truthound/secrets/oidc/github/enhanced_provider.py +693 -0
  562. truthound/secrets/oidc/github/trust_policy.py +742 -0
  563. truthound/secrets/oidc/github/verification.py +723 -0
  564. truthound/secrets/oidc/github/workflow.py +691 -0
  565. truthound/secrets/oidc/providers.py +825 -0
  566. truthound/secrets/providers.py +506 -0
  567. truthound/secrets/resolver.py +495 -0
  568. truthound/stores/__init__.py +177 -0
  569. truthound/stores/backends/__init__.py +18 -0
  570. truthound/stores/backends/_protocols.py +340 -0
  571. truthound/stores/backends/azure_blob.py +530 -0
  572. truthound/stores/backends/concurrent_filesystem.py +915 -0
  573. truthound/stores/backends/connection_pool.py +1365 -0
  574. truthound/stores/backends/database.py +743 -0
  575. truthound/stores/backends/filesystem.py +538 -0
  576. truthound/stores/backends/gcs.py +399 -0
  577. truthound/stores/backends/memory.py +354 -0
  578. truthound/stores/backends/s3.py +434 -0
  579. truthound/stores/backpressure/__init__.py +84 -0
  580. truthound/stores/backpressure/base.py +375 -0
  581. truthound/stores/backpressure/circuit_breaker.py +434 -0
  582. truthound/stores/backpressure/monitor.py +376 -0
  583. truthound/stores/backpressure/strategies.py +677 -0
  584. truthound/stores/base.py +551 -0
  585. truthound/stores/batching/__init__.py +65 -0
  586. truthound/stores/batching/base.py +305 -0
  587. truthound/stores/batching/buffer.py +370 -0
  588. truthound/stores/batching/store.py +248 -0
  589. truthound/stores/batching/writer.py +521 -0
  590. truthound/stores/caching/__init__.py +60 -0
  591. truthound/stores/caching/backends.py +684 -0
  592. truthound/stores/caching/base.py +356 -0
  593. truthound/stores/caching/store.py +305 -0
  594. truthound/stores/compression/__init__.py +193 -0
  595. truthound/stores/compression/adaptive.py +694 -0
  596. truthound/stores/compression/base.py +514 -0
  597. truthound/stores/compression/pipeline.py +868 -0
  598. truthound/stores/compression/providers.py +672 -0
  599. truthound/stores/compression/streaming.py +832 -0
  600. truthound/stores/concurrency/__init__.py +81 -0
  601. truthound/stores/concurrency/atomic.py +556 -0
  602. truthound/stores/concurrency/index.py +775 -0
  603. truthound/stores/concurrency/locks.py +576 -0
  604. truthound/stores/concurrency/manager.py +482 -0
  605. truthound/stores/encryption/__init__.py +297 -0
  606. truthound/stores/encryption/base.py +952 -0
  607. truthound/stores/encryption/keys.py +1191 -0
  608. truthound/stores/encryption/pipeline.py +903 -0
  609. truthound/stores/encryption/providers.py +953 -0
  610. truthound/stores/encryption/streaming.py +950 -0
  611. truthound/stores/expectations.py +227 -0
  612. truthound/stores/factory.py +246 -0
  613. truthound/stores/migration/__init__.py +75 -0
  614. truthound/stores/migration/base.py +480 -0
  615. truthound/stores/migration/manager.py +347 -0
  616. truthound/stores/migration/registry.py +382 -0
  617. truthound/stores/migration/store.py +559 -0
  618. truthound/stores/observability/__init__.py +106 -0
  619. truthound/stores/observability/audit.py +718 -0
  620. truthound/stores/observability/config.py +270 -0
  621. truthound/stores/observability/factory.py +208 -0
  622. truthound/stores/observability/metrics.py +636 -0
  623. truthound/stores/observability/protocols.py +410 -0
  624. truthound/stores/observability/store.py +570 -0
  625. truthound/stores/observability/tracing.py +784 -0
  626. truthound/stores/replication/__init__.py +76 -0
  627. truthound/stores/replication/base.py +260 -0
  628. truthound/stores/replication/monitor.py +269 -0
  629. truthound/stores/replication/store.py +439 -0
  630. truthound/stores/replication/syncer.py +391 -0
  631. truthound/stores/results.py +359 -0
  632. truthound/stores/retention/__init__.py +77 -0
  633. truthound/stores/retention/base.py +378 -0
  634. truthound/stores/retention/policies.py +621 -0
  635. truthound/stores/retention/scheduler.py +279 -0
  636. truthound/stores/retention/store.py +526 -0
  637. truthound/stores/streaming/__init__.py +138 -0
  638. truthound/stores/streaming/base.py +801 -0
  639. truthound/stores/streaming/database.py +984 -0
  640. truthound/stores/streaming/filesystem.py +719 -0
  641. truthound/stores/streaming/reader.py +629 -0
  642. truthound/stores/streaming/s3.py +843 -0
  643. truthound/stores/streaming/writer.py +790 -0
  644. truthound/stores/tiering/__init__.py +108 -0
  645. truthound/stores/tiering/base.py +462 -0
  646. truthound/stores/tiering/manager.py +249 -0
  647. truthound/stores/tiering/policies.py +692 -0
  648. truthound/stores/tiering/store.py +526 -0
  649. truthound/stores/versioning/__init__.py +56 -0
  650. truthound/stores/versioning/base.py +376 -0
  651. truthound/stores/versioning/store.py +660 -0
  652. truthound/stores/versioning/strategies.py +353 -0
  653. truthound/types.py +56 -0
  654. truthound/validators/__init__.py +774 -0
  655. truthound/validators/aggregate/__init__.py +27 -0
  656. truthound/validators/aggregate/central.py +116 -0
  657. truthound/validators/aggregate/extremes.py +116 -0
  658. truthound/validators/aggregate/spread.py +118 -0
  659. truthound/validators/aggregate/sum.py +64 -0
  660. truthound/validators/aggregate/type.py +78 -0
  661. truthound/validators/anomaly/__init__.py +93 -0
  662. truthound/validators/anomaly/base.py +431 -0
  663. truthound/validators/anomaly/ml_based.py +1190 -0
  664. truthound/validators/anomaly/multivariate.py +647 -0
  665. truthound/validators/anomaly/statistical.py +599 -0
  666. truthound/validators/base.py +1089 -0
  667. truthound/validators/business_rule/__init__.py +46 -0
  668. truthound/validators/business_rule/base.py +147 -0
  669. truthound/validators/business_rule/checksum.py +509 -0
  670. truthound/validators/business_rule/financial.py +526 -0
  671. truthound/validators/cache.py +733 -0
  672. truthound/validators/completeness/__init__.py +39 -0
  673. truthound/validators/completeness/conditional.py +73 -0
  674. truthound/validators/completeness/default.py +98 -0
  675. truthound/validators/completeness/empty.py +103 -0
  676. truthound/validators/completeness/nan.py +337 -0
  677. truthound/validators/completeness/null.py +152 -0
  678. truthound/validators/cross_table/__init__.py +17 -0
  679. truthound/validators/cross_table/aggregate.py +333 -0
  680. truthound/validators/cross_table/row_count.py +122 -0
  681. truthound/validators/datetime/__init__.py +29 -0
  682. truthound/validators/datetime/format.py +78 -0
  683. truthound/validators/datetime/freshness.py +269 -0
  684. truthound/validators/datetime/order.py +73 -0
  685. truthound/validators/datetime/parseable.py +185 -0
  686. truthound/validators/datetime/range.py +202 -0
  687. truthound/validators/datetime/timezone.py +69 -0
  688. truthound/validators/distribution/__init__.py +49 -0
  689. truthound/validators/distribution/distribution.py +128 -0
  690. truthound/validators/distribution/monotonic.py +119 -0
  691. truthound/validators/distribution/outlier.py +178 -0
  692. truthound/validators/distribution/quantile.py +80 -0
  693. truthound/validators/distribution/range.py +254 -0
  694. truthound/validators/distribution/set.py +125 -0
  695. truthound/validators/distribution/statistical.py +459 -0
  696. truthound/validators/drift/__init__.py +79 -0
  697. truthound/validators/drift/base.py +427 -0
  698. truthound/validators/drift/multi_feature.py +401 -0
  699. truthound/validators/drift/numeric.py +395 -0
  700. truthound/validators/drift/psi.py +446 -0
  701. truthound/validators/drift/statistical.py +510 -0
  702. truthound/validators/enterprise.py +1658 -0
  703. truthound/validators/geospatial/__init__.py +80 -0
  704. truthound/validators/geospatial/base.py +97 -0
  705. truthound/validators/geospatial/boundary.py +238 -0
  706. truthound/validators/geospatial/coordinate.py +351 -0
  707. truthound/validators/geospatial/distance.py +399 -0
  708. truthound/validators/geospatial/polygon.py +665 -0
  709. truthound/validators/i18n/__init__.py +308 -0
  710. truthound/validators/i18n/bidi.py +571 -0
  711. truthound/validators/i18n/catalogs.py +570 -0
  712. truthound/validators/i18n/dialects.py +763 -0
  713. truthound/validators/i18n/extended_catalogs.py +549 -0
  714. truthound/validators/i18n/formatting.py +1434 -0
  715. truthound/validators/i18n/loader.py +1020 -0
  716. truthound/validators/i18n/messages.py +521 -0
  717. truthound/validators/i18n/plural.py +683 -0
  718. truthound/validators/i18n/protocols.py +855 -0
  719. truthound/validators/i18n/tms.py +1162 -0
  720. truthound/validators/localization/__init__.py +53 -0
  721. truthound/validators/localization/base.py +122 -0
  722. truthound/validators/localization/chinese.py +362 -0
  723. truthound/validators/localization/japanese.py +275 -0
  724. truthound/validators/localization/korean.py +524 -0
  725. truthound/validators/memory/__init__.py +94 -0
  726. truthound/validators/memory/approximate_knn.py +506 -0
  727. truthound/validators/memory/base.py +547 -0
  728. truthound/validators/memory/sgd_online.py +719 -0
  729. truthound/validators/memory/streaming_ecdf.py +753 -0
  730. truthound/validators/ml_feature/__init__.py +54 -0
  731. truthound/validators/ml_feature/base.py +249 -0
  732. truthound/validators/ml_feature/correlation.py +299 -0
  733. truthound/validators/ml_feature/leakage.py +344 -0
  734. truthound/validators/ml_feature/null_impact.py +270 -0
  735. truthound/validators/ml_feature/scale.py +264 -0
  736. truthound/validators/multi_column/__init__.py +89 -0
  737. truthound/validators/multi_column/arithmetic.py +284 -0
  738. truthound/validators/multi_column/base.py +231 -0
  739. truthound/validators/multi_column/comparison.py +273 -0
  740. truthound/validators/multi_column/consistency.py +312 -0
  741. truthound/validators/multi_column/statistical.py +299 -0
  742. truthound/validators/optimization/__init__.py +164 -0
  743. truthound/validators/optimization/aggregation.py +563 -0
  744. truthound/validators/optimization/covariance.py +556 -0
  745. truthound/validators/optimization/geo.py +626 -0
  746. truthound/validators/optimization/graph.py +587 -0
  747. truthound/validators/optimization/orchestrator.py +970 -0
  748. truthound/validators/optimization/profiling.py +1312 -0
  749. truthound/validators/privacy/__init__.py +223 -0
  750. truthound/validators/privacy/base.py +635 -0
  751. truthound/validators/privacy/ccpa.py +670 -0
  752. truthound/validators/privacy/gdpr.py +728 -0
  753. truthound/validators/privacy/global_patterns.py +604 -0
  754. truthound/validators/privacy/plugins.py +867 -0
  755. truthound/validators/profiling/__init__.py +52 -0
  756. truthound/validators/profiling/base.py +175 -0
  757. truthound/validators/profiling/cardinality.py +312 -0
  758. truthound/validators/profiling/entropy.py +391 -0
  759. truthound/validators/profiling/frequency.py +455 -0
  760. truthound/validators/pushdown_support.py +660 -0
  761. truthound/validators/query/__init__.py +91 -0
  762. truthound/validators/query/aggregate.py +346 -0
  763. truthound/validators/query/base.py +246 -0
  764. truthound/validators/query/column.py +249 -0
  765. truthound/validators/query/expression.py +274 -0
  766. truthound/validators/query/result.py +323 -0
  767. truthound/validators/query/row_count.py +264 -0
  768. truthound/validators/referential/__init__.py +80 -0
  769. truthound/validators/referential/base.py +395 -0
  770. truthound/validators/referential/cascade.py +391 -0
  771. truthound/validators/referential/circular.py +563 -0
  772. truthound/validators/referential/foreign_key.py +624 -0
  773. truthound/validators/referential/orphan.py +485 -0
  774. truthound/validators/registry.py +112 -0
  775. truthound/validators/schema/__init__.py +41 -0
  776. truthound/validators/schema/column_count.py +142 -0
  777. truthound/validators/schema/column_exists.py +80 -0
  778. truthound/validators/schema/column_order.py +82 -0
  779. truthound/validators/schema/column_pair.py +85 -0
  780. truthound/validators/schema/column_pair_set.py +195 -0
  781. truthound/validators/schema/column_type.py +94 -0
  782. truthound/validators/schema/multi_column.py +53 -0
  783. truthound/validators/schema/multi_column_aggregate.py +175 -0
  784. truthound/validators/schema/referential.py +274 -0
  785. truthound/validators/schema/table_schema.py +91 -0
  786. truthound/validators/schema_validator.py +219 -0
  787. truthound/validators/sdk/__init__.py +250 -0
  788. truthound/validators/sdk/builder.py +680 -0
  789. truthound/validators/sdk/decorators.py +474 -0
  790. truthound/validators/sdk/enterprise/__init__.py +211 -0
  791. truthound/validators/sdk/enterprise/docs.py +725 -0
  792. truthound/validators/sdk/enterprise/fuzzing.py +659 -0
  793. truthound/validators/sdk/enterprise/licensing.py +709 -0
  794. truthound/validators/sdk/enterprise/manager.py +543 -0
  795. truthound/validators/sdk/enterprise/resources.py +628 -0
  796. truthound/validators/sdk/enterprise/sandbox.py +766 -0
  797. truthound/validators/sdk/enterprise/signing.py +603 -0
  798. truthound/validators/sdk/enterprise/templates.py +865 -0
  799. truthound/validators/sdk/enterprise/versioning.py +659 -0
  800. truthound/validators/sdk/templates.py +757 -0
  801. truthound/validators/sdk/testing.py +807 -0
  802. truthound/validators/security/__init__.py +181 -0
  803. truthound/validators/security/redos/__init__.py +182 -0
  804. truthound/validators/security/redos/core.py +861 -0
  805. truthound/validators/security/redos/cpu_monitor.py +593 -0
  806. truthound/validators/security/redos/cve_database.py +791 -0
  807. truthound/validators/security/redos/ml/__init__.py +155 -0
  808. truthound/validators/security/redos/ml/base.py +785 -0
  809. truthound/validators/security/redos/ml/datasets.py +618 -0
  810. truthound/validators/security/redos/ml/features.py +359 -0
  811. truthound/validators/security/redos/ml/models.py +1000 -0
  812. truthound/validators/security/redos/ml/predictor.py +507 -0
  813. truthound/validators/security/redos/ml/storage.py +632 -0
  814. truthound/validators/security/redos/ml/training.py +571 -0
  815. truthound/validators/security/redos/ml_analyzer.py +937 -0
  816. truthound/validators/security/redos/optimizer.py +674 -0
  817. truthound/validators/security/redos/profiler.py +682 -0
  818. truthound/validators/security/redos/re2_engine.py +709 -0
  819. truthound/validators/security/redos.py +886 -0
  820. truthound/validators/security/sql_security.py +1247 -0
  821. truthound/validators/streaming/__init__.py +126 -0
  822. truthound/validators/streaming/base.py +292 -0
  823. truthound/validators/streaming/completeness.py +210 -0
  824. truthound/validators/streaming/mixin.py +575 -0
  825. truthound/validators/streaming/range.py +308 -0
  826. truthound/validators/streaming/sources.py +846 -0
  827. truthound/validators/string/__init__.py +57 -0
  828. truthound/validators/string/casing.py +158 -0
  829. truthound/validators/string/charset.py +96 -0
  830. truthound/validators/string/format.py +501 -0
  831. truthound/validators/string/json.py +77 -0
  832. truthound/validators/string/json_schema.py +184 -0
  833. truthound/validators/string/length.py +104 -0
  834. truthound/validators/string/like_pattern.py +237 -0
  835. truthound/validators/string/regex.py +202 -0
  836. truthound/validators/string/regex_extended.py +435 -0
  837. truthound/validators/table/__init__.py +88 -0
  838. truthound/validators/table/base.py +78 -0
  839. truthound/validators/table/column_count.py +198 -0
  840. truthound/validators/table/freshness.py +362 -0
  841. truthound/validators/table/row_count.py +251 -0
  842. truthound/validators/table/schema.py +333 -0
  843. truthound/validators/table/size.py +285 -0
  844. truthound/validators/timeout/__init__.py +102 -0
  845. truthound/validators/timeout/advanced/__init__.py +247 -0
  846. truthound/validators/timeout/advanced/circuit_breaker.py +675 -0
  847. truthound/validators/timeout/advanced/prediction.py +773 -0
  848. truthound/validators/timeout/advanced/priority.py +618 -0
  849. truthound/validators/timeout/advanced/redis_backend.py +770 -0
  850. truthound/validators/timeout/advanced/retry.py +721 -0
  851. truthound/validators/timeout/advanced/sampling.py +788 -0
  852. truthound/validators/timeout/advanced/sla.py +661 -0
  853. truthound/validators/timeout/advanced/telemetry.py +804 -0
  854. truthound/validators/timeout/cascade.py +477 -0
  855. truthound/validators/timeout/deadline.py +657 -0
  856. truthound/validators/timeout/degradation.py +525 -0
  857. truthound/validators/timeout/distributed.py +597 -0
  858. truthound/validators/timeseries/__init__.py +89 -0
  859. truthound/validators/timeseries/base.py +326 -0
  860. truthound/validators/timeseries/completeness.py +617 -0
  861. truthound/validators/timeseries/gap.py +485 -0
  862. truthound/validators/timeseries/monotonic.py +310 -0
  863. truthound/validators/timeseries/seasonality.py +422 -0
  864. truthound/validators/timeseries/trend.py +510 -0
  865. truthound/validators/uniqueness/__init__.py +59 -0
  866. truthound/validators/uniqueness/approximate.py +475 -0
  867. truthound/validators/uniqueness/distinct_values.py +253 -0
  868. truthound/validators/uniqueness/duplicate.py +118 -0
  869. truthound/validators/uniqueness/primary_key.py +140 -0
  870. truthound/validators/uniqueness/unique.py +191 -0
  871. truthound/validators/uniqueness/within_record.py +599 -0
  872. truthound/validators/utils.py +756 -0
  873. truthound-1.0.8.dist-info/METADATA +474 -0
  874. truthound-1.0.8.dist-info/RECORD +877 -0
  875. truthound-1.0.8.dist-info/WHEEL +4 -0
  876. truthound-1.0.8.dist-info/entry_points.txt +2 -0
  877. truthound-1.0.8.dist-info/licenses/LICENSE +190 -0
@@ -0,0 +1,1550 @@
1
+ """SQL Abstract Syntax Tree (AST) for Query Pushdown.
2
+
3
+ This module defines the AST nodes that represent SQL queries in a
4
+ database-agnostic way. The AST can be traversed and transformed
5
+ into dialect-specific SQL strings.
6
+
7
+ Design Principles:
8
+ - Immutable nodes for thread safety
9
+ - Visitor pattern support for traversal
10
+ - Type-safe construction
11
+ - Full SQL expression coverage
12
+
13
+ Example:
14
+ >>> from truthound.execution.pushdown.ast import (
15
+ ... SelectStatement,
16
+ ... Column,
17
+ ... Table,
18
+ ... BinaryExpression,
19
+ ... ComparisonOp,
20
+ ... Literal,
21
+ ... )
22
+ >>>
23
+ >>> # Build: SELECT * FROM users WHERE age > 18
24
+ >>> stmt = SelectStatement(
25
+ ... select_items=[Column("*")],
26
+ ... from_clause=FromClause(Table("users")),
27
+ ... where_clause=WhereClause(
28
+ ... BinaryExpression(
29
+ ... Column("age"),
30
+ ... ComparisonOp.GT,
31
+ ... Literal(18),
32
+ ... )
33
+ ... ),
34
+ ... )
35
+ """
36
+
37
+ from __future__ import annotations
38
+
39
+ from abc import ABC, abstractmethod
40
+ from dataclasses import dataclass, field
41
+ from enum import Enum, auto
42
+ from typing import Any, Generic, Sequence, TypeVar
43
+
44
+
45
+ # =============================================================================
46
+ # Base Classes
47
+ # =============================================================================
48
+
49
+
50
+ class SQLNode(ABC):
51
+ """Base class for all SQL AST nodes.
52
+
53
+ All AST nodes inherit from this class, providing a common
54
+ interface for traversal and transformation.
55
+ """
56
+
57
+ @abstractmethod
58
+ def accept(self, visitor: "SQLVisitor") -> Any:
59
+ """Accept a visitor for traversal.
60
+
61
+ Args:
62
+ visitor: The visitor to accept.
63
+
64
+ Returns:
65
+ Result from the visitor.
66
+ """
67
+ pass
68
+
69
+ def children(self) -> Sequence["SQLNode"]:
70
+ """Get child nodes for traversal.
71
+
72
+ Returns:
73
+ Sequence of child nodes.
74
+ """
75
+ return []
76
+
77
+
78
+ class Expression(SQLNode):
79
+ """Base class for SQL expressions.
80
+
81
+ Expressions are nodes that evaluate to a value, such as:
82
+ - Column references
83
+ - Literals
84
+ - Function calls
85
+ - Binary/Unary operations
86
+ """
87
+
88
+ def __and__(self, other: "Expression") -> "BinaryExpression":
89
+ """AND operator."""
90
+ return BinaryExpression(self, LogicalOp.AND, other)
91
+
92
+ def __or__(self, other: "Expression") -> "BinaryExpression":
93
+ """OR operator."""
94
+ return BinaryExpression(self, LogicalOp.OR, other)
95
+
96
+ def __invert__(self) -> "UnaryExpression":
97
+ """NOT operator."""
98
+ return UnaryExpression(UnaryOp.NOT, self)
99
+
100
+ def __eq__(self, other: Any) -> "BinaryExpression": # type: ignore[override]
101
+ """Equality comparison."""
102
+ return BinaryExpression(self, ComparisonOp.EQ, _to_expression(other))
103
+
104
+ def __ne__(self, other: Any) -> "BinaryExpression": # type: ignore[override]
105
+ """Inequality comparison."""
106
+ return BinaryExpression(self, ComparisonOp.NE, _to_expression(other))
107
+
108
+ def __lt__(self, other: Any) -> "BinaryExpression":
109
+ """Less than comparison."""
110
+ return BinaryExpression(self, ComparisonOp.LT, _to_expression(other))
111
+
112
+ def __le__(self, other: Any) -> "BinaryExpression":
113
+ """Less than or equal comparison."""
114
+ return BinaryExpression(self, ComparisonOp.LE, _to_expression(other))
115
+
116
+ def __gt__(self, other: Any) -> "BinaryExpression":
117
+ """Greater than comparison."""
118
+ return BinaryExpression(self, ComparisonOp.GT, _to_expression(other))
119
+
120
+ def __ge__(self, other: Any) -> "BinaryExpression":
121
+ """Greater than or equal comparison."""
122
+ return BinaryExpression(self, ComparisonOp.GE, _to_expression(other))
123
+
124
+ def __add__(self, other: Any) -> "BinaryExpression":
125
+ """Addition."""
126
+ return BinaryExpression(self, ArithmeticOp.ADD, _to_expression(other))
127
+
128
+ def __sub__(self, other: Any) -> "BinaryExpression":
129
+ """Subtraction."""
130
+ return BinaryExpression(self, ArithmeticOp.SUB, _to_expression(other))
131
+
132
+ def __mul__(self, other: Any) -> "BinaryExpression":
133
+ """Multiplication."""
134
+ return BinaryExpression(self, ArithmeticOp.MUL, _to_expression(other))
135
+
136
+ def __truediv__(self, other: Any) -> "BinaryExpression":
137
+ """Division."""
138
+ return BinaryExpression(self, ArithmeticOp.DIV, _to_expression(other))
139
+
140
+ def __mod__(self, other: Any) -> "BinaryExpression":
141
+ """Modulo."""
142
+ return BinaryExpression(self, ArithmeticOp.MOD, _to_expression(other))
143
+
144
+ def __neg__(self) -> "UnaryExpression":
145
+ """Negation."""
146
+ return UnaryExpression(UnaryOp.MINUS, self)
147
+
148
+ def alias(self, name: str) -> "Alias":
149
+ """Create an alias for this expression."""
150
+ return Alias(self, name)
151
+
152
+ def asc(self) -> "OrderByItem":
153
+ """Create ascending order by item."""
154
+ return OrderByItem(self, SortOrder.ASC)
155
+
156
+ def desc(self) -> "OrderByItem":
157
+ """Create descending order by item."""
158
+ return OrderByItem(self, SortOrder.DESC)
159
+
160
+ def is_null(self) -> "UnaryExpression":
161
+ """IS NULL check."""
162
+ return UnaryExpression(UnaryOp.IS_NULL, self)
163
+
164
+ def is_not_null(self) -> "UnaryExpression":
165
+ """IS NOT NULL check."""
166
+ return UnaryExpression(UnaryOp.IS_NOT_NULL, self)
167
+
168
+ def in_(self, values: Sequence[Any]) -> "InExpression":
169
+ """IN operator."""
170
+ exprs = [_to_expression(v) for v in values]
171
+ return InExpression(self, exprs, negated=False)
172
+
173
+ def not_in(self, values: Sequence[Any]) -> "InExpression":
174
+ """NOT IN operator."""
175
+ exprs = [_to_expression(v) for v in values]
176
+ return InExpression(self, exprs, negated=True)
177
+
178
+ def between(self, low: Any, high: Any) -> "BetweenExpression":
179
+ """BETWEEN operator."""
180
+ return BetweenExpression(
181
+ self,
182
+ _to_expression(low),
183
+ _to_expression(high),
184
+ negated=False,
185
+ )
186
+
187
+ def not_between(self, low: Any, high: Any) -> "BetweenExpression":
188
+ """NOT BETWEEN operator."""
189
+ return BetweenExpression(
190
+ self,
191
+ _to_expression(low),
192
+ _to_expression(high),
193
+ negated=True,
194
+ )
195
+
196
+ def like(self, pattern: str) -> "BinaryExpression":
197
+ """LIKE operator."""
198
+ return BinaryExpression(self, ComparisonOp.LIKE, Literal(pattern))
199
+
200
+ def not_like(self, pattern: str) -> "BinaryExpression":
201
+ """NOT LIKE operator."""
202
+ return BinaryExpression(self, ComparisonOp.NOT_LIKE, Literal(pattern))
203
+
204
+ def ilike(self, pattern: str) -> "BinaryExpression":
205
+ """ILIKE operator (case-insensitive LIKE)."""
206
+ return BinaryExpression(self, ComparisonOp.ILIKE, Literal(pattern))
207
+
208
+ def regexp(self, pattern: str) -> "BinaryExpression":
209
+ """Regular expression match."""
210
+ return BinaryExpression(self, ComparisonOp.REGEXP, Literal(pattern))
211
+
212
+
213
+ class Statement(SQLNode):
214
+ """Base class for SQL statements (SELECT, INSERT, etc.)."""
215
+ pass
216
+
217
+
218
+ # =============================================================================
219
+ # Enums
220
+ # =============================================================================
221
+
222
+
223
+ class QueryType(Enum):
224
+ """Type of SQL query."""
225
+
226
+ SELECT = "select"
227
+ INSERT = "insert"
228
+ UPDATE = "update"
229
+ DELETE = "delete"
230
+ MERGE = "merge"
231
+
232
+
233
+ class ComparisonOp(Enum):
234
+ """SQL comparison operators."""
235
+
236
+ EQ = "="
237
+ NE = "<>"
238
+ LT = "<"
239
+ LE = "<="
240
+ GT = ">"
241
+ GE = ">="
242
+ LIKE = "LIKE"
243
+ NOT_LIKE = "NOT LIKE"
244
+ ILIKE = "ILIKE" # Case-insensitive LIKE
245
+ REGEXP = "REGEXP"
246
+ SIMILAR_TO = "SIMILAR TO"
247
+
248
+
249
+ class LogicalOp(Enum):
250
+ """SQL logical operators."""
251
+
252
+ AND = "AND"
253
+ OR = "OR"
254
+
255
+
256
+ class ArithmeticOp(Enum):
257
+ """SQL arithmetic operators."""
258
+
259
+ ADD = "+"
260
+ SUB = "-"
261
+ MUL = "*"
262
+ DIV = "/"
263
+ MOD = "%"
264
+ POWER = "^"
265
+
266
+
267
+ class UnaryOp(Enum):
268
+ """SQL unary operators."""
269
+
270
+ NOT = "NOT"
271
+ MINUS = "-"
272
+ PLUS = "+"
273
+ IS_NULL = "IS NULL"
274
+ IS_NOT_NULL = "IS NOT NULL"
275
+ EXISTS = "EXISTS"
276
+ NOT_EXISTS = "NOT EXISTS"
277
+
278
+
279
+ class BinaryOp(Enum):
280
+ """Combined binary operator enum for convenience."""
281
+
282
+ # Comparison
283
+ EQ = "="
284
+ NE = "<>"
285
+ LT = "<"
286
+ LE = "<="
287
+ GT = ">"
288
+ GE = ">="
289
+ # Logical
290
+ AND = "AND"
291
+ OR = "OR"
292
+ # Arithmetic
293
+ ADD = "+"
294
+ SUB = "-"
295
+ MUL = "*"
296
+ DIV = "/"
297
+ MOD = "%"
298
+ # String
299
+ LIKE = "LIKE"
300
+ ILIKE = "ILIKE"
301
+ CONCAT = "||"
302
+
303
+
304
+ class JoinType(Enum):
305
+ """SQL JOIN types."""
306
+
307
+ INNER = "INNER JOIN"
308
+ LEFT = "LEFT JOIN"
309
+ LEFT_OUTER = "LEFT OUTER JOIN"
310
+ RIGHT = "RIGHT JOIN"
311
+ RIGHT_OUTER = "RIGHT OUTER JOIN"
312
+ FULL = "FULL JOIN"
313
+ FULL_OUTER = "FULL OUTER JOIN"
314
+ CROSS = "CROSS JOIN"
315
+ NATURAL = "NATURAL JOIN"
316
+
317
+
318
+ class SortOrder(Enum):
319
+ """SQL sort order."""
320
+
321
+ ASC = "ASC"
322
+ DESC = "DESC"
323
+
324
+
325
+ class NullsPosition(Enum):
326
+ """Position of NULLs in ORDER BY."""
327
+
328
+ FIRST = "NULLS FIRST"
329
+ LAST = "NULLS LAST"
330
+
331
+
332
+ class FrameType(Enum):
333
+ """Window frame type."""
334
+
335
+ ROWS = "ROWS"
336
+ RANGE = "RANGE"
337
+ GROUPS = "GROUPS"
338
+
339
+
340
+ class FrameBoundType(Enum):
341
+ """Window frame bound type."""
342
+
343
+ UNBOUNDED_PRECEDING = "UNBOUNDED PRECEDING"
344
+ PRECEDING = "PRECEDING"
345
+ CURRENT_ROW = "CURRENT ROW"
346
+ FOLLOWING = "FOLLOWING"
347
+ UNBOUNDED_FOLLOWING = "UNBOUNDED FOLLOWING"
348
+
349
+
350
+ class SetOperation(Enum):
351
+ """SQL set operations."""
352
+
353
+ UNION = "UNION"
354
+ UNION_ALL = "UNION ALL"
355
+ INTERSECT = "INTERSECT"
356
+ INTERSECT_ALL = "INTERSECT ALL"
357
+ EXCEPT = "EXCEPT"
358
+ EXCEPT_ALL = "EXCEPT ALL"
359
+
360
+
361
+ # =============================================================================
362
+ # Literals
363
+ # =============================================================================
364
+
365
+
366
+ @dataclass(frozen=True, eq=False)
367
+ class Literal(Expression):
368
+ """A literal value (number, string, boolean, etc.).
369
+
370
+ Attributes:
371
+ value: The literal value.
372
+ """
373
+
374
+ value: Any
375
+
376
+ def accept(self, visitor: "SQLVisitor") -> Any:
377
+ return visitor.visit_literal(self)
378
+
379
+ def __repr__(self) -> str:
380
+ return f"Literal({self.value!r})"
381
+
382
+
383
+ @dataclass(frozen=True, eq=False)
384
+ class NullLiteral(Expression):
385
+ """SQL NULL literal."""
386
+
387
+ def accept(self, visitor: "SQLVisitor") -> Any:
388
+ return visitor.visit_null_literal(self)
389
+
390
+ def __repr__(self) -> str:
391
+ return "NULL"
392
+
393
+
394
+ @dataclass(frozen=True, eq=False)
395
+ class BooleanLiteral(Expression):
396
+ """SQL boolean literal (TRUE/FALSE)."""
397
+
398
+ value: bool
399
+
400
+ def accept(self, visitor: "SQLVisitor") -> Any:
401
+ return visitor.visit_boolean_literal(self)
402
+
403
+ def __repr__(self) -> str:
404
+ return "TRUE" if self.value else "FALSE"
405
+
406
+
407
+ @dataclass(frozen=True, eq=False)
408
+ class ArrayLiteral(Expression):
409
+ """SQL array literal."""
410
+
411
+ elements: tuple[Expression, ...]
412
+
413
+ def accept(self, visitor: "SQLVisitor") -> Any:
414
+ return visitor.visit_array_literal(self)
415
+
416
+ def children(self) -> Sequence[SQLNode]:
417
+ return self.elements
418
+
419
+
420
+ # =============================================================================
421
+ # Identifiers
422
+ # =============================================================================
423
+
424
+
425
+ @dataclass(frozen=True, eq=False)
426
+ class Identifier(Expression):
427
+ """A SQL identifier (table name, column name, etc.).
428
+
429
+ Attributes:
430
+ name: The identifier name.
431
+ quoted: Whether the identifier should be quoted.
432
+ """
433
+
434
+ name: str
435
+ quoted: bool = False
436
+
437
+ def accept(self, visitor: "SQLVisitor") -> Any:
438
+ return visitor.visit_identifier(self)
439
+
440
+ def __repr__(self) -> str:
441
+ return f"Identifier({self.name!r})"
442
+
443
+
444
+ @dataclass(frozen=True, eq=False)
445
+ class Column(Expression):
446
+ """A column reference.
447
+
448
+ Attributes:
449
+ name: Column name.
450
+ table: Optional table/alias name.
451
+ schema: Optional schema name.
452
+ """
453
+
454
+ name: str
455
+ table: str | None = None
456
+ schema: str | None = None
457
+
458
+ def accept(self, visitor: "SQLVisitor") -> Any:
459
+ return visitor.visit_column(self)
460
+
461
+ def __repr__(self) -> str:
462
+ parts = []
463
+ if self.schema:
464
+ parts.append(self.schema)
465
+ if self.table:
466
+ parts.append(self.table)
467
+ parts.append(self.name)
468
+ return f"Column({'.'.join(parts)})"
469
+
470
+
471
+ @dataclass(frozen=True)
472
+ class Table(SQLNode):
473
+ """A table reference.
474
+
475
+ Attributes:
476
+ name: Table name.
477
+ schema: Optional schema name.
478
+ catalog: Optional catalog/database name.
479
+ alias: Optional table alias.
480
+ """
481
+
482
+ name: str
483
+ schema: str | None = None
484
+ catalog: str | None = None
485
+ alias: str | None = None
486
+
487
+ def accept(self, visitor: "SQLVisitor") -> Any:
488
+ return visitor.visit_table(self)
489
+
490
+ def __repr__(self) -> str:
491
+ parts = []
492
+ if self.catalog:
493
+ parts.append(self.catalog)
494
+ if self.schema:
495
+ parts.append(self.schema)
496
+ parts.append(self.name)
497
+ result = '.'.join(parts)
498
+ if self.alias:
499
+ result += f" AS {self.alias}"
500
+ return f"Table({result})"
501
+
502
+
503
+ @dataclass(frozen=True, eq=False)
504
+ class Alias(Expression):
505
+ """An aliased expression.
506
+
507
+ Attributes:
508
+ expression: The expression being aliased.
509
+ alias: The alias name.
510
+ """
511
+
512
+ expression: Expression
513
+ alias: str
514
+
515
+ def accept(self, visitor: "SQLVisitor") -> Any:
516
+ return visitor.visit_alias(self)
517
+
518
+ def children(self) -> Sequence[SQLNode]:
519
+ return [self.expression]
520
+
521
+ def __repr__(self) -> str:
522
+ return f"Alias({self.expression!r} AS {self.alias})"
523
+
524
+
525
+ @dataclass(frozen=True, eq=False)
526
+ class Star(Expression):
527
+ """SELECT * or table.* expression.
528
+
529
+ Attributes:
530
+ table: Optional table name for table.* syntax.
531
+ """
532
+
533
+ table: str | None = None
534
+
535
+ def accept(self, visitor: "SQLVisitor") -> Any:
536
+ return visitor.visit_star(self)
537
+
538
+ def __repr__(self) -> str:
539
+ if self.table:
540
+ return f"Star({self.table}.*)"
541
+ return "Star(*)"
542
+
543
+
544
+ # =============================================================================
545
+ # Expressions
546
+ # =============================================================================
547
+
548
+
549
+ @dataclass(frozen=True, eq=False)
550
+ class BinaryExpression(Expression):
551
+ """A binary expression (left op right).
552
+
553
+ Attributes:
554
+ left: Left operand.
555
+ operator: Binary operator.
556
+ right: Right operand.
557
+ """
558
+
559
+ left: Expression
560
+ operator: ComparisonOp | LogicalOp | ArithmeticOp | BinaryOp
561
+ right: Expression
562
+
563
+ def accept(self, visitor: "SQLVisitor") -> Any:
564
+ return visitor.visit_binary_expression(self)
565
+
566
+ def children(self) -> Sequence[SQLNode]:
567
+ return [self.left, self.right]
568
+
569
+ def __repr__(self) -> str:
570
+ op = self.operator.value if isinstance(self.operator, Enum) else self.operator
571
+ return f"({self.left!r} {op} {self.right!r})"
572
+
573
+
574
+ @dataclass(frozen=True, eq=False)
575
+ class UnaryExpression(Expression):
576
+ """A unary expression (op operand).
577
+
578
+ Attributes:
579
+ operator: Unary operator.
580
+ operand: The operand.
581
+ """
582
+
583
+ operator: UnaryOp
584
+ operand: Expression
585
+
586
+ def accept(self, visitor: "SQLVisitor") -> Any:
587
+ return visitor.visit_unary_expression(self)
588
+
589
+ def children(self) -> Sequence[SQLNode]:
590
+ return [self.operand]
591
+
592
+ def __repr__(self) -> str:
593
+ return f"({self.operator.value} {self.operand!r})"
594
+
595
+
596
+ @dataclass(frozen=True, eq=False)
597
+ class InExpression(Expression):
598
+ """IN expression (expr IN (values)).
599
+
600
+ Attributes:
601
+ expression: The expression to test.
602
+ values: List of values or subquery.
603
+ negated: Whether this is NOT IN.
604
+ """
605
+
606
+ expression: Expression
607
+ values: tuple[Expression, ...] | "SelectStatement"
608
+ negated: bool = False
609
+
610
+ def __init__(
611
+ self,
612
+ expression: Expression,
613
+ values: Sequence[Expression] | "SelectStatement",
614
+ negated: bool = False,
615
+ ):
616
+ object.__setattr__(self, "expression", expression)
617
+ if isinstance(values, SelectStatement):
618
+ object.__setattr__(self, "values", values)
619
+ else:
620
+ object.__setattr__(self, "values", tuple(values))
621
+ object.__setattr__(self, "negated", negated)
622
+
623
+ def accept(self, visitor: "SQLVisitor") -> Any:
624
+ return visitor.visit_in_expression(self)
625
+
626
+ def children(self) -> Sequence[SQLNode]:
627
+ children: list[SQLNode] = [self.expression]
628
+ if isinstance(self.values, SelectStatement):
629
+ children.append(self.values)
630
+ else:
631
+ children.extend(self.values)
632
+ return children
633
+
634
+ def __repr__(self) -> str:
635
+ op = "NOT IN" if self.negated else "IN"
636
+ return f"({self.expression!r} {op} {self.values!r})"
637
+
638
+
639
+ @dataclass(frozen=True, eq=False)
640
+ class BetweenExpression(Expression):
641
+ """BETWEEN expression (expr BETWEEN low AND high).
642
+
643
+ Attributes:
644
+ expression: The expression to test.
645
+ low: Lower bound.
646
+ high: Upper bound.
647
+ negated: Whether this is NOT BETWEEN.
648
+ """
649
+
650
+ expression: Expression
651
+ low: Expression
652
+ high: Expression
653
+ negated: bool = False
654
+
655
+ def accept(self, visitor: "SQLVisitor") -> Any:
656
+ return visitor.visit_between_expression(self)
657
+
658
+ def children(self) -> Sequence[SQLNode]:
659
+ return [self.expression, self.low, self.high]
660
+
661
+ def __repr__(self) -> str:
662
+ op = "NOT BETWEEN" if self.negated else "BETWEEN"
663
+ return f"({self.expression!r} {op} {self.low!r} AND {self.high!r})"
664
+
665
+
666
+ @dataclass(frozen=True, eq=False)
667
+ class ExistsExpression(Expression):
668
+ """EXISTS expression.
669
+
670
+ Attributes:
671
+ subquery: The subquery to test.
672
+ negated: Whether this is NOT EXISTS.
673
+ """
674
+
675
+ subquery: "SelectStatement"
676
+ negated: bool = False
677
+
678
+ def accept(self, visitor: "SQLVisitor") -> Any:
679
+ return visitor.visit_exists_expression(self)
680
+
681
+ def children(self) -> Sequence[SQLNode]:
682
+ return [self.subquery]
683
+
684
+ def __repr__(self) -> str:
685
+ op = "NOT EXISTS" if self.negated else "EXISTS"
686
+ return f"({op} {self.subquery!r})"
687
+
688
+
689
+ @dataclass(frozen=True, eq=False)
690
+ class SubqueryExpression(Expression):
691
+ """A subquery used as an expression.
692
+
693
+ Attributes:
694
+ subquery: The subquery.
695
+ """
696
+
697
+ subquery: "SelectStatement"
698
+
699
+ def accept(self, visitor: "SQLVisitor") -> Any:
700
+ return visitor.visit_subquery_expression(self)
701
+
702
+ def children(self) -> Sequence[SQLNode]:
703
+ return [self.subquery]
704
+
705
+
706
+ @dataclass(frozen=True, eq=False)
707
+ class CastExpression(Expression):
708
+ """CAST expression (CAST(expr AS type)).
709
+
710
+ Attributes:
711
+ expression: The expression to cast.
712
+ target_type: The target SQL type.
713
+ """
714
+
715
+ expression: Expression
716
+ target_type: str
717
+
718
+ def accept(self, visitor: "SQLVisitor") -> Any:
719
+ return visitor.visit_cast_expression(self)
720
+
721
+ def children(self) -> Sequence[SQLNode]:
722
+ return [self.expression]
723
+
724
+ def __repr__(self) -> str:
725
+ return f"CAST({self.expression!r} AS {self.target_type})"
726
+
727
+
728
+ @dataclass(frozen=True)
729
+ class WhenClause(SQLNode):
730
+ """WHEN clause in CASE expression.
731
+
732
+ Attributes:
733
+ condition: The condition to test.
734
+ result: The result if condition is true.
735
+ """
736
+
737
+ condition: Expression
738
+ result: Expression
739
+
740
+ def accept(self, visitor: "SQLVisitor") -> Any:
741
+ return visitor.visit_when_clause(self)
742
+
743
+ def children(self) -> Sequence[SQLNode]:
744
+ return [self.condition, self.result]
745
+
746
+
747
+ @dataclass(frozen=True, eq=False)
748
+ class CaseExpression(Expression):
749
+ """CASE expression.
750
+
751
+ Attributes:
752
+ operand: Optional operand for simple CASE.
753
+ when_clauses: List of WHEN clauses.
754
+ else_result: Optional ELSE result.
755
+ """
756
+
757
+ when_clauses: tuple[WhenClause, ...]
758
+ operand: Expression | None = None
759
+ else_result: Expression | None = None
760
+
761
+ def __init__(
762
+ self,
763
+ when_clauses: Sequence[WhenClause],
764
+ operand: Expression | None = None,
765
+ else_result: Expression | None = None,
766
+ ):
767
+ object.__setattr__(self, "when_clauses", tuple(when_clauses))
768
+ object.__setattr__(self, "operand", operand)
769
+ object.__setattr__(self, "else_result", else_result)
770
+
771
+ def accept(self, visitor: "SQLVisitor") -> Any:
772
+ return visitor.visit_case_expression(self)
773
+
774
+ def children(self) -> Sequence[SQLNode]:
775
+ children: list[SQLNode] = []
776
+ if self.operand:
777
+ children.append(self.operand)
778
+ children.extend(self.when_clauses)
779
+ if self.else_result:
780
+ children.append(self.else_result)
781
+ return children
782
+
783
+
784
+ # =============================================================================
785
+ # Function Calls
786
+ # =============================================================================
787
+
788
+
789
+ @dataclass(frozen=True, eq=False)
790
+ class FunctionCall(Expression):
791
+ """A SQL function call.
792
+
793
+ Attributes:
794
+ name: Function name.
795
+ arguments: Function arguments.
796
+ distinct: Whether DISTINCT is applied (for aggregates).
797
+ filter_clause: Optional FILTER clause.
798
+ """
799
+
800
+ name: str
801
+ arguments: tuple[Expression, ...]
802
+ distinct: bool = False
803
+ filter_clause: Expression | None = None
804
+
805
+ def __init__(
806
+ self,
807
+ name: str,
808
+ arguments: Sequence[Expression] | None = None,
809
+ distinct: bool = False,
810
+ filter_clause: Expression | None = None,
811
+ ):
812
+ object.__setattr__(self, "name", name)
813
+ object.__setattr__(self, "arguments", tuple(arguments or []))
814
+ object.__setattr__(self, "distinct", distinct)
815
+ object.__setattr__(self, "filter_clause", filter_clause)
816
+
817
+ def accept(self, visitor: "SQLVisitor") -> Any:
818
+ return visitor.visit_function_call(self)
819
+
820
+ def children(self) -> Sequence[SQLNode]:
821
+ children: list[SQLNode] = list(self.arguments)
822
+ if self.filter_clause:
823
+ children.append(self.filter_clause)
824
+ return children
825
+
826
+ def __repr__(self) -> str:
827
+ args = ", ".join(repr(a) for a in self.arguments)
828
+ distinct = "DISTINCT " if self.distinct else ""
829
+ return f"{self.name}({distinct}{args})"
830
+
831
+
832
+ @dataclass(frozen=True, eq=False)
833
+ class AggregateFunction(Expression):
834
+ """An aggregate function call (COUNT, SUM, AVG, etc.).
835
+
836
+ Attributes:
837
+ name: Function name (COUNT, SUM, AVG, MIN, MAX, etc.).
838
+ argument: The argument to aggregate.
839
+ distinct: Whether DISTINCT is applied.
840
+ filter_clause: Optional FILTER (WHERE ...) clause.
841
+ order_by: Optional ORDER BY for ordered-set aggregates.
842
+ """
843
+
844
+ name: str
845
+ argument: Expression | None
846
+ distinct: bool = False
847
+ filter_clause: Expression | None = None
848
+ order_by: tuple["OrderByItem", ...] | None = None
849
+
850
+ def __init__(
851
+ self,
852
+ name: str,
853
+ argument: Expression | None = None,
854
+ distinct: bool = False,
855
+ filter_clause: Expression | None = None,
856
+ order_by: Sequence["OrderByItem"] | None = None,
857
+ ):
858
+ object.__setattr__(self, "name", name)
859
+ object.__setattr__(self, "argument", argument)
860
+ object.__setattr__(self, "distinct", distinct)
861
+ object.__setattr__(self, "filter_clause", filter_clause)
862
+ object.__setattr__(
863
+ self, "order_by", tuple(order_by) if order_by else None
864
+ )
865
+
866
+ def accept(self, visitor: "SQLVisitor") -> Any:
867
+ return visitor.visit_aggregate_function(self)
868
+
869
+ def children(self) -> Sequence[SQLNode]:
870
+ children: list[SQLNode] = []
871
+ if self.argument:
872
+ children.append(self.argument)
873
+ if self.filter_clause:
874
+ children.append(self.filter_clause)
875
+ if self.order_by:
876
+ children.extend(self.order_by)
877
+ return children
878
+
879
+ def over(self, window: "WindowSpec | str | None" = None) -> "WindowFunction":
880
+ """Add OVER clause to create a window function."""
881
+ return WindowFunction(self, window)
882
+
883
+ def __repr__(self) -> str:
884
+ if self.argument:
885
+ distinct = "DISTINCT " if self.distinct else ""
886
+ return f"{self.name}({distinct}{self.argument!r})"
887
+ return f"{self.name}(*)"
888
+
889
+
890
+ @dataclass(frozen=True)
891
+ class FrameBound(SQLNode):
892
+ """Window frame bound.
893
+
894
+ Attributes:
895
+ bound_type: Type of bound.
896
+ offset: Optional numeric offset.
897
+ """
898
+
899
+ bound_type: FrameBoundType
900
+ offset: int | None = None
901
+
902
+ def accept(self, visitor: "SQLVisitor") -> Any:
903
+ return visitor.visit_frame_bound(self)
904
+
905
+ def __repr__(self) -> str:
906
+ if self.offset is not None:
907
+ if self.bound_type == FrameBoundType.PRECEDING:
908
+ return f"{self.offset} PRECEDING"
909
+ elif self.bound_type == FrameBoundType.FOLLOWING:
910
+ return f"{self.offset} FOLLOWING"
911
+ return self.bound_type.value
912
+
913
+
914
+ @dataclass(frozen=True)
915
+ class WindowSpec(SQLNode):
916
+ """Window specification for window functions.
917
+
918
+ Attributes:
919
+ partition_by: Optional PARTITION BY columns.
920
+ order_by: Optional ORDER BY items.
921
+ frame_type: Optional frame type (ROWS, RANGE, GROUPS).
922
+ frame_start: Optional frame start bound.
923
+ frame_end: Optional frame end bound.
924
+ name: Optional window name (for WINDOW clause).
925
+ """
926
+
927
+ partition_by: tuple[Expression, ...] | None = None
928
+ order_by: tuple["OrderByItem", ...] | None = None
929
+ frame_type: FrameType | None = None
930
+ frame_start: FrameBound | None = None
931
+ frame_end: FrameBound | None = None
932
+ name: str | None = None
933
+
934
+ def __init__(
935
+ self,
936
+ partition_by: Sequence[Expression] | None = None,
937
+ order_by: Sequence["OrderByItem"] | None = None,
938
+ frame_type: FrameType | None = None,
939
+ frame_start: FrameBound | None = None,
940
+ frame_end: FrameBound | None = None,
941
+ name: str | None = None,
942
+ ):
943
+ object.__setattr__(
944
+ self, "partition_by", tuple(partition_by) if partition_by else None
945
+ )
946
+ object.__setattr__(
947
+ self, "order_by", tuple(order_by) if order_by else None
948
+ )
949
+ object.__setattr__(self, "frame_type", frame_type)
950
+ object.__setattr__(self, "frame_start", frame_start)
951
+ object.__setattr__(self, "frame_end", frame_end)
952
+ object.__setattr__(self, "name", name)
953
+
954
+ def accept(self, visitor: "SQLVisitor") -> Any:
955
+ return visitor.visit_window_spec(self)
956
+
957
+ def children(self) -> Sequence[SQLNode]:
958
+ children: list[SQLNode] = []
959
+ if self.partition_by:
960
+ children.extend(self.partition_by)
961
+ if self.order_by:
962
+ children.extend(self.order_by)
963
+ if self.frame_start:
964
+ children.append(self.frame_start)
965
+ if self.frame_end:
966
+ children.append(self.frame_end)
967
+ return children
968
+
969
+
970
+ @dataclass(frozen=True, eq=False)
971
+ class WindowFunction(Expression):
972
+ """A window function expression.
973
+
974
+ Attributes:
975
+ function: The aggregate or window function.
976
+ window_spec: The window specification or named window.
977
+ """
978
+
979
+ function: AggregateFunction | FunctionCall
980
+ window_spec: WindowSpec | str | None
981
+
982
+ def accept(self, visitor: "SQLVisitor") -> Any:
983
+ return visitor.visit_window_function(self)
984
+
985
+ def children(self) -> Sequence[SQLNode]:
986
+ children: list[SQLNode] = [self.function]
987
+ if isinstance(self.window_spec, WindowSpec):
988
+ children.append(self.window_spec)
989
+ return children
990
+
991
+ def __repr__(self) -> str:
992
+ if self.window_spec:
993
+ return f"{self.function!r} OVER ({self.window_spec!r})"
994
+ return f"{self.function!r} OVER ()"
995
+
996
+
997
+ # =============================================================================
998
+ # SELECT Clauses
999
+ # =============================================================================
1000
+
1001
+
1002
+ @dataclass(frozen=True)
1003
+ class SelectItem(SQLNode):
1004
+ """A single item in SELECT clause.
1005
+
1006
+ Attributes:
1007
+ expression: The expression.
1008
+ alias: Optional alias.
1009
+ """
1010
+
1011
+ expression: Expression
1012
+ alias: str | None = None
1013
+
1014
+ def accept(self, visitor: "SQLVisitor") -> Any:
1015
+ return visitor.visit_select_item(self)
1016
+
1017
+ def children(self) -> Sequence[SQLNode]:
1018
+ return [self.expression]
1019
+
1020
+
1021
+ @dataclass(frozen=True)
1022
+ class FromClause(SQLNode):
1023
+ """FROM clause.
1024
+
1025
+ Attributes:
1026
+ source: Table, subquery, or joined tables.
1027
+ """
1028
+
1029
+ source: Table | "SelectStatement" | "JoinClause"
1030
+
1031
+ def accept(self, visitor: "SQLVisitor") -> Any:
1032
+ return visitor.visit_from_clause(self)
1033
+
1034
+ def children(self) -> Sequence[SQLNode]:
1035
+ return [self.source]
1036
+
1037
+
1038
+ @dataclass(frozen=True)
1039
+ class JoinClause(SQLNode):
1040
+ """A JOIN clause.
1041
+
1042
+ Attributes:
1043
+ left: Left side of join.
1044
+ right: Right side of join.
1045
+ join_type: Type of join.
1046
+ condition: Optional join condition (for ON clause).
1047
+ using_columns: Optional USING columns.
1048
+ """
1049
+
1050
+ left: Table | "SelectStatement" | "JoinClause"
1051
+ right: Table | "SelectStatement"
1052
+ join_type: JoinType
1053
+ condition: Expression | None = None
1054
+ using_columns: tuple[str, ...] | None = None
1055
+
1056
+ def __init__(
1057
+ self,
1058
+ left: Table | "SelectStatement" | "JoinClause",
1059
+ right: Table | "SelectStatement",
1060
+ join_type: JoinType,
1061
+ condition: Expression | None = None,
1062
+ using_columns: Sequence[str] | None = None,
1063
+ ):
1064
+ object.__setattr__(self, "left", left)
1065
+ object.__setattr__(self, "right", right)
1066
+ object.__setattr__(self, "join_type", join_type)
1067
+ object.__setattr__(self, "condition", condition)
1068
+ object.__setattr__(
1069
+ self, "using_columns", tuple(using_columns) if using_columns else None
1070
+ )
1071
+
1072
+ def accept(self, visitor: "SQLVisitor") -> Any:
1073
+ return visitor.visit_join_clause(self)
1074
+
1075
+ def children(self) -> Sequence[SQLNode]:
1076
+ children: list[SQLNode] = [self.left, self.right]
1077
+ if self.condition:
1078
+ children.append(self.condition)
1079
+ return children
1080
+
1081
+
1082
+ @dataclass(frozen=True)
1083
+ class WhereClause(SQLNode):
1084
+ """WHERE clause.
1085
+
1086
+ Attributes:
1087
+ condition: The filter condition.
1088
+ """
1089
+
1090
+ condition: Expression
1091
+
1092
+ def accept(self, visitor: "SQLVisitor") -> Any:
1093
+ return visitor.visit_where_clause(self)
1094
+
1095
+ def children(self) -> Sequence[SQLNode]:
1096
+ return [self.condition]
1097
+
1098
+
1099
+ @dataclass(frozen=True)
1100
+ class GroupByClause(SQLNode):
1101
+ """GROUP BY clause.
1102
+
1103
+ Attributes:
1104
+ expressions: Grouping expressions.
1105
+ with_rollup: Whether to include ROLLUP.
1106
+ with_cube: Whether to include CUBE.
1107
+ grouping_sets: Optional grouping sets.
1108
+ """
1109
+
1110
+ expressions: tuple[Expression, ...]
1111
+ with_rollup: bool = False
1112
+ with_cube: bool = False
1113
+ grouping_sets: tuple[tuple[Expression, ...], ...] | None = None
1114
+
1115
+ def __init__(
1116
+ self,
1117
+ expressions: Sequence[Expression],
1118
+ with_rollup: bool = False,
1119
+ with_cube: bool = False,
1120
+ grouping_sets: Sequence[Sequence[Expression]] | None = None,
1121
+ ):
1122
+ object.__setattr__(self, "expressions", tuple(expressions))
1123
+ object.__setattr__(self, "with_rollup", with_rollup)
1124
+ object.__setattr__(self, "with_cube", with_cube)
1125
+ if grouping_sets:
1126
+ object.__setattr__(
1127
+ self,
1128
+ "grouping_sets",
1129
+ tuple(tuple(gs) for gs in grouping_sets),
1130
+ )
1131
+ else:
1132
+ object.__setattr__(self, "grouping_sets", None)
1133
+
1134
+ def accept(self, visitor: "SQLVisitor") -> Any:
1135
+ return visitor.visit_group_by_clause(self)
1136
+
1137
+ def children(self) -> Sequence[SQLNode]:
1138
+ return list(self.expressions)
1139
+
1140
+
1141
+ @dataclass(frozen=True)
1142
+ class HavingClause(SQLNode):
1143
+ """HAVING clause.
1144
+
1145
+ Attributes:
1146
+ condition: The filter condition (applied after GROUP BY).
1147
+ """
1148
+
1149
+ condition: Expression
1150
+
1151
+ def accept(self, visitor: "SQLVisitor") -> Any:
1152
+ return visitor.visit_having_clause(self)
1153
+
1154
+ def children(self) -> Sequence[SQLNode]:
1155
+ return [self.condition]
1156
+
1157
+
1158
+ @dataclass(frozen=True)
1159
+ class OrderByItem(SQLNode):
1160
+ """A single item in ORDER BY clause.
1161
+
1162
+ Attributes:
1163
+ expression: The expression to sort by.
1164
+ order: Sort order (ASC/DESC).
1165
+ nulls: Position of NULLs.
1166
+ """
1167
+
1168
+ expression: Expression
1169
+ order: SortOrder = SortOrder.ASC
1170
+ nulls: NullsPosition | None = None
1171
+
1172
+ def accept(self, visitor: "SQLVisitor") -> Any:
1173
+ return visitor.visit_order_by_item(self)
1174
+
1175
+ def children(self) -> Sequence[SQLNode]:
1176
+ return [self.expression]
1177
+
1178
+
1179
+ @dataclass(frozen=True)
1180
+ class OrderByClause(SQLNode):
1181
+ """ORDER BY clause.
1182
+
1183
+ Attributes:
1184
+ items: Order by items.
1185
+ """
1186
+
1187
+ items: tuple[OrderByItem, ...]
1188
+
1189
+ def __init__(self, items: Sequence[OrderByItem]):
1190
+ object.__setattr__(self, "items", tuple(items))
1191
+
1192
+ def accept(self, visitor: "SQLVisitor") -> Any:
1193
+ return visitor.visit_order_by_clause(self)
1194
+
1195
+ def children(self) -> Sequence[SQLNode]:
1196
+ return list(self.items)
1197
+
1198
+
1199
+ @dataclass(frozen=True)
1200
+ class LimitClause(SQLNode):
1201
+ """LIMIT clause.
1202
+
1203
+ Attributes:
1204
+ count: Maximum number of rows.
1205
+ """
1206
+
1207
+ count: int | Expression
1208
+
1209
+ def accept(self, visitor: "SQLVisitor") -> Any:
1210
+ return visitor.visit_limit_clause(self)
1211
+
1212
+ def children(self) -> Sequence[SQLNode]:
1213
+ if isinstance(self.count, Expression):
1214
+ return [self.count]
1215
+ return []
1216
+
1217
+
1218
+ @dataclass(frozen=True)
1219
+ class OffsetClause(SQLNode):
1220
+ """OFFSET clause.
1221
+
1222
+ Attributes:
1223
+ offset: Number of rows to skip.
1224
+ """
1225
+
1226
+ offset: int | Expression
1227
+
1228
+ def accept(self, visitor: "SQLVisitor") -> Any:
1229
+ return visitor.visit_offset_clause(self)
1230
+
1231
+ def children(self) -> Sequence[SQLNode]:
1232
+ if isinstance(self.offset, Expression):
1233
+ return [self.offset]
1234
+ return []
1235
+
1236
+
1237
+ # =============================================================================
1238
+ # Statements
1239
+ # =============================================================================
1240
+
1241
+
1242
+ @dataclass(frozen=True)
1243
+ class SelectStatement(Statement):
1244
+ """A complete SELECT statement.
1245
+
1246
+ Attributes:
1247
+ select_items: Items to select.
1248
+ from_clause: Optional FROM clause.
1249
+ where_clause: Optional WHERE clause.
1250
+ group_by_clause: Optional GROUP BY clause.
1251
+ having_clause: Optional HAVING clause.
1252
+ order_by_clause: Optional ORDER BY clause.
1253
+ limit_clause: Optional LIMIT clause.
1254
+ offset_clause: Optional OFFSET clause.
1255
+ distinct: Whether to use SELECT DISTINCT.
1256
+ ctes: Optional Common Table Expressions.
1257
+ """
1258
+
1259
+ select_items: tuple[SelectItem | Expression, ...]
1260
+ from_clause: FromClause | None = None
1261
+ where_clause: WhereClause | None = None
1262
+ group_by_clause: GroupByClause | None = None
1263
+ having_clause: HavingClause | None = None
1264
+ order_by_clause: OrderByClause | None = None
1265
+ limit_clause: LimitClause | None = None
1266
+ offset_clause: OffsetClause | None = None
1267
+ distinct: bool = False
1268
+ ctes: tuple["CTEClause", ...] | None = None
1269
+
1270
+ def __init__(
1271
+ self,
1272
+ select_items: Sequence[SelectItem | Expression],
1273
+ from_clause: FromClause | None = None,
1274
+ where_clause: WhereClause | None = None,
1275
+ group_by_clause: GroupByClause | None = None,
1276
+ having_clause: HavingClause | None = None,
1277
+ order_by_clause: OrderByClause | None = None,
1278
+ limit_clause: LimitClause | None = None,
1279
+ offset_clause: OffsetClause | None = None,
1280
+ distinct: bool = False,
1281
+ ctes: Sequence["CTEClause"] | None = None,
1282
+ ):
1283
+ object.__setattr__(self, "select_items", tuple(select_items))
1284
+ object.__setattr__(self, "from_clause", from_clause)
1285
+ object.__setattr__(self, "where_clause", where_clause)
1286
+ object.__setattr__(self, "group_by_clause", group_by_clause)
1287
+ object.__setattr__(self, "having_clause", having_clause)
1288
+ object.__setattr__(self, "order_by_clause", order_by_clause)
1289
+ object.__setattr__(self, "limit_clause", limit_clause)
1290
+ object.__setattr__(self, "offset_clause", offset_clause)
1291
+ object.__setattr__(self, "distinct", distinct)
1292
+ object.__setattr__(self, "ctes", tuple(ctes) if ctes else None)
1293
+
1294
+ def accept(self, visitor: "SQLVisitor") -> Any:
1295
+ return visitor.visit_select_statement(self)
1296
+
1297
+ def children(self) -> Sequence[SQLNode]:
1298
+ children: list[SQLNode] = list(self.select_items)
1299
+ if self.ctes:
1300
+ children.extend(self.ctes)
1301
+ if self.from_clause:
1302
+ children.append(self.from_clause)
1303
+ if self.where_clause:
1304
+ children.append(self.where_clause)
1305
+ if self.group_by_clause:
1306
+ children.append(self.group_by_clause)
1307
+ if self.having_clause:
1308
+ children.append(self.having_clause)
1309
+ if self.order_by_clause:
1310
+ children.append(self.order_by_clause)
1311
+ if self.limit_clause:
1312
+ children.append(self.limit_clause)
1313
+ if self.offset_clause:
1314
+ children.append(self.offset_clause)
1315
+ return children
1316
+
1317
+
1318
+ @dataclass(frozen=True)
1319
+ class CTEClause(SQLNode):
1320
+ """Common Table Expression (WITH clause).
1321
+
1322
+ Attributes:
1323
+ name: CTE name.
1324
+ query: The CTE query.
1325
+ columns: Optional column names.
1326
+ recursive: Whether this is a recursive CTE.
1327
+ """
1328
+
1329
+ name: str
1330
+ query: SelectStatement
1331
+ columns: tuple[str, ...] | None = None
1332
+ recursive: bool = False
1333
+
1334
+ def __init__(
1335
+ self,
1336
+ name: str,
1337
+ query: SelectStatement,
1338
+ columns: Sequence[str] | None = None,
1339
+ recursive: bool = False,
1340
+ ):
1341
+ object.__setattr__(self, "name", name)
1342
+ object.__setattr__(self, "query", query)
1343
+ object.__setattr__(self, "columns", tuple(columns) if columns else None)
1344
+ object.__setattr__(self, "recursive", recursive)
1345
+
1346
+ def accept(self, visitor: "SQLVisitor") -> Any:
1347
+ return visitor.visit_cte_clause(self)
1348
+
1349
+ def children(self) -> Sequence[SQLNode]:
1350
+ return [self.query]
1351
+
1352
+
1353
+ @dataclass(frozen=True)
1354
+ class SetOperationStatement(Statement):
1355
+ """A set operation (UNION, INTERSECT, EXCEPT).
1356
+
1357
+ Attributes:
1358
+ left: Left query.
1359
+ right: Right query.
1360
+ operation: Set operation type.
1361
+ """
1362
+
1363
+ left: SelectStatement | "SetOperationStatement"
1364
+ right: SelectStatement | "SetOperationStatement"
1365
+ operation: SetOperation
1366
+
1367
+ def accept(self, visitor: "SQLVisitor") -> Any:
1368
+ return visitor.visit_set_operation(self)
1369
+
1370
+ def children(self) -> Sequence[SQLNode]:
1371
+ return [self.left, self.right]
1372
+
1373
+
1374
+ # =============================================================================
1375
+ # Visitor Pattern
1376
+ # =============================================================================
1377
+
1378
+
1379
+ class SQLVisitor(ABC):
1380
+ """Abstract visitor for SQL AST traversal.
1381
+
1382
+ Implement this class to transform or analyze SQL AST nodes.
1383
+ """
1384
+
1385
+ @abstractmethod
1386
+ def visit_literal(self, node: Literal) -> Any:
1387
+ pass
1388
+
1389
+ @abstractmethod
1390
+ def visit_null_literal(self, node: NullLiteral) -> Any:
1391
+ pass
1392
+
1393
+ @abstractmethod
1394
+ def visit_boolean_literal(self, node: BooleanLiteral) -> Any:
1395
+ pass
1396
+
1397
+ @abstractmethod
1398
+ def visit_array_literal(self, node: ArrayLiteral) -> Any:
1399
+ pass
1400
+
1401
+ @abstractmethod
1402
+ def visit_identifier(self, node: Identifier) -> Any:
1403
+ pass
1404
+
1405
+ @abstractmethod
1406
+ def visit_column(self, node: Column) -> Any:
1407
+ pass
1408
+
1409
+ @abstractmethod
1410
+ def visit_table(self, node: Table) -> Any:
1411
+ pass
1412
+
1413
+ @abstractmethod
1414
+ def visit_alias(self, node: Alias) -> Any:
1415
+ pass
1416
+
1417
+ @abstractmethod
1418
+ def visit_star(self, node: Star) -> Any:
1419
+ pass
1420
+
1421
+ @abstractmethod
1422
+ def visit_binary_expression(self, node: BinaryExpression) -> Any:
1423
+ pass
1424
+
1425
+ @abstractmethod
1426
+ def visit_unary_expression(self, node: UnaryExpression) -> Any:
1427
+ pass
1428
+
1429
+ @abstractmethod
1430
+ def visit_in_expression(self, node: InExpression) -> Any:
1431
+ pass
1432
+
1433
+ @abstractmethod
1434
+ def visit_between_expression(self, node: BetweenExpression) -> Any:
1435
+ pass
1436
+
1437
+ @abstractmethod
1438
+ def visit_exists_expression(self, node: ExistsExpression) -> Any:
1439
+ pass
1440
+
1441
+ @abstractmethod
1442
+ def visit_subquery_expression(self, node: SubqueryExpression) -> Any:
1443
+ pass
1444
+
1445
+ @abstractmethod
1446
+ def visit_cast_expression(self, node: CastExpression) -> Any:
1447
+ pass
1448
+
1449
+ @abstractmethod
1450
+ def visit_when_clause(self, node: WhenClause) -> Any:
1451
+ pass
1452
+
1453
+ @abstractmethod
1454
+ def visit_case_expression(self, node: CaseExpression) -> Any:
1455
+ pass
1456
+
1457
+ @abstractmethod
1458
+ def visit_function_call(self, node: FunctionCall) -> Any:
1459
+ pass
1460
+
1461
+ @abstractmethod
1462
+ def visit_aggregate_function(self, node: AggregateFunction) -> Any:
1463
+ pass
1464
+
1465
+ @abstractmethod
1466
+ def visit_frame_bound(self, node: FrameBound) -> Any:
1467
+ pass
1468
+
1469
+ @abstractmethod
1470
+ def visit_window_spec(self, node: WindowSpec) -> Any:
1471
+ pass
1472
+
1473
+ @abstractmethod
1474
+ def visit_window_function(self, node: WindowFunction) -> Any:
1475
+ pass
1476
+
1477
+ @abstractmethod
1478
+ def visit_select_item(self, node: SelectItem) -> Any:
1479
+ pass
1480
+
1481
+ @abstractmethod
1482
+ def visit_from_clause(self, node: FromClause) -> Any:
1483
+ pass
1484
+
1485
+ @abstractmethod
1486
+ def visit_join_clause(self, node: JoinClause) -> Any:
1487
+ pass
1488
+
1489
+ @abstractmethod
1490
+ def visit_where_clause(self, node: WhereClause) -> Any:
1491
+ pass
1492
+
1493
+ @abstractmethod
1494
+ def visit_group_by_clause(self, node: GroupByClause) -> Any:
1495
+ pass
1496
+
1497
+ @abstractmethod
1498
+ def visit_having_clause(self, node: HavingClause) -> Any:
1499
+ pass
1500
+
1501
+ @abstractmethod
1502
+ def visit_order_by_item(self, node: OrderByItem) -> Any:
1503
+ pass
1504
+
1505
+ @abstractmethod
1506
+ def visit_order_by_clause(self, node: OrderByClause) -> Any:
1507
+ pass
1508
+
1509
+ @abstractmethod
1510
+ def visit_limit_clause(self, node: LimitClause) -> Any:
1511
+ pass
1512
+
1513
+ @abstractmethod
1514
+ def visit_offset_clause(self, node: OffsetClause) -> Any:
1515
+ pass
1516
+
1517
+ @abstractmethod
1518
+ def visit_select_statement(self, node: SelectStatement) -> Any:
1519
+ pass
1520
+
1521
+ @abstractmethod
1522
+ def visit_cte_clause(self, node: CTEClause) -> Any:
1523
+ pass
1524
+
1525
+ @abstractmethod
1526
+ def visit_set_operation(self, node: SetOperationStatement) -> Any:
1527
+ pass
1528
+
1529
+
1530
+ # =============================================================================
1531
+ # Helper Functions
1532
+ # =============================================================================
1533
+
1534
+
1535
+ def _to_expression(value: Any) -> Expression:
1536
+ """Convert a value to an Expression.
1537
+
1538
+ Args:
1539
+ value: Value to convert.
1540
+
1541
+ Returns:
1542
+ Expression representing the value.
1543
+ """
1544
+ if isinstance(value, Expression):
1545
+ return value
1546
+ if value is None:
1547
+ return NullLiteral()
1548
+ if isinstance(value, bool):
1549
+ return BooleanLiteral(value)
1550
+ return Literal(value)