dataface 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (455) hide show
  1. d3_format/__init__.py +14 -0
  2. d3_format/errors.py +19 -0
  3. d3_format/format.py +551 -0
  4. d3_format/spec.py +159 -0
  5. dataface/DATAFACE_SYNTAX.md +1135 -0
  6. dataface/__init__.py +93 -0
  7. dataface/_docs_site.py +20 -0
  8. dataface/_install_hint.py +26 -0
  9. dataface/agent_api/__init__.py +79 -0
  10. dataface/agent_api/_init_templates/__init__.py +0 -0
  11. dataface/agent_api/_init_templates/agents_dft_snippet.md +26 -0
  12. dataface/agent_api/_init_templates/dataface.yml +15 -0
  13. dataface/agent_api/_init_templates/faces-dataface.yml +144 -0
  14. dataface/agent_api/_init_templates/index.md +24 -0
  15. dataface/agent_api/_paths.py +118 -0
  16. dataface/agent_api/_project_agents_md.py +43 -0
  17. dataface/agent_api/_session_store.py +486 -0
  18. dataface/agent_api/_state.py +28 -0
  19. dataface/agent_api/chat.py +221 -0
  20. dataface/agent_api/dashboards.py +257 -0
  21. dataface/agent_api/describe.py +366 -0
  22. dataface/agent_api/describe_query.py +120 -0
  23. dataface/agent_api/docs/__init__.py +25 -0
  24. dataface/agent_api/docs/_loader.py +292 -0
  25. dataface/agent_api/docs/yaml-reference.md +2757 -0
  26. dataface/agent_api/file_refs.py +118 -0
  27. dataface/agent_api/init.py +126 -0
  28. dataface/agent_api/inspect.py +128 -0
  29. dataface/agent_api/mcp_install.py +170 -0
  30. dataface/agent_api/query.py +274 -0
  31. dataface/agent_api/schema.py +658 -0
  32. dataface/agent_api/schema_search.py +284 -0
  33. dataface/agent_api/search.py +270 -0
  34. dataface/agent_api/skill_install.py +141 -0
  35. dataface/agent_api/skill_render.py +90 -0
  36. dataface/agent_api/skills.py +293 -0
  37. dataface/agent_api/surface_aliases.yaml +128 -0
  38. dataface/agent_api/validate.py +175 -0
  39. dataface/agent_api/validate_query.py +84 -0
  40. dataface/ai/__init__.py +39 -0
  41. dataface/ai/agent.py +139 -0
  42. dataface/ai/context.py +45 -0
  43. dataface/ai/events.py +62 -0
  44. dataface/ai/external_mcp.py +610 -0
  45. dataface/ai/generate_sql.py +96 -0
  46. dataface/ai/llm.py +403 -0
  47. dataface/ai/mcp/__init__.py +51 -0
  48. dataface/ai/mcp/server.py +289 -0
  49. dataface/ai/memories.py +85 -0
  50. dataface/ai/prompts.py +177 -0
  51. dataface/ai/schema_context.py +138 -0
  52. dataface/ai/skills/before-after-comparison/SKILL.md +102 -0
  53. dataface/ai/skills/before-after-comparison/examples/before-after-comparison.yml +24 -0
  54. dataface/ai/skills/dashboard-build/SKILL.md +212 -0
  55. dataface/ai/skills/dashboard-build/examples/_smoke.yml +15 -0
  56. dataface/ai/skills/dashboard-design/SKILL.md +182 -0
  57. dataface/ai/skills/dashboard-review/SKILL.md +113 -0
  58. dataface/ai/skills/dashboard-structural-review/SKILL.md +173 -0
  59. dataface/ai/skills/dashboard-visual-review/SKILL.md +139 -0
  60. dataface/ai/skills/dataface-mcp-setup/SKILL.md +177 -0
  61. dataface/ai/skills/dataface-troubleshooting/SKILL.md +225 -0
  62. dataface/ai/skills/drill-down-link/SKILL.md +112 -0
  63. dataface/ai/skills/drill-down-link/examples/drill-down-link.yml +27 -0
  64. dataface/ai/skills/faceted-small-multiples/SKILL.md +116 -0
  65. dataface/ai/skills/faceted-small-multiples/examples/faceted-small-multiples.yml +33 -0
  66. dataface/ai/skills/filter-bar-with-variables/SKILL.md +105 -0
  67. dataface/ai/skills/filter-bar-with-variables/examples/filter-bar-with-variables.yml +49 -0
  68. dataface/ai/skills/kpi-row/SKILL.md +101 -0
  69. dataface/ai/skills/kpi-row/examples/kpi-row.yml +55 -0
  70. dataface/ai/skills/report-design/SKILL.md +184 -0
  71. dataface/ai/skills/single-metric-bignum/SKILL.md +90 -0
  72. dataface/ai/skills/single-metric-bignum/examples/single-metric-bignum.yml +27 -0
  73. dataface/ai/skills/table-heavy-ops-dashboard/SKILL.md +114 -0
  74. dataface/ai/skills/table-heavy-ops-dashboard/examples/table-heavy-ops-dashboard.yml +48 -0
  75. dataface/ai/skills/time-series-trend/SKILL.md +93 -0
  76. dataface/ai/skills/time-series-trend/examples/time-series-trend.yml +26 -0
  77. dataface/ai/skills/top-n-with-detail/SKILL.md +98 -0
  78. dataface/ai/skills/top-n-with-detail/examples/top-n-with-detail.yml +45 -0
  79. dataface/ai/skills/two-by-two-grid-overview/SKILL.md +78 -0
  80. dataface/ai/skills/two-by-two-grid-overview/examples/two-by-two-grid-overview.yml +64 -0
  81. dataface/ai/tool_schemas.py +132 -0
  82. dataface/ai/tools/__init__.py +312 -0
  83. dataface/ai/yaml_utils.py +57 -0
  84. dataface/cli/__init__.py +3 -0
  85. dataface/cli/_console.py +48 -0
  86. dataface/cli/_error_format.py +83 -0
  87. dataface/cli/_extras.py +190 -0
  88. dataface/cli/_json_output.py +8 -0
  89. dataface/cli/_parsing.py +17 -0
  90. dataface/cli/_version_info.py +56 -0
  91. dataface/cli/commands/__init__.py +3 -0
  92. dataface/cli/commands/_agent_input.py +205 -0
  93. dataface/cli/commands/_agent_server.py +115 -0
  94. dataface/cli/commands/chat.py +645 -0
  95. dataface/cli/commands/describe.py +107 -0
  96. dataface/cli/commands/docs.py +131 -0
  97. dataface/cli/commands/extension.py +179 -0
  98. dataface/cli/commands/init.py +240 -0
  99. dataface/cli/commands/inspect.py +94 -0
  100. dataface/cli/commands/mcp_init.py +167 -0
  101. dataface/cli/commands/query.py +386 -0
  102. dataface/cli/commands/render.py +291 -0
  103. dataface/cli/commands/schema.py +411 -0
  104. dataface/cli/commands/search.py +49 -0
  105. dataface/cli/commands/serve.py +114 -0
  106. dataface/cli/commands/skills.py +133 -0
  107. dataface/cli/commands/skills_init.py +161 -0
  108. dataface/cli/commands/validate.py +63 -0
  109. dataface/cli/main.py +1501 -0
  110. dataface/core/__init__.py +75 -0
  111. dataface/core/compile/__init__.py +244 -0
  112. dataface/core/compile/_jinja_helpers.py +78 -0
  113. dataface/core/compile/channel.py +222 -0
  114. dataface/core/compile/chart_focus.py +101 -0
  115. dataface/core/compile/chart_resolved.py +169 -0
  116. dataface/core/compile/chart_type_detection.py +489 -0
  117. dataface/core/compile/chart_update.py +261 -0
  118. dataface/core/compile/colors.py +64 -0
  119. dataface/core/compile/compiler.py +904 -0
  120. dataface/core/compile/config.py +823 -0
  121. dataface/core/compile/custom_chart_types.py +208 -0
  122. dataface/core/compile/data_table_attachment.py +1287 -0
  123. dataface/core/compile/detect.py +110 -0
  124. dataface/core/compile/errors.py +302 -0
  125. dataface/core/compile/filter_injection.py +319 -0
  126. dataface/core/compile/introspection.py +527 -0
  127. dataface/core/compile/jinja.py +511 -0
  128. dataface/core/compile/labels_env.py +52 -0
  129. dataface/core/compile/markdown.py +154 -0
  130. dataface/core/compile/meta.py +388 -0
  131. dataface/core/compile/models/__init__.py +0 -0
  132. dataface/core/compile/models/chart/__init__.py +0 -0
  133. dataface/core/compile/models/chart/authored.py +2137 -0
  134. dataface/core/compile/models/chart/compiled.py +398 -0
  135. dataface/core/compile/models/config.py +347 -0
  136. dataface/core/compile/models/face/__init__.py +0 -0
  137. dataface/core/compile/models/face/authored.py +659 -0
  138. dataface/core/compile/models/face/compiled.py +522 -0
  139. dataface/core/compile/models/factories.py +201 -0
  140. dataface/core/compile/models/markers.py +40 -0
  141. dataface/core/compile/models/palette.py +36 -0
  142. dataface/core/compile/models/primitives.py +415 -0
  143. dataface/core/compile/models/query/__init__.py +0 -0
  144. dataface/core/compile/models/query/authored.py +246 -0
  145. dataface/core/compile/models/query/compiled.py +710 -0
  146. dataface/core/compile/models/refs.py +137 -0
  147. dataface/core/compile/models/source.py +611 -0
  148. dataface/core/compile/models/style/__init__.py +0 -0
  149. dataface/core/compile/models/style/authored.py +481 -0
  150. dataface/core/compile/models/style/compiled.py +3399 -0
  151. dataface/core/compile/models/style/merged.py +1682 -0
  152. dataface/core/compile/models/theme.py +362 -0
  153. dataface/core/compile/models/variable/__init__.py +0 -0
  154. dataface/core/compile/models/variable/authored.py +254 -0
  155. dataface/core/compile/models/vega_lite/__init__.py +0 -0
  156. dataface/core/compile/models/vega_lite/config.py +510 -0
  157. dataface/core/compile/models/vega_lite/contracts.py +171 -0
  158. dataface/core/compile/normalize_charts.py +494 -0
  159. dataface/core/compile/normalize_layout.py +1000 -0
  160. dataface/core/compile/normalize_queries.py +297 -0
  161. dataface/core/compile/normalize_variables.py +489 -0
  162. dataface/core/compile/normalizer.py +543 -0
  163. dataface/core/compile/palette.py +1100 -0
  164. dataface/core/compile/parameterized.py +658 -0
  165. dataface/core/compile/parser.py +228 -0
  166. dataface/core/compile/schema.py +20 -0
  167. dataface/core/compile/schema_renderers/__init__.py +0 -0
  168. dataface/core/compile/schema_renderers/json_schema.py +163 -0
  169. dataface/core/compile/schema_renderers/prompt.py +152 -0
  170. dataface/core/compile/schema_renderers/vscode_schema.py +301 -0
  171. dataface/core/compile/sizing.py +2126 -0
  172. dataface/core/compile/sources.py +518 -0
  173. dataface/core/compile/sql_authoring_lint.py +56 -0
  174. dataface/core/compile/style_cascade.py +471 -0
  175. dataface/core/compile/typography.py +299 -0
  176. dataface/core/compile/validator.py +301 -0
  177. dataface/core/compile/variables.py +53 -0
  178. dataface/core/compile/vega_config.py +98 -0
  179. dataface/core/compile/vega_lite/__init__.py +6 -0
  180. dataface/core/compile/vega_lite/validation.py +95 -0
  181. dataface/core/compile/yaml_error_formatter.py +838 -0
  182. dataface/core/connections.py +38 -0
  183. dataface/core/dashboard.py +358 -0
  184. dataface/core/defaults/default_config.yml +101 -0
  185. dataface/core/defaults/palettes/categorical/category-10-dark.yml +32 -0
  186. dataface/core/defaults/palettes/categorical/category-10-light.yml +43 -0
  187. dataface/core/defaults/palettes/categorical/category-10.yml +31 -0
  188. dataface/core/defaults/palettes/categorical/category-6-tonal-blue.yml +22 -0
  189. dataface/core/defaults/palettes/categorical/category-6-tonal-brown.yml +29 -0
  190. dataface/core/defaults/palettes/categorical/category-6-tonal-green.yml +20 -0
  191. dataface/core/defaults/palettes/categorical/category-6-tonal-orange.yml +21 -0
  192. dataface/core/defaults/palettes/categorical/category-6-tonal-purple.yml +20 -0
  193. dataface/core/defaults/palettes/categorical/editorial-10-dark.yml +32 -0
  194. dataface/core/defaults/palettes/categorical/editorial-10.yml +40 -0
  195. dataface/core/defaults/palettes/categorical/hero-6.yml +17 -0
  196. dataface/core/defaults/palettes/categorical/single-blue.yml +11 -0
  197. dataface/core/defaults/palettes/categorical/tableau.yml +20 -0
  198. dataface/core/defaults/palettes/data/xkcd_colors.json +3803 -0
  199. dataface/core/defaults/palettes/diverging/blue-red.yml +25 -0
  200. dataface/core/defaults/palettes/diverging/coolwarm.yml +24 -0
  201. dataface/core/defaults/palettes/diverging/crimson-green.yml +23 -0
  202. dataface/core/defaults/palettes/diverging/orange-teal.yml +23 -0
  203. dataface/core/defaults/palettes/diverging/sunset.yml +24 -0
  204. dataface/core/defaults/palettes/scaffold/dft-creams.yml +38 -0
  205. dataface/core/defaults/palettes/scaffold/dft-grays.yml +53 -0
  206. dataface/core/defaults/palettes/sequential/amber.yml +22 -0
  207. dataface/core/defaults/palettes/sequential/blue.yml +22 -0
  208. dataface/core/defaults/palettes/sequential/brown.yml +22 -0
  209. dataface/core/defaults/palettes/sequential/gray.yml +22 -0
  210. dataface/core/defaults/palettes/sequential/green.yml +22 -0
  211. dataface/core/defaults/palettes/sequential/purple.yml +22 -0
  212. dataface/core/defaults/palettes/sequential/rust.yml +22 -0
  213. dataface/core/defaults/palettes/sequential/teal.yml +22 -0
  214. dataface/core/defaults/palettes/tone/negative.yml +32 -0
  215. dataface/core/defaults/palettes/tone/positive.yml +22 -0
  216. dataface/core/defaults/palettes/tone/warning.yml +22 -0
  217. dataface/core/defaults/themes/_base.yaml +786 -0
  218. dataface/core/defaults/themes/bi.yaml +16 -0
  219. dataface/core/defaults/themes/carbong100.yaml +41 -0
  220. dataface/core/defaults/themes/cream.yaml +122 -0
  221. dataface/core/defaults/themes/dark.yaml +40 -0
  222. dataface/core/defaults/themes/diagnostics-title-angle-extreme.yaml +9 -0
  223. dataface/core/defaults/themes/diagnostics-title-baseline-extreme.yaml +9 -0
  224. dataface/core/defaults/themes/diagnostics-title-baseline.yaml +24 -0
  225. dataface/core/defaults/themes/diagnostics-title-center.yaml +8 -0
  226. dataface/core/defaults/themes/diagnostics-title-color-extreme.yaml +24 -0
  227. dataface/core/defaults/themes/diagnostics-title-font-extreme.yaml +25 -0
  228. dataface/core/defaults/themes/diagnostics-title-left.yaml +8 -0
  229. dataface/core/defaults/themes/diagnostics-title-offset-extreme.yaml +9 -0
  230. dataface/core/defaults/themes/diagnostics-title-size-extreme.yaml +24 -0
  231. dataface/core/defaults/themes/diagnostics-title-weight-extreme.yaml +24 -0
  232. dataface/core/defaults/themes/editorial.yaml +147 -0
  233. dataface/core/defaults/themes/light.yaml +30 -0
  234. dataface/core/defaults/themes/looker.yaml +17 -0
  235. dataface/core/defaults/themes/stark.yaml +134 -0
  236. dataface/core/errors/__init__.py +67 -0
  237. dataface/core/errors/codes_compile.py +56 -0
  238. dataface/core/errors/codes_execute.py +177 -0
  239. dataface/core/errors/codes_render.py +106 -0
  240. dataface/core/errors/codes_unknown.py +15 -0
  241. dataface/core/errors/hints.py +74 -0
  242. dataface/core/errors/registry.py +42 -0
  243. dataface/core/errors/structured.py +92 -0
  244. dataface/core/execute/__init__.py +91 -0
  245. dataface/core/execute/adapters/__init__.py +49 -0
  246. dataface/core/execute/adapters/adapter_registry.py +400 -0
  247. dataface/core/execute/adapters/base.py +245 -0
  248. dataface/core/execute/adapters/csv_adapter.py +239 -0
  249. dataface/core/execute/adapters/dbt_adapter.py +283 -0
  250. dataface/core/execute/adapters/dbt_adapter_factory.py +212 -0
  251. dataface/core/execute/adapters/dbt_macro_loader.py +95 -0
  252. dataface/core/execute/adapters/dbt_utils.py +150 -0
  253. dataface/core/execute/adapters/http_adapter.py +224 -0
  254. dataface/core/execute/adapters/metricflow_adapter.py +94 -0
  255. dataface/core/execute/adapters/schema_resolver_adapter.py +144 -0
  256. dataface/core/execute/adapters/sql_adapter.py +710 -0
  257. dataface/core/execute/adapters/values_adapter.py +58 -0
  258. dataface/core/execute/batch.py +744 -0
  259. dataface/core/execute/cache_backend.py +135 -0
  260. dataface/core/execute/cache_keys.py +66 -0
  261. dataface/core/execute/dbt_jinja.py +21 -0
  262. dataface/core/execute/dialects/__init__.py +121 -0
  263. dataface/core/execute/dialects/athena.py +75 -0
  264. dataface/core/execute/dialects/base.py +302 -0
  265. dataface/core/execute/dialects/bigquery.py +38 -0
  266. dataface/core/execute/dialects/databricks.py +68 -0
  267. dataface/core/execute/dialects/duckdb.py +35 -0
  268. dataface/core/execute/dialects/mysql.py +68 -0
  269. dataface/core/execute/dialects/postgres.py +39 -0
  270. dataface/core/execute/dialects/redshift.py +12 -0
  271. dataface/core/execute/dialects/snowflake.py +51 -0
  272. dataface/core/execute/dialects/sqlserver.py +92 -0
  273. dataface/core/execute/duckdb_cache.py +712 -0
  274. dataface/core/execute/duckdb_config.py +26 -0
  275. dataface/core/execute/errors.py +213 -0
  276. dataface/core/execute/executor.py +1249 -0
  277. dataface/core/execute/parallel.py +162 -0
  278. dataface/core/execute/setup_sql.py +58 -0
  279. dataface/core/execute/source_registry.py +72 -0
  280. dataface/core/execute/source_resolver.py +255 -0
  281. dataface/core/execute/sql_guard.py +387 -0
  282. dataface/core/execute/sql_literals.py +199 -0
  283. dataface/core/fonts.py +52 -0
  284. dataface/core/inspect/__init__.py +32 -0
  285. dataface/core/inspect/cache_factory.py +98 -0
  286. dataface/core/inspect/db_types.py +162 -0
  287. dataface/core/inspect/dbt_schema.py +96 -0
  288. dataface/core/inspect/defaults.yml +37 -0
  289. dataface/core/inspect/fanout_risk.py +109 -0
  290. dataface/core/inspect/manifest_utils.py +77 -0
  291. dataface/core/inspect/partials/categorical.yml +40 -0
  292. dataface/core/inspect/partials/date.yml +40 -0
  293. dataface/core/inspect/partials/numeric.yml +55 -0
  294. dataface/core/inspect/partition_types.py +38 -0
  295. dataface/core/inspect/query_validator.py +975 -0
  296. dataface/core/inspect/renderer.py +354 -0
  297. dataface/core/inspect/resolver.py +808 -0
  298. dataface/core/inspect/search.py +461 -0
  299. dataface/core/inspect/sources/__init__.py +32 -0
  300. dataface/core/inspect/sources/dbt.py +738 -0
  301. dataface/core/inspect/sources/duckdb_utils.py +66 -0
  302. dataface/core/inspect/templates/__init__.py +1 -0
  303. dataface/core/inspect/templates/categorical_column.yml +196 -0
  304. dataface/core/inspect/templates/charts.yml +109 -0
  305. dataface/core/inspect/templates/date_column.yml +248 -0
  306. dataface/core/inspect/templates/model.yml +138 -0
  307. dataface/core/inspect/templates/numeric_column.yml +261 -0
  308. dataface/core/inspect/templates/quality.yml +80 -0
  309. dataface/core/inspect/templates/string_column.yml +263 -0
  310. dataface/core/project_roots.py +165 -0
  311. dataface/core/render/__init__.py +87 -0
  312. dataface/core/render/board_links.py +176 -0
  313. dataface/core/render/chart/__init__.py +27 -0
  314. dataface/core/render/chart/arc_attached_table.py +251 -0
  315. dataface/core/render/chart/artifacts.py +16 -0
  316. dataface/core/render/chart/callout.py +225 -0
  317. dataface/core/render/chart/decisions.py +358 -0
  318. dataface/core/render/chart/geo.py +700 -0
  319. dataface/core/render/chart/kpi.py +916 -0
  320. dataface/core/render/chart/labels.py +76 -0
  321. dataface/core/render/chart/pipeline.py +818 -0
  322. dataface/core/render/chart/presentation.py +36 -0
  323. dataface/core/render/chart/profile.py +3438 -0
  324. dataface/core/render/chart/render_single.py +347 -0
  325. dataface/core/render/chart/renderers.py +193 -0
  326. dataface/core/render/chart/rendering.py +565 -0
  327. dataface/core/render/chart/serialization.py +90 -0
  328. dataface/core/render/chart/spark.py +496 -0
  329. dataface/core/render/chart/spark_bar.py +370 -0
  330. dataface/core/render/chart/spec_builders.py +154 -0
  331. dataface/core/render/chart/standard_renderer.py +2645 -0
  332. dataface/core/render/chart/table.py +2957 -0
  333. dataface/core/render/chart/table_support.py +1452 -0
  334. dataface/core/render/chart/tick_values.py +66 -0
  335. dataface/core/render/chart/time_unit_detect.py +809 -0
  336. dataface/core/render/chart/title_overflow.py +157 -0
  337. dataface/core/render/chart/type_inference.py +122 -0
  338. dataface/core/render/chart/validation.py +99 -0
  339. dataface/core/render/chart/vega_lite.py +125 -0
  340. dataface/core/render/chart/vega_lite_types.py +268 -0
  341. dataface/core/render/chart/vl_field_maps.py +346 -0
  342. dataface/core/render/chart_interactivity.py +24 -0
  343. dataface/core/render/control_registry.py +287 -0
  344. dataface/core/render/converters/__init__.py +24 -0
  345. dataface/core/render/converters/chart.py +276 -0
  346. dataface/core/render/converters/html.py +98 -0
  347. dataface/core/render/converters/pdf.py +40 -0
  348. dataface/core/render/converters/png.py +41 -0
  349. dataface/core/render/errors.py +144 -0
  350. dataface/core/render/face_api.py +160 -0
  351. dataface/core/render/faces.py +1194 -0
  352. dataface/core/render/font_measurement.py +48 -0
  353. dataface/core/render/font_support.py +197 -0
  354. dataface/core/render/fonts/DFTSansTabular-Regular.ttf +0 -0
  355. dataface/core/render/fonts/DFTSansTabular-Regular.woff2 +0 -0
  356. dataface/core/render/fonts/DFTSerifOldstyleProportional-Regular.ttf +0 -0
  357. dataface/core/render/fonts/DFTSerifOldstyleTabular-Regular.ttf +0 -0
  358. dataface/core/render/fonts/InterVariable.ttf +0 -0
  359. dataface/core/render/fonts/InterVariable.woff2 +0 -0
  360. dataface/core/render/fonts/NOTO_COLOR_EMOJI_LICENSE.txt +93 -0
  361. dataface/core/render/fonts/NOTO_EMOJI_LICENSE.txt +93 -0
  362. dataface/core/render/fonts/NotoColorEmoji-Regular.ttf +0 -0
  363. dataface/core/render/fonts/NotoColorEmoji-Regular.woff2 +0 -0
  364. dataface/core/render/fonts/NotoEmoji-Regular.ttf +0 -0
  365. dataface/core/render/fonts/NotoEmoji-Regular.woff2 +0 -0
  366. dataface/core/render/fonts/SOURCE_CODE_PRO_LICENSE.txt +93 -0
  367. dataface/core/render/fonts/SOURCE_SERIF_4_LICENSE.txt +98 -0
  368. dataface/core/render/fonts/SourceCodePro-Regular.ttf +0 -0
  369. dataface/core/render/fonts/SourceSerif4-Regular.ttf +0 -0
  370. dataface/core/render/fonts/_emoji_font_face.css +43 -0
  371. dataface/core/render/fonts/source-serif-4-variable-latin.woff2 +0 -0
  372. dataface/core/render/format_utils.py +329 -0
  373. dataface/core/render/geo_defaults.yml +28 -0
  374. dataface/core/render/json_format.py +146 -0
  375. dataface/core/render/layout_sizing.py +865 -0
  376. dataface/core/render/layouts.py +541 -0
  377. dataface/core/render/markdown_defaults.yml +16 -0
  378. dataface/core/render/missing_vars_prompt.py +79 -0
  379. dataface/core/render/placeholder.py +389 -0
  380. dataface/core/render/render_result.py +14 -0
  381. dataface/core/render/renderer.py +467 -0
  382. dataface/core/render/script_embedding.py +16 -0
  383. dataface/core/render/svg_utils.py +212 -0
  384. dataface/core/render/template_loader.py +69 -0
  385. dataface/core/render/templates/controls/_styles.css +606 -0
  386. dataface/core/render/templates/controls/checkbox.html +16 -0
  387. dataface/core/render/templates/controls/date.html +16 -0
  388. dataface/core/render/templates/controls/number.html +19 -0
  389. dataface/core/render/templates/controls/readonly.html +9 -0
  390. dataface/core/render/templates/controls/select.html +21 -0
  391. dataface/core/render/templates/controls/slider.html +22 -0
  392. dataface/core/render/templates/controls/text.html +16 -0
  393. dataface/core/render/templates/scripts/chart_interactivity.js +191 -0
  394. dataface/core/render/templates/scripts/variables.js +976 -0
  395. dataface/core/render/templates/svg/grid_pattern.svg +3 -0
  396. dataface/core/render/templates/svg/styles.css +51 -0
  397. dataface/core/render/terminal.py +311 -0
  398. dataface/core/render/terminal_charts.py +563 -0
  399. dataface/core/render/terminal_defaults.yml +2 -0
  400. dataface/core/render/terminal_layouts.py +299 -0
  401. dataface/core/render/terminal_text.py +31 -0
  402. dataface/core/render/text/__init__.py +1 -0
  403. dataface/core/render/text/case.py +113 -0
  404. dataface/core/render/text_format.py +129 -0
  405. dataface/core/render/utils.py +106 -0
  406. dataface/core/render/variable_controls.py +946 -0
  407. dataface/core/render/variable_input_refinement.py +140 -0
  408. dataface/core/render/warnings/__init__.py +15 -0
  409. dataface/core/render/warnings/bar_color_1_to_1_with_x.py +80 -0
  410. dataface/core/render/warnings/base.py +44 -0
  411. dataface/core/render/warnings/fanout_risk.py +15 -0
  412. dataface/core/render/warnings/from_query_diagnostic.py +56 -0
  413. dataface/core/render/warnings/missing_join_predicate.py +13 -0
  414. dataface/core/render/warnings/query_parse_error.py +14 -0
  415. dataface/core/render/warnings/query_returned_zero_rows.py +42 -0
  416. dataface/core/render/warnings/reaggregation.py +14 -0
  417. dataface/core/render/warnings/registry.py +45 -0
  418. dataface/core/render/warnings/suppression.py +46 -0
  419. dataface/core/render/warnings/temporal_single_point.py +63 -0
  420. dataface/core/render/warnings/unreferenced_chart.py +15 -0
  421. dataface/core/render/warnings/y_encoding_mostly_null.py +76 -0
  422. dataface/core/render/yaml_format.py +167 -0
  423. dataface/core/resolve_face.py +195 -0
  424. dataface/core/schema/__init__.py +0 -0
  425. dataface/core/schema/guidance.py +151 -0
  426. dataface/core/scoped_paths.py +59 -0
  427. dataface/core/serve/__init__.py +14 -0
  428. dataface/core/serve/bootstrap.py +39 -0
  429. dataface/core/serve/embedded.py +57 -0
  430. dataface/core/serve/port.py +129 -0
  431. dataface/core/serve/server.py +938 -0
  432. dataface/core/serve/templates/__init__.py +0 -0
  433. dataface/core/serve/templates/directory.yml +6 -0
  434. dataface/core/serve/templates/error.html.j2 +217 -0
  435. dataface/core/utils.py +121 -0
  436. dataface/core/validate.py +64 -0
  437. dataface/integrations/__init__.py +0 -0
  438. dataface/integrations/highlighting.py +351 -0
  439. dataface/integrations/markdown.py +537 -0
  440. dataface/py.typed +0 -0
  441. dataface-0.1.2.dist-info/METADATA +375 -0
  442. dataface-0.1.2.dist-info/RECORD +455 -0
  443. dataface-0.1.2.dist-info/WHEEL +4 -0
  444. dataface-0.1.2.dist-info/entry_points.txt +2 -0
  445. dataface-0.1.2.dist-info/licenses/LICENSE +202 -0
  446. mdsvg/__init__.py +168 -0
  447. mdsvg/fonts.py +656 -0
  448. mdsvg/images.py +299 -0
  449. mdsvg/parser.py +629 -0
  450. mdsvg/playground.py +284 -0
  451. mdsvg/py.typed +2 -0
  452. mdsvg/renderer.py +1623 -0
  453. mdsvg/style.py +355 -0
  454. mdsvg/types.py +200 -0
  455. mdsvg/utils.py +86 -0
@@ -0,0 +1,302 @@
1
+ """Base SQL dialect interface for database-specific behavior.
2
+
3
+ Stage: EXECUTE
4
+ Purpose: Define the abstract interface for database-specific SQL generation.
5
+
6
+ This module provides the base SQLDialect class that all database-specific
7
+ dialects inherit from. Each dialect encapsulates its own quirks for:
8
+ - Temp table syntax
9
+ - Parameter placeholders
10
+ - Filter macros
11
+ - (Future) SQL transpilation
12
+
13
+ Rather than spreading conditionals throughout the codebase, each dialect
14
+ encapsulates its own behavior.
15
+ """
16
+
17
+ from abc import ABC, abstractmethod
18
+
19
+ # Allowlist of valid SQL operators for filter() method
20
+ # This prevents SQL injection via operator parameter
21
+ VALID_OPERATORS = frozenset(
22
+ {
23
+ "=",
24
+ "!=",
25
+ "<>",
26
+ ">",
27
+ "<",
28
+ ">=",
29
+ "<=",
30
+ "LIKE",
31
+ "NOT LIKE",
32
+ "ILIKE",
33
+ "NOT ILIKE",
34
+ "IN",
35
+ "NOT IN",
36
+ "IS",
37
+ "IS NOT",
38
+ "BETWEEN",
39
+ "NOT BETWEEN",
40
+ "~",
41
+ "~*",
42
+ "!~",
43
+ "!~*", # PostgreSQL regex operators
44
+ }
45
+ )
46
+
47
+
48
+ class SQLDialect(ABC):
49
+ """Abstract base class for SQL dialect implementations.
50
+
51
+ Each database dialect inherits from this class and implements
52
+ database-specific behavior for SQL generation.
53
+
54
+ Attributes:
55
+ name: The canonical name of the dialect (e.g., 'postgres', 'mysql')
56
+
57
+ Example:
58
+ >>> dialect = PostgresDialect()
59
+ >>> dialect.param(1)
60
+ '$1'
61
+ >>> dialect.temp_table('tmp', 'SELECT 1')
62
+ 'CREATE TEMP TABLE tmp AS SELECT 1'
63
+ """
64
+
65
+ name: str
66
+
67
+ # --- Temp Tables ---
68
+
69
+ @property
70
+ def supports_temp_tables(self) -> bool:
71
+ """Check if the dialect supports temporary tables.
72
+
73
+ Returns:
74
+ True if temp tables are supported, False otherwise.
75
+ Default is True for most databases.
76
+ """
77
+ return True
78
+
79
+ def temp_table(self, name: str, sql: str) -> str:
80
+ """Generate CREATE TEMP TABLE statement.
81
+
82
+ Args:
83
+ name: Name of the temporary table to create
84
+ sql: SQL query to populate the table
85
+
86
+ Returns:
87
+ Complete CREATE TEMP TABLE statement
88
+
89
+ Raises:
90
+ NotImplementedError: If the dialect doesn't support temp tables
91
+ """
92
+ return f"CREATE TEMP TABLE {name} AS {sql}"
93
+
94
+ def temp_table_ref(self, name: str) -> str:
95
+ """Generate reference to a temporary table.
96
+
97
+ Override for dialects with special temp table naming (e.g., SQL Server #name).
98
+
99
+ Args:
100
+ name: Name of the temporary table
101
+
102
+ Returns:
103
+ How to reference the temp table in SQL
104
+ """
105
+ return name
106
+
107
+ def drop_temp_table(self, name: str) -> str:
108
+ """Generate DROP TEMP TABLE statement.
109
+
110
+ Args:
111
+ name: Name of the temporary table to drop
112
+
113
+ Returns:
114
+ Complete DROP TABLE IF EXISTS statement
115
+ """
116
+ return f"DROP TABLE IF EXISTS {self.temp_table_ref(name)}"
117
+
118
+ # --- Parameters ---
119
+
120
+ @abstractmethod
121
+ def param(self, index: int) -> str:
122
+ """Generate parameter placeholder for the given index.
123
+
124
+ This is the only abstract method that must be implemented by all dialects,
125
+ as parameter syntax varies significantly between databases.
126
+
127
+ Args:
128
+ index: 1-based parameter index
129
+
130
+ Returns:
131
+ Parameter placeholder string (e.g., '$1', '?', '%s', '@p1')
132
+ """
133
+ pass
134
+
135
+ def params(self, count: int) -> list[str]:
136
+ """Generate a list of parameter placeholders.
137
+
138
+ Args:
139
+ count: Number of parameters needed
140
+
141
+ Returns:
142
+ List of parameter placeholders (e.g., ['$1', '$2', '$3'])
143
+ """
144
+ return [self.param(i) for i in range(1, count + 1)]
145
+
146
+ # --- Filters ---
147
+
148
+ def filter(self, column: str, operator: str, param_index: int) -> str:
149
+ """Generate filter expression with parameterized value.
150
+
151
+ This is the primary filter method that matches the Jinja filter macro:
152
+ {{ filter('column', '=', variable) }}
153
+
154
+ For null-safe filtering (same SQL regardless of value), use
155
+ filter_nullable() instead.
156
+
157
+ Security note: The operator is validated against an allowlist to prevent
158
+ SQL injection. Column names should come from schema definitions, not
159
+ user input.
160
+
161
+ Args:
162
+ column: Column name to filter on (must be from schema, not user input)
163
+ operator: SQL operator (=, !=, >, <, >=, <=, LIKE, IN, etc.)
164
+ param_index: Parameter index for the value
165
+
166
+ Returns:
167
+ SQL expression (e.g., 'column = $1', 'column > $1')
168
+
169
+ Raises:
170
+ ValueError: If operator is not in the allowlist
171
+
172
+ Example:
173
+ >>> dialect = PostgresDialect()
174
+ >>> dialect.filter('country', '=', 1)
175
+ 'country = $1'
176
+ >>> dialect.filter('price', '>', 2)
177
+ 'price > $2'
178
+ """
179
+ # Validate operator to prevent SQL injection
180
+ op_upper = operator.upper().strip()
181
+ if op_upper not in VALID_OPERATORS:
182
+ raise ValueError(
183
+ f"Invalid SQL operator: {operator!r}. "
184
+ f"Must be one of: {', '.join(sorted(VALID_OPERATORS))}"
185
+ )
186
+ return f"{column} {operator} {self.param(param_index)}"
187
+
188
+ def filter_nullable(self, column: str, operator: str, param_index: int) -> str:
189
+ """Generate null-safe filter expression.
190
+
191
+ Produces SQL that handles NULL parameter values gracefully, allowing
192
+ the same query string to be used regardless of whether filtering is
193
+ applied. This enables query plan caching.
194
+
195
+ When the parameter is NULL, all rows match (no filtering).
196
+ When the parameter has a value, normal filtering applies.
197
+
198
+ Pattern: (param IS NULL OR column operator param)
199
+
200
+ Args:
201
+ column: Column name to filter on (must be from schema, not user input)
202
+ operator: SQL operator (=, !=, >, <, >=, <=, LIKE, etc.)
203
+ param_index: Parameter index for the value
204
+
205
+ Returns:
206
+ SQL expression like '($1 IS NULL OR column = $1)'
207
+
208
+ Raises:
209
+ ValueError: If operator is not in the allowlist
210
+
211
+ Example:
212
+ >>> dialect = PostgresDialect()
213
+ >>> dialect.filter_nullable('country', '=', 1)
214
+ '($1 IS NULL OR country = $1)'
215
+
216
+ # With param='USA': filters to USA
217
+ # With param=NULL: ($1 IS NULL) is true, all rows match
218
+ """
219
+ # Validate operator to prevent SQL injection
220
+ op_upper = operator.upper().strip()
221
+ if op_upper not in VALID_OPERATORS:
222
+ raise ValueError(
223
+ f"Invalid SQL operator: {operator!r}. "
224
+ f"Must be one of: {', '.join(sorted(VALID_OPERATORS))}"
225
+ )
226
+ param = self.param(param_index)
227
+ return f"({param} IS NULL OR {column} {operator} {param})"
228
+
229
+ # --- Param Conversion ---
230
+
231
+ uses_named_params: bool = False
232
+ """Whether this dialect uses named parameters (dict) vs positional (list).
233
+
234
+ Positional dialects (default): $1, ?, %s — params passed as list.
235
+ Named dialects: @param1, @p1, :param1 — params passed as dict.
236
+ """
237
+
238
+ dbapi_placeholder: str = ""
239
+ """The placeholder format that DB-API drivers for this dialect expect.
240
+
241
+ Most DB-API drivers use either '?' (qmark) or '%s' (pyformat).
242
+ Override for dialects where param() doesn't match the DB-API driver.
243
+ Empty string means no rewriting is needed (param() already matches).
244
+ """
245
+
246
+ def rewrite_sql_for_dbapi(self, sql: str, param_count: int) -> str:
247
+ """Rewrite SQL to replace dialect placeholders with DB-API driver placeholders.
248
+
249
+ For dialects where param() matches what the driver expects (SQLite '?',
250
+ MySQL '%s'), this is a no-op. For dialects where they differ (Postgres '$1'
251
+ → '%s', SQL Server '@p1' → '%s'), this replaces each placeholder.
252
+ """
253
+ placeholder = self.dbapi_placeholder
254
+ if not placeholder:
255
+ return sql
256
+ # Replace each dialect placeholder with the DB-API placeholder,
257
+ # going in reverse order to avoid $1 matching inside $10
258
+ for i in range(param_count, 0, -1):
259
+ sql = sql.replace(self.param(i), placeholder)
260
+ return sql
261
+
262
+ def build_params(self, params: list) -> list | dict:
263
+ """Convert positional param list to the format this dialect expects.
264
+
265
+ Positional dialects return the list as-is.
266
+ Named dialects convert to a dict keyed by param name (without prefix).
267
+ When dbapi_placeholder is set, SQL has been rewritten to positional
268
+ format, so params stay as a list regardless of uses_named_params.
269
+ """
270
+ if self.dbapi_placeholder or not self.uses_named_params:
271
+ return params
272
+ return self._params_to_dict(params)
273
+
274
+ def _params_to_dict(self, params: list) -> dict:
275
+ """Convert param list to named dict. Override for custom key format."""
276
+ # Default: strip the prefix/sigil from param(i) to get the key
277
+ # e.g. @param1 -> param1, @p1 -> p1, :param1 -> param1
278
+ return {self.param(i + 1).lstrip("@:"): v for i, v in enumerate(params)}
279
+
280
+ # --- Quoting ---
281
+
282
+ def quote_identifier(self, identifier: str) -> str:
283
+ """Quote an identifier (table name, column name, etc.).
284
+
285
+ Default uses double quotes which works for PostgreSQL, BigQuery, etc.
286
+ Override for databases with different quoting conventions.
287
+
288
+ Args:
289
+ identifier: The identifier to quote
290
+
291
+ Returns:
292
+ Quoted identifier string
293
+ """
294
+ # Escape any existing double quotes
295
+ escaped = identifier.replace('"', '""')
296
+ return f'"{escaped}"'
297
+
298
+ # --- Representation ---
299
+
300
+ def __repr__(self) -> str:
301
+ """Return string representation of the dialect."""
302
+ return f"{self.__class__.__name__}(name={self.name!r})"
@@ -0,0 +1,38 @@
1
+ """BigQuery dialect implementation.
2
+
3
+ BigQuery uses:
4
+ - @param1, @param2 for named parameter placeholders
5
+ - CREATE TEMP TABLE x AS for temporary tables
6
+ """
7
+
8
+ from dataface.core.execute.dialects.base import SQLDialect
9
+
10
+
11
+ class BigQueryDialect(SQLDialect):
12
+ """BigQuery dialect with @paramN parameter style.
13
+
14
+ BigQuery uses named parameters with @ prefix and supports temp tables.
15
+
16
+ Example:
17
+ >>> dialect = BigQueryDialect()
18
+ >>> dialect.param(1)
19
+ '@param1'
20
+ >>> dialect.filter('category', '=', 1)
21
+ 'category = @param1'
22
+ """
23
+
24
+ name = "bigquery"
25
+ uses_named_params = True
26
+
27
+ def param(self, index: int) -> str:
28
+ """Generate BigQuery parameter placeholder.
29
+
30
+ BigQuery uses @paramN named style.
31
+
32
+ Args:
33
+ index: 1-based parameter index
34
+
35
+ Returns:
36
+ Parameter placeholder in @paramN format
37
+ """
38
+ return f"@param{index}"
@@ -0,0 +1,68 @@
1
+ """Databricks dialect implementation.
2
+
3
+ Databricks uses:
4
+ - :param1, :param2 for named parameter placeholders
5
+ - CREATE TEMPORARY VIEW x AS for temporary views (not tables)
6
+ """
7
+
8
+ from dataface.core.execute.dialects.base import SQLDialect
9
+
10
+
11
+ class DatabricksDialect(SQLDialect):
12
+ """Databricks dialect with :paramN parameter style.
13
+
14
+ Databricks (Spark SQL) uses named parameters with : prefix.
15
+ It creates temporary views instead of temporary tables.
16
+
17
+ Example:
18
+ >>> dialect = DatabricksDialect()
19
+ >>> dialect.param(1)
20
+ ':param1'
21
+ >>> dialect.temp_table('tmp', 'SELECT 1')
22
+ 'CREATE OR REPLACE TEMPORARY VIEW tmp AS SELECT 1'
23
+ >>> dialect.filter('category', '=', 1)
24
+ 'category = :param1'
25
+ """
26
+
27
+ name = "databricks"
28
+ uses_named_params = True
29
+
30
+ def param(self, index: int) -> str:
31
+ """Generate Databricks parameter placeholder.
32
+
33
+ Databricks uses :paramN named style.
34
+
35
+ Args:
36
+ index: 1-based parameter index
37
+
38
+ Returns:
39
+ Parameter placeholder in :paramN format
40
+ """
41
+ return f":param{index}"
42
+
43
+ def temp_table(self, name: str, sql: str) -> str:
44
+ """Generate Databricks temporary view creation.
45
+
46
+ Databricks uses TEMPORARY VIEW instead of TEMP TABLE.
47
+
48
+ Args:
49
+ name: Name of the temporary view
50
+ sql: SQL query for the view
51
+
52
+ Returns:
53
+ CREATE OR REPLACE TEMPORARY VIEW statement
54
+ """
55
+ return f"CREATE OR REPLACE TEMPORARY VIEW {name} AS {sql}"
56
+
57
+ def drop_temp_table(self, name: str) -> str:
58
+ """Generate Databricks DROP VIEW statement.
59
+
60
+ Since Databricks uses views, we drop the view.
61
+
62
+ Args:
63
+ name: Name of the temporary view
64
+
65
+ Returns:
66
+ DROP VIEW IF EXISTS statement
67
+ """
68
+ return f"DROP VIEW IF EXISTS {name}"
@@ -0,0 +1,35 @@
1
+ """DuckDB dialect implementation.
2
+
3
+ DuckDB uses:
4
+ - $1, $2, ... for parameter placeholders (also supports ?)
5
+ - CREATE TEMP TABLE x AS for temporary tables
6
+ """
7
+
8
+ from dataface.core.execute.dialects.base import SQLDialect
9
+
10
+
11
+ class DuckDBDialect(SQLDialect):
12
+ """DuckDB dialect with $1, $2 parameter style.
13
+
14
+ DuckDB is similar to PostgreSQL and uses the same parameter syntax.
15
+
16
+ Example:
17
+ >>> dialect = DuckDBDialect()
18
+ >>> dialect.param(1)
19
+ '$1'
20
+ >>> dialect.filter('category', '=', 1)
21
+ 'category = $1'
22
+ """
23
+
24
+ name = "duckdb"
25
+
26
+ def param(self, index: int) -> str:
27
+ """Generate DuckDB parameter placeholder.
28
+
29
+ Args:
30
+ index: 1-based parameter index
31
+
32
+ Returns:
33
+ Parameter placeholder in $N format
34
+ """
35
+ return f"${index}"
@@ -0,0 +1,68 @@
1
+ """MySQL dialect implementation.
2
+
3
+ MySQL uses:
4
+ - %s for parameter placeholders (positional)
5
+ - CREATE TEMPORARY TABLE x AS for temporary tables
6
+ - Backticks for identifier quoting
7
+ """
8
+
9
+ from dataface.core.execute.dialects.base import SQLDialect
10
+
11
+
12
+ class MySQLDialect(SQLDialect):
13
+ """MySQL dialect with %s parameter style.
14
+
15
+ MySQL uses format-style parameter placeholders and TEMPORARY keyword
16
+ for temp tables.
17
+
18
+ Example:
19
+ >>> dialect = MySQLDialect()
20
+ >>> dialect.param()
21
+ '%s'
22
+ >>> dialect.temp_table('tmp', 'SELECT 1')
23
+ 'CREATE TEMPORARY TABLE tmp AS SELECT 1'
24
+ >>> dialect.filter('category', '=', 1)
25
+ 'category = %s'
26
+ """
27
+
28
+ name = "mysql"
29
+
30
+ def param(self, index: int) -> str:
31
+ """Generate MySQL parameter placeholder.
32
+
33
+ MySQL uses %s for all parameters (positional, not indexed).
34
+
35
+ Args:
36
+ index: 1-based parameter index (ignored for MySQL)
37
+
38
+ Returns:
39
+ Parameter placeholder '%s'
40
+ """
41
+ return "%s"
42
+
43
+ def temp_table(self, name: str, sql: str) -> str:
44
+ """Generate MySQL CREATE TEMPORARY TABLE statement.
45
+
46
+ MySQL uses TEMPORARY instead of TEMP.
47
+
48
+ Args:
49
+ name: Name of the temporary table
50
+ sql: SQL query to populate the table
51
+
52
+ Returns:
53
+ CREATE TEMPORARY TABLE statement
54
+ """
55
+ return f"CREATE TEMPORARY TABLE {name} AS {sql}"
56
+
57
+ def quote_identifier(self, identifier: str) -> str:
58
+ """Quote an identifier using MySQL backticks.
59
+
60
+ Args:
61
+ identifier: The identifier to quote
62
+
63
+ Returns:
64
+ Backtick-quoted identifier
65
+ """
66
+ # Escape backticks by doubling them
67
+ escaped = identifier.replace("`", "``")
68
+ return f"`{escaped}`"
@@ -0,0 +1,39 @@
1
+ """PostgreSQL dialect implementation.
2
+
3
+ PostgreSQL uses:
4
+ - $1, $2, ... for parameter placeholders
5
+ - CREATE TEMP TABLE x AS for temporary tables
6
+ """
7
+
8
+ from dataface.core.execute.dialects.base import SQLDialect
9
+
10
+
11
+ class PostgresDialect(SQLDialect):
12
+ """PostgreSQL dialect with $1, $2 parameter style.
13
+
14
+ PostgreSQL is the default dialect and uses standard SQL syntax
15
+ with numbered parameter placeholders.
16
+
17
+ Example:
18
+ >>> dialect = PostgresDialect()
19
+ >>> dialect.param(1)
20
+ '$1'
21
+ >>> dialect.params(3)
22
+ ['$1', '$2', '$3']
23
+ >>> dialect.filter('country', '=', 1)
24
+ 'country = $1'
25
+ """
26
+
27
+ name = "postgres"
28
+ dbapi_placeholder = "%s"
29
+
30
+ def param(self, index: int) -> str:
31
+ """Generate PostgreSQL parameter placeholder.
32
+
33
+ Args:
34
+ index: 1-based parameter index
35
+
36
+ Returns:
37
+ Parameter placeholder in $N format
38
+ """
39
+ return f"${index}"
@@ -0,0 +1,12 @@
1
+ """Redshift dialect implementation.
2
+
3
+ Redshift is PostgreSQL-based (8.0.2), so it inherits all PostgreSQL behavior.
4
+ """
5
+
6
+ from dataface.core.execute.dialects.postgres import PostgresDialect
7
+
8
+
9
+ class RedshiftDialect(PostgresDialect):
10
+ """Redshift dialect — identical to PostgreSQL."""
11
+
12
+ name = "redshift"
@@ -0,0 +1,51 @@
1
+ """Snowflake dialect implementation.
2
+
3
+ Snowflake uses:
4
+ - ? for positional parameters or :name for named parameters
5
+ - CREATE TEMPORARY TABLE x AS for temporary tables
6
+ """
7
+
8
+ from dataface.core.execute.dialects.base import SQLDialect
9
+
10
+
11
+ class SnowflakeDialect(SQLDialect):
12
+ """Snowflake dialect with ? parameter style.
13
+
14
+ Snowflake uses positional ? placeholders and has TEMPORARY tables.
15
+
16
+ Example:
17
+ >>> dialect = SnowflakeDialect()
18
+ >>> dialect.param()
19
+ '?'
20
+ >>> dialect.temp_table('tmp', 'SELECT 1')
21
+ 'CREATE TEMPORARY TABLE tmp AS SELECT 1'
22
+ >>> dialect.filter('category', '=', 1)
23
+ 'category = ?'
24
+ """
25
+
26
+ name = "snowflake"
27
+
28
+ def param(self, index: int) -> str:
29
+ """Generate Snowflake parameter placeholder.
30
+
31
+ Snowflake uses ? for positional parameters.
32
+
33
+ Args:
34
+ index: 1-based parameter index (ignored for positional)
35
+
36
+ Returns:
37
+ Parameter placeholder '?'
38
+ """
39
+ return "?"
40
+
41
+ def temp_table(self, name: str, sql: str) -> str:
42
+ """Generate Snowflake CREATE TEMPORARY TABLE statement.
43
+
44
+ Args:
45
+ name: Name of the temporary table
46
+ sql: SQL query to populate the table
47
+
48
+ Returns:
49
+ CREATE TEMPORARY TABLE statement
50
+ """
51
+ return f"CREATE TEMPORARY TABLE {name} AS {sql}"