sqlty 0.0.1.dev1__tar.gz → 0.2.0__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.2.0/PKG-INFO +212 -0
  2. sqlty-0.2.0/README.md +178 -0
  3. sqlty-0.2.0/pyproject.toml +172 -0
  4. sqlty-0.2.0/rust/Cargo.lock +876 -0
  5. sqlty-0.2.0/rust/Cargo.toml +58 -0
  6. sqlty-0.2.0/rust/crates/sqlty-ext/Cargo.toml +22 -0
  7. sqlty-0.2.0/rust/crates/sqlty-ext/build.rs +51 -0
  8. sqlty-0.2.0/rust/crates/sqlty-ext/src/lib.rs +949 -0
  9. sqlty-0.2.0/rust/crates/sqlty-python/Cargo.toml +17 -0
  10. sqlty-0.2.0/rust/crates/sqlty-python/src/checker.rs +1620 -0
  11. sqlty-0.2.0/rust/crates/sqlty-python/src/edit.rs +54 -0
  12. sqlty-0.2.0/rust/crates/sqlty-python/src/fixer.rs +240 -0
  13. sqlty-0.2.0/rust/crates/sqlty-python/src/lib.rs +41 -0
  14. sqlty-0.2.0/rust/crates/sqlty-python/src/options.rs +50 -0
  15. sqlty-0.2.0/rust/crates/sqlty-python/src/rewriter.rs +1528 -0
  16. sqlty-0.2.0/rust/crates/sqlty-python/src/rules.rs +360 -0
  17. sqlty-0.2.0/rust/crates/sqlty-python/src/scan.rs +201 -0
  18. sqlty-0.2.0/rust/crates/sqlty-python/src/template.rs +212 -0
  19. sqlty-0.2.0/rust/crates/sqlty-python/src/tokens.rs +721 -0
  20. sqlty-0.2.0/rust/crates/sqlty-sql/Cargo.toml +28 -0
  21. sqlty-0.2.0/rust/crates/sqlty-sql/build.rs +47 -0
  22. sqlty-0.2.0/rust/crates/sqlty-sql/rules/README.md +263 -0
  23. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/aggregates.inference.toml +101 -0
  24. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/arithmetic.inference.toml +54 -0
  25. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/comparison.inference.toml +60 -0
  26. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/concat.inference.toml +35 -0
  27. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/conditional.inference.toml +17 -0
  28. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/datetime.inference.toml +25 -0
  29. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/json.inference.toml +78 -0
  30. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/math.inference.toml +17 -0
  31. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/strings.inference.toml +33 -0
  32. sqlty-0.2.0/rust/crates/sqlty-sql/rules/common/window.inference.toml +41 -0
  33. sqlty-0.2.0/rust/crates/sqlty-sql/rules/compile.rs +1055 -0
  34. sqlty-0.2.0/rust/crates/sqlty-sql/rules/dialects.toml +6 -0
  35. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/aggregates.inference.toml +49 -0
  36. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/arithmetic.inference.toml +132 -0
  37. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/bits.inference.toml +10 -0
  38. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/comparison.inference.toml +28 -0
  39. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/concat.inference.toml +9 -0
  40. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/conditional.inference.toml +19 -0
  41. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/datetime.inference.toml +136 -0
  42. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/encryption.inference.toml +46 -0
  43. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/json.inference.toml +102 -0
  44. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/math.inference.toml +84 -0
  45. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/misc.inference.toml +109 -0
  46. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/spatial.inference.toml +120 -0
  47. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/strings.inference.toml +228 -0
  48. sqlty-0.2.0/rust/crates/sqlty-sql/rules/mysql/system.inference.toml +118 -0
  49. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/admin.inference.toml +145 -0
  50. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/aggregates.inference.toml +178 -0
  51. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/arithmetic.inference.toml +527 -0
  52. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/arrays.inference.toml +120 -0
  53. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/binary.inference.toml +46 -0
  54. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/comparison.inference.toml +20 -0
  55. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/concat.inference.toml +69 -0
  56. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/conditional.inference.toml +10 -0
  57. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/datetime.inference.toml +127 -0
  58. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/enums.inference.toml +19 -0
  59. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/events.inference.toml +19 -0
  60. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/extensions.inference.toml +28 -0
  61. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/formatting.inference.toml +28 -0
  62. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/geometry.inference.toml +175 -0
  63. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/json.inference.toml +258 -0
  64. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/math.inference.toml +92 -0
  65. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/merge.inference.toml +10 -0
  66. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/network.inference.toml +64 -0
  67. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/ranges.inference.toml +136 -0
  68. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/rows.inference.toml +10 -0
  69. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/sequences.inference.toml +10 -0
  70. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/series.inference.toml +19 -0
  71. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/strings.inference.toml +101 -0
  72. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/system.inference.toml +353 -0
  73. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/textsearch.inference.toml +162 -0
  74. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/uuid.inference.toml +28 -0
  75. sqlty-0.2.0/rust/crates/sqlty-sql/rules/postgres/xml.inference.toml +55 -0
  76. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/aggregates.inference.toml +29 -0
  77. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/arithmetic.inference.toml +54 -0
  78. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/bitwise.inference.toml +17 -0
  79. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/datetime.inference.toml +28 -0
  80. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/fts.inference.toml +37 -0
  81. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/json.inference.toml +100 -0
  82. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/math.inference.toml +38 -0
  83. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/scalar.inference.toml +91 -0
  84. sqlty-0.2.0/rust/crates/sqlty-sql/rules/sqlite/strings.inference.toml +10 -0
  85. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/api.rs +194 -0
  86. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/dialect.rs +171 -0
  87. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/dml.rs +745 -0
  88. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/explain.rs +131 -0
  89. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/expr.rs +815 -0
  90. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/functions.rs +565 -0
  91. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/grouping.rs +244 -0
  92. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/hashing.rs +30 -0
  93. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/inference.rs +403 -0
  94. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/json.rs +738 -0
  95. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/literals.rs +254 -0
  96. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/memo.rs +125 -0
  97. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/merged_star.rs +178 -0
  98. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/mod.rs +132 -0
  99. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/names.rs +351 -0
  100. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/narrowing.rs +776 -0
  101. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/nullability.rs +1477 -0
  102. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/operators.rs +725 -0
  103. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/params.rs +1119 -0
  104. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/pg_record_functions.rs +599 -0
  105. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/preprocess.rs +472 -0
  106. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/query.rs +1099 -0
  107. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/references.rs +102 -0
  108. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/registry.rs +264 -0
  109. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/resolve.rs +776 -0
  110. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/respell.rs +557 -0
  111. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/scope.rs +1016 -0
  112. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__dml__tests__returning_columns_in_queries.snap +49 -0
  113. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__arrays_and_subscripts.snap +36 -0
  114. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__case_expressions.snap +28 -0
  115. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts.snap +41 -0
  116. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__casts_without_a_schema_do_not_complain.snap +9 -0
  117. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__composite_fields_and_json_access.snap +23 -0
  118. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__literals_and_unary_operators.snap +29 -0
  119. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__misc_expressions.snap +38 -0
  120. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__expr__tests__mysql_and_sqlite_expressions.snap +30 -0
  121. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__aggregates_in_postgres.snap +44 -0
  122. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__function_availability_differs_by_dialect.snap +37 -0
  123. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__return_types_follow_the_argument.snap +74 -0
  124. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__functions__tests__unknown_functions_are_untyped_and_explained.snap +16 -0
  125. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__literals__tests__value_sets_flow_through_expressions.snap +43 -0
  126. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__names__tests__column_names_follow_postgres_figure_colname.snap +34 -0
  127. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__arithmetic_promotes_numbers_and_types_date_math.snap +149 -0
  128. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__binary_operators_in_queries.snap +58 -0
  129. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__common_type_follows_postgres_union_rules.snap +24 -0
  130. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__operators__tests__division_differs_between_postgres_and_mysql.snap +13 -0
  131. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__column_names_come_from_the_first_branch.snap +9 -0
  132. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__ctes.snap +18 -0
  133. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__dialects_name_and_type_the_same_query_differently.snap +33 -0
  134. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__projection_forms.snap +42 -0
  135. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__recursive_ctes_settle_nullability.snap +17 -0
  136. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_combine_nullability.snap +27 -0
  137. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__set_operations_unify_types.snap +30 -0
  138. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__statements_that_are_not_queries_have_no_columns.snap +21 -0
  139. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__unsupported_query_forms_are_explained.snap +14 -0
  140. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__query__tests__values_lists.snap +51 -0
  141. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__ambiguous_names_are_reported_once_per_query.snap +30 -0
  142. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__cte_columns_are_resolved_like_tables.snap +18 -0
  143. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__names_are_not_judged_without_a_schema.snap +15 -0
  144. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__nullability_comes_from_the_declaration.snap +15 -0
  145. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__quoted_names_keep_their_case_in_postgres_only.snap +29 -0
  146. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__star_over_unreadable_sources_names_the_reason.snap +35 -0
  147. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__system_columns_exist_without_being_declared.snap +29 -0
  148. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unknown_names_say_what_is_missing.snap +47 -0
  149. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__resolve__tests__unqualified_names_resolve_to_the_first_source_that_has_them.snap +24 -0
  150. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__correlated_subqueries_see_the_outer_scope.snap +21 -0
  151. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__derived_tables_ctes_and_views.snap +36 -0
  152. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__nullability_follows_the_join_kind.snap +33 -0
  153. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__opaque_sources_explain_themselves.snap +51 -0
  154. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__star_expansion_over_joins.snap +58 -0
  155. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/snapshots/sqlty_sql__analyzer__scope__tests__table_names_fold_by_dialect.snap +28 -0
  156. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/sql_type.rs +927 -0
  157. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/star_expand.rs +257 -0
  158. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/table_functions.rs +308 -0
  159. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/test_support.rs +62 -0
  160. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/tests.rs +421 -0
  161. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/text_names.rs +174 -0
  162. sqlty-0.2.0/rust/crates/sqlty-sql/src/analyzer/typed.rs +111 -0
  163. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/alter.rs +401 -0
  164. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/builtin_catalog.sql +190 -0
  165. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/columns.rs +368 -0
  166. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/loader.rs +954 -0
  167. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/mod.rs +977 -0
  168. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/names.rs +165 -0
  169. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/read.rs +385 -0
  170. sqlty-0.2.0/rust/crates/sqlty-sql/src/catalog/resolve.rs +485 -0
  171. sqlty-0.2.0/rust/crates/sqlty-sql/src/ddl.rs +1150 -0
  172. sqlty-0.2.0/rust/crates/sqlty-sql/src/diagnostics.rs +274 -0
  173. sqlty-0.2.0/rust/crates/sqlty-sql/src/json.rs +486 -0
  174. sqlty-0.2.0/rust/crates/sqlty-sql/src/lib.rs +40 -0
  175. sqlty-0.2.0/rust/crates/sqlty-sql/src/placeholders.rs +324 -0
  176. sqlty-0.2.0/rust/crates/sqlty-sql/src/values.rs +344 -0
  177. sqlty-0.2.0/rust/crates/sqlty-sql/tests/inference_compiler.rs +462 -0
  178. sqlty-0.2.0/rust/crates/sqlty-sql/tests/timing.rs +70 -0
  179. sqlty-0.2.0/skills/sqlty/SKILL.md +81 -0
  180. sqlty-0.2.0/skills/sqlty-adopt/SKILL.md +125 -0
  181. sqlty-0.2.0/skills/sqlty-breaking/SKILL.md +130 -0
  182. sqlty-0.2.0/skills/sqlty-check/SKILL.md +144 -0
  183. sqlty-0.2.0/skills/sqlty-ci/SKILL.md +120 -0
  184. sqlty-0.2.0/skills/sqlty-rewrite/SKILL.md +134 -0
  185. sqlty-0.2.0/src/sqlty/__init__.py +99 -0
  186. {sqlty-0.0.1.dev1 → sqlty-0.2.0}/src/sqlty/__main__.py +1 -1
  187. sqlty-0.2.0/src/sqlty/_breaking.py +314 -0
  188. sqlty-0.2.0/src/sqlty/_check.py +911 -0
  189. sqlty-0.2.0/src/sqlty/_cli.py +1264 -0
  190. sqlty-0.2.0/src/sqlty/_config.py +666 -0
  191. sqlty-0.2.0/src/sqlty/_core.pyi +109 -0
  192. sqlty-0.2.0/src/sqlty/_decode.py +62 -0
  193. sqlty-0.2.0/src/sqlty/_drivers.py +274 -0
  194. sqlty-0.2.0/src/sqlty/_gitignore.py +58 -0
  195. sqlty-0.2.0/src/sqlty/_helpers.py +629 -0
  196. sqlty-0.2.0/src/sqlty/_json_shape.py +299 -0
  197. sqlty-0.2.0/src/sqlty/_json_types.py +225 -0
  198. sqlty-0.2.0/src/sqlty/_lint.py +364 -0
  199. sqlty-0.2.0/src/sqlty/_params.py +210 -0
  200. sqlty-0.2.0/src/sqlty/_psycopg.py +269 -0
  201. sqlty-0.2.0/src/sqlty/_snapshot.py +169 -0
  202. sqlty-0.2.0/src/sqlty/_source.py +654 -0
  203. sqlty-0.2.0/src/sqlty/_type_extractor/__init__.py +51 -0
  204. sqlty-0.2.0/src/sqlty/_type_extractor/ast_fields.py +869 -0
  205. sqlty-0.2.0/src/sqlty/_type_extractor/compat.py +252 -0
  206. sqlty-0.2.0/src/sqlty/_type_extractor/extract.py +228 -0
  207. sqlty-0.2.0/src/sqlty/_type_extractor/generic.py +95 -0
  208. sqlty-0.2.0/src/sqlty/_type_extractor/info.py +161 -0
  209. sqlty-0.2.0/src/sqlty/_type_extractor/sandbox.py +385 -0
  210. sqlty-0.2.0/src/sqlty/_type_extractor/subtype.py +156 -0
  211. sqlty-0.2.0/src/sqlty/core.py +571 -0
  212. sqlty-0.2.0/src/sqlty/drivers/psycopg.py +104 -0
  213. sqlty-0.2.0/src/sqlty/magic.py +126 -0
  214. sqlty-0.2.0/src/sqlty/rules/ambiguous-column.md +48 -0
  215. sqlty-0.2.0/src/sqlty/rules/column-count-mismatch.md +30 -0
  216. sqlty-0.2.0/src/sqlty/rules/column-name-mismatch.md +34 -0
  217. sqlty-0.2.0/src/sqlty/rules/column-type-mismatch.md +75 -0
  218. sqlty-0.2.0/src/sqlty/rules/fstring-skipped.md +23 -0
  219. sqlty-0.2.0/src/sqlty/rules/inline-sql-comment.md +27 -0
  220. sqlty-0.2.0/src/sqlty/rules/insert-missing-column.md +63 -0
  221. sqlty-0.2.0/src/sqlty/rules/insert-value-count.md +58 -0
  222. sqlty-0.2.0/src/sqlty/rules/json-shape-mismatch.md +96 -0
  223. sqlty-0.2.0/src/sqlty/rules/literal-mismatch.md +83 -0
  224. sqlty-0.2.0/src/sqlty/rules/mysql-sql-marker.md +32 -0
  225. sqlty-0.2.0/src/sqlty/rules/narrow-type.md +50 -0
  226. sqlty-0.2.0/src/sqlty/rules/nullable-mismatch.md +76 -0
  227. sqlty-0.2.0/src/sqlty/rules/param-count-mismatch.md +66 -0
  228. sqlty-0.2.0/src/sqlty/rules/param-type-mismatch.md +77 -0
  229. sqlty-0.2.0/src/sqlty/rules/redundant-literal.md +68 -0
  230. sqlty-0.2.0/src/sqlty/rules/redundant-optional.md +100 -0
  231. sqlty-0.2.0/src/sqlty/rules/select-star-no-schema.md +24 -0
  232. sqlty-0.2.0/src/sqlty/rules/select-star.md +77 -0
  233. sqlty-0.2.0/src/sqlty/rules/stale-rewrite.md +33 -0
  234. sqlty-0.2.0/src/sqlty/rules/stale-type.md +56 -0
  235. sqlty-0.2.0/src/sqlty/rules/tstring-skipped.md +68 -0
  236. sqlty-0.2.0/src/sqlty/rules/typeddict-inheritance.md +35 -0
  237. sqlty-0.2.0/src/sqlty/rules/typeddict-key-mismatch.md +38 -0
  238. sqlty-0.2.0/src/sqlty/rules/unchecked-query.md +34 -0
  239. sqlty-0.2.0/src/sqlty/rules/ungrouped-column.md +67 -0
  240. sqlty-0.2.0/src/sqlty/rules/unknown-column.md +68 -0
  241. sqlty-0.2.0/src/sqlty/rules/unknown-function.md +49 -0
  242. sqlty-0.2.0/src/sqlty/rules/unknown-table.md +47 -0
  243. sqlty-0.2.0/src/sqlty/rules/unknown-type.md +74 -0
  244. sqlty-0.2.0/src/sqlty/rules/unparsed-query.md +46 -0
  245. sqlty-0.2.0/src/sqlty/rules/unsupported-syntax.md +69 -0
  246. sqlty-0.2.0/src/sqlty/rules/untyped-query.md +39 -0
  247. sqlty-0.2.0/src/sqlty/rules/unused-ignore.md +36 -0
  248. sqlty-0.2.0/src/sqlty_magic.pth +1 -0
  249. sqlty-0.0.1.dev1/.gitignore +0 -20
  250. sqlty-0.0.1.dev1/PKG-INFO +0 -187
  251. sqlty-0.0.1.dev1/README.md +0 -138
  252. sqlty-0.0.1.dev1/pyproject.toml +0 -139
  253. sqlty-0.0.1.dev1/src/sqlty/__init__.py +0 -55
  254. sqlty-0.0.1.dev1/src/sqlty/_ast_builder.py +0 -211
  255. sqlty-0.0.1.dev1/src/sqlty/_ast_unparser.py +0 -215
  256. sqlty-0.0.1.dev1/src/sqlty/_auto_generator.py +0 -44
  257. sqlty-0.0.1.dev1/src/sqlty/_collector.py +0 -126
  258. sqlty-0.0.1.dev1/src/sqlty/_config.py +0 -114
  259. sqlty-0.0.1.dev1/src/sqlty/_generator.py +0 -587
  260. sqlty-0.0.1.dev1/src/sqlty/_registry.py +0 -146
  261. sqlty-0.0.1.dev1/src/sqlty/_sql_analyzer.py +0 -228
  262. sqlty-0.0.1.dev1/src/sqlty/_stub_merger.py +0 -275
  263. sqlty-0.0.1.dev1/src/sqlty/drivers/psycopg.py +0 -12
  264. {sqlty-0.0.1.dev1 → sqlty-0.2.0}/LICENSE +0 -0
  265. {sqlty-0.0.1.dev1 → sqlty-0.2.0}/src/sqlty/py.typed +0 -0
sqlty-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,212 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlty
3
+ Version: 0.2.0
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Environment :: Console
6
+ Classifier: Intended Audience :: Developers
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3 :: Only
9
+ Classifier: Programming Language :: Python :: 3.14
10
+ Classifier: Programming Language :: Python :: 3.15
11
+ Classifier: Programming Language :: Rust
12
+ Classifier: Programming Language :: SQL
13
+ Classifier: Topic :: Software Development :: Code Generators
14
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
15
+ Classifier: Topic :: Database
16
+ Classifier: Typing :: Typed
17
+ Requires-Dist: pathspec>=0.12.1
18
+ Requires-Dist: typing-extensions>=4.15.0 ; python_full_version < '3.15'
19
+ Requires-Dist: psycopg>=3.2.12 ; extra == 'psycopg'
20
+ Provides-Extra: psycopg
21
+ License-File: LICENSE
22
+ Summary: Type-safe SQL queries for Python
23
+ Keywords: sql,type-hints,mypy,type-safety,static-analysis,code-generation
24
+ Author-email: Jiri Kuncar <jiri.kuncar@gmail.com>
25
+ License-Expression: MIT
26
+ Requires-Python: >=3.14
27
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
28
+ Project-URL: Changelog, https://github.com/jirikuncar/sqlty/releases
29
+ Project-URL: Documentation, https://jirikuncar.github.io/sqlty/
30
+ Project-URL: Homepage, https://github.com/jirikuncar/sqlty
31
+ Project-URL: Issues, https://github.com/jirikuncar/sqlty/issues
32
+ Project-URL: Repository, https://github.com/jirikuncar/sqlty
33
+
34
+ # SQLTy
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/sqlty.svg)](https://pypi.org/project/sqlty/)
37
+ [![Python 3.14+](https://img.shields.io/badge/python-3.14+-blue.svg)](https://www.python.org/downloads/)
38
+ [![Tests](https://github.com/jirikuncar/sqlty/actions/workflows/tests.yml/badge.svg)](https://github.com/jirikuncar/sqlty/actions/workflows/tests.yml)
39
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
40
+
41
+ Your SQL already knows its types. SQLTy tells Python.
42
+
43
+ Type-safe raw SQL without an ORM or a database connection. sqlty reads row and
44
+ parameter types from your SQL and schema, and checks them on every commit, so a
45
+ migration that changes a column is caught in review, not in production.
46
+
47
+ <p align="center">
48
+ <img src="https://raw.githubusercontent.com/jirikuncar/sqlty/main/docs/assets/demo.gif" alt="A terminal session: sqlty rewrite adds the row type to a query, a migration makes email nullable, sqlty check --fix updates the type and mypy reports the line that would crash" width="720">
49
+ <br>
50
+ <em>A migration makes <code>email</code> nullable. sqlty and mypy find the code that would crash.</em>
51
+ (<a href="https://github.com/jirikuncar/sqlty/blob/main/docs/assets/demo.tape">view source</a>)
52
+ </p>
53
+
54
+ **Documentation: [jirikuncar.github.io/sqlty](https://jirikuncar.github.io/sqlty/)**
55
+
56
+ **Fits if** you write SQL as string literals on Python 3.14+, against
57
+ PostgreSQL, SQLite or MySQL, with a schema dump or SQL migrations in the
58
+ repository. Rows are typed end to end with psycopg 3; with other drivers sqlty
59
+ checks the query and its parameters, and you annotate what the cursor returns
60
+ ([Drivers](https://jirikuncar.github.io/sqlty/guide/drivers-and-orms/)).
61
+
62
+ > **Beta.** APIs and configuration may change before 1.0. Feedback welcome in
63
+ > [GitHub Issues](https://github.com/jirikuncar/sqlty/issues).
64
+
65
+ ## How it works
66
+
67
+ Drivers return rows of `Any`, so nothing ties a query's columns to the code
68
+ that reads them. Start a query with `--sql` and a newline, and
69
+ `sqlty rewrite .` adds the row type inferred from your `CREATE TABLE`
70
+ statements:
71
+
72
+ ```toml
73
+ # pyproject.toml
74
+ [tool.sqlty]
75
+ schema = "schema.sql"
76
+ ```
77
+
78
+ `schema.sql`:
79
+
80
+ ```sql
81
+ CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email VARCHAR(255) NOT NULL);
82
+ ```
83
+
84
+ ```python
85
+ query = "--sql\nSELECT id, name, email FROM users"
86
+ # rewritten: query = SQL[tuple[int, str, str]]("--sql\nSELECT id, name, email FROM users")
87
+ ```
88
+
89
+ `SQL[T]` is a `str` subclass, so the query still runs anywhere a string does,
90
+ and mypy, pyright and ty see `T`. Without a schema, casts such as `id::INTEGER`
91
+ type the columns; a query with neither stays as it is. With a space instead of
92
+ the newline, `"--sql SELECT ..."` is a SQL comment, and `sqlty check` warns.
93
+
94
+ ## What it catches
95
+
96
+ ### A migration changes a column
97
+
98
+ ```toml
99
+ [tool.sqlty]
100
+ schema = "schema.sql"
101
+ ```
102
+
103
+ A migration dropped `NOT NULL` from `email`.
104
+
105
+ `schema.sql`:
106
+
107
+ ```sql
108
+ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
109
+ ```
110
+
111
+ ```python
112
+ from sqlty import SQL
113
+
114
+ # error: [narrow-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
115
+ query = SQL[tuple[int, str]]("--sql\nSELECT id, email FROM users")
116
+ ```
117
+
118
+ `sqlty check --fix .` updates the type, and your type checker finds every
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
122
+ ([CI](https://jirikuncar.github.io/sqlty/recipes/ci/)). For rolling deploys,
123
+ `sqlty breaking --against origin/main` exits 1 when old code breaks on the new
124
+ schema or new code on the old one
125
+ ([Breaking schema changes](https://jirikuncar.github.io/sqlty/guide/breaking-changes/)).
126
+
127
+ ### A row type that doesn't match its query
128
+
129
+ ```python
130
+ from typing import TypedDict
131
+ from sqlty import SQL
132
+
133
+ class User(TypedDict):
134
+ id: str
135
+ name: str
136
+
137
+ # error: [column-type-mismatch] "User.id is str but query column 'id' infers int"
138
+ query = SQL[User]("--sql\nSELECT id::INTEGER, name::TEXT FROM users")
139
+ ```
140
+
141
+ `TypedDict`, `NamedTuple`, dataclasses and Pydantic models are all checked
142
+ ([Row types](https://jirikuncar.github.io/sqlty/guide/row-types/)).
143
+
144
+ ### Wrong parameters, misspelled columns
145
+
146
+ ```toml
147
+ [tool.sqlty]
148
+ dialect = "sqlite"
149
+ schema = "schema.sql"
150
+
151
+ [tool.sqlty.rules]
152
+ unknown-column = "warn"
153
+ ```
154
+
155
+ `schema.sql`:
156
+
157
+ ```sql
158
+ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
159
+ ```
160
+
161
+ ```python
162
+ import sqlite3
163
+ from sqlty import SQL
164
+
165
+ conn = sqlite3.connect("app.db")
166
+
167
+ # error: [param-count-mismatch] "query has 1 parameter, the call passes 2"
168
+ conn.execute(SQL[tuple[str | None]]("--sql\nSELECT email FROM users WHERE id = ?"), (1, 2))
169
+
170
+ # error: [unknown-column] "column `emial` does not exist in `users`"
171
+ conn.execute("--sql\nSELECT emial FROM users")
172
+ ```
173
+
174
+ `?`, `$1`, `%s` and `:name` placeholders are checked on sqlite3, psycopg and
175
+ asyncpg calls ([Parameters](https://jirikuncar.github.io/sqlty/guide/parameters/)).
176
+ These are the mistakes coding agents make: every problem is one
177
+ `file:line: [rule] message` line and a non-zero exit code they can act on, and
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.
181
+
182
+ ## Get started
183
+
184
+ ```bash
185
+ pip install "sqlty[psycopg]" # or: uv add sqlty; the extra adds the psycopg helpers
186
+ printf '%s\n' 'q = "--sql\nSELECT id::INTEGER, name::TEXT FROM users"' > queries.py
187
+ sqlty rewrite -v . # q = SQL[tuple[int, str]]("--sql\n...")
188
+ sqlty check . # report drift and mismatches
189
+ sqlty strip . # undo: back to plain strings
190
+ ```
191
+
192
+ `rewrite` and `strip` only touch the wrapper, never the SQL, so you can adopt
193
+ sqlty one module at a time and back out. New project:
194
+ [Quickstart](https://jirikuncar.github.io/sqlty/quickstart/). Existing codebase:
195
+ [Migration](https://jirikuncar.github.io/sqlty/recipes/migration/), starting
196
+ with `pg_dump --schema-only app > schema.sql`.
197
+
198
+ Not a fit for ORMs, SQL built at runtime, or runtime validation;
199
+ [Why SQLTy?](https://jirikuncar.github.io/sqlty/motivation/) compares it with
200
+ sqlc, sqlx, PgTyped and others.
201
+
202
+ ## About
203
+
204
+ The engine is Rust ([sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs)
205
+ via [PyO3](https://pyo3.rs)), with wheels for Linux, macOS and Windows. SQLTy is
206
+ developed with AI coding agents, mainly Claude Code; every change is reviewed by
207
+ a maintainer (see the
208
+ [AI-assisted contributions](https://github.com/jirikuncar/sqlty/blob/main/CONTRIBUTING.md#ai-assisted-contributions)
209
+ policy). [Contributing](https://github.com/jirikuncar/sqlty/blob/main/CONTRIBUTING.md) ·
210
+ [Credits](https://jirikuncar.github.io/sqlty/credits/) ·
211
+ MIT [License](https://github.com/jirikuncar/sqlty/blob/main/LICENSE).
212
+
sqlty-0.2.0/README.md ADDED
@@ -0,0 +1,178 @@
1
+ # SQLTy
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/sqlty.svg)](https://pypi.org/project/sqlty/)
4
+ [![Python 3.14+](https://img.shields.io/badge/python-3.14+-blue.svg)](https://www.python.org/downloads/)
5
+ [![Tests](https://github.com/jirikuncar/sqlty/actions/workflows/tests.yml/badge.svg)](https://github.com/jirikuncar/sqlty/actions/workflows/tests.yml)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ Your SQL already knows its types. SQLTy tells Python.
9
+
10
+ Type-safe raw SQL without an ORM or a database connection. sqlty reads row and
11
+ parameter types from your SQL and schema, and checks them on every commit, so a
12
+ migration that changes a column is caught in review, not in production.
13
+
14
+ <p align="center">
15
+ <img src="https://raw.githubusercontent.com/jirikuncar/sqlty/main/docs/assets/demo.gif" alt="A terminal session: sqlty rewrite adds the row type to a query, a migration makes email nullable, sqlty check --fix updates the type and mypy reports the line that would crash" width="720">
16
+ <br>
17
+ <em>A migration makes <code>email</code> nullable. sqlty and mypy find the code that would crash.</em>
18
+ (<a href="https://github.com/jirikuncar/sqlty/blob/main/docs/assets/demo.tape">view source</a>)
19
+ </p>
20
+
21
+ **Documentation: [jirikuncar.github.io/sqlty](https://jirikuncar.github.io/sqlty/)**
22
+
23
+ **Fits if** you write SQL as string literals on Python 3.14+, against
24
+ PostgreSQL, SQLite or MySQL, with a schema dump or SQL migrations in the
25
+ repository. Rows are typed end to end with psycopg 3; with other drivers sqlty
26
+ checks the query and its parameters, and you annotate what the cursor returns
27
+ ([Drivers](https://jirikuncar.github.io/sqlty/guide/drivers-and-orms/)).
28
+
29
+ > **Beta.** APIs and configuration may change before 1.0. Feedback welcome in
30
+ > [GitHub Issues](https://github.com/jirikuncar/sqlty/issues).
31
+
32
+ ## How it works
33
+
34
+ Drivers return rows of `Any`, so nothing ties a query's columns to the code
35
+ that reads them. Start a query with `--sql` and a newline, and
36
+ `sqlty rewrite .` adds the row type inferred from your `CREATE TABLE`
37
+ statements:
38
+
39
+ ```toml
40
+ # pyproject.toml
41
+ [tool.sqlty]
42
+ schema = "schema.sql"
43
+ ```
44
+
45
+ `schema.sql`:
46
+
47
+ ```sql
48
+ CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, email VARCHAR(255) NOT NULL);
49
+ ```
50
+
51
+ ```python
52
+ query = "--sql\nSELECT id, name, email FROM users"
53
+ # rewritten: query = SQL[tuple[int, str, str]]("--sql\nSELECT id, name, email FROM users")
54
+ ```
55
+
56
+ `SQL[T]` is a `str` subclass, so the query still runs anywhere a string does,
57
+ and mypy, pyright and ty see `T`. Without a schema, casts such as `id::INTEGER`
58
+ type the columns; a query with neither stays as it is. With a space instead of
59
+ the newline, `"--sql SELECT ..."` is a SQL comment, and `sqlty check` warns.
60
+
61
+ ## What it catches
62
+
63
+ ### A migration changes a column
64
+
65
+ ```toml
66
+ [tool.sqlty]
67
+ schema = "schema.sql"
68
+ ```
69
+
70
+ A migration dropped `NOT NULL` from `email`.
71
+
72
+ `schema.sql`:
73
+
74
+ ```sql
75
+ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
76
+ ```
77
+
78
+ ```python
79
+ from sqlty import SQL
80
+
81
+ # error: [narrow-type] "SQL[tuple[int, str]] should be SQL[tuple[int, str | None]]"
82
+ query = SQL[tuple[int, str]]("--sql\nSELECT id, email FROM users")
83
+ ```
84
+
85
+ `sqlty check --fix .` updates the type, and your type checker finds every
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
89
+ ([CI](https://jirikuncar.github.io/sqlty/recipes/ci/)). For rolling deploys,
90
+ `sqlty breaking --against origin/main` exits 1 when old code breaks on the new
91
+ schema or new code on the old one
92
+ ([Breaking schema changes](https://jirikuncar.github.io/sqlty/guide/breaking-changes/)).
93
+
94
+ ### A row type that doesn't match its query
95
+
96
+ ```python
97
+ from typing import TypedDict
98
+ from sqlty import SQL
99
+
100
+ class User(TypedDict):
101
+ id: str
102
+ name: str
103
+
104
+ # error: [column-type-mismatch] "User.id is str but query column 'id' infers int"
105
+ query = SQL[User]("--sql\nSELECT id::INTEGER, name::TEXT FROM users")
106
+ ```
107
+
108
+ `TypedDict`, `NamedTuple`, dataclasses and Pydantic models are all checked
109
+ ([Row types](https://jirikuncar.github.io/sqlty/guide/row-types/)).
110
+
111
+ ### Wrong parameters, misspelled columns
112
+
113
+ ```toml
114
+ [tool.sqlty]
115
+ dialect = "sqlite"
116
+ schema = "schema.sql"
117
+
118
+ [tool.sqlty.rules]
119
+ unknown-column = "warn"
120
+ ```
121
+
122
+ `schema.sql`:
123
+
124
+ ```sql
125
+ CREATE TABLE users (id INTEGER PRIMARY KEY, email TEXT);
126
+ ```
127
+
128
+ ```python
129
+ import sqlite3
130
+ from sqlty import SQL
131
+
132
+ conn = sqlite3.connect("app.db")
133
+
134
+ # error: [param-count-mismatch] "query has 1 parameter, the call passes 2"
135
+ conn.execute(SQL[tuple[str | None]]("--sql\nSELECT email FROM users WHERE id = ?"), (1, 2))
136
+
137
+ # error: [unknown-column] "column `emial` does not exist in `users`"
138
+ conn.execute("--sql\nSELECT emial FROM users")
139
+ ```
140
+
141
+ `?`, `$1`, `%s` and `:name` placeholders are checked on sqlite3, psycopg and
142
+ asyncpg calls ([Parameters](https://jirikuncar.github.io/sqlty/guide/parameters/)).
143
+ These are the mistakes coding agents make: every problem is one
144
+ `file:line: [rule] message` line and a non-zero exit code they can act on, and
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.
148
+
149
+ ## Get started
150
+
151
+ ```bash
152
+ pip install "sqlty[psycopg]" # or: uv add sqlty; the extra adds the psycopg helpers
153
+ printf '%s\n' 'q = "--sql\nSELECT id::INTEGER, name::TEXT FROM users"' > queries.py
154
+ sqlty rewrite -v . # q = SQL[tuple[int, str]]("--sql\n...")
155
+ sqlty check . # report drift and mismatches
156
+ sqlty strip . # undo: back to plain strings
157
+ ```
158
+
159
+ `rewrite` and `strip` only touch the wrapper, never the SQL, so you can adopt
160
+ sqlty one module at a time and back out. New project:
161
+ [Quickstart](https://jirikuncar.github.io/sqlty/quickstart/). Existing codebase:
162
+ [Migration](https://jirikuncar.github.io/sqlty/recipes/migration/), starting
163
+ with `pg_dump --schema-only app > schema.sql`.
164
+
165
+ Not a fit for ORMs, SQL built at runtime, or runtime validation;
166
+ [Why SQLTy?](https://jirikuncar.github.io/sqlty/motivation/) compares it with
167
+ sqlc, sqlx, PgTyped and others.
168
+
169
+ ## About
170
+
171
+ The engine is Rust ([sqlparser-rs](https://github.com/apache/datafusion-sqlparser-rs)
172
+ via [PyO3](https://pyo3.rs)), with wheels for Linux, macOS and Windows. SQLTy is
173
+ developed with AI coding agents, mainly Claude Code; every change is reviewed by
174
+ a maintainer (see the
175
+ [AI-assisted contributions](https://github.com/jirikuncar/sqlty/blob/main/CONTRIBUTING.md#ai-assisted-contributions)
176
+ policy). [Contributing](https://github.com/jirikuncar/sqlty/blob/main/CONTRIBUTING.md) ·
177
+ [Credits](https://jirikuncar.github.io/sqlty/credits/) ·
178
+ MIT [License](https://github.com/jirikuncar/sqlty/blob/main/LICENSE).
@@ -0,0 +1,172 @@
1
+ [project]
2
+ name = "sqlty"
3
+ dynamic = ["version"]
4
+ description = "Type-safe SQL queries for Python"
5
+ readme = "README.md"
6
+ requires-python = ">=3.14"
7
+ license = "MIT"
8
+ license-files = ["LICENSE"]
9
+ authors = [{ name = "Jiri Kuncar", email = "jiri.kuncar@gmail.com" }]
10
+ keywords = [
11
+ "sql",
12
+ "type-hints",
13
+ "mypy",
14
+ "type-safety",
15
+ "static-analysis",
16
+ "code-generation",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Environment :: Console",
21
+ "Intended Audience :: Developers",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3 :: Only",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Programming Language :: Python :: 3.15",
26
+ "Programming Language :: Rust",
27
+ "Programming Language :: SQL",
28
+ "Topic :: Software Development :: Code Generators",
29
+ "Topic :: Software Development :: Libraries :: Python Modules",
30
+ "Topic :: Database",
31
+ "Typing :: Typed",
32
+ ]
33
+ dependencies = [
34
+ "pathspec>=0.12.1",
35
+ "typing-extensions>=4.15.0; python_version < '3.15'",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/jirikuncar/sqlty"
40
+ Documentation = "https://jirikuncar.github.io/sqlty/"
41
+ Repository = "https://github.com/jirikuncar/sqlty"
42
+ Changelog = "https://github.com/jirikuncar/sqlty/releases"
43
+ Issues = "https://github.com/jirikuncar/sqlty/issues"
44
+
45
+ [project.scripts]
46
+ sqlty = "sqlty._cli:main"
47
+
48
+ [project.optional-dependencies]
49
+ psycopg = ["psycopg>=3.2.12"]
50
+
51
+ [build-system]
52
+ requires = ["maturin>=1.12.1,<2.0"]
53
+ build-backend = "maturin"
54
+
55
+ [tool.maturin]
56
+ python-source = "src"
57
+ module-name = "sqlty._core"
58
+ features = ["pyo3/extension-module"]
59
+ manifest-path = "rust/crates/sqlty-ext/Cargo.toml"
60
+ # Ship the startup hook at the wheel root so it lands in site-packages and
61
+ # registers the lazy "sqlty" codec lookup (see docs/guide/magic-codec.md).
62
+ # The path is relative to the project root (maturin >= 1.12.1): the wheel gets
63
+ # it at the root (python-source prefix stripped), the sdist at src/.
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" }]
66
+
67
+ [dependency-groups]
68
+ dev = [
69
+ "inline-snapshot>=0.15.0",
70
+ "maturin>=1.12.1,<2.0",
71
+ "mypy>=2.4.0",
72
+ "prek>=0.5.4",
73
+ "pyright>=1.1.414",
74
+ "pytest>=8.4.2",
75
+ "pytest-cov>=6.0.0",
76
+ "pytest-randomly>=3.16.0",
77
+ "pyyaml>=6.0.2",
78
+ "ruff>=0.16.10",
79
+ "ty>=0.0.85",
80
+ "rumdl>=0.3.0",
81
+ "vale>=3.22.0.0",
82
+ "zizmor>=1.31.1",
83
+ ]
84
+ cli = ["rich>=15.0.0"]
85
+ # Only the DuckDB type tests need it, and it has no wheel for every Python.
86
+ duckdb = ["duckdb>=1.4.0"]
87
+ psycopg = ["psycopg>=3.2.12"]
88
+ fuzz = [
89
+ "hypothesis>=6.140",
90
+ ]
91
+
92
+ [tool.pytest.ini_options]
93
+ addopts = ["-p", "tests._mdtest.plugin", "--cov-report=term-missing", "--cov-report=html", "-v"]
94
+ pythonpath = ["."]
95
+ testpaths = ["tests", "docs", "src/sqlty/rules", "README.md"]
96
+ mdtest_paths = ["tests/mdtest", "docs", "src/sqlty/rules", "README.md", "skills"]
97
+ markers = [
98
+ "e2e: end-to-end tests (subprocess + inline-snapshot)",
99
+ "slow: slow tests that can be skipped with -m 'not slow'",
100
+ "pg: needs a PostgreSQL server (SQLTY_PG_DSN); skipped without it",
101
+ ]
102
+
103
+ [tool.coverage.run]
104
+ concurrency = ["multiprocessing"]
105
+ parallel = true
106
+ sigterm = true
107
+ patch = ["subprocess"]
108
+ omit = ["tests/*", "examples/*"]
109
+
110
+ [tool.coverage.paths]
111
+ source = ["src/"]
112
+
113
+ [tool.coverage.combine]
114
+ show_missing = true
115
+
116
+ [tool.mypy]
117
+ python_version = "3.15"
118
+ strict = true
119
+ warn_return_any = true
120
+ warn_unused_configs = true
121
+ disallow_untyped_defs = true
122
+ disallow_any_generics = true
123
+ check_untyped_defs = true
124
+ warn_redundant_casts = true
125
+ warn_unused_ignores = true
126
+ warn_no_return = true
127
+
128
+ [[tool.mypy.overrides]]
129
+ module = "psycopg.*"
130
+ ignore_missing_imports = true
131
+
132
+ [tool.ty.environment]
133
+ # Python version will be inferred from requires-python
134
+ root = ["./src", "./examples"]
135
+
136
+ [tool.ty.src]
137
+ include = ["src", "examples"]
138
+
139
+ [tool.ruff]
140
+ target-version = "py314"
141
+ line-length = 100
142
+ # Markdown code blocks are test data (mdtest, README) and must not be reformatted.
143
+ extend-exclude = ["tests/typechecks", "*.md"]
144
+
145
+ [tool.ruff.lint]
146
+ select = [
147
+ "E", # pycodestyle errors
148
+ "W", # pycodestyle warnings
149
+ "F", # pyflakes
150
+ "I", # isort
151
+ "UP", # pyupgrade
152
+ "B", # flake8-bugbear
153
+ "C4", # flake8-comprehensions
154
+ "SIM", # flake8-simplify
155
+ ]
156
+ ignore = [
157
+ "E501", # line too long (handled by formatter)
158
+ "SIM102", # nested if statements (can be more readable)
159
+ ]
160
+
161
+ [tool.ruff.format]
162
+ quote-style = "double"
163
+ indent-style = "space"
164
+
165
+ [tool.rumdl]
166
+ # Long lines are tables and links; spaces in code spans show `--sql ` on purpose.
167
+ disable = ["MD013", "MD038"]
168
+ exclude = ["site", ".vale", ".github", "tests", "scripts/compat/reports", "PLAN-FUTURE.md", "rust/target", "proofs/.lake"]
169
+
170
+ [tool.rumdl.per-file-ignores]
171
+ # The demo GIF needs HTML for its width and centering.
172
+ "README.md" = ["MD033"]