sqlty 0.1.0__tar.gz → 0.2.1__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 (265) hide show
  1. {sqlty-0.1.0 → sqlty-0.2.1}/PKG-INFO +8 -6
  2. {sqlty-0.1.0 → sqlty-0.2.1}/README.md +7 -5
  3. {sqlty-0.1.0 → sqlty-0.2.1}/pyproject.toml +2 -1
  4. {sqlty-0.1.0 → sqlty-0.2.1}/rust/Cargo.lock +7 -4
  5. {sqlty-0.1.0 → sqlty-0.2.1}/rust/Cargo.toml +2 -1
  6. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-ext/Cargo.toml +2 -0
  7. sqlty-0.2.1/rust/crates/sqlty-ext/build.rs +51 -0
  8. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-ext/src/lib.rs +52 -21
  9. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/checker.rs +187 -9
  10. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/fixer.rs +3 -2
  11. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/rules.rs +11 -2
  12. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/tokens.rs +13 -0
  13. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/Cargo.toml +1 -0
  14. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/build.rs +3 -1
  15. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/README.md +96 -18
  16. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/aggregates.inference.toml +41 -1
  17. sqlty-0.2.1/rust/crates/sqlty-sql/rules/common/conditional.inference.toml +17 -0
  18. sqlty-0.2.1/rust/crates/sqlty-sql/rules/common/datetime.inference.toml +25 -0
  19. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/json.inference.toml +34 -2
  20. sqlty-0.2.1/rust/crates/sqlty-sql/rules/common/math.inference.toml +17 -0
  21. sqlty-0.2.1/rust/crates/sqlty-sql/rules/common/strings.inference.toml +33 -0
  22. sqlty-0.2.1/rust/crates/sqlty-sql/rules/common/window.inference.toml +41 -0
  23. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/compile.rs +387 -69
  24. sqlty-0.2.1/rust/crates/sqlty-sql/rules/dialects.toml +6 -0
  25. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/aggregates.inference.toml +49 -0
  26. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/arithmetic.inference.toml +132 -0
  27. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/bits.inference.toml +10 -0
  28. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/comparison.inference.toml +28 -0
  29. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/conditional.inference.toml +19 -0
  30. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/datetime.inference.toml +136 -0
  31. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/encryption.inference.toml +46 -0
  32. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/json.inference.toml +102 -0
  33. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/math.inference.toml +84 -0
  34. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/misc.inference.toml +109 -0
  35. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/spatial.inference.toml +120 -0
  36. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/strings.inference.toml +228 -0
  37. sqlty-0.2.1/rust/crates/sqlty-sql/rules/mysql/system.inference.toml +118 -0
  38. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/admin.inference.toml +145 -0
  39. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/aggregates.inference.toml +178 -0
  40. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/arithmetic.inference.toml +185 -0
  41. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/arrays.inference.toml +120 -0
  42. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/binary.inference.toml +46 -0
  43. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/comparison.inference.toml +20 -0
  44. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/postgres/concat.inference.toml +20 -0
  45. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/conditional.inference.toml +10 -0
  46. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/datetime.inference.toml +127 -0
  47. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/enums.inference.toml +19 -0
  48. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/events.inference.toml +19 -0
  49. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/extensions.inference.toml +28 -0
  50. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/formatting.inference.toml +28 -0
  51. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/geometry.inference.toml +175 -0
  52. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/json.inference.toml +258 -0
  53. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/math.inference.toml +92 -0
  54. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/merge.inference.toml +10 -0
  55. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/network.inference.toml +64 -0
  56. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/ranges.inference.toml +136 -0
  57. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/rows.inference.toml +10 -0
  58. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/sequences.inference.toml +10 -0
  59. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/series.inference.toml +19 -0
  60. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/strings.inference.toml +101 -0
  61. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/system.inference.toml +353 -0
  62. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/textsearch.inference.toml +162 -0
  63. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/uuid.inference.toml +28 -0
  64. sqlty-0.2.1/rust/crates/sqlty-sql/rules/postgres/xml.inference.toml +55 -0
  65. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/aggregates.inference.toml +29 -0
  66. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/arithmetic.inference.toml +54 -0
  67. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/bitwise.inference.toml +17 -0
  68. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/datetime.inference.toml +28 -0
  69. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/fts.inference.toml +37 -0
  70. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/json.inference.toml +100 -0
  71. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/math.inference.toml +38 -0
  72. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/scalar.inference.toml +91 -0
  73. sqlty-0.2.1/rust/crates/sqlty-sql/rules/sqlite/strings.inference.toml +10 -0
  74. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/api.rs +11 -1
  75. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/dml.rs +797 -0
  76. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/explain.rs +6 -1
  77. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/expr.rs +203 -76
  78. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/functions.rs +153 -496
  79. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/grouping.rs +80 -24
  80. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/inference.rs +95 -12
  81. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/json.rs +2 -1
  82. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/literals.rs +7 -1
  83. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/merged_star.rs +178 -0
  84. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/mod.rs +18 -1
  85. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/names.rs +4 -0
  86. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/narrowing.rs +100 -8
  87. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/nullability.rs +416 -120
  88. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/operators.rs +177 -5
  89. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/params.rs +66 -1
  90. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/pg_record_functions.rs +599 -0
  91. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/preprocess.rs +128 -13
  92. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/query.rs +214 -27
  93. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/references.rs +21 -1
  94. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/registry.rs +264 -0
  95. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/resolve.rs +54 -19
  96. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/respell.rs +569 -0
  97. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/scope.rs +85 -17
  98. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__dml__tests__returning_columns_in_queries.snap +11 -10
  99. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__arrays_and_subscripts.snap +1 -1
  100. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__composite_fields_and_json_access.snap +1 -2
  101. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__literals_and_unary_operators.snap +2 -2
  102. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__misc_expressions.snap +1 -1
  103. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__mysql_and_sqlite_expressions.snap +5 -6
  104. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__function_availability_differs_by_dialect.snap +1 -1
  105. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__division_differs_between_postgres_and_mysql.snap +1 -2
  106. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__dialects_name_and_type_the_same_query_differently.snap +3 -3
  107. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__unsupported_query_forms_are_explained.snap +3 -2
  108. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__values_lists.snap +23 -4
  109. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__quoted_names_keep_their_case_in_postgres_only.snap +1 -1
  110. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__star_over_unreadable_sources_names_the_reason.snap +8 -4
  111. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__opaque_sources_explain_themselves.snap +5 -5
  112. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__star_expansion_over_joins.snap +15 -6
  113. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/sql_type.rs +5 -4
  114. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/table_functions.rs +103 -32
  115. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/tests.rs +2 -2
  116. sqlty-0.2.1/rust/crates/sqlty-sql/src/analyzer/text_names.rs +174 -0
  117. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/alter.rs +75 -11
  118. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/columns.rs +46 -4
  119. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/loader.rs +208 -20
  120. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/mod.rs +79 -7
  121. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/read.rs +162 -8
  122. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/resolve.rs +52 -9
  123. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/ddl.rs +325 -20
  124. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/diagnostics.rs +6 -1
  125. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/tests/inference_compiler.rs +180 -0
  126. sqlty-0.2.1/skills/sqlty/SKILL.md +81 -0
  127. sqlty-0.2.1/skills/sqlty-adopt/SKILL.md +125 -0
  128. sqlty-0.2.1/skills/sqlty-breaking/SKILL.md +130 -0
  129. sqlty-0.2.1/skills/sqlty-check/SKILL.md +144 -0
  130. sqlty-0.2.1/skills/sqlty-ci/SKILL.md +120 -0
  131. sqlty-0.2.1/skills/sqlty-rewrite/SKILL.md +134 -0
  132. sqlty-0.2.1/src/sqlty/_breaking.py +314 -0
  133. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_check.py +34 -4
  134. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_cli.py +69 -24
  135. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_core.pyi +2 -1
  136. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_drivers.py +79 -16
  137. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_helpers.py +17 -1
  138. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_lint.py +15 -1
  139. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_params.py +39 -6
  140. sqlty-0.2.1/src/sqlty/_snapshot.py +169 -0
  141. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_source.py +16 -4
  142. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/ast_fields.py +55 -9
  143. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/extract.py +59 -10
  144. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/core.py +36 -30
  145. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/insert-missing-column.md +9 -4
  146. sqlty-0.2.1/src/sqlty/rules/insert-value-count.md +58 -0
  147. sqlty-0.2.1/src/sqlty/rules/narrow-type.md +50 -0
  148. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/param-type-mismatch.md +10 -2
  149. sqlty-0.2.1/src/sqlty/rules/stale-type.md +56 -0
  150. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/ungrouped-column.md +3 -0
  151. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unparsed-query.md +5 -3
  152. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unsupported-syntax.md +3 -3
  153. sqlty-0.1.0/rust/crates/sqlty-sql/rules/mysql/aggregates.inference.toml +0 -21
  154. sqlty-0.1.0/rust/crates/sqlty-sql/rules/mysql/arithmetic.inference.toml +0 -30
  155. sqlty-0.1.0/rust/crates/sqlty-sql/rules/mysql/comparison.inference.toml +0 -10
  156. sqlty-0.1.0/rust/crates/sqlty-sql/rules/mysql/json.inference.toml +0 -21
  157. sqlty-0.1.0/rust/crates/sqlty-sql/rules/mysql/strings.inference.toml +0 -51
  158. sqlty-0.1.0/rust/crates/sqlty-sql/rules/postgres/aggregates.inference.toml +0 -51
  159. sqlty-0.1.0/rust/crates/sqlty-sql/rules/postgres/json.inference.toml +0 -123
  160. sqlty-0.1.0/rust/crates/sqlty-sql/rules/sqlite/json.inference.toml +0 -28
  161. sqlty-0.1.0/rust/crates/sqlty-sql/src/analyzer/dialect_functions.rs +0 -379
  162. sqlty-0.1.0/rust/crates/sqlty-sql/src/analyzer/dml.rs +0 -388
  163. sqlty-0.1.0/rust/crates/sqlty-sql/src/analyzer/registry.rs +0 -439
  164. sqlty-0.1.0/src/sqlty/_breaking.py +0 -191
  165. sqlty-0.1.0/src/sqlty/_widening.py +0 -89
  166. sqlty-0.1.0/src/sqlty/rules/stale-type.md +0 -50
  167. sqlty-0.1.0/src/sqlty/skill/SKILL.md +0 -110
  168. {sqlty-0.1.0 → sqlty-0.2.1}/LICENSE +0 -0
  169. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/Cargo.toml +0 -0
  170. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/edit.rs +0 -0
  171. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/lib.rs +0 -0
  172. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/options.rs +0 -0
  173. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/rewriter.rs +0 -0
  174. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/scan.rs +0 -0
  175. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-python/src/template.rs +0 -0
  176. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/arithmetic.inference.toml +0 -0
  177. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/comparison.inference.toml +0 -0
  178. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/common/concat.inference.toml +0 -0
  179. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/rules/mysql/concat.inference.toml +0 -0
  180. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/dialect.rs +0 -0
  181. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/hashing.rs +0 -0
  182. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/memo.rs +0 -0
  183. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__case_expressions.snap +0 -0
  184. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts.snap +0 -0
  185. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts_without_a_schema_do_not_complain.snap +0 -0
  186. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__aggregates_in_postgres.snap +0 -0
  187. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__return_types_follow_the_argument.snap +0 -0
  188. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__unknown_functions_are_untyped_and_explained.snap +0 -0
  189. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__literals__tests__value_sets_flow_through_expressions.snap +0 -0
  190. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__names__tests__column_names_follow_postgres_figure_colname.snap +0 -0
  191. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__arithmetic_promotes_numbers_and_types_date_math.snap +0 -0
  192. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__binary_operators_in_queries.snap +0 -0
  193. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__common_type_follows_postgres_union_rules.snap +0 -0
  194. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__column_names_come_from_the_first_branch.snap +0 -0
  195. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__ctes.snap +0 -0
  196. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__projection_forms.snap +0 -0
  197. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__recursive_ctes_settle_nullability.snap +0 -0
  198. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_combine_nullability.snap +0 -0
  199. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_unify_types.snap +0 -0
  200. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__statements_that_are_not_queries_have_no_columns.snap +0 -0
  201. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__ambiguous_names_are_reported_once_per_query.snap +0 -0
  202. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__cte_columns_are_resolved_like_tables.snap +0 -0
  203. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__names_are_not_judged_without_a_schema.snap +0 -0
  204. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__nullability_comes_from_the_declaration.snap +0 -0
  205. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__system_columns_exist_without_being_declared.snap +0 -0
  206. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unknown_names_say_what_is_missing.snap +0 -0
  207. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unqualified_names_resolve_to_the_first_source_that_has_them.snap +0 -0
  208. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__correlated_subqueries_see_the_outer_scope.snap +0 -0
  209. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__derived_tables_ctes_and_views.snap +0 -0
  210. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__nullability_follows_the_join_kind.snap +0 -0
  211. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__table_names_fold_by_dialect.snap +0 -0
  212. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/star_expand.rs +0 -0
  213. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/test_support.rs +0 -0
  214. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/analyzer/typed.rs +0 -0
  215. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/builtin_catalog.sql +0 -0
  216. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/catalog/names.rs +0 -0
  217. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/json.rs +0 -0
  218. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/lib.rs +0 -0
  219. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/placeholders.rs +0 -0
  220. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/src/values.rs +0 -0
  221. {sqlty-0.1.0 → sqlty-0.2.1}/rust/crates/sqlty-sql/tests/timing.rs +0 -0
  222. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/__init__.py +0 -0
  223. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/__main__.py +0 -0
  224. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_config.py +0 -0
  225. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_decode.py +0 -0
  226. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_gitignore.py +0 -0
  227. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_json_shape.py +0 -0
  228. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_json_types.py +0 -0
  229. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_psycopg.py +0 -0
  230. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/__init__.py +0 -0
  231. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/compat.py +0 -0
  232. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/generic.py +0 -0
  233. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/info.py +0 -0
  234. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/sandbox.py +0 -0
  235. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/_type_extractor/subtype.py +0 -0
  236. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/drivers/psycopg.py +0 -0
  237. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/magic.py +0 -0
  238. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/py.typed +0 -0
  239. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/ambiguous-column.md +0 -0
  240. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/column-count-mismatch.md +0 -0
  241. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/column-name-mismatch.md +0 -0
  242. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/column-type-mismatch.md +0 -0
  243. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/fstring-skipped.md +0 -0
  244. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/inline-sql-comment.md +0 -0
  245. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/json-shape-mismatch.md +0 -0
  246. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/literal-mismatch.md +0 -0
  247. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/mysql-sql-marker.md +0 -0
  248. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/nullable-mismatch.md +0 -0
  249. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/param-count-mismatch.md +0 -0
  250. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/redundant-literal.md +0 -0
  251. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/redundant-optional.md +0 -0
  252. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/select-star-no-schema.md +0 -0
  253. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/select-star.md +0 -0
  254. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/stale-rewrite.md +0 -0
  255. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/tstring-skipped.md +0 -0
  256. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/typeddict-inheritance.md +0 -0
  257. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/typeddict-key-mismatch.md +0 -0
  258. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unchecked-query.md +0 -0
  259. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-column.md +0 -0
  260. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-function.md +0 -0
  261. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-table.md +0 -0
  262. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unknown-type.md +0 -0
  263. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/untyped-query.md +0 -0
  264. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty/rules/unused-ignore.md +0 -0
  265. {sqlty-0.1.0 → sqlty-0.2.1}/src/sqlty_magic.pth +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlty
3
- Version: 0.1.0
3
+ Version: 0.2.1
4
4
  Classifier: Development Status :: 4 - Beta
5
5
  Classifier: Environment :: Console
6
6
  Classifier: Intended Audience :: Developers
@@ -111,13 +111,14 @@ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
111
111
  ```python
112
112
  from sqlty import SQL
113
113
 
114
- # error: [stale-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
114
+ # error: [narrow-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
115
115
  query = SQL[tuple[int, str]]("--sql\nSELECT id, email FROM users")
116
116
  ```
117
117
 
118
118
  `sqlty check --fix .` updates the type, and your type checker finds every
119
- caller that now needs a `None` check. `stale-type` is a warning by default; set
120
- `stale-type = "error"` under `[tool.sqlty.rules]` to fail CI on it
119
+ caller that now needs a `None` check. `narrow-type` is an error, so CI fails on
120
+ it; an annotation that is only wider than the rows, such as `str | None` for a
121
+ column made `NOT NULL`, is a `stale-type` warning
121
122
  ([CI](https://jirikuncar.github.io/sqlty/recipes/ci/)). For rolling deploys,
122
123
  `sqlty breaking --against origin/main` exits 1 when old code breaks on the new
123
124
  schema or new code on the old one
@@ -174,8 +175,9 @@ conn.execute("--sql\nSELECT emial FROM users")
174
175
  asyncpg calls ([Parameters](https://jirikuncar.github.io/sqlty/guide/parameters/)).
175
176
  These are the mistakes coding agents make: every problem is one
176
177
  `file:line: [rule] message` line and a non-zero exit code they can act on, and
177
- the [sqlty skill](https://jirikuncar.github.io/sqlty/recipes/agents/) teaches
178
- them the conventions.
178
+ the [sqlty skills](https://jirikuncar.github.io/sqlty/recipes/agents/) teach
179
+ them the conventions. In Claude Code, `/plugin install sqlty --marketplace jirikuncar/sqlty`
180
+ installs them.
179
181
 
180
182
  ## Get started
181
183
 
@@ -78,13 +78,14 @@ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
78
78
  ```python
79
79
  from sqlty import SQL
80
80
 
81
- # error: [stale-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
81
+ # error: [narrow-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
82
82
  query = SQL[tuple[int, str]]("--sql\nSELECT id, email FROM users")
83
83
  ```
84
84
 
85
85
  `sqlty check --fix .` updates the type, and your type checker finds every
86
- caller that now needs a `None` check. `stale-type` is a warning by default; set
87
- `stale-type = "error"` under `[tool.sqlty.rules]` to fail CI on it
86
+ caller that now needs a `None` check. `narrow-type` is an error, so CI fails on
87
+ it; an annotation that is only wider than the rows, such as `str | None` for a
88
+ column made `NOT NULL`, is a `stale-type` warning
88
89
  ([CI](https://jirikuncar.github.io/sqlty/recipes/ci/)). For rolling deploys,
89
90
  `sqlty breaking --against origin/main` exits 1 when old code breaks on the new
90
91
  schema or new code on the old one
@@ -141,8 +142,9 @@ conn.execute("--sql\nSELECT emial FROM users")
141
142
  asyncpg calls ([Parameters](https://jirikuncar.github.io/sqlty/guide/parameters/)).
142
143
  These are the mistakes coding agents make: every problem is one
143
144
  `file:line: [rule] message` line and a non-zero exit code they can act on, and
144
- the [sqlty skill](https://jirikuncar.github.io/sqlty/recipes/agents/) teaches
145
- them the conventions.
145
+ the [sqlty skills](https://jirikuncar.github.io/sqlty/recipes/agents/) teach
146
+ them the conventions. In Claude Code, `/plugin install sqlty --marketplace jirikuncar/sqlty`
147
+ installs them.
146
148
 
147
149
  ## Get started
148
150
 
@@ -61,7 +61,8 @@ manifest-path = "rust/crates/sqlty-ext/Cargo.toml"
61
61
  # registers the lazy "sqlty" codec lookup (see docs/guide/magic-codec.md).
62
62
  # The path is relative to the project root (maturin >= 1.12.1): the wheel gets
63
63
  # it at the root (python-source prefix stripped), the sdist at src/.
64
- include = ["src/sqlty_magic.pth"]
64
+ # The Agent Skills are compiled into the extension, so only the sdist needs them.
65
+ include = ["src/sqlty_magic.pth", { path = "skills/**/*", format = "sdist" }]
65
66
 
66
67
  [dependency-groups]
67
68
  dev = [
@@ -614,7 +614,7 @@ dependencies = [
614
614
 
615
615
  [[package]]
616
616
  name = "sqlty-bench"
617
- version = "0.1.0"
617
+ version = "0.2.1"
618
618
  dependencies = [
619
619
  "criterion",
620
620
  "sqlty-python",
@@ -623,17 +623,19 @@ dependencies = [
623
623
 
624
624
  [[package]]
625
625
  name = "sqlty-core"
626
- version = "0.1.0"
626
+ version = "0.2.1"
627
627
  dependencies = [
628
628
  "pyo3",
629
+ "recursive",
629
630
  "sqlty-python",
630
631
  "sqlty-sql",
632
+ "stacker",
631
633
  "thiserror",
632
634
  ]
633
635
 
634
636
  [[package]]
635
637
  name = "sqlty-python"
636
- version = "0.1.0"
638
+ version = "0.2.1"
637
639
  dependencies = [
638
640
  "regex",
639
641
  "sqlty-sql",
@@ -642,9 +644,10 @@ dependencies = [
642
644
 
643
645
  [[package]]
644
646
  name = "sqlty-sql"
645
- version = "0.1.0"
647
+ version = "0.2.1"
646
648
  dependencies = [
647
649
  "insta",
650
+ "recursive",
648
651
  "regex",
649
652
  "rustc-hash",
650
653
  "serde",
@@ -3,7 +3,7 @@ resolver = "2"
3
3
  members = ["crates/*"]
4
4
 
5
5
  [workspace.package]
6
- version = "0.1.0"
6
+ version = "0.2.1"
7
7
  edition = "2021"
8
8
  description = "Rust engine of sqlty: SQL type inference and Python source rewriting"
9
9
  license = "MIT"
@@ -15,6 +15,7 @@ rust-version = "1.88"
15
15
  pyo3 = { version = "0.29", features = ["extension-module"] }
16
16
  sqlparser = { version = "0.63", features = ["visitor"] }
17
17
  regex = "1"
18
+ recursive = "0.1"
18
19
  rustc-hash = "2"
19
20
  thiserror = "2"
20
21
  insta = "1.49"
@@ -19,4 +19,6 @@ crate-type = ["cdylib"]
19
19
  pyo3.workspace = true
20
20
  sqlty-sql.workspace = true
21
21
  sqlty-python.workspace = true
22
+ recursive.workspace = true
23
+ stacker = "0.1"
22
24
  thiserror.workspace = true
@@ -0,0 +1,51 @@
1
+ //! Embeds the Agent Skills of `skills/` at the repository root, so `sqlty skill` prints the
2
+ //! ones of its own version wherever the wheel is installed.
3
+
4
+ use std::fmt::Write as _;
5
+ use std::path::{Path, PathBuf};
6
+ use std::{env, fs};
7
+
8
+ fn main() {
9
+ let root = Path::new(&env::var("CARGO_MANIFEST_DIR").unwrap()).join("../../../skills");
10
+ let root = root
11
+ .canonicalize()
12
+ .unwrap_or_else(|e| panic!("{}: {e}", root.display()));
13
+ let mut files = Vec::new();
14
+ collect(&root, &mut files);
15
+ files.sort();
16
+ let mut out = String::from("pub(crate) static SKILLS: &[(&str, &str)] = &[\n");
17
+ for file in &files {
18
+ let relative = file
19
+ .strip_prefix(&root)
20
+ .unwrap()
21
+ .to_str()
22
+ .unwrap()
23
+ .replace('\\', "/");
24
+ writeln!(
25
+ out,
26
+ " ({relative:?}, include_str!({:?})),",
27
+ file.to_str().unwrap()
28
+ )
29
+ .unwrap();
30
+ }
31
+ out.push_str("];\n");
32
+ fs::write(
33
+ Path::new(&env::var("OUT_DIR").unwrap()).join("skills.rs"),
34
+ out,
35
+ )
36
+ .unwrap();
37
+ }
38
+
39
+ /// Every file under `dir`, and every directory for Cargo to watch.
40
+ fn collect(dir: &Path, files: &mut Vec<PathBuf>) {
41
+ println!("cargo:rerun-if-changed={}", dir.display());
42
+ for entry in fs::read_dir(dir).unwrap() {
43
+ let path = entry.unwrap().path();
44
+ if path.is_dir() {
45
+ collect(&path, files);
46
+ } else {
47
+ println!("cargo:rerun-if-changed={}", path.display());
48
+ files.push(path);
49
+ }
50
+ }
51
+ }
@@ -52,6 +52,7 @@ type ParamTuple = (
52
52
  Option<String>,
53
53
  Option<bool>,
54
54
  bool,
55
+ Option<String>,
55
56
  );
56
57
 
57
58
  /// A parsed schema and the tables and views it could not parse.
@@ -186,7 +187,7 @@ fn load_schema(
186
187
  let dialect = dialect.0;
187
188
  let overrides = analyzer::TypeOverrides::new(&types.unwrap_or_default(), dialect)
188
189
  .map_err(PyValueError::new_err)?;
189
- let loaded = py.detach(|| {
190
+ let loaded = detach(py, || {
190
191
  let (schema, skipped) = if overrides.is_empty() {
191
192
  analyzer::load_schema_with_skipped(schema_sql, dialect)
192
193
  } else {
@@ -293,7 +294,28 @@ fn infer_type(
293
294
  schema_sql: Option<SchemaArg>,
294
295
  ) -> Result<Option<String>, Error> {
295
296
  let dialect = dialect.0;
296
- Ok(py.detach(|| analyzer::infer_type(sql, dialect, schema(schema_sql, dialect).as_deref()))?)
297
+ Ok(detach(py, || {
298
+ analyzer::infer_type(sql, dialect, schema(schema_sql, dialect).as_deref())
299
+ })?)
300
+ }
301
+
302
+ /// The stack the analyzer's recursion keeps free: it moves to a new stack of
303
+ /// [`STACK_SEGMENT`] when less is left, so an expression nested `MAX_DEPTH` (1000) levels
304
+ /// deep fits whatever thread calls it.
305
+ const STACK_RED_ZONE: usize = 2 << 20;
306
+ const STACK_SEGMENT: usize = 16 << 20;
307
+
308
+ /// Runs `f` without the GIL, with at least [`STACK_RED_ZONE`] of stack.
309
+ fn detach<T: Send, F: Send + FnOnce() -> T>(py: Python<'_>, f: F) -> T {
310
+ py.detach(|| stacker::maybe_grow(STACK_RED_ZONE, STACK_SEGMENT, f))
311
+ }
312
+
313
+ include!(concat!(env!("OUT_DIR"), "/skills.rs"));
314
+
315
+ /// The files of the Agent Skills, as `(path, text)` with paths like `sqlty/SKILL.md`.
316
+ #[pyfunction]
317
+ fn skills() -> Vec<(&'static str, &'static str)> {
318
+ SKILLS.to_vec()
297
319
  }
298
320
 
299
321
  /// Result columns of a query as `(name, python_type, sql_type)` tuples.
@@ -311,7 +333,7 @@ fn analyze_select(
311
333
  schema_sql: Option<SchemaArg>,
312
334
  ) -> Result<Option<Vec<ColumnTuple>>, Error> {
313
335
  let dialect = dialect.0;
314
- let columns = py.detach(|| {
336
+ let columns = detach(py, || {
315
337
  analyzer::analyze_select(sql, dialect, schema(schema_sql, dialect).as_deref())
316
338
  })?;
317
339
  Ok(columns.map(|columns| {
@@ -340,7 +362,7 @@ fn explain_select(
340
362
  schema_sql: Option<SchemaArg>,
341
363
  ) -> Option<Vec<ColumnRulesTuple>> {
342
364
  let dialect = dialect.0;
343
- let columns = py.detach(|| {
365
+ let columns = detach(py, || {
344
366
  analyzer::explain_select(sql, dialect, schema(schema_sql, dialect).as_deref())
345
367
  })?;
346
368
  let tuple = |rule: analyzer::RuleRef| (rule.id, rule.reference, rule.reasoning);
@@ -376,7 +398,7 @@ fn analyze_columns(
376
398
  schema_sql: Option<SchemaArg>,
377
399
  ) -> Result<Option<Vec<NullableColumnTuple>>, Error> {
378
400
  let dialect = dialect.0;
379
- let columns = py.detach(|| {
401
+ let columns = detach(py, || {
380
402
  analyzer::analyze_select(sql, dialect, schema(schema_sql, dialect).as_deref())
381
403
  })?;
382
404
  Ok(columns.map(|columns| {
@@ -439,7 +461,7 @@ fn analyze_params(
439
461
  schema_sql: Option<SchemaArg>,
440
462
  ) -> Option<Vec<ParamTuple>> {
441
463
  let dialect = dialect.0;
442
- let params = py.detach(|| {
464
+ let params = detach(py, || {
443
465
  analyzer::analyze_params(sql, dialect, schema(schema_sql, dialect).as_deref())
444
466
  })?;
445
467
  Some(
@@ -453,6 +475,7 @@ fn analyze_params(
453
475
  param.sql_type,
454
476
  nullable(param.nullability),
455
477
  param.cast,
478
+ param.untyped_sql_type,
456
479
  )
457
480
  })
458
481
  .collect(),
@@ -483,7 +506,8 @@ fn name_rules() -> Vec<&'static str> {
483
506
 
484
507
  /// Why a query has untyped columns, or names what it cannot, as `(rule, message)` pairs:
485
508
  /// `unknown-table`, `unknown-column`, `ambiguous-column`, `unknown-function`,
486
- /// `unknown-type`, `unsupported-syntax`, `insert-missing-column` and `ungrouped-column`.
509
+ /// `unknown-type`, `unsupported-syntax`, `insert-missing-column`, `insert-value-count` and
510
+ /// `ungrouped-column`.
487
511
  /// Tables, columns and
488
512
  /// ambiguity are only judged with a schema.
489
513
  ///
@@ -498,7 +522,7 @@ fn query_diagnostics(
498
522
  schema_sql: Option<SchemaArg>,
499
523
  ) -> Vec<(String, String)> {
500
524
  let dialect = dialect.0;
501
- py.detach(|| {
525
+ detach(py, || {
502
526
  analyzer::analyze_with_diagnostics(sql, dialect, schema(schema_sql, dialect).as_deref())
503
527
  .1
504
528
  .into_iter()
@@ -517,7 +541,7 @@ fn schema_skipped_tables(
517
541
  dialect: DialectArg,
518
542
  ) -> Vec<String> {
519
543
  let dialect = dialect.0;
520
- py.detach(|| skipped_objects(schema_sql, dialect, Some("table")))
544
+ detach(py, || skipped_objects(schema_sql, dialect, Some("table")))
521
545
  .into_iter()
522
546
  .map(|(_, name)| name)
523
547
  .collect()
@@ -533,7 +557,7 @@ fn schema_skipped_objects(
533
557
  dialect: DialectArg,
534
558
  ) -> Vec<(String, String)> {
535
559
  let dialect = dialect.0;
536
- py.detach(|| skipped_objects(schema_sql, dialect, None))
560
+ detach(py, || skipped_objects(schema_sql, dialect, None))
537
561
  }
538
562
 
539
563
  fn skipped_objects<S: AsRef<str>>(
@@ -558,7 +582,7 @@ fn skipped_objects<S: AsRef<str>>(
558
582
  #[pyo3(signature = (sql, *, dialect = DialectArg::POSTGRES))]
559
583
  fn parse_error(py: Python<'_>, sql: &str, dialect: DialectArg) -> Option<String> {
560
584
  let dialect = dialect.0;
561
- py.detach(|| analyzer::parse_error(sql, dialect))
585
+ detach(py, || analyzer::parse_error(sql, dialect))
562
586
  }
563
587
 
564
588
  /// Whether a query yields rows: a query, DML with RETURNING, or unparseable SQL.
@@ -568,7 +592,7 @@ fn parse_error(py: Python<'_>, sql: &str, dialect: DialectArg) -> Option<String>
568
592
  #[pyo3(signature = (sql, *, dialect = DialectArg::POSTGRES))]
569
593
  fn returns_rows(py: Python<'_>, sql: &str, dialect: DialectArg) -> bool {
570
594
  let dialect = dialect.0;
571
- py.detach(|| analyzer::returns_rows(sql, dialect))
595
+ detach(py, || analyzer::returns_rows(sql, dialect))
572
596
  }
573
597
 
574
598
  /// Rewrite Python source: "--sql\n..." -> SQL[T]("--sql\n...").
@@ -592,7 +616,7 @@ fn rewrite_source(
592
616
  keep_lines: bool,
593
617
  ) -> Result<String, Error> {
594
618
  let dialect = dialect.0;
595
- py.detach(|| {
619
+ detach(py, || {
596
620
  let schema = schema_for(source, schema_sql, dialect);
597
621
  let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
598
622
  Ok(rewriter::rewrite_source_with(source, &options, keep_lines))
@@ -608,7 +632,7 @@ fn rewrite_source(
608
632
  #[pyfunction]
609
633
  #[pyo3(signature = (source, *, import_style = None))]
610
634
  fn strip_source(py: Python<'_>, source: &str, import_style: Option<&str>) -> Result<String, Error> {
611
- py.detach(|| {
635
+ detach(py, || {
612
636
  let style = ImportStyle::parse(import_style)?;
613
637
  Ok(rewriter::strip_source(source, &style))
614
638
  })
@@ -638,7 +662,7 @@ fn fix_source(
638
662
  suppressed: Option<rewriter::Suppressed>,
639
663
  ) -> Result<String, Error> {
640
664
  let dialect = dialect.0;
641
- py.detach(|| {
665
+ detach(py, || {
642
666
  let schema = schema_for(source, schema_sql, dialect);
643
667
  let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
644
668
  let rules = RuleConfig::from_overrides(rules).map_err(ConfigError::from)?;
@@ -664,7 +688,9 @@ fn expand_star(
664
688
  schema_sql: Option<SchemaArg>,
665
689
  ) -> Option<String> {
666
690
  let dialect = dialect.0;
667
- py.detach(|| analyzer::expand_star(sql, dialect, schema(schema_sql, dialect).as_deref()))
691
+ detach(py, || {
692
+ analyzer::expand_star(sql, dialect, schema(schema_sql, dialect).as_deref())
693
+ })
668
694
  }
669
695
 
670
696
  /// `(rule, message)` of `select-star` or `select-star-no-schema` for a query whose
@@ -682,8 +708,10 @@ fn select_star_finding(
682
708
  has_schema: bool,
683
709
  ) -> Option<(&'static str, String)> {
684
710
  let dialect = dialect.0;
685
- py.detach(|| checker::select_star_finding(sql, dialect, has_schema))
686
- .map(|(rule, message)| (rule.name(), message))
711
+ detach(py, || {
712
+ checker::select_star_finding(sql, dialect, has_schema)
713
+ })
714
+ .map(|(rule, message)| (rule.name(), message))
687
715
  }
688
716
 
689
717
  /// A finding of `check_source`, which Python reads as a dict.
@@ -726,7 +754,7 @@ fn check_source(
726
754
  any_calls: Vec<usize>,
727
755
  ) -> Result<Vec<DiagnosticOut>, Error> {
728
756
  let dialect = dialect.0;
729
- py.detach(|| {
757
+ detach(py, || {
730
758
  let schema = schema_for(source, schema_sql, dialect);
731
759
  let options = Options::new(dialect, schema.as_deref(), import_style, untyped)?;
732
760
  let rules = RuleConfig::from_overrides(rules).map_err(ConfigError::from)?;
@@ -756,7 +784,7 @@ fn wrapped_queries(
756
784
  source: &str,
757
785
  import_style: Option<&str>,
758
786
  ) -> Result<Vec<(usize, String, Option<String>)>, Error> {
759
- py.detach(|| {
787
+ detach(py, || {
760
788
  let style = ImportStyle::parse(import_style)?;
761
789
  Ok(checker::wrapped_queries(source, &style))
762
790
  })
@@ -784,7 +812,7 @@ fn query_sites(
784
812
  import_style: Option<&str>,
785
813
  any_calls: Vec<usize>,
786
814
  ) -> Result<Vec<(usize, String, String)>, Error> {
787
- py.detach(|| {
815
+ detach(py, || {
788
816
  let style = ImportStyle::parse(import_style)?;
789
817
  Ok(checker::query_sites(source, &style, &any_calls)
790
818
  .into_iter()
@@ -797,6 +825,8 @@ fn query_sites(
797
825
  /// module runs without the GIL on free-threaded builds.
798
826
  #[pymodule(gil_used = false)]
799
827
  fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
828
+ recursive::set_minimum_stack_size(STACK_RED_ZONE);
829
+ recursive::set_stack_allocation_size(STACK_SEGMENT);
800
830
  m.add_function(wrap_pyfunction!(infer_type, m)?)?;
801
831
  m.add_function(wrap_pyfunction!(load_schema, m)?)?;
802
832
  m.add_class::<SchemaHandle>()?;
@@ -821,6 +851,7 @@ fn _core(m: &Bound<'_, PyModule>) -> PyResult<()> {
821
851
  m.add_function(wrap_pyfunction!(check_source, m)?)?;
822
852
  m.add_function(wrap_pyfunction!(wrapped_queries, m)?)?;
823
853
  m.add_function(wrap_pyfunction!(query_sites, m)?)?;
854
+ m.add_function(wrap_pyfunction!(skills, m)?)?;
824
855
  Ok(())
825
856
  }
826
857