polyglot-sql 0.5.9__tar.gz → 0.5.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/Cargo.lock +5 -5
  2. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/Cargo.toml +1 -1
  3. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/PKG-INFO +1 -1
  4. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/Cargo.toml +1 -1
  5. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/duckdb.rs +40 -1
  6. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/mod.rs +18 -0
  7. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/generator.rs +44 -12
  8. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/lineage.rs +86 -2
  9. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/query_analysis.rs +3 -1
  10. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/validation/tests.rs +23 -0
  11. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue227_strict_unsupported.rs +25 -0
  12. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/query_analysis.rs +112 -0
  13. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/tsql_regression.rs +47 -2
  14. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_lineage.py +17 -0
  15. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_query_analysis.py +30 -0
  16. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/README.md +0 -0
  17. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/README.md +0 -0
  18. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/in_list.rs +0 -0
  19. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/parsing.rs +0 -0
  20. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/rust_parsing.rs +0 -0
  21. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/benches/transpile.rs +0 -0
  22. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/examples/basic_usage.rs +0 -0
  23. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/examples/bench_json.rs +0 -0
  24. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/ast_json.rs +0 -0
  25. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/ast_transforms.rs +0 -0
  26. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/builder.rs +0 -0
  27. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/athena.rs +0 -0
  28. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/bigquery.rs +0 -0
  29. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/clickhouse.rs +0 -0
  30. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/cockroachdb.rs +0 -0
  31. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/databricks.rs +0 -0
  32. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/datafusion.rs +0 -0
  33. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/doris.rs +0 -0
  34. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/dremio.rs +0 -0
  35. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/drill.rs +0 -0
  36. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/druid.rs +0 -0
  37. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/dune.rs +0 -0
  38. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/exasol.rs +0 -0
  39. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/fabric.rs +0 -0
  40. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/generic.rs +0 -0
  41. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/hive.rs +0 -0
  42. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/materialize.rs +0 -0
  43. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/mysql.rs +0 -0
  44. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/oracle.rs +0 -0
  45. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/postgres.rs +0 -0
  46. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/presto.rs +0 -0
  47. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/redshift.rs +0 -0
  48. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/risingwave.rs +0 -0
  49. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/singlestore.rs +0 -0
  50. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/snowflake.rs +0 -0
  51. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/solr.rs +0 -0
  52. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/spark.rs +0 -0
  53. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/sqlite.rs +0 -0
  54. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/starrocks.rs +0 -0
  55. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tableau.rs +0 -0
  56. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/teradata.rs +0 -0
  57. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tidb.rs +0 -0
  58. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/trino.rs +0 -0
  59. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/dialects/tsql.rs +0 -0
  60. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/diff.rs +0 -0
  61. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/error.rs +0 -0
  62. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/expressions.rs +0 -0
  63. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/function_catalog.rs +0 -0
  64. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/function_registry.rs +0 -0
  65. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/helper.rs +0 -0
  66. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/lib.rs +0 -0
  67. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/openlineage.rs +0 -0
  68. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/annotate_types.rs +0 -0
  69. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/canonicalize.rs +0 -0
  70. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/eliminate_ctes.rs +0 -0
  71. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/eliminate_joins.rs +0 -0
  72. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/isolate_table_selects.rs +0 -0
  73. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/mod.rs +0 -0
  74. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/normalize.rs +0 -0
  75. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/normalize_identifiers.rs +0 -0
  76. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/optimize_joins.rs +0 -0
  77. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/optimizer.rs +0 -0
  78. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/pushdown_predicates.rs +0 -0
  79. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/pushdown_projections.rs +0 -0
  80. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/qualify_columns.rs +0 -0
  81. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/qualify_tables.rs +0 -0
  82. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/simplify.rs +0 -0
  83. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/optimizer/subquery.rs +0 -0
  84. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/parser.rs +0 -0
  85. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/planner.rs +0 -0
  86. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/resolver.rs +0 -0
  87. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/schema.rs +0 -0
  88. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/scope.rs +0 -0
  89. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/time.rs +0 -0
  90. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/tokens.rs +0 -0
  91. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/transforms.rs +0 -0
  92. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/traversal.rs +0 -0
  93. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/trie.rs +0 -0
  94. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/src/validation.rs +0 -0
  95. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/analyze_failures.rs +0 -0
  96. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/clickhouse_regression.rs +0 -0
  97. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/known_failures.rs +0 -0
  98. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/mod.rs +0 -0
  99. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/test_data.rs +0 -0
  100. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/common/test_runner.rs +0 -0
  101. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_clickhouse_coverage.rs +0 -0
  102. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_clickhouse_parser.rs +0 -0
  103. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_dialect.rs +0 -0
  104. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_dialect_tests.rs +0 -0
  105. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/ddl.json +0 -0
  106. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/dml.json +0 -0
  107. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/functions.json +0 -0
  108. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/identity.json +0 -0
  109. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/operators.json +0 -0
  110. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/select.json +0 -0
  111. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/transpilation.json +0 -0
  112. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/custom_fixtures/datafusion/types.json +0 -0
  113. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/data_type_api.rs +0 -0
  114. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/deep_nesting_regression.rs +0 -0
  115. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/dialect_matrix.rs +0 -0
  116. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/error_handling.rs +0 -0
  117. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/fabric_regression.rs +0 -0
  118. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/fabric_tpch_regression.rs +0 -0
  119. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/identity_roundtrip.rs +0 -0
  120. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue201_regression_test.rs +0 -0
  121. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue210_regression_test.rs +0 -0
  122. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/issue226_regression_test.rs +0 -0
  123. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/postgres_sqlite_regression.rs +0 -0
  124. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/query_analysis_regression.rs +0 -0
  125. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/snowflake_regression_test.rs +0 -0
  126. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_compat.rs +0 -0
  127. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_dialect_identity.rs +0 -0
  128. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_identity.rs +0 -0
  129. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_identity_detailed.rs +0 -0
  130. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_parser.rs +0 -0
  131. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_pretty.rs +0 -0
  132. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_transpilation.rs +0 -0
  133. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/sqlglot_transpile.rs +0 -0
  134. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/tpch_transpile_stack.rs +0 -0
  135. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql/tests/transform_regression.rs +0 -0
  136. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/Cargo.toml +0 -0
  137. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/README.md +0 -0
  138. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/clickhouse.rs +0 -0
  139. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/duckdb.rs +0 -0
  140. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/src/lib.rs +0 -0
  141. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/tools/clickhouse/extract_functions.py +0 -0
  142. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-function-catalogs/tools/duckdb/extract_functions.py +0 -0
  143. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/Cargo.toml +0 -0
  144. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/README.md +0 -0
  145. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/docs/api.md +0 -0
  146. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/docs/index.md +0 -0
  147. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/mkdocs.yml +0 -0
  148. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/annotate_types.rs +0 -0
  149. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/dialects.rs +0 -0
  150. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/diff.rs +0 -0
  151. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/errors.rs +0 -0
  152. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/expr.rs +0 -0
  153. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/expr_types.rs +0 -0
  154. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/format.rs +0 -0
  155. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/generate.rs +0 -0
  156. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/helpers.rs +0 -0
  157. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/lib.rs +0 -0
  158. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/lineage.rs +0 -0
  159. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/openlineage.rs +0 -0
  160. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/optimize.rs +0 -0
  161. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/parse.rs +0 -0
  162. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/query_analysis.rs +0 -0
  163. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/tokenize.rs +0 -0
  164. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/transforms.rs +0 -0
  165. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/transpile.rs +0 -0
  166. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/types.rs +0 -0
  167. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/src/validate.rs +0 -0
  168. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/conftest.py +0 -0
  169. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_compat.py +0 -0
  170. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_dialects.py +0 -0
  171. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_diff.py +0 -0
  172. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_expression.py +0 -0
  173. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_format.py +0 -0
  174. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_generate.py +0 -0
  175. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_optimize.py +0 -0
  176. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_parse.py +0 -0
  177. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_transforms.py +0 -0
  178. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_transpile.py +0 -0
  179. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/tests/test_validate.py +0 -0
  180. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/crates/polyglot-sql-python/uv.lock +0 -0
  181. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/pyproject.toml +0 -0
  182. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/python/polyglot_sql/__init__.py +0 -0
  183. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/python/polyglot_sql/__init__.pyi +0 -0
  184. {polyglot_sql-0.5.9 → polyglot_sql-0.5.11}/python/polyglot_sql/py.typed +0 -0
@@ -605,7 +605,7 @@ dependencies = [
605
605
 
606
606
  [[package]]
607
607
  name = "polyglot-sql"
608
- version = "0.5.9"
608
+ version = "0.5.11"
609
609
  dependencies = [
610
610
  "criterion",
611
611
  "once_cell",
@@ -621,7 +621,7 @@ dependencies = [
621
621
 
622
622
  [[package]]
623
623
  name = "polyglot-sql-ffi"
624
- version = "0.5.9"
624
+ version = "0.5.11"
625
625
  dependencies = [
626
626
  "cbindgen",
627
627
  "polyglot-sql",
@@ -631,11 +631,11 @@ dependencies = [
631
631
 
632
632
  [[package]]
633
633
  name = "polyglot-sql-function-catalogs"
634
- version = "0.5.9"
634
+ version = "0.5.11"
635
635
 
636
636
  [[package]]
637
637
  name = "polyglot-sql-python"
638
- version = "0.5.9"
638
+ version = "0.5.11"
639
639
  dependencies = [
640
640
  "polyglot-sql",
641
641
  "pyo3",
@@ -646,7 +646,7 @@ dependencies = [
646
646
 
647
647
  [[package]]
648
648
  name = "polyglot-sql-wasm"
649
- version = "0.5.9"
649
+ version = "0.5.11"
650
650
  dependencies = [
651
651
  "console_error_panic_hook",
652
652
  "js-sys",
@@ -6,7 +6,7 @@ exclude = [
6
6
  ]
7
7
 
8
8
  [workspace.package]
9
- version = "0.5.9"
9
+ version = "0.5.11"
10
10
  edition = "2021"
11
11
  license = "MIT"
12
12
  authors = ["polyglot contributors"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: polyglot-sql
3
- Version: 0.5.9
3
+ Version: 0.5.11
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: License :: OSI Approved :: MIT License
@@ -106,7 +106,7 @@ thiserror = { workspace = true }
106
106
  unicode-segmentation = { workspace = true }
107
107
  stacker = { version = "0.1", optional = true }
108
108
  ts-rs = { version = "12.0", features = ["serde-compat"], optional = true }
109
- polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.9", optional = true, default-features = false }
109
+ polyglot-sql-function-catalogs = { path = "../polyglot-sql-function-catalogs", version = "0.5.11", optional = true, default-features = false }
110
110
 
111
111
  [dev-dependencies]
112
112
  pretty_assertions = "1.4"
@@ -1068,6 +1068,11 @@ impl DialectImpl for DuckDBDialect {
1068
1068
  // WithinGroup: PERCENTILE_CONT/DISC WITHIN GROUP (ORDER BY ...) -> QUANTILE_CONT/DISC(col, quantile ORDER BY ...)
1069
1069
  Expression::WithinGroup(wg) => {
1070
1070
  match &wg.this {
1071
+ Expression::ListAgg(listagg) => {
1072
+ let mut listagg = listagg.clone();
1073
+ listagg.order_by = Some(wg.order_by.clone());
1074
+ Ok(Expression::ListAgg(listagg))
1075
+ }
1071
1076
  Expression::PercentileCont(p) => {
1072
1077
  let column = wg
1073
1078
  .order_by
@@ -7496,7 +7501,11 @@ mod tests {
7496
7501
  use crate::dialects::Dialect;
7497
7502
 
7498
7503
  fn transpile_to_duckdb(sql: &str) -> String {
7499
- let dialect = Dialect::get(DialectType::Generic);
7504
+ transpile_to_duckdb_from(sql, DialectType::Generic)
7505
+ }
7506
+
7507
+ fn transpile_to_duckdb_from(sql: &str, read: DialectType) -> String {
7508
+ let dialect = Dialect::get(read);
7500
7509
  let result = dialect
7501
7510
  .transpile(sql, DialectType::DuckDB)
7502
7511
  .expect("Transpile failed");
@@ -7550,6 +7559,36 @@ mod tests {
7550
7559
  );
7551
7560
  }
7552
7561
 
7562
+ #[test]
7563
+ fn test_ordered_string_agg_uses_duckdb_listagg_order_syntax() {
7564
+ let result = transpile_to_duckdb_from(
7565
+ "SELECT string_agg(nm, ',' ORDER BY id) AS v FROM t",
7566
+ DialectType::PostgreSQL,
7567
+ );
7568
+ assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
7569
+ }
7570
+
7571
+ #[test]
7572
+ fn test_ordered_listagg_uses_duckdb_order_syntax() {
7573
+ let result = transpile_to_duckdb_from(
7574
+ "SELECT LISTAGG(col, '|SEPARATOR|') WITHIN GROUP (ORDER BY col2) FROM t",
7575
+ DialectType::Snowflake,
7576
+ );
7577
+ assert_eq!(
7578
+ result,
7579
+ "SELECT LISTAGG(col, '|SEPARATOR|' ORDER BY col2) FROM t"
7580
+ );
7581
+ }
7582
+
7583
+ #[test]
7584
+ fn test_ordered_group_concat_uses_duckdb_listagg_order_syntax() {
7585
+ let result = transpile_to_duckdb_from(
7586
+ "SELECT GROUP_CONCAT(nm ORDER BY id SEPARATOR ',') AS v FROM t",
7587
+ DialectType::MySQL,
7588
+ );
7589
+ assert_eq!(result, "SELECT LISTAGG(nm, ',' ORDER BY id) AS v FROM t");
7590
+ }
7591
+
7553
7592
  #[test]
7554
7593
  fn test_date_format_to_strftime() {
7555
7594
  let result = transpile_to_duckdb("SELECT DATE_FORMAT(d, '%Y-%m-%d')");
@@ -4879,6 +4879,15 @@ impl Dialect {
4879
4879
  Self::push_unsupported_diagnostic(&mut diagnostics, "ARRAY_AGG");
4880
4880
  }
4881
4881
 
4882
+ if matches!(target, DialectType::TSQL | DialectType::Fabric)
4883
+ && Self::node_is_regex_predicate(node)
4884
+ {
4885
+ Self::push_unsupported_diagnostic(
4886
+ &mut diagnostics,
4887
+ "regular expression predicates",
4888
+ );
4889
+ }
4890
+
4882
4891
  if matches!(source, DialectType::PostgreSQL | DialectType::CockroachDB)
4883
4892
  && !matches!(target, DialectType::PostgreSQL | DialectType::CockroachDB)
4884
4893
  {
@@ -5018,6 +5027,15 @@ impl Dialect {
5018
5027
  matches!(expr, Expression::ArrayAgg(_)) || Self::node_is_function_named(expr, "ARRAY_AGG")
5019
5028
  }
5020
5029
 
5030
+ fn node_is_regex_predicate(expr: &Expression) -> bool {
5031
+ matches!(
5032
+ expr,
5033
+ Expression::SimilarTo(_) | Expression::RegexpLike(_) | Expression::RegexpILike(_)
5034
+ ) || Self::node_is_function_named(expr, "REGEXP_LIKE")
5035
+ || Self::node_is_function_named(expr, "REGEXP_I_LIKE")
5036
+ || Self::node_is_function_named(expr, "REGEXP_ILIKE")
5037
+ }
5038
+
5021
5039
  fn node_is_function_named(expr: &Expression, name: &str) -> bool {
5022
5040
  match expr {
5023
5041
  Expression::Function(function) => function.name.eq_ignore_ascii_case(name),
@@ -17924,7 +17924,7 @@ impl Generator {
17924
17924
  {
17925
17925
  self.write_keyword("DATEPART");
17926
17926
  self.write("(");
17927
- self.generate_expression(&func.args[0])?;
17927
+ self.write_tsql_date_part(&func.args[0])?;
17928
17928
  self.write(", ");
17929
17929
  self.generate_expression(&func.args[1])?;
17930
17930
  self.write(")");
@@ -18888,6 +18888,22 @@ impl Generator {
18888
18888
  }
18889
18889
  }
18890
18890
 
18891
+ fn write_tsql_date_part(&mut self, expr: &Expression) -> Result<()> {
18892
+ if let Some(part) = self.extract_date_part_string(expr) {
18893
+ let upper = part.to_ascii_uppercase();
18894
+ let unmapped = match upper.as_str() {
18895
+ "DAYOFWEEK" => "WEEKDAY",
18896
+ "WEEKISO" => "ISO_WEEK",
18897
+ "TIMEZONE_MINUTE" => "TZOFFSET",
18898
+ _ => part.as_str(),
18899
+ };
18900
+ self.write_keyword(unmapped);
18901
+ } else {
18902
+ self.generate_expression(expr)?;
18903
+ }
18904
+ Ok(())
18905
+ }
18906
+
18891
18907
  /// Extract date part string from expression (handles string literals and identifiers)
18892
18908
  fn extract_date_part_string(&self, expr: &Expression) -> Option<String> {
18893
18909
  match expr {
@@ -20369,6 +20385,7 @@ impl Generator {
20369
20385
 
20370
20386
  fn generate_listagg(&mut self, f: &ListAggFunc) -> Result<()> {
20371
20387
  use crate::dialects::DialectType;
20388
+ let order_inside_args = matches!(self.config.dialect, Some(DialectType::DuckDB));
20372
20389
  self.write_keyword("LISTAGG");
20373
20390
  self.write("(");
20374
20391
  if f.distinct {
@@ -20408,20 +20425,35 @@ impl Generator {
20408
20425
  }
20409
20426
  }
20410
20427
  }
20428
+ if order_inside_args {
20429
+ if let Some(ref order_by) = f.order_by {
20430
+ self.write_space();
20431
+ self.write_keyword("ORDER BY");
20432
+ self.write_space();
20433
+ for (i, ord) in order_by.iter().enumerate() {
20434
+ if i > 0 {
20435
+ self.write(", ");
20436
+ }
20437
+ self.generate_ordered(ord)?;
20438
+ }
20439
+ }
20440
+ }
20411
20441
  self.write(")");
20412
- if let Some(ref order_by) = f.order_by {
20413
- self.write_space();
20414
- self.write_keyword("WITHIN GROUP");
20415
- self.write(" (");
20416
- self.write_keyword("ORDER BY");
20417
- self.write_space();
20418
- for (i, ord) in order_by.iter().enumerate() {
20419
- if i > 0 {
20420
- self.write(", ");
20442
+ if !order_inside_args {
20443
+ if let Some(ref order_by) = f.order_by {
20444
+ self.write_space();
20445
+ self.write_keyword("WITHIN GROUP");
20446
+ self.write(" (");
20447
+ self.write_keyword("ORDER BY");
20448
+ self.write_space();
20449
+ for (i, ord) in order_by.iter().enumerate() {
20450
+ if i > 0 {
20451
+ self.write(", ");
20452
+ }
20453
+ self.generate_ordered(ord)?;
20421
20454
  }
20422
- self.generate_ordered(ord)?;
20455
+ self.write(")");
20423
20456
  }
20424
- self.write(")");
20425
20457
  }
20426
20458
  if let Some(ref filter) = f.filter {
20427
20459
  self.write_space();
@@ -194,9 +194,11 @@ pub fn lineage_with_schema(
194
194
  let normalized_expression = lineage_normalized_expression(sql);
195
195
  let mut qualified_expression = if let Some(schema) = schema {
196
196
  let options = if let Some(dialect_type) = dialect.or_else(|| schema.dialect()) {
197
- QualifyColumnsOptions::new().with_dialect(dialect_type)
198
- } else {
199
197
  QualifyColumnsOptions::new()
198
+ .with_dialect(dialect_type)
199
+ .with_allow_partial(true)
200
+ } else {
201
+ QualifyColumnsOptions::new().with_allow_partial(true)
200
202
  };
201
203
 
202
204
  qualify_columns(normalized_expression.clone(), schema, &options).map_err(|e| {
@@ -3705,6 +3707,88 @@ mod tests {
3705
3707
  assert_eq!(expr_with.inferred_type(), Some(&DataType::Text));
3706
3708
  }
3707
3709
 
3710
+ #[test]
3711
+ fn test_lineage_with_schema_tolerates_partial_schema_for_known_column() {
3712
+ let expr = parse_dialect("SELECT order_id, amount FROM t", DialectType::DuckDB);
3713
+ let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3714
+ schema
3715
+ .add_table(
3716
+ "t",
3717
+ &[("amount".into(), DataType::BigInt { length: None })],
3718
+ None,
3719
+ )
3720
+ .expect("schema setup");
3721
+
3722
+ let node = lineage_with_schema(
3723
+ "amount",
3724
+ &expr,
3725
+ Some(&schema),
3726
+ Some(DialectType::DuckDB),
3727
+ false,
3728
+ )
3729
+ .expect("lineage_with_schema should tolerate unrelated unknown columns");
3730
+
3731
+ assert_lineage_contains(&node, "t.amount");
3732
+ }
3733
+
3734
+ #[test]
3735
+ fn test_lineage_with_schema_tolerates_partial_schema_for_unknown_column() {
3736
+ let expr = parse_dialect("SELECT order_id, amount FROM t", DialectType::DuckDB);
3737
+ let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3738
+ schema
3739
+ .add_table(
3740
+ "t",
3741
+ &[("amount".into(), DataType::BigInt { length: None })],
3742
+ None,
3743
+ )
3744
+ .expect("schema setup");
3745
+
3746
+ let node = lineage_with_schema(
3747
+ "order_id",
3748
+ &expr,
3749
+ Some(&schema),
3750
+ Some(DialectType::DuckDB),
3751
+ false,
3752
+ )
3753
+ .expect("lineage_with_schema should keep unknown selected columns");
3754
+
3755
+ assert_lineage_contains(&node, "t.order_id");
3756
+ }
3757
+
3758
+ #[test]
3759
+ fn test_lineage_with_schema_tolerates_partial_schema_for_join_conditions() {
3760
+ let expr = parse_dialect(
3761
+ "SELECT a.order_id, b.amount FROM t a JOIN u b ON a.id = b.id",
3762
+ DialectType::DuckDB,
3763
+ );
3764
+ let mut schema = MappingSchema::with_dialect(DialectType::DuckDB);
3765
+ schema
3766
+ .add_table(
3767
+ "t",
3768
+ &[("order_id".into(), DataType::BigInt { length: None })],
3769
+ None,
3770
+ )
3771
+ .expect("schema setup");
3772
+ schema
3773
+ .add_table(
3774
+ "u",
3775
+ &[("amount".into(), DataType::BigInt { length: None })],
3776
+ None,
3777
+ )
3778
+ .expect("schema setup");
3779
+
3780
+ let node = lineage_with_schema(
3781
+ "amount",
3782
+ &expr,
3783
+ Some(&schema),
3784
+ Some(DialectType::DuckDB),
3785
+ false,
3786
+ )
3787
+ .expect("lineage_with_schema should tolerate unknown join keys");
3788
+
3789
+ assert_lineage_contains(&node, "b.amount");
3790
+ }
3791
+
3708
3792
  #[test]
3709
3793
  fn test_lineage_with_schema_correlated_scalar_subquery() {
3710
3794
  let query = "SELECT id, (SELECT AVG(val) FROM t2 WHERE t2.id = t1.id) AS avg_val FROM t1";
@@ -187,7 +187,9 @@ pub fn analyze_query(sql: &str, options: AnalyzeQueryOptions) -> Result<QueryAna
187
187
  let star_projections = star_projection_facts(&original_expression, mapping_schema.as_ref());
188
188
 
189
189
  if let Some(schema) = mapping_schema.as_ref() {
190
- let qualify_options = QualifyColumnsOptions::new().with_dialect(options.dialect);
190
+ let qualify_options = QualifyColumnsOptions::new()
191
+ .with_dialect(options.dialect)
192
+ .with_allow_partial(true);
191
193
  expression = qualify_columns(expression, schema, &qualify_options)
192
194
  .map_err(|e| Error::internal(format!("query analysis qualification failed: {e}")))?;
193
195
  }
@@ -217,6 +217,29 @@ fn test_validate_with_schema_unknown_column() {
217
217
  );
218
218
  }
219
219
 
220
+ #[test]
221
+ fn test_validate_with_schema_partial_schema_stays_strict() {
222
+ let mut schema = base_schema();
223
+ let users = schema
224
+ .tables
225
+ .iter_mut()
226
+ .find(|table| table.name == "users")
227
+ .expect("users table");
228
+ users.columns.retain(|column| column.name == "id");
229
+
230
+ let opts = SchemaValidationOptions::default();
231
+ let result = validate_with_schema(
232
+ "SELECT id, name FROM users",
233
+ DialectType::Generic,
234
+ &schema,
235
+ &opts,
236
+ );
237
+ assert!(!result.valid);
238
+ assert!(result.errors.iter().any(|error| {
239
+ error.code == validation_codes::E_UNKNOWN_COLUMN && error.message.contains("name")
240
+ }));
241
+ }
242
+
220
243
  #[test]
221
244
  fn test_validate_with_schema_function_catalog_unknown_function() {
222
245
  let schema = base_schema();
@@ -138,6 +138,31 @@ fn strict_transpile_rejects_array_agg_for_lossy_targets() {
138
138
  assert!(err.to_string().contains("ARRAY_AGG"));
139
139
  }
140
140
 
141
+ #[test]
142
+ fn strict_transpile_rejects_regex_predicates_for_tsql_targets() {
143
+ let sqls = [
144
+ "SELECT 1 FROM t WHERE p_brand SIMILAR TO 'Brand#[1-3][0-9]'",
145
+ "SELECT 1 FROM t WHERE c_phone ~ '^1[0-9]'",
146
+ "SELECT 1 FROM t WHERE c_phone !~ '^1[0-9]'",
147
+ "SELECT 1 FROM t WHERE c_phone ~* '^1[0-9]'",
148
+ "SELECT 1 FROM t WHERE c_phone !~* '^1[0-9]'",
149
+ "SELECT 1 FROM t WHERE REGEXP_LIKE(c_phone, '^1[0-9]')",
150
+ ];
151
+
152
+ for sql in sqls {
153
+ for write in [DialectType::Fabric, DialectType::TSQL] {
154
+ let err =
155
+ transpile_with_level(sql, DialectType::PostgreSQL, write, UnsupportedLevel::Raise)
156
+ .expect_err("strict TSQL/Fabric transpile should reject regex predicates");
157
+
158
+ assert!(
159
+ err.to_string().contains("regular expression predicates"),
160
+ "unexpected error for PostgreSQL -> {write:?}: {err}"
161
+ );
162
+ }
163
+ }
164
+ }
165
+
141
166
  #[test]
142
167
  fn strict_transpile_rejects_postgres_only_functions() {
143
168
  let err = transpile_with_level(
@@ -736,6 +736,118 @@ fn analyze_query_resolves_unnest_virtual_output_aliases_with_schema() {
736
736
  }
737
737
  }
738
738
 
739
+ #[test]
740
+ fn analyze_query_tolerates_partial_schema_for_unknown_columns() {
741
+ let analysis = analyze_query(
742
+ "SELECT order_id, amount FROM t",
743
+ AnalyzeQueryOptions {
744
+ dialect: DialectType::DuckDB,
745
+ schema: Some(single_column_schema(&["t"], "amount")),
746
+ },
747
+ )
748
+ .unwrap();
749
+
750
+ assert_eq!(analysis.projections.len(), 2);
751
+ assert_eq!(analysis.projections[0].name.as_deref(), Some("order_id"));
752
+ assert_eq!(analysis.projections[1].name.as_deref(), Some("amount"));
753
+
754
+ let order_id = &analysis.projections[0].upstream;
755
+ assert!(
756
+ order_id.iter().any(|reference| {
757
+ reference.column == "order_id"
758
+ && reference.confidence == ReferenceConfidence::Resolved
759
+ && reference.source_name.as_deref() == Some("t")
760
+ && reference.table.as_deref() == Some("t")
761
+ }),
762
+ "expected best-effort order_id reference, got {order_id:?}"
763
+ );
764
+
765
+ let amount = &analysis.projections[1].upstream;
766
+ assert!(
767
+ amount.iter().any(|reference| {
768
+ reference.column == "amount"
769
+ && reference.confidence == ReferenceConfidence::Resolved
770
+ && reference.table.as_deref() == Some("t")
771
+ }),
772
+ "expected schema-backed amount reference, got {amount:?}"
773
+ );
774
+ }
775
+
776
+ #[test]
777
+ fn analyze_query_tolerates_partial_schema_for_qualified_unknown_columns() {
778
+ let analysis = analyze_query(
779
+ "SELECT t.order_id, t.amount FROM t",
780
+ AnalyzeQueryOptions {
781
+ dialect: DialectType::DuckDB,
782
+ schema: Some(single_column_schema(&["t"], "amount")),
783
+ },
784
+ )
785
+ .unwrap();
786
+
787
+ assert!(
788
+ analysis.projections[0].upstream.iter().any(|reference| {
789
+ reference.column == "order_id"
790
+ && reference.confidence == ReferenceConfidence::Resolved
791
+ && reference.table.as_deref() == Some("t")
792
+ }),
793
+ "expected qualified unknown column to stay as best-effort t.order_id, got {:?}",
794
+ analysis.projections[0].upstream
795
+ );
796
+ assert!(
797
+ analysis.projections[1].upstream.iter().any(|reference| {
798
+ reference.column == "amount" && reference.table.as_deref() == Some("t")
799
+ }),
800
+ "expected known t.amount to resolve, got {:?}",
801
+ analysis.projections[1].upstream
802
+ );
803
+ }
804
+
805
+ #[test]
806
+ fn analyze_query_tolerates_partial_schema_for_join_conditions() {
807
+ let schema: ValidationSchema = serde_json::from_value(json!({
808
+ "tables": [
809
+ {
810
+ "name": "t",
811
+ "columns": [{"name": "order_id", "type": "INT"}]
812
+ },
813
+ {
814
+ "name": "u",
815
+ "columns": [{"name": "amount", "type": "INT"}]
816
+ }
817
+ ]
818
+ }))
819
+ .unwrap();
820
+
821
+ let analysis = analyze_query(
822
+ "SELECT a.order_id, b.amount FROM t a JOIN u b ON a.id = b.id",
823
+ AnalyzeQueryOptions {
824
+ dialect: DialectType::DuckDB,
825
+ schema: Some(schema),
826
+ },
827
+ )
828
+ .unwrap();
829
+
830
+ assert_eq!(analysis.projections.len(), 2);
831
+ assert!(
832
+ analysis.projections[0].upstream.iter().any(|reference| {
833
+ reference.column == "order_id"
834
+ && reference.source_alias.as_deref() == Some("a")
835
+ && reference.table.as_deref() == Some("t")
836
+ }),
837
+ "expected a.order_id to resolve, got {:?}",
838
+ analysis.projections[0].upstream
839
+ );
840
+ assert!(
841
+ analysis.projections[1].upstream.iter().any(|reference| {
842
+ reference.column == "amount"
843
+ && reference.source_alias.as_deref() == Some("b")
844
+ && reference.table.as_deref() == Some("u")
845
+ }),
846
+ "expected b.amount to resolve, got {:?}",
847
+ analysis.projections[1].upstream
848
+ );
849
+ }
850
+
739
851
  #[test]
740
852
  fn analyze_query_resolves_same_select_alias_reference() {
741
853
  let analysis = analyze_query(
@@ -2,8 +2,8 @@
2
2
 
3
3
  use polyglot_sql::generator::{Generator, GeneratorConfig};
4
4
  use polyglot_sql::{
5
- get_all_tables, parse, transpile, validate, Dialect, DialectType, Expression, ExpressionWalk,
6
- Parser, TokenType,
5
+ generate, get_all_tables, parse, transpile, validate, Dialect, DialectType, Expression,
6
+ ExpressionWalk, Parser, TokenType,
7
7
  };
8
8
 
9
9
  fn pg_to_tsql(sql: &str) -> String {
@@ -72,6 +72,51 @@ fn tsql_hex_literals_parse_and_roundtrip() {
72
72
  }
73
73
  }
74
74
 
75
+ #[test]
76
+ fn tsql_datepart_dayofweek_generates_valid_tsql_datepart() {
77
+ let cases = [
78
+ ("WEEKDAY", "WEEKDAY"),
79
+ ("dw", "WEEKDAY"),
80
+ ("DAYOFWEEK", "WEEKDAY"),
81
+ ("isowk", "ISO_WEEK"),
82
+ ("WEEKISO", "ISO_WEEK"),
83
+ ("tz", "TZOFFSET"),
84
+ ("TIMEZONE_MINUTE", "TZOFFSET"),
85
+ ];
86
+
87
+ for dialect in [DialectType::TSQL, DialectType::Fabric] {
88
+ for (input, expected) in cases {
89
+ let sql = format!("SELECT DATEPART({input}, o.order_date) AS dow FROM orders o");
90
+ let ast = parse(&sql, dialect)
91
+ .unwrap_or_else(|error| panic!("{dialect:?} DATEPART should parse: {error}"));
92
+ assert_eq!(ast.len(), 1);
93
+
94
+ let generated = generate(&ast[0], dialect)
95
+ .unwrap_or_else(|error| panic!("{dialect:?} DATEPART should generate: {error}"));
96
+
97
+ assert_eq!(
98
+ generated,
99
+ format!("SELECT DATEPART({expected}, o.order_date) AS dow FROM orders AS o"),
100
+ "failed for {dialect:?} DATEPART({input}, ...)"
101
+ );
102
+ }
103
+ }
104
+ }
105
+
106
+ #[test]
107
+ fn tsql_datepart_dayofweek_transpiles_to_valid_tsql_datepart() {
108
+ let sql = "SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders o";
109
+
110
+ assert_eq!(
111
+ transpile(sql, DialectType::TSQL, DialectType::TSQL).expect("TSQL identity transpile"),
112
+ vec!["SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders AS o"]
113
+ );
114
+ assert_eq!(
115
+ transpile(sql, DialectType::TSQL, DialectType::Fabric).expect("TSQL to Fabric transpile"),
116
+ vec!["SELECT DATEPART(WEEKDAY, o.order_date) AS dow FROM orders AS o"]
117
+ );
118
+ }
119
+
75
120
  // ---------------------------------------------------------------------------
76
121
  // T-SQL SET options
77
122
  // ---------------------------------------------------------------------------
@@ -113,6 +113,23 @@ def test_lineage_with_schema_resolves_ambiguous_column():
113
113
  assert any(name == "u.id" for name in names), f"expected u.id in lineage tree, got: {names}"
114
114
 
115
115
 
116
+ def test_lineage_with_schema_tolerates_partial_schema():
117
+ schema = {
118
+ "tables": [
119
+ {
120
+ "name": "t",
121
+ "columns": [{"name": "amount", "type": "INT"}],
122
+ }
123
+ ]
124
+ }
125
+ result = polyglot_sql.lineage_with_schema(
126
+ "amount", "SELECT order_id, amount FROM t", schema, dialect="duckdb"
127
+ )
128
+
129
+ names = collect_names(result)
130
+ assert "t.amount" in names
131
+
132
+
116
133
  def test_bigquery_unnest_lineage_marks_virtual_source():
117
134
  sql = """
118
135
  SELECT date_val AS week_start
@@ -35,6 +35,36 @@ def test_analyze_query_accepts_schema_options():
35
35
  assert result["projections"][0]["castType"] == "TEXT"
36
36
 
37
37
 
38
+ def test_analyze_query_tolerates_partial_schema():
39
+ schema = {
40
+ "tables": [
41
+ {
42
+ "name": "t",
43
+ "columns": [{"name": "amount", "type": "INT"}],
44
+ }
45
+ ]
46
+ }
47
+ result = polyglot_sql.analyze_query(
48
+ "SELECT order_id, amount FROM t",
49
+ {"schema": schema, "dialect": "duckdb"},
50
+ )
51
+
52
+ assert [projection["name"] for projection in result["projections"]] == [
53
+ "order_id",
54
+ "amount",
55
+ ]
56
+ assert any(
57
+ reference["column"] == "order_id"
58
+ and reference["table"] == "t"
59
+ and reference["confidence"] == "resolved"
60
+ for reference in result["projections"][0]["upstream"]
61
+ )
62
+ assert any(
63
+ reference["column"] == "amount" and reference["table"] == "t"
64
+ for reference in result["projections"][1]["upstream"]
65
+ )
66
+
67
+
38
68
  def test_analyze_query_reports_transform_function_arguments():
39
69
  schema = {
40
70
  "tables": [
File without changes