sqlspec 0.16.0__tar.gz → 0.16.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.

Potentially problematic release.


This version of sqlspec might be problematic. Click here for more details.

Files changed (301) hide show
  1. {sqlspec-0.16.0 → sqlspec-0.16.1}/PKG-INFO +1 -1
  2. {sqlspec-0.16.0 → sqlspec-0.16.1}/pyproject.toml +1 -1
  3. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_sql.py +448 -15
  4. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_base.py +77 -44
  5. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_column.py +0 -4
  6. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_ddl.py +15 -52
  7. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_ddl_utils.py +0 -1
  8. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_delete.py +4 -5
  9. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_insert.py +59 -44
  10. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_merge.py +17 -2
  11. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_parsing_utils.py +11 -11
  12. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_select.py +29 -33
  13. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/_update.py +4 -2
  14. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_cte_and_set_ops.py +47 -20
  15. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_delete_operations.py +6 -1
  16. sqlspec-0.16.1/sqlspec/builder/mixins/_insert_operations.py +244 -0
  17. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_join_operations.py +11 -4
  18. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_merge_operations.py +81 -21
  19. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_order_limit_operations.py +15 -3
  20. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_pivot_operations.py +11 -2
  21. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_select_operations.py +12 -8
  22. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_update_operations.py +37 -14
  23. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/_where_clause.py +55 -43
  24. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/cache.py +26 -28
  25. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/compiler.py +58 -37
  26. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/parameters.py +80 -52
  27. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/result.py +30 -17
  28. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/statement.py +31 -21
  29. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_async.py +76 -46
  30. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_common.py +25 -6
  31. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/_sync.py +73 -43
  32. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/mixins/_result_tools.py +51 -22
  33. sqlspec-0.16.1/sqlspec/driver/mixins/_sql_translator.py +86 -0
  34. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/protocols.py +7 -0
  35. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/type_guards.py +7 -3
  36. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder_parameter_naming.py +11 -20
  37. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_filters.py +97 -0
  38. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_sql_factory.py +402 -0
  39. {sqlspec-0.16.0 → sqlspec-0.16.1}/uv.lock +91 -87
  40. sqlspec-0.16.0/sqlspec/builder/mixins/_insert_operations.py +0 -152
  41. sqlspec-0.16.0/sqlspec/driver/mixins/_sql_translator.py +0 -36
  42. {sqlspec-0.16.0 → sqlspec-0.16.1}/.gitignore +0 -0
  43. {sqlspec-0.16.0 → sqlspec-0.16.1}/.pre-commit-config.yaml +0 -0
  44. {sqlspec-0.16.0 → sqlspec-0.16.1}/CONTRIBUTING.rst +0 -0
  45. {sqlspec-0.16.0 → sqlspec-0.16.1}/LICENSE +0 -0
  46. {sqlspec-0.16.0 → sqlspec-0.16.1}/Makefile +0 -0
  47. {sqlspec-0.16.0 → sqlspec-0.16.1}/NOTICE +0 -0
  48. {sqlspec-0.16.0 → sqlspec-0.16.1}/README.md +0 -0
  49. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__init__.py +0 -0
  50. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__main__.py +0 -0
  51. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/__metadata__.py +0 -0
  52. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_serialization.py +0 -0
  53. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/_typing.py +0 -0
  54. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/__init__.py +0 -0
  55. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/__init__.py +0 -0
  56. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/_types.py +0 -0
  57. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/config.py +0 -0
  58. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/adbc/driver.py +0 -0
  59. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/__init__.py +0 -0
  60. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/_types.py +0 -0
  61. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/config.py +0 -0
  62. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/aiosqlite/driver.py +0 -0
  63. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/__init__.py +0 -0
  64. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/_types.py +0 -0
  65. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/config.py +0 -0
  66. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncmy/driver.py +0 -0
  67. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/__init__.py +0 -0
  68. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/_types.py +0 -0
  69. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/config.py +0 -0
  70. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/asyncpg/driver.py +0 -0
  71. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/__init__.py +0 -0
  72. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/_types.py +0 -0
  73. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/config.py +0 -0
  74. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/bigquery/driver.py +0 -0
  75. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/__init__.py +0 -0
  76. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/_types.py +0 -0
  77. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/config.py +0 -0
  78. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/duckdb/driver.py +0 -0
  79. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/__init__.py +0 -0
  80. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/_types.py +0 -0
  81. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/config.py +0 -0
  82. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/oracledb/driver.py +0 -0
  83. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/__init__.py +0 -0
  84. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/_types.py +0 -0
  85. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/config.py +0 -0
  86. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psqlpy/driver.py +0 -0
  87. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/__init__.py +0 -0
  88. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/_types.py +0 -0
  89. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/config.py +0 -0
  90. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/psycopg/driver.py +0 -0
  91. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/__init__.py +0 -0
  92. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/_types.py +0 -0
  93. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/config.py +0 -0
  94. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/adapters/sqlite/driver.py +0 -0
  95. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/base.py +0 -0
  96. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/__init__.py +0 -0
  97. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/builder/mixins/__init__.py +0 -0
  98. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/cli.py +0 -0
  99. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/config.py +0 -0
  100. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/__init__.py +0 -0
  101. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/filters.py +0 -0
  102. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/hashing.py +0 -0
  103. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/core/splitter.py +0 -0
  104. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/__init__.py +0 -0
  105. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/driver/mixins/__init__.py +0 -0
  106. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/exceptions.py +0 -0
  107. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/__init__.py +0 -0
  108. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/aiosql/__init__.py +0 -0
  109. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/aiosql/adapter.py +0 -0
  110. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/__init__.py +0 -0
  111. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/_utils.py +0 -0
  112. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/cli.py +0 -0
  113. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/config.py +0 -0
  114. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/handlers.py +0 -0
  115. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/plugin.py +0 -0
  116. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/extensions/litestar/providers.py +0 -0
  117. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/loader.py +0 -0
  118. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/__init__.py +0 -0
  119. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/base.py +0 -0
  120. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/commands.py +0 -0
  121. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/loaders.py +0 -0
  122. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/runner.py +0 -0
  123. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/tracker.py +0 -0
  124. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/migrations/utils.py +0 -0
  125. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/py.typed +0 -0
  126. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/__init__.py +0 -0
  127. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/__init__.py +0 -0
  128. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/base.py +0 -0
  129. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/fsspec.py +0 -0
  130. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/backends/obstore.py +0 -0
  131. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/capabilities.py +0 -0
  132. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/storage/registry.py +0 -0
  133. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/typing.py +0 -0
  134. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/__init__.py +0 -0
  135. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/correlation.py +0 -0
  136. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/deprecation.py +0 -0
  137. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/fixtures.py +0 -0
  138. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/logging.py +0 -0
  139. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/module_loader.py +0 -0
  140. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/serializers.py +0 -0
  141. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/singleton.py +0 -0
  142. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/sync_tools.py +0 -0
  143. {sqlspec-0.16.0 → sqlspec-0.16.1}/sqlspec/utils/text.py +0 -0
  144. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/__init__.py +0 -0
  145. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/conftest.py +0 -0
  146. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/__init__.py +0 -0
  147. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/ddls-mysql-collection.sql +0 -0
  148. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/ddls-postgres-collection.sql +0 -0
  149. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/example_usage.py +0 -0
  150. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/init.sql +0 -0
  151. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-config.sql +0 -0
  152. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-data_types.sql +0 -0
  153. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-database_details.sql +0 -0
  154. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-engines.sql +0 -0
  155. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-hostname.sql +0 -0
  156. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-plugins.sql +0 -0
  157. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-process_list.sql +0 -0
  158. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-resource-groups.sql +0 -0
  159. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-schema_objects.sql +0 -0
  160. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-table_details.sql +0 -0
  161. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/collection-users.sql +0 -0
  162. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/mysql/init.sql +0 -0
  163. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/oracle.ddl.sql +0 -0
  164. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-applications.sql +0 -0
  165. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-aws_extension_dependency.sql +0 -0
  166. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-aws_oracle_exists.sql +0 -0
  167. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-bg_writer_stats.sql +0 -0
  168. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-calculated_metrics.sql +0 -0
  169. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-data_types.sql +0 -0
  170. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-database_details.sql +0 -0
  171. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-extensions.sql +0 -0
  172. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-index_details.sql +0 -0
  173. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-pglogical-details.sql +0 -0
  174. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-privileges.sql +0 -0
  175. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-replication_slots.sql +0 -0
  176. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-replication_stats.sql +0 -0
  177. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-schema_details.sql +0 -0
  178. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-schema_objects.sql +0 -0
  179. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-settings.sql +0 -0
  180. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-source_details.sql +0 -0
  181. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/collection-table_details.sql +0 -0
  182. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/extended-collection-all-databases.sql +0 -0
  183. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/postgres/init.sql +0 -0
  184. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/readiness-check.sql +0 -0
  185. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/fixtures/sql_utils.py +0 -0
  186. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/__init__.py +0 -0
  187. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/conftest.py +0 -0
  188. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/__init__.py +0 -0
  189. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/__init__.py +0 -0
  190. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/conftest.py +0 -0
  191. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_arrow_features.py +0 -0
  192. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_backends.py +0 -0
  193. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_connection.py +0 -0
  194. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_driver.py +0 -0
  195. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_edge_cases.py +0 -0
  196. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_adbc/test_adbc_results.py +0 -0
  197. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/__init__.py +0 -0
  198. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/conftest.py +0 -0
  199. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_connection.py +0 -0
  200. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_driver.py +0 -0
  201. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_aiosqlite/test_pooling.py +0 -0
  202. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/__init__.py +0 -0
  203. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/conftest.py +0 -0
  204. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_asyncmy_features.py +0 -0
  205. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_config.py +0 -0
  206. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_driver.py +0 -0
  207. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncmy/test_parameter_styles.py +0 -0
  208. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/__init__.py +0 -0
  209. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/conftest.py +0 -0
  210. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_connection.py +0 -0
  211. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_driver.py +0 -0
  212. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_execute_many.py +0 -0
  213. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_asyncpg/test_parameter_styles.py +0 -0
  214. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/__init__.py +0 -0
  215. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/conftest.py +0 -0
  216. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_bigquery_features.py +0 -0
  217. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_config.py +0 -0
  218. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_connection.py +0 -0
  219. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_driver.py +0 -0
  220. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_bigquery/test_parameter_styles.py +0 -0
  221. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/__init__.py +0 -0
  222. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_connection.py +0 -0
  223. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_driver.py +0 -0
  224. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_execute_many.py +0 -0
  225. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_mixed_parameter_styles.py +0 -0
  226. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_parameter_styles.py +0 -0
  227. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/test_pooling.py +0 -0
  228. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_duckdb/utils.py +0 -0
  229. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/__init__.py +0 -0
  230. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/conftest.py +0 -0
  231. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_connection.py +0 -0
  232. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_driver_async.py +0 -0
  233. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_driver_sync.py +0 -0
  234. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_execute_many.py +0 -0
  235. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_oracle_features.py +0 -0
  236. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_oracledb/test_parameter_styles.py +0 -0
  237. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/__init__.py +0 -0
  238. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/conftest.py +0 -0
  239. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_connection.py +0 -0
  240. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_driver.py +0 -0
  241. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_parameter_styles.py +0 -0
  242. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psqlpy/test_psqlpy_features.py +0 -0
  243. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/__init__.py +0 -0
  244. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/conftest.py +0 -0
  245. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_async_copy.py +0 -0
  246. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_connection.py +0 -0
  247. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_driver.py +0 -0
  248. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_execute_many.py +0 -0
  249. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_psycopg/test_parameter_styles.py +0 -0
  250. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/__init__.py +0 -0
  251. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/conftest.py +0 -0
  252. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_driver.py +0 -0
  253. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_parameter_styles.py +0 -0
  254. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_pooling.py +0 -0
  255. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_adapters/test_sqlite/test_query_mixin.py +0 -0
  256. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_loader/__init__.py +0 -0
  257. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_loader/test_file_system_loading.py +0 -0
  258. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_migrations/__init__.py +0 -0
  259. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/integration/test_migrations/test_migration_execution.py +0 -0
  260. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/conftest.py +0 -0
  261. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/__init__.py +0 -0
  262. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/conftest.py +0 -0
  263. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_adapter_implementations.py +0 -0
  264. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_async_adapters.py +0 -0
  265. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_adapters/test_sync_adapters.py +0 -0
  266. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_base/__init__.py +0 -0
  267. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_base/test_sqlspec_class.py +0 -0
  268. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder/__init__.py +0 -0
  269. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_builder/test_parameter_naming.py +0 -0
  270. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_cache.py +0 -0
  271. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_compiler.py +0 -0
  272. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_hashing.py +0 -0
  273. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_parameters.py +0 -0
  274. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_result.py +0 -0
  275. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_core/test_statement.py +0 -0
  276. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/__init__.py +0 -0
  277. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_cache_integration.py +0 -0
  278. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_loading_patterns.py +0 -0
  279. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_loader/test_sql_file_loader.py +0 -0
  280. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/__init__.py +0 -0
  281. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration.py +0 -0
  282. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration_execution.py +0 -0
  283. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_migrations/test_migration_runner.py +0 -0
  284. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/__init__.py +0 -0
  285. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_correlation.py +0 -0
  286. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_deprecation.py +0 -0
  287. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_fixtures.py +0 -0
  288. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_logging.py +0 -0
  289. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_module_loader.py +0 -0
  290. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_serializers.py +0 -0
  291. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_singleton.py +0 -0
  292. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_sync_tools.py +0 -0
  293. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_text.py +0 -0
  294. {sqlspec-0.16.0 → sqlspec-0.16.1}/tests/unit/test_utils/test_type_guards.py +0 -0
  295. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/__init__.py +0 -0
  296. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/build_docs.py +0 -0
  297. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/local-infra.sh +0 -0
  298. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/pypi_readme.py +0 -0
  299. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/sphinx_ext/__init__.py +0 -0
  300. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/sphinx_ext/changelog.py +0 -0
  301. {sqlspec-0.16.0 → sqlspec-0.16.1}/tools/sphinx_ext/missing_references.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlspec
3
- Version: 0.16.0
3
+ Version: 0.16.1
4
4
  Summary: SQL Experiments in Python
5
5
  Project-URL: Discord, https://discord.gg/litestar
6
6
  Project-URL: Issue, https://github.com/litestar-org/sqlspec/issues/
@@ -13,7 +13,7 @@ maintainers = [{ name = "Litestar Developers", email = "hello@litestar.dev" }]
13
13
  name = "sqlspec"
14
14
  readme = "README.md"
15
15
  requires-python = ">=3.9, <4.0"
16
- version = "0.16.0"
16
+ version = "0.16.1"
17
17
 
18
18
  [project.urls]
19
19
  Discord = "https://discord.gg/litestar"
@@ -4,9 +4,10 @@ Provides both statement builders (select, insert, update, etc.) and column expre
4
4
  """
5
5
 
6
6
  import logging
7
- from typing import TYPE_CHECKING, Any, Optional, Union
7
+ from typing import TYPE_CHECKING, Any, Optional, Union, cast
8
8
 
9
9
  import sqlglot
10
+ from mypy_extensions import trait
10
11
  from sqlglot import exp
11
12
  from sqlglot.dialects.dialect import DialectType
12
13
  from sqlglot.errors import ParseError as SQLGlotParseError
@@ -36,6 +37,7 @@ from sqlspec.builder import (
36
37
  from sqlspec.exceptions import SQLBuilderError
37
38
 
38
39
  if TYPE_CHECKING:
40
+ from sqlspec.builder._column import ColumnExpression
39
41
  from sqlspec.core.statement import SQL
40
42
 
41
43
  __all__ = (
@@ -61,6 +63,7 @@ __all__ = (
61
63
  "Select",
62
64
  "Truncate",
63
65
  "Update",
66
+ "WindowFunctionBuilder",
64
67
  "sql",
65
68
  )
66
69
 
@@ -188,12 +191,8 @@ class SQLFactory:
188
191
  )
189
192
  raise SQLBuilderError(msg)
190
193
  select_builder = Select(dialect=builder_dialect)
191
- if select_builder._expression is None:
192
- select_builder.__post_init__()
193
194
  return self._populate_select_from_sql(select_builder, sql_candidate)
194
195
  select_builder = Select(dialect=builder_dialect)
195
- if select_builder._expression is None:
196
- select_builder.__post_init__()
197
196
  if columns_or_sql:
198
197
  select_builder.select(*columns_or_sql)
199
198
  return select_builder
@@ -201,8 +200,6 @@ class SQLFactory:
201
200
  def insert(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Insert":
202
201
  builder_dialect = dialect or self.dialect
203
202
  builder = Insert(dialect=builder_dialect)
204
- if builder._expression is None:
205
- builder.__post_init__()
206
203
  if table_or_sql:
207
204
  if self._looks_like_sql(table_or_sql):
208
205
  detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
@@ -220,8 +217,6 @@ class SQLFactory:
220
217
  def update(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Update":
221
218
  builder_dialect = dialect or self.dialect
222
219
  builder = Update(dialect=builder_dialect)
223
- if builder._expression is None:
224
- builder.__post_init__()
225
220
  if table_or_sql:
226
221
  if self._looks_like_sql(table_or_sql):
227
222
  detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
@@ -235,8 +230,6 @@ class SQLFactory:
235
230
  def delete(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Delete":
236
231
  builder_dialect = dialect or self.dialect
237
232
  builder = Delete(dialect=builder_dialect)
238
- if builder._expression is None:
239
- builder.__post_init__()
240
233
  if table_or_sql and self._looks_like_sql(table_or_sql):
241
234
  detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
242
235
  if detected != "DELETE":
@@ -248,8 +241,6 @@ class SQLFactory:
248
241
  def merge(self, table_or_sql: Optional[str] = None, dialect: DialectType = None) -> "Merge":
249
242
  builder_dialect = dialect or self.dialect
250
243
  builder = Merge(dialect=builder_dialect)
251
- if builder._expression is None:
252
- builder.__post_init__()
253
244
  if table_or_sql:
254
245
  if self._looks_like_sql(table_or_sql):
255
246
  detected = self.detect_sql_type(table_or_sql, dialect=builder_dialect)
@@ -563,14 +554,112 @@ class SQLFactory:
563
554
  """
564
555
  return Column(name, table)
565
556
 
566
- def __getattr__(self, name: str) -> Column:
557
+ @property
558
+ def case_(self) -> "Case":
559
+ """Create a CASE expression builder with improved syntax.
560
+
561
+ Returns:
562
+ Case builder instance for fluent CASE expression building.
563
+
564
+ Example:
565
+ ```python
566
+ case_expr = (
567
+ sql.case_.when("x = 1", "one")
568
+ .when("x = 2", "two")
569
+ .else_("other")
570
+ .end()
571
+ )
572
+ aliased_case = (
573
+ sql.case_.when("status = 'active'", 1)
574
+ .else_(0)
575
+ .as_("is_active")
576
+ )
577
+ ```
578
+ """
579
+ return Case()
580
+
581
+ @property
582
+ def row_number_(self) -> "WindowFunctionBuilder":
583
+ """Create a ROW_NUMBER() window function builder."""
584
+ return WindowFunctionBuilder("row_number")
585
+
586
+ @property
587
+ def rank_(self) -> "WindowFunctionBuilder":
588
+ """Create a RANK() window function builder."""
589
+ return WindowFunctionBuilder("rank")
590
+
591
+ @property
592
+ def dense_rank_(self) -> "WindowFunctionBuilder":
593
+ """Create a DENSE_RANK() window function builder."""
594
+ return WindowFunctionBuilder("dense_rank")
595
+
596
+ @property
597
+ def lag_(self) -> "WindowFunctionBuilder":
598
+ """Create a LAG() window function builder."""
599
+ return WindowFunctionBuilder("lag")
600
+
601
+ @property
602
+ def lead_(self) -> "WindowFunctionBuilder":
603
+ """Create a LEAD() window function builder."""
604
+ return WindowFunctionBuilder("lead")
605
+
606
+ @property
607
+ def exists_(self) -> "SubqueryBuilder":
608
+ """Create an EXISTS subquery builder."""
609
+ return SubqueryBuilder("exists")
610
+
611
+ @property
612
+ def in_(self) -> "SubqueryBuilder":
613
+ """Create an IN subquery builder."""
614
+ return SubqueryBuilder("in")
615
+
616
+ @property
617
+ def any_(self) -> "SubqueryBuilder":
618
+ """Create an ANY subquery builder."""
619
+ return SubqueryBuilder("any")
620
+
621
+ @property
622
+ def all_(self) -> "SubqueryBuilder":
623
+ """Create an ALL subquery builder."""
624
+ return SubqueryBuilder("all")
625
+
626
+ @property
627
+ def inner_join_(self) -> "JoinBuilder":
628
+ """Create an INNER JOIN builder."""
629
+ return JoinBuilder("inner join")
630
+
631
+ @property
632
+ def left_join_(self) -> "JoinBuilder":
633
+ """Create a LEFT JOIN builder."""
634
+ return JoinBuilder("left join")
635
+
636
+ @property
637
+ def right_join_(self) -> "JoinBuilder":
638
+ """Create a RIGHT JOIN builder."""
639
+ return JoinBuilder("right join")
640
+
641
+ @property
642
+ def full_join_(self) -> "JoinBuilder":
643
+ """Create a FULL OUTER JOIN builder."""
644
+ return JoinBuilder("full join")
645
+
646
+ @property
647
+ def cross_join_(self) -> "JoinBuilder":
648
+ """Create a CROSS JOIN builder."""
649
+ return JoinBuilder("cross join")
650
+
651
+ def __getattr__(self, name: str) -> "Column":
567
652
  """Dynamically create column references.
568
653
 
569
654
  Args:
570
655
  name: Column name.
571
656
 
572
657
  Returns:
573
- Column object that supports method chaining and operator overloading.
658
+ Column object for the given name.
659
+
660
+ Note:
661
+ Special SQL constructs like case_, row_number_, etc. are now
662
+ handled as properties for better type safety.
574
663
  """
575
664
  return Column(name)
576
665
 
@@ -1282,6 +1371,7 @@ class SQLFactory:
1282
1371
  return exp.Window(this=func_expr, **over_args)
1283
1372
 
1284
1373
 
1374
+ @trait
1285
1375
  class Case:
1286
1376
  """Builder for CASE expressions using the SQL factory.
1287
1377
 
@@ -1304,6 +1394,19 @@ class Case:
1304
1394
  self._conditions: list[exp.If] = []
1305
1395
  self._default: Optional[exp.Expression] = None
1306
1396
 
1397
+ def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
1398
+ """Equal to (==) - convert to expression then compare."""
1399
+ from sqlspec.builder._column import ColumnExpression
1400
+
1401
+ case_expr = exp.Case(ifs=self._conditions, default=self._default)
1402
+ if other is None:
1403
+ return ColumnExpression(exp.Is(this=case_expr, expression=exp.Null()))
1404
+ return ColumnExpression(exp.EQ(this=case_expr, expression=exp.convert(other)))
1405
+
1406
+ def __hash__(self) -> int:
1407
+ """Make Case hashable."""
1408
+ return hash(id(self))
1409
+
1307
1410
  def when(self, condition: Union[str, exp.Expression], value: Union[str, exp.Expression, Any]) -> "Case":
1308
1411
  """Add a WHEN clause.
1309
1412
 
@@ -1342,6 +1445,336 @@ class Case:
1342
1445
  """
1343
1446
  return exp.Case(ifs=self._conditions, default=self._default)
1344
1447
 
1448
+ def as_(self, alias: str) -> exp.Alias:
1449
+ """Complete the CASE expression with an alias.
1450
+
1451
+ Args:
1452
+ alias: Alias name for the CASE expression.
1453
+
1454
+ Returns:
1455
+ Aliased CASE expression.
1456
+ """
1457
+ case_expr = exp.Case(ifs=self._conditions, default=self._default)
1458
+ return cast("exp.Alias", exp.alias_(case_expr, alias))
1459
+
1460
+
1461
+ @trait
1462
+ class WindowFunctionBuilder:
1463
+ """Builder for window functions with fluent syntax.
1464
+
1465
+ Example:
1466
+ ```python
1467
+ from sqlspec import sql
1468
+
1469
+ # sql.row_number_.partition_by("department").order_by("salary")
1470
+ window_func = (
1471
+ sql.row_number_.partition_by("department")
1472
+ .order_by("salary")
1473
+ .as_("row_num")
1474
+ )
1475
+ ```
1476
+ """
1477
+
1478
+ def __init__(self, function_name: str) -> None:
1479
+ """Initialize the window function builder.
1480
+
1481
+ Args:
1482
+ function_name: Name of the window function (row_number, rank, etc.)
1483
+ """
1484
+ self._function_name = function_name
1485
+ self._partition_by_cols: list[exp.Expression] = []
1486
+ self._order_by_cols: list[exp.Expression] = []
1487
+ self._alias: Optional[str] = None
1488
+
1489
+ def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
1490
+ """Equal to (==) - convert to expression then compare."""
1491
+ from sqlspec.builder._column import ColumnExpression
1492
+
1493
+ window_expr = self._build_expression()
1494
+ if other is None:
1495
+ return ColumnExpression(exp.Is(this=window_expr, expression=exp.Null()))
1496
+ return ColumnExpression(exp.EQ(this=window_expr, expression=exp.convert(other)))
1497
+
1498
+ def __hash__(self) -> int:
1499
+ """Make WindowFunctionBuilder hashable."""
1500
+ return hash(id(self))
1501
+
1502
+ def partition_by(self, *columns: Union[str, exp.Expression]) -> "WindowFunctionBuilder":
1503
+ """Add PARTITION BY clause.
1504
+
1505
+ Args:
1506
+ *columns: Columns to partition by.
1507
+
1508
+ Returns:
1509
+ Self for method chaining.
1510
+ """
1511
+ for col in columns:
1512
+ col_expr = exp.column(col) if isinstance(col, str) else col
1513
+ self._partition_by_cols.append(col_expr)
1514
+ return self
1515
+
1516
+ def order_by(self, *columns: Union[str, exp.Expression]) -> "WindowFunctionBuilder":
1517
+ """Add ORDER BY clause.
1518
+
1519
+ Args:
1520
+ *columns: Columns to order by.
1521
+
1522
+ Returns:
1523
+ Self for method chaining.
1524
+ """
1525
+ for col in columns:
1526
+ if isinstance(col, str):
1527
+ col_expr = exp.column(col).asc()
1528
+ self._order_by_cols.append(col_expr)
1529
+ else:
1530
+ # Convert to ordered expression
1531
+ self._order_by_cols.append(exp.Ordered(this=col, desc=False))
1532
+ return self
1533
+
1534
+ def as_(self, alias: str) -> exp.Expression:
1535
+ """Complete the window function with an alias.
1536
+
1537
+ Args:
1538
+ alias: Alias name for the window function.
1539
+
1540
+ Returns:
1541
+ Aliased window function expression.
1542
+ """
1543
+ window_expr = self._build_expression()
1544
+ return cast("exp.Alias", exp.alias_(window_expr, alias))
1545
+
1546
+ def build(self) -> exp.Expression:
1547
+ """Complete the window function without an alias.
1548
+
1549
+ Returns:
1550
+ Window function expression.
1551
+ """
1552
+ return self._build_expression()
1553
+
1554
+ def _build_expression(self) -> exp.Expression:
1555
+ """Build the complete window function expression."""
1556
+ # Create the function expression
1557
+ func_expr = exp.Anonymous(this=self._function_name.upper(), expressions=[])
1558
+
1559
+ # Build the OVER clause arguments
1560
+ over_args: dict[str, Any] = {}
1561
+
1562
+ if self._partition_by_cols:
1563
+ over_args["partition_by"] = self._partition_by_cols
1564
+
1565
+ if self._order_by_cols:
1566
+ over_args["order"] = exp.Order(expressions=self._order_by_cols)
1567
+
1568
+ return exp.Window(this=func_expr, **over_args)
1569
+
1570
+
1571
+ @trait
1572
+ class SubqueryBuilder:
1573
+ """Builder for subquery operations with fluent syntax.
1574
+
1575
+ Example:
1576
+ ```python
1577
+ from sqlspec import sql
1578
+
1579
+ # sql.exists_(subquery)
1580
+ exists_check = sql.exists_(
1581
+ sql.select("1")
1582
+ .from_("orders")
1583
+ .where_eq("user_id", sql.users.id)
1584
+ )
1585
+
1586
+ # sql.in_(subquery)
1587
+ in_check = sql.in_(
1588
+ sql.select("category_id")
1589
+ .from_("categories")
1590
+ .where_eq("active", True)
1591
+ )
1592
+ ```
1593
+ """
1594
+
1595
+ def __init__(self, operation: str) -> None:
1596
+ """Initialize the subquery builder.
1597
+
1598
+ Args:
1599
+ operation: Type of subquery operation (exists, in, any, all)
1600
+ """
1601
+ self._operation = operation
1602
+
1603
+ def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
1604
+ """Equal to (==) - not typically used but needed for type consistency."""
1605
+ from sqlspec.builder._column import ColumnExpression
1606
+
1607
+ # SubqueryBuilder doesn't have a direct expression, so this is a placeholder
1608
+ # In practice, this shouldn't be called as subqueries are used differently
1609
+ placeholder_expr = exp.Literal.string(f"subquery_{self._operation}")
1610
+ if other is None:
1611
+ return ColumnExpression(exp.Is(this=placeholder_expr, expression=exp.Null()))
1612
+ return ColumnExpression(exp.EQ(this=placeholder_expr, expression=exp.convert(other)))
1613
+
1614
+ def __hash__(self) -> int:
1615
+ """Make SubqueryBuilder hashable."""
1616
+ return hash(id(self))
1617
+
1618
+ def __call__(self, subquery: Union[str, exp.Expression, Any]) -> exp.Expression:
1619
+ """Build the subquery expression.
1620
+
1621
+ Args:
1622
+ subquery: The subquery - can be a SQL string, SelectBuilder, or expression
1623
+
1624
+ Returns:
1625
+ The subquery expression (EXISTS, IN, ANY, ALL, etc.)
1626
+ """
1627
+ subquery_expr: exp.Expression
1628
+ if isinstance(subquery, str):
1629
+ # Parse as SQL
1630
+ parsed: Optional[exp.Expression] = exp.maybe_parse(subquery)
1631
+ if not parsed:
1632
+ msg = f"Could not parse subquery SQL: {subquery}"
1633
+ raise SQLBuilderError(msg)
1634
+ subquery_expr = parsed
1635
+ elif hasattr(subquery, "build") and callable(getattr(subquery, "build", None)):
1636
+ # It's a query builder - build it to get the SQL and parse
1637
+ built_query = subquery.build() # pyright: ignore[reportAttributeAccessIssue]
1638
+ subquery_expr = exp.maybe_parse(built_query.sql)
1639
+ if not subquery_expr:
1640
+ msg = f"Could not parse built query: {built_query.sql}"
1641
+ raise SQLBuilderError(msg)
1642
+ elif isinstance(subquery, exp.Expression):
1643
+ subquery_expr = subquery
1644
+ else:
1645
+ # Try to convert to expression
1646
+ parsed = exp.maybe_parse(str(subquery))
1647
+ if not parsed:
1648
+ msg = f"Could not convert subquery to expression: {subquery}"
1649
+ raise SQLBuilderError(msg)
1650
+ subquery_expr = parsed
1651
+
1652
+ # Build the appropriate expression based on operation
1653
+ if self._operation == "exists":
1654
+ return exp.Exists(this=subquery_expr)
1655
+ if self._operation == "in":
1656
+ # For IN, we create a subquery that can be used with WHERE column IN (subquery)
1657
+ return exp.In(expressions=[subquery_expr])
1658
+ if self._operation == "any":
1659
+ return exp.Any(this=subquery_expr)
1660
+ if self._operation == "all":
1661
+ return exp.All(this=subquery_expr)
1662
+ msg = f"Unknown subquery operation: {self._operation}"
1663
+ raise SQLBuilderError(msg)
1664
+
1665
+
1666
+ @trait
1667
+ class JoinBuilder:
1668
+ """Builder for JOIN operations with fluent syntax.
1669
+
1670
+ Example:
1671
+ ```python
1672
+ from sqlspec import sql
1673
+
1674
+ # sql.left_join_("posts").on("users.id = posts.user_id")
1675
+ join_clause = sql.left_join_("posts").on(
1676
+ "users.id = posts.user_id"
1677
+ )
1678
+
1679
+ # Or with query builder
1680
+ query = (
1681
+ sql.select("users.name", "posts.title")
1682
+ .from_("users")
1683
+ .join(
1684
+ sql.left_join_("posts").on(
1685
+ "users.id = posts.user_id"
1686
+ )
1687
+ )
1688
+ )
1689
+ ```
1690
+ """
1691
+
1692
+ def __init__(self, join_type: str) -> None:
1693
+ """Initialize the join builder.
1694
+
1695
+ Args:
1696
+ join_type: Type of join (inner, left, right, full, cross)
1697
+ """
1698
+ self._join_type = join_type.upper()
1699
+ self._table: Optional[Union[str, exp.Expression]] = None
1700
+ self._condition: Optional[exp.Expression] = None
1701
+ self._alias: Optional[str] = None
1702
+
1703
+ def __eq__(self, other: object) -> "ColumnExpression": # type: ignore[override]
1704
+ """Equal to (==) - not typically used but needed for type consistency."""
1705
+ from sqlspec.builder._column import ColumnExpression
1706
+
1707
+ # JoinBuilder doesn't have a direct expression, so this is a placeholder
1708
+ # In practice, this shouldn't be called as joins are used differently
1709
+ placeholder_expr = exp.Literal.string(f"join_{self._join_type.lower()}")
1710
+ if other is None:
1711
+ return ColumnExpression(exp.Is(this=placeholder_expr, expression=exp.Null()))
1712
+ return ColumnExpression(exp.EQ(this=placeholder_expr, expression=exp.convert(other)))
1713
+
1714
+ def __hash__(self) -> int:
1715
+ """Make JoinBuilder hashable."""
1716
+ return hash(id(self))
1717
+
1718
+ def __call__(self, table: Union[str, exp.Expression], alias: Optional[str] = None) -> "JoinBuilder":
1719
+ """Set the table to join.
1720
+
1721
+ Args:
1722
+ table: Table name or expression to join
1723
+ alias: Optional alias for the table
1724
+
1725
+ Returns:
1726
+ Self for method chaining
1727
+ """
1728
+ self._table = table
1729
+ self._alias = alias
1730
+ return self
1731
+
1732
+ def on(self, condition: Union[str, exp.Expression]) -> exp.Expression:
1733
+ """Set the join condition and build the JOIN expression.
1734
+
1735
+ Args:
1736
+ condition: JOIN condition (e.g., "users.id = posts.user_id")
1737
+
1738
+ Returns:
1739
+ Complete JOIN expression
1740
+ """
1741
+ if not self._table:
1742
+ msg = "Table must be set before calling .on()"
1743
+ raise SQLBuilderError(msg)
1744
+
1745
+ # Parse the condition
1746
+ condition_expr: exp.Expression
1747
+ if isinstance(condition, str):
1748
+ parsed: Optional[exp.Expression] = exp.maybe_parse(condition)
1749
+ condition_expr = parsed or exp.condition(condition)
1750
+ else:
1751
+ condition_expr = condition
1752
+
1753
+ # Build table expression
1754
+ table_expr: exp.Expression
1755
+ if isinstance(self._table, str):
1756
+ table_expr = exp.to_table(self._table)
1757
+ if self._alias:
1758
+ table_expr = cast("exp.Expression", exp.alias_(table_expr, self._alias))
1759
+ else:
1760
+ table_expr = self._table
1761
+ if self._alias:
1762
+ table_expr = cast("exp.Expression", exp.alias_(table_expr, self._alias))
1763
+
1764
+ # Create the appropriate join type using same pattern as existing JoinClauseMixin
1765
+ if self._join_type == "INNER JOIN":
1766
+ return exp.Join(this=table_expr, on=condition_expr)
1767
+ if self._join_type == "LEFT JOIN":
1768
+ return exp.Join(this=table_expr, on=condition_expr, side="LEFT")
1769
+ if self._join_type == "RIGHT JOIN":
1770
+ return exp.Join(this=table_expr, on=condition_expr, side="RIGHT")
1771
+ if self._join_type == "FULL JOIN":
1772
+ return exp.Join(this=table_expr, on=condition_expr, side="FULL", kind="OUTER")
1773
+ if self._join_type == "CROSS JOIN":
1774
+ # CROSS JOIN doesn't use ON condition
1775
+ return exp.Join(this=table_expr, kind="CROSS")
1776
+ return exp.Join(this=table_expr, on=condition_expr)
1777
+
1345
1778
 
1346
1779
  # Create a default SQL factory instance
1347
1780
  sql = SQLFactory()