sqlspec 0.47.0__cp314-cp314-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (621) hide show
  1. f68e0789eb443ecb1c2c__mypyc.cp314-win_amd64.pyd +0 -0
  2. sqlspec/__init__.py +167 -0
  3. sqlspec/__main__.py +12 -0
  4. sqlspec/__metadata__.py +14 -0
  5. sqlspec/_typing.py +714 -0
  6. sqlspec/adapters/__init__.py +0 -0
  7. sqlspec/adapters/adbc/__init__.py +13 -0
  8. sqlspec/adapters/adbc/_typing.py +106 -0
  9. sqlspec/adapters/adbc/adk/__init__.py +5 -0
  10. sqlspec/adapters/adbc/adk/store.py +1280 -0
  11. sqlspec/adapters/adbc/config.py +378 -0
  12. sqlspec/adapters/adbc/core.cp314-win_amd64.pyd +0 -0
  13. sqlspec/adapters/adbc/core.py +922 -0
  14. sqlspec/adapters/adbc/data_dictionary.py +339 -0
  15. sqlspec/adapters/adbc/driver.py +534 -0
  16. sqlspec/adapters/adbc/events/__init__.py +5 -0
  17. sqlspec/adapters/adbc/events/store.py +285 -0
  18. sqlspec/adapters/adbc/litestar/__init__.py +5 -0
  19. sqlspec/adapters/adbc/litestar/store.py +534 -0
  20. sqlspec/adapters/adbc/type_converter.cp314-win_amd64.pyd +0 -0
  21. sqlspec/adapters/adbc/type_converter.py +142 -0
  22. sqlspec/adapters/aiomysql/__init__.py +21 -0
  23. sqlspec/adapters/aiomysql/_typing.py +137 -0
  24. sqlspec/adapters/aiomysql/adk/__init__.py +5 -0
  25. sqlspec/adapters/aiomysql/adk/store.py +678 -0
  26. sqlspec/adapters/aiomysql/config.py +305 -0
  27. sqlspec/adapters/aiomysql/core.cp314-win_amd64.pyd +0 -0
  28. sqlspec/adapters/aiomysql/core.py +536 -0
  29. sqlspec/adapters/aiomysql/data_dictionary.py +121 -0
  30. sqlspec/adapters/aiomysql/driver.py +386 -0
  31. sqlspec/adapters/aiomysql/events/__init__.py +5 -0
  32. sqlspec/adapters/aiomysql/events/store.py +104 -0
  33. sqlspec/adapters/aiomysql/litestar/__init__.py +5 -0
  34. sqlspec/adapters/aiomysql/litestar/store.py +314 -0
  35. sqlspec/adapters/aiosqlite/__init__.py +26 -0
  36. sqlspec/adapters/aiosqlite/_typing.py +109 -0
  37. sqlspec/adapters/aiosqlite/adk/__init__.py +5 -0
  38. sqlspec/adapters/aiosqlite/adk/store.py +829 -0
  39. sqlspec/adapters/aiosqlite/config.py +315 -0
  40. sqlspec/adapters/aiosqlite/core.cp314-win_amd64.pyd +0 -0
  41. sqlspec/adapters/aiosqlite/core.py +315 -0
  42. sqlspec/adapters/aiosqlite/data_dictionary.py +202 -0
  43. sqlspec/adapters/aiosqlite/driver.py +311 -0
  44. sqlspec/adapters/aiosqlite/events/__init__.py +5 -0
  45. sqlspec/adapters/aiosqlite/events/store.py +20 -0
  46. sqlspec/adapters/aiosqlite/litestar/__init__.py +5 -0
  47. sqlspec/adapters/aiosqlite/litestar/store.py +279 -0
  48. sqlspec/adapters/aiosqlite/pool.cp314-win_amd64.pyd +0 -0
  49. sqlspec/adapters/aiosqlite/pool.py +734 -0
  50. sqlspec/adapters/asyncmy/__init__.py +21 -0
  51. sqlspec/adapters/asyncmy/_typing.py +113 -0
  52. sqlspec/adapters/asyncmy/adk/__init__.py +5 -0
  53. sqlspec/adapters/asyncmy/adk/store.py +644 -0
  54. sqlspec/adapters/asyncmy/config.py +307 -0
  55. sqlspec/adapters/asyncmy/core.cp314-win_amd64.pyd +0 -0
  56. sqlspec/adapters/asyncmy/core.py +538 -0
  57. sqlspec/adapters/asyncmy/data_dictionary.py +122 -0
  58. sqlspec/adapters/asyncmy/driver.py +391 -0
  59. sqlspec/adapters/asyncmy/events/__init__.py +5 -0
  60. sqlspec/adapters/asyncmy/events/store.py +104 -0
  61. sqlspec/adapters/asyncmy/litestar/__init__.py +5 -0
  62. sqlspec/adapters/asyncmy/litestar/store.py +296 -0
  63. sqlspec/adapters/asyncpg/__init__.py +26 -0
  64. sqlspec/adapters/asyncpg/_typing.py +103 -0
  65. sqlspec/adapters/asyncpg/adk/__init__.py +5 -0
  66. sqlspec/adapters/asyncpg/adk/store.py +483 -0
  67. sqlspec/adapters/asyncpg/config.py +575 -0
  68. sqlspec/adapters/asyncpg/core.cp314-win_amd64.pyd +0 -0
  69. sqlspec/adapters/asyncpg/core.py +480 -0
  70. sqlspec/adapters/asyncpg/data_dictionary.py +157 -0
  71. sqlspec/adapters/asyncpg/driver.py +487 -0
  72. sqlspec/adapters/asyncpg/events/__init__.py +6 -0
  73. sqlspec/adapters/asyncpg/events/_hub.py +181 -0
  74. sqlspec/adapters/asyncpg/events/backend.py +210 -0
  75. sqlspec/adapters/asyncpg/events/store.py +40 -0
  76. sqlspec/adapters/asyncpg/litestar/__init__.py +5 -0
  77. sqlspec/adapters/asyncpg/litestar/store.py +251 -0
  78. sqlspec/adapters/bigquery/__init__.py +15 -0
  79. sqlspec/adapters/bigquery/_typing.py +108 -0
  80. sqlspec/adapters/bigquery/config.py +362 -0
  81. sqlspec/adapters/bigquery/core.cp314-win_amd64.pyd +0 -0
  82. sqlspec/adapters/bigquery/core.py +768 -0
  83. sqlspec/adapters/bigquery/data_dictionary.py +120 -0
  84. sqlspec/adapters/bigquery/driver.py +542 -0
  85. sqlspec/adapters/bigquery/events/__init__.py +5 -0
  86. sqlspec/adapters/bigquery/events/store.py +139 -0
  87. sqlspec/adapters/bigquery/litestar/__init__.py +5 -0
  88. sqlspec/adapters/bigquery/litestar/store.py +325 -0
  89. sqlspec/adapters/bigquery/type_converter.cp314-win_amd64.pyd +0 -0
  90. sqlspec/adapters/bigquery/type_converter.py +107 -0
  91. sqlspec/adapters/cockroach_asyncpg/__init__.py +26 -0
  92. sqlspec/adapters/cockroach_asyncpg/_typing.py +73 -0
  93. sqlspec/adapters/cockroach_asyncpg/adk/__init__.py +3 -0
  94. sqlspec/adapters/cockroach_asyncpg/adk/store.py +465 -0
  95. sqlspec/adapters/cockroach_asyncpg/config.py +248 -0
  96. sqlspec/adapters/cockroach_asyncpg/core.cp314-win_amd64.pyd +0 -0
  97. sqlspec/adapters/cockroach_asyncpg/core.py +55 -0
  98. sqlspec/adapters/cockroach_asyncpg/data_dictionary.py +110 -0
  99. sqlspec/adapters/cockroach_asyncpg/driver.py +142 -0
  100. sqlspec/adapters/cockroach_asyncpg/events/__init__.py +3 -0
  101. sqlspec/adapters/cockroach_asyncpg/events/store.py +20 -0
  102. sqlspec/adapters/cockroach_asyncpg/litestar/__init__.py +3 -0
  103. sqlspec/adapters/cockroach_asyncpg/litestar/store.py +142 -0
  104. sqlspec/adapters/cockroach_psycopg/__init__.py +39 -0
  105. sqlspec/adapters/cockroach_psycopg/_typing.py +137 -0
  106. sqlspec/adapters/cockroach_psycopg/adk/__init__.py +13 -0
  107. sqlspec/adapters/cockroach_psycopg/adk/store.py +1039 -0
  108. sqlspec/adapters/cockroach_psycopg/config.py +511 -0
  109. sqlspec/adapters/cockroach_psycopg/core.cp314-win_amd64.pyd +0 -0
  110. sqlspec/adapters/cockroach_psycopg/core.py +63 -0
  111. sqlspec/adapters/cockroach_psycopg/data_dictionary.py +220 -0
  112. sqlspec/adapters/cockroach_psycopg/driver.py +273 -0
  113. sqlspec/adapters/cockroach_psycopg/events/__init__.py +6 -0
  114. sqlspec/adapters/cockroach_psycopg/events/store.py +34 -0
  115. sqlspec/adapters/cockroach_psycopg/litestar/__init__.py +3 -0
  116. sqlspec/adapters/cockroach_psycopg/litestar/store.py +327 -0
  117. sqlspec/adapters/duckdb/__init__.py +29 -0
  118. sqlspec/adapters/duckdb/_typing.py +104 -0
  119. sqlspec/adapters/duckdb/adk/__init__.py +14 -0
  120. sqlspec/adapters/duckdb/adk/store.py +935 -0
  121. sqlspec/adapters/duckdb/config.py +386 -0
  122. sqlspec/adapters/duckdb/core.cp314-win_amd64.pyd +0 -0
  123. sqlspec/adapters/duckdb/core.py +332 -0
  124. sqlspec/adapters/duckdb/data_dictionary.py +140 -0
  125. sqlspec/adapters/duckdb/driver.py +426 -0
  126. sqlspec/adapters/duckdb/events/__init__.py +5 -0
  127. sqlspec/adapters/duckdb/events/store.py +57 -0
  128. sqlspec/adapters/duckdb/litestar/__init__.py +5 -0
  129. sqlspec/adapters/duckdb/litestar/store.py +330 -0
  130. sqlspec/adapters/duckdb/pool.cp314-win_amd64.pyd +0 -0
  131. sqlspec/adapters/duckdb/pool.py +350 -0
  132. sqlspec/adapters/duckdb/type_converter.cp314-win_amd64.pyd +0 -0
  133. sqlspec/adapters/duckdb/type_converter.py +118 -0
  134. sqlspec/adapters/mysqlconnector/__init__.py +39 -0
  135. sqlspec/adapters/mysqlconnector/_typing.py +186 -0
  136. sqlspec/adapters/mysqlconnector/adk/__init__.py +15 -0
  137. sqlspec/adapters/mysqlconnector/adk/store.py +1183 -0
  138. sqlspec/adapters/mysqlconnector/config.py +421 -0
  139. sqlspec/adapters/mysqlconnector/core.cp314-win_amd64.pyd +0 -0
  140. sqlspec/adapters/mysqlconnector/core.py +472 -0
  141. sqlspec/adapters/mysqlconnector/data_dictionary.py +230 -0
  142. sqlspec/adapters/mysqlconnector/driver.py +516 -0
  143. sqlspec/adapters/mysqlconnector/events/__init__.py +8 -0
  144. sqlspec/adapters/mysqlconnector/events/store.py +98 -0
  145. sqlspec/adapters/mysqlconnector/litestar/__init__.py +5 -0
  146. sqlspec/adapters/mysqlconnector/litestar/store.py +426 -0
  147. sqlspec/adapters/oracledb/__init__.py +39 -0
  148. sqlspec/adapters/oracledb/_json_handlers.cp314-win_amd64.pyd +0 -0
  149. sqlspec/adapters/oracledb/_json_handlers.py +196 -0
  150. sqlspec/adapters/oracledb/_param_types.cp314-win_amd64.pyd +0 -0
  151. sqlspec/adapters/oracledb/_param_types.py +46 -0
  152. sqlspec/adapters/oracledb/_typing.py +258 -0
  153. sqlspec/adapters/oracledb/_uuid_handlers.cp314-win_amd64.pyd +0 -0
  154. sqlspec/adapters/oracledb/_uuid_handlers.py +163 -0
  155. sqlspec/adapters/oracledb/_vector_handlers.cp314-win_amd64.pyd +0 -0
  156. sqlspec/adapters/oracledb/_vector_handlers.py +228 -0
  157. sqlspec/adapters/oracledb/adk/__init__.py +21 -0
  158. sqlspec/adapters/oracledb/adk/store.py +2453 -0
  159. sqlspec/adapters/oracledb/config.py +575 -0
  160. sqlspec/adapters/oracledb/core.cp314-win_amd64.pyd +0 -0
  161. sqlspec/adapters/oracledb/core.py +820 -0
  162. sqlspec/adapters/oracledb/data_dictionary.py +404 -0
  163. sqlspec/adapters/oracledb/driver.py +1277 -0
  164. sqlspec/adapters/oracledb/events/__init__.py +16 -0
  165. sqlspec/adapters/oracledb/events/_hub.py +345 -0
  166. sqlspec/adapters/oracledb/events/backend.py +300 -0
  167. sqlspec/adapters/oracledb/events/store.py +420 -0
  168. sqlspec/adapters/oracledb/litestar/__init__.py +5 -0
  169. sqlspec/adapters/oracledb/litestar/store.py +781 -0
  170. sqlspec/adapters/oracledb/migrations.py +539 -0
  171. sqlspec/adapters/oracledb/type_converter.cp314-win_amd64.pyd +0 -0
  172. sqlspec/adapters/oracledb/type_converter.py +211 -0
  173. sqlspec/adapters/psqlpy/__init__.py +18 -0
  174. sqlspec/adapters/psqlpy/_typing.py +121 -0
  175. sqlspec/adapters/psqlpy/adk/__init__.py +5 -0
  176. sqlspec/adapters/psqlpy/adk/store.py +591 -0
  177. sqlspec/adapters/psqlpy/config.py +376 -0
  178. sqlspec/adapters/psqlpy/core.cp314-win_amd64.pyd +0 -0
  179. sqlspec/adapters/psqlpy/core.py +694 -0
  180. sqlspec/adapters/psqlpy/data_dictionary.py +121 -0
  181. sqlspec/adapters/psqlpy/driver.py +411 -0
  182. sqlspec/adapters/psqlpy/events/__init__.py +6 -0
  183. sqlspec/adapters/psqlpy/events/_hub.py +204 -0
  184. sqlspec/adapters/psqlpy/events/backend.py +210 -0
  185. sqlspec/adapters/psqlpy/events/store.py +20 -0
  186. sqlspec/adapters/psqlpy/litestar/__init__.py +5 -0
  187. sqlspec/adapters/psqlpy/litestar/store.py +270 -0
  188. sqlspec/adapters/psqlpy/type_converter.cp314-win_amd64.pyd +0 -0
  189. sqlspec/adapters/psqlpy/type_converter.py +113 -0
  190. sqlspec/adapters/psycopg/__init__.py +38 -0
  191. sqlspec/adapters/psycopg/_typing.py +218 -0
  192. sqlspec/adapters/psycopg/adk/__init__.py +10 -0
  193. sqlspec/adapters/psycopg/adk/store.py +1106 -0
  194. sqlspec/adapters/psycopg/config.py +695 -0
  195. sqlspec/adapters/psycopg/core.cp314-win_amd64.pyd +0 -0
  196. sqlspec/adapters/psycopg/core.py +520 -0
  197. sqlspec/adapters/psycopg/data_dictionary.py +278 -0
  198. sqlspec/adapters/psycopg/driver.py +1033 -0
  199. sqlspec/adapters/psycopg/events/__init__.py +20 -0
  200. sqlspec/adapters/psycopg/events/_hub.py +388 -0
  201. sqlspec/adapters/psycopg/events/backend.py +398 -0
  202. sqlspec/adapters/psycopg/events/store.py +42 -0
  203. sqlspec/adapters/psycopg/litestar/__init__.py +5 -0
  204. sqlspec/adapters/psycopg/litestar/store.py +554 -0
  205. sqlspec/adapters/psycopg/type_converter.cp314-win_amd64.pyd +0 -0
  206. sqlspec/adapters/psycopg/type_converter.py +93 -0
  207. sqlspec/adapters/pymysql/__init__.py +21 -0
  208. sqlspec/adapters/pymysql/_typing.py +92 -0
  209. sqlspec/adapters/pymysql/adk/__init__.py +5 -0
  210. sqlspec/adapters/pymysql/adk/store.py +657 -0
  211. sqlspec/adapters/pymysql/config.py +176 -0
  212. sqlspec/adapters/pymysql/core.cp314-win_amd64.pyd +0 -0
  213. sqlspec/adapters/pymysql/core.py +469 -0
  214. sqlspec/adapters/pymysql/data_dictionary.py +120 -0
  215. sqlspec/adapters/pymysql/driver.py +271 -0
  216. sqlspec/adapters/pymysql/events/__init__.py +5 -0
  217. sqlspec/adapters/pymysql/events/store.py +50 -0
  218. sqlspec/adapters/pymysql/litestar/__init__.py +5 -0
  219. sqlspec/adapters/pymysql/litestar/store.py +232 -0
  220. sqlspec/adapters/pymysql/pool.cp314-win_amd64.pyd +0 -0
  221. sqlspec/adapters/pymysql/pool.py +184 -0
  222. sqlspec/adapters/spanner/__init__.py +33 -0
  223. sqlspec/adapters/spanner/_typing.py +102 -0
  224. sqlspec/adapters/spanner/adk/__init__.py +5 -0
  225. sqlspec/adapters/spanner/adk/store.py +758 -0
  226. sqlspec/adapters/spanner/config.py +355 -0
  227. sqlspec/adapters/spanner/core.cp314-win_amd64.pyd +0 -0
  228. sqlspec/adapters/spanner/core.py +263 -0
  229. sqlspec/adapters/spanner/data_dictionary.py +120 -0
  230. sqlspec/adapters/spanner/driver.py +407 -0
  231. sqlspec/adapters/spanner/events/__init__.py +5 -0
  232. sqlspec/adapters/spanner/events/store.py +187 -0
  233. sqlspec/adapters/spanner/litestar/__init__.py +5 -0
  234. sqlspec/adapters/spanner/litestar/store.py +291 -0
  235. sqlspec/adapters/spanner/type_converter.cp314-win_amd64.pyd +0 -0
  236. sqlspec/adapters/spanner/type_converter.py +342 -0
  237. sqlspec/adapters/sqlite/__init__.py +19 -0
  238. sqlspec/adapters/sqlite/_typing.py +123 -0
  239. sqlspec/adapters/sqlite/adk/__init__.py +5 -0
  240. sqlspec/adapters/sqlite/adk/store.py +992 -0
  241. sqlspec/adapters/sqlite/config.py +240 -0
  242. sqlspec/adapters/sqlite/core.cp314-win_amd64.pyd +0 -0
  243. sqlspec/adapters/sqlite/core.py +357 -0
  244. sqlspec/adapters/sqlite/data_dictionary.py +198 -0
  245. sqlspec/adapters/sqlite/driver.py +527 -0
  246. sqlspec/adapters/sqlite/events/__init__.py +5 -0
  247. sqlspec/adapters/sqlite/events/store.py +20 -0
  248. sqlspec/adapters/sqlite/litestar/__init__.py +5 -0
  249. sqlspec/adapters/sqlite/litestar/store.py +316 -0
  250. sqlspec/adapters/sqlite/pool.cp314-win_amd64.pyd +0 -0
  251. sqlspec/adapters/sqlite/pool.py +237 -0
  252. sqlspec/adapters/sqlite/type_converter.cp314-win_amd64.pyd +0 -0
  253. sqlspec/adapters/sqlite/type_converter.py +114 -0
  254. sqlspec/base.py +832 -0
  255. sqlspec/builder/__init__.py +181 -0
  256. sqlspec/builder/_base.cp314-win_amd64.pyd +0 -0
  257. sqlspec/builder/_base.py +1071 -0
  258. sqlspec/builder/_column.cp314-win_amd64.pyd +0 -0
  259. sqlspec/builder/_column.py +521 -0
  260. sqlspec/builder/_ddl.cp314-win_amd64.pyd +0 -0
  261. sqlspec/builder/_ddl.py +1691 -0
  262. sqlspec/builder/_delete.cp314-win_amd64.pyd +0 -0
  263. sqlspec/builder/_delete.py +95 -0
  264. sqlspec/builder/_dml.cp314-win_amd64.pyd +0 -0
  265. sqlspec/builder/_dml.py +386 -0
  266. sqlspec/builder/_explain.cp314-win_amd64.pyd +0 -0
  267. sqlspec/builder/_explain.py +579 -0
  268. sqlspec/builder/_expression_wrappers.cp314-win_amd64.pyd +0 -0
  269. sqlspec/builder/_expression_wrappers.py +46 -0
  270. sqlspec/builder/_factory.cp314-win_amd64.pyd +0 -0
  271. sqlspec/builder/_factory.py +1884 -0
  272. sqlspec/builder/_insert.cp314-win_amd64.pyd +0 -0
  273. sqlspec/builder/_insert.py +405 -0
  274. sqlspec/builder/_join.cp314-win_amd64.pyd +0 -0
  275. sqlspec/builder/_join.py +489 -0
  276. sqlspec/builder/_merge.cp314-win_amd64.pyd +0 -0
  277. sqlspec/builder/_merge.py +823 -0
  278. sqlspec/builder/_parsing_utils.cp314-win_amd64.pyd +0 -0
  279. sqlspec/builder/_parsing_utils.py +295 -0
  280. sqlspec/builder/_select.cp314-win_amd64.pyd +0 -0
  281. sqlspec/builder/_select.py +1666 -0
  282. sqlspec/builder/_temporal.cp314-win_amd64.pyd +0 -0
  283. sqlspec/builder/_temporal.py +167 -0
  284. sqlspec/builder/_update.cp314-win_amd64.pyd +0 -0
  285. sqlspec/builder/_update.py +173 -0
  286. sqlspec/builder/_vector_distance.cp314-win_amd64.pyd +0 -0
  287. sqlspec/builder/_vector_distance.py +330 -0
  288. sqlspec/cli.py +1095 -0
  289. sqlspec/config.py +2383 -0
  290. sqlspec/core/__init__.py +372 -0
  291. sqlspec/core/_correlation.cp314-win_amd64.pyd +0 -0
  292. sqlspec/core/_correlation.py +176 -0
  293. sqlspec/core/_pagination.py +42 -0
  294. sqlspec/core/_pool.cp314-win_amd64.pyd +0 -0
  295. sqlspec/core/_pool.py +76 -0
  296. sqlspec/core/cache.cp314-win_amd64.pyd +0 -0
  297. sqlspec/core/cache.py +1085 -0
  298. sqlspec/core/compiler.cp314-win_amd64.pyd +0 -0
  299. sqlspec/core/compiler.py +1090 -0
  300. sqlspec/core/config_runtime.cp314-win_amd64.pyd +0 -0
  301. sqlspec/core/config_runtime.py +174 -0
  302. sqlspec/core/explain.cp314-win_amd64.pyd +0 -0
  303. sqlspec/core/explain.py +275 -0
  304. sqlspec/core/filters.cp314-win_amd64.pyd +0 -0
  305. sqlspec/core/filters.py +969 -0
  306. sqlspec/core/hashing.cp314-win_amd64.pyd +0 -0
  307. sqlspec/core/hashing.py +266 -0
  308. sqlspec/core/metrics.cp314-win_amd64.pyd +0 -0
  309. sqlspec/core/metrics.py +83 -0
  310. sqlspec/core/parameters/__init__.py +72 -0
  311. sqlspec/core/parameters/_alignment.cp314-win_amd64.pyd +0 -0
  312. sqlspec/core/parameters/_alignment.py +283 -0
  313. sqlspec/core/parameters/_converter.cp314-win_amd64.pyd +0 -0
  314. sqlspec/core/parameters/_converter.py +554 -0
  315. sqlspec/core/parameters/_processor.cp314-win_amd64.pyd +0 -0
  316. sqlspec/core/parameters/_processor.py +1182 -0
  317. sqlspec/core/parameters/_registry.cp314-win_amd64.pyd +0 -0
  318. sqlspec/core/parameters/_registry.py +206 -0
  319. sqlspec/core/parameters/_transformers.cp314-win_amd64.pyd +0 -0
  320. sqlspec/core/parameters/_transformers.py +324 -0
  321. sqlspec/core/parameters/_types.cp314-win_amd64.pyd +0 -0
  322. sqlspec/core/parameters/_types.py +536 -0
  323. sqlspec/core/parameters/_validator.cp314-win_amd64.pyd +0 -0
  324. sqlspec/core/parameters/_validator.py +171 -0
  325. sqlspec/core/pipeline.cp314-win_amd64.pyd +0 -0
  326. sqlspec/core/pipeline.py +333 -0
  327. sqlspec/core/query_modifiers.cp314-win_amd64.pyd +0 -0
  328. sqlspec/core/query_modifiers.py +508 -0
  329. sqlspec/core/result/__init__.py +25 -0
  330. sqlspec/core/result/_base.cp314-win_amd64.pyd +0 -0
  331. sqlspec/core/result/_base.py +1232 -0
  332. sqlspec/core/result/_io.cp314-win_amd64.pyd +0 -0
  333. sqlspec/core/result/_io.py +28 -0
  334. sqlspec/core/splitter.cp314-win_amd64.pyd +0 -0
  335. sqlspec/core/splitter.py +1021 -0
  336. sqlspec/core/sqlcommenter.cp314-win_amd64.pyd +0 -0
  337. sqlspec/core/sqlcommenter.py +249 -0
  338. sqlspec/core/stack.cp314-win_amd64.pyd +0 -0
  339. sqlspec/core/stack.py +163 -0
  340. sqlspec/core/statement.cp314-win_amd64.pyd +0 -0
  341. sqlspec/core/statement.py +1865 -0
  342. sqlspec/core/type_converter.cp314-win_amd64.pyd +0 -0
  343. sqlspec/core/type_converter.py +340 -0
  344. sqlspec/data_dictionary/__init__.py +22 -0
  345. sqlspec/data_dictionary/_loader.cp314-win_amd64.pyd +0 -0
  346. sqlspec/data_dictionary/_loader.py +138 -0
  347. sqlspec/data_dictionary/_registry.cp314-win_amd64.pyd +0 -0
  348. sqlspec/data_dictionary/_registry.py +74 -0
  349. sqlspec/data_dictionary/_types.cp314-win_amd64.pyd +0 -0
  350. sqlspec/data_dictionary/_types.py +121 -0
  351. sqlspec/data_dictionary/dialects/__init__.py +21 -0
  352. sqlspec/data_dictionary/dialects/bigquery.cp314-win_amd64.pyd +0 -0
  353. sqlspec/data_dictionary/dialects/bigquery.py +81 -0
  354. sqlspec/data_dictionary/dialects/cockroachdb.cp314-win_amd64.pyd +0 -0
  355. sqlspec/data_dictionary/dialects/cockroachdb.py +54 -0
  356. sqlspec/data_dictionary/dialects/duckdb.cp314-win_amd64.pyd +0 -0
  357. sqlspec/data_dictionary/dialects/duckdb.py +47 -0
  358. sqlspec/data_dictionary/dialects/mysql.cp314-win_amd64.pyd +0 -0
  359. sqlspec/data_dictionary/dialects/mysql.py +53 -0
  360. sqlspec/data_dictionary/dialects/oracle.cp314-win_amd64.pyd +0 -0
  361. sqlspec/data_dictionary/dialects/oracle.py +197 -0
  362. sqlspec/data_dictionary/dialects/postgres.cp314-win_amd64.pyd +0 -0
  363. sqlspec/data_dictionary/dialects/postgres.py +69 -0
  364. sqlspec/data_dictionary/dialects/spanner.cp314-win_amd64.pyd +0 -0
  365. sqlspec/data_dictionary/dialects/spanner.py +37 -0
  366. sqlspec/data_dictionary/dialects/sqlite.cp314-win_amd64.pyd +0 -0
  367. sqlspec/data_dictionary/dialects/sqlite.py +59 -0
  368. sqlspec/data_dictionary/sql/.gitkeep +0 -0
  369. sqlspec/data_dictionary/sql/bigquery/columns.sql +23 -0
  370. sqlspec/data_dictionary/sql/bigquery/foreign_keys.sql +34 -0
  371. sqlspec/data_dictionary/sql/bigquery/indexes.sql +19 -0
  372. sqlspec/data_dictionary/sql/bigquery/tables.sql +33 -0
  373. sqlspec/data_dictionary/sql/bigquery/version.sql +3 -0
  374. sqlspec/data_dictionary/sql/cockroachdb/columns.sql +34 -0
  375. sqlspec/data_dictionary/sql/cockroachdb/foreign_keys.sql +40 -0
  376. sqlspec/data_dictionary/sql/cockroachdb/indexes.sql +32 -0
  377. sqlspec/data_dictionary/sql/cockroachdb/tables.sql +44 -0
  378. sqlspec/data_dictionary/sql/cockroachdb/version.sql +3 -0
  379. sqlspec/data_dictionary/sql/duckdb/columns.sql +23 -0
  380. sqlspec/data_dictionary/sql/duckdb/foreign_keys.sql +36 -0
  381. sqlspec/data_dictionary/sql/duckdb/indexes.sql +19 -0
  382. sqlspec/data_dictionary/sql/duckdb/tables.sql +38 -0
  383. sqlspec/data_dictionary/sql/duckdb/version.sql +3 -0
  384. sqlspec/data_dictionary/sql/mysql/columns.sql +23 -0
  385. sqlspec/data_dictionary/sql/mysql/foreign_keys.sql +28 -0
  386. sqlspec/data_dictionary/sql/mysql/indexes.sql +26 -0
  387. sqlspec/data_dictionary/sql/mysql/tables.sql +33 -0
  388. sqlspec/data_dictionary/sql/mysql/version.sql +3 -0
  389. sqlspec/data_dictionary/sql/oracle/columns.sql +23 -0
  390. sqlspec/data_dictionary/sql/oracle/foreign_keys.sql +48 -0
  391. sqlspec/data_dictionary/sql/oracle/indexes.sql +44 -0
  392. sqlspec/data_dictionary/sql/oracle/tables.sql +25 -0
  393. sqlspec/data_dictionary/sql/oracle/version.sql +20 -0
  394. sqlspec/data_dictionary/sql/postgres/columns.sql +34 -0
  395. sqlspec/data_dictionary/sql/postgres/foreign_keys.sql +40 -0
  396. sqlspec/data_dictionary/sql/postgres/indexes.sql +56 -0
  397. sqlspec/data_dictionary/sql/postgres/tables.sql +44 -0
  398. sqlspec/data_dictionary/sql/postgres/version.sql +3 -0
  399. sqlspec/data_dictionary/sql/spanner/columns.sql +23 -0
  400. sqlspec/data_dictionary/sql/spanner/foreign_keys.sql +70 -0
  401. sqlspec/data_dictionary/sql/spanner/indexes.sql +30 -0
  402. sqlspec/data_dictionary/sql/spanner/tables.sql +9 -0
  403. sqlspec/data_dictionary/sql/spanner/version.sql +3 -0
  404. sqlspec/data_dictionary/sql/sqlite/columns.sql +23 -0
  405. sqlspec/data_dictionary/sql/sqlite/foreign_keys.sql +22 -0
  406. sqlspec/data_dictionary/sql/sqlite/indexes.sql +7 -0
  407. sqlspec/data_dictionary/sql/sqlite/tables.sql +28 -0
  408. sqlspec/data_dictionary/sql/sqlite/version.sql +3 -0
  409. sqlspec/dialects/__init__.py +22 -0
  410. sqlspec/dialects/_compat.cp314-win_amd64.pyd +0 -0
  411. sqlspec/dialects/_compat.py +14 -0
  412. sqlspec/dialects/postgres/__init__.py +9 -0
  413. sqlspec/dialects/postgres/_generators.cp314-win_amd64.pyd +0 -0
  414. sqlspec/dialects/postgres/_generators.py +57 -0
  415. sqlspec/dialects/postgres/_operators.cp314-win_amd64.pyd +0 -0
  416. sqlspec/dialects/postgres/_operators.py +81 -0
  417. sqlspec/dialects/postgres/_paradedb.py +50 -0
  418. sqlspec/dialects/postgres/_pgvector.py +36 -0
  419. sqlspec/dialects/spanner/__init__.py +6 -0
  420. sqlspec/dialects/spanner/_generators.cp314-win_amd64.pyd +0 -0
  421. sqlspec/dialects/spanner/_generators.py +206 -0
  422. sqlspec/dialects/spanner/_spangres.py +77 -0
  423. sqlspec/dialects/spanner/_spanner.py +179 -0
  424. sqlspec/driver/__init__.py +49 -0
  425. sqlspec/driver/_async.cp314-win_amd64.pyd +0 -0
  426. sqlspec/driver/_async.py +1830 -0
  427. sqlspec/driver/_common.cp314-win_amd64.pyd +0 -0
  428. sqlspec/driver/_common.py +2292 -0
  429. sqlspec/driver/_exception_handler.cp314-win_amd64.pyd +0 -0
  430. sqlspec/driver/_exception_handler.py +108 -0
  431. sqlspec/driver/_query_cache.cp314-win_amd64.pyd +0 -0
  432. sqlspec/driver/_query_cache.py +96 -0
  433. sqlspec/driver/_sql_helpers.cp314-win_amd64.pyd +0 -0
  434. sqlspec/driver/_sql_helpers.py +139 -0
  435. sqlspec/driver/_storage_helpers.cp314-win_amd64.pyd +0 -0
  436. sqlspec/driver/_storage_helpers.py +153 -0
  437. sqlspec/driver/_sync.cp314-win_amd64.pyd +0 -0
  438. sqlspec/driver/_sync.py +1817 -0
  439. sqlspec/exceptions.cp314-win_amd64.pyd +0 -0
  440. sqlspec/exceptions.py +480 -0
  441. sqlspec/extensions/__init__.py +0 -0
  442. sqlspec/extensions/adk/__init__.py +84 -0
  443. sqlspec/extensions/adk/_config_utils.py +199 -0
  444. sqlspec/extensions/adk/_types.cp314-win_amd64.pyd +0 -0
  445. sqlspec/extensions/adk/_types.py +41 -0
  446. sqlspec/extensions/adk/artifact/__init__.py +57 -0
  447. sqlspec/extensions/adk/artifact/_types.cp314-win_amd64.pyd +0 -0
  448. sqlspec/extensions/adk/artifact/_types.py +32 -0
  449. sqlspec/extensions/adk/artifact/service.py +508 -0
  450. sqlspec/extensions/adk/artifact/store.py +361 -0
  451. sqlspec/extensions/adk/converters.py +212 -0
  452. sqlspec/extensions/adk/memory/__init__.py +69 -0
  453. sqlspec/extensions/adk/memory/_types.cp314-win_amd64.pyd +0 -0
  454. sqlspec/extensions/adk/memory/_types.py +30 -0
  455. sqlspec/extensions/adk/memory/converters.py +225 -0
  456. sqlspec/extensions/adk/memory/service.py +316 -0
  457. sqlspec/extensions/adk/memory/store.py +525 -0
  458. sqlspec/extensions/adk/migrations/0001_create_adk_tables.py +184 -0
  459. sqlspec/extensions/adk/migrations/__init__.py +0 -0
  460. sqlspec/extensions/adk/service.py +279 -0
  461. sqlspec/extensions/adk/store.py +590 -0
  462. sqlspec/extensions/events/__init__.py +51 -0
  463. sqlspec/extensions/events/_channel.py +703 -0
  464. sqlspec/extensions/events/_hints.cp314-win_amd64.pyd +0 -0
  465. sqlspec/extensions/events/_hints.py +45 -0
  466. sqlspec/extensions/events/_models.py +23 -0
  467. sqlspec/extensions/events/_payload.cp314-win_amd64.pyd +0 -0
  468. sqlspec/extensions/events/_payload.py +69 -0
  469. sqlspec/extensions/events/_protocols.py +134 -0
  470. sqlspec/extensions/events/_queue.py +462 -0
  471. sqlspec/extensions/events/_store.py +209 -0
  472. sqlspec/extensions/events/migrations/0001_create_event_queue.py +59 -0
  473. sqlspec/extensions/events/migrations/__init__.py +3 -0
  474. sqlspec/extensions/fastapi/__init__.py +22 -0
  475. sqlspec/extensions/fastapi/extension.py +391 -0
  476. sqlspec/extensions/fastapi/providers.cp314-win_amd64.pyd +0 -0
  477. sqlspec/extensions/fastapi/providers.py +712 -0
  478. sqlspec/extensions/flask/__init__.py +38 -0
  479. sqlspec/extensions/flask/_state.py +87 -0
  480. sqlspec/extensions/flask/_utils.py +71 -0
  481. sqlspec/extensions/flask/extension.py +539 -0
  482. sqlspec/extensions/litestar/__init__.py +31 -0
  483. sqlspec/extensions/litestar/_utils.py +52 -0
  484. sqlspec/extensions/litestar/channels.py +165 -0
  485. sqlspec/extensions/litestar/cli.py +102 -0
  486. sqlspec/extensions/litestar/config.py +90 -0
  487. sqlspec/extensions/litestar/handlers.py +316 -0
  488. sqlspec/extensions/litestar/migrations/0001_create_session_table.py +137 -0
  489. sqlspec/extensions/litestar/migrations/__init__.py +3 -0
  490. sqlspec/extensions/litestar/plugin.py +1066 -0
  491. sqlspec/extensions/litestar/providers.cp314-win_amd64.pyd +0 -0
  492. sqlspec/extensions/litestar/providers.py +784 -0
  493. sqlspec/extensions/litestar/store.py +298 -0
  494. sqlspec/extensions/otel/__init__.py +58 -0
  495. sqlspec/extensions/prometheus/__init__.py +113 -0
  496. sqlspec/extensions/sanic/__init__.py +19 -0
  497. sqlspec/extensions/sanic/_state.py +43 -0
  498. sqlspec/extensions/sanic/_utils.py +127 -0
  499. sqlspec/extensions/sanic/extension.py +647 -0
  500. sqlspec/extensions/starlette/__init__.py +22 -0
  501. sqlspec/extensions/starlette/_state.py +42 -0
  502. sqlspec/extensions/starlette/_utils.py +96 -0
  503. sqlspec/extensions/starlette/extension.py +374 -0
  504. sqlspec/extensions/starlette/middleware.py +281 -0
  505. sqlspec/loader.cp314-win_amd64.pyd +0 -0
  506. sqlspec/loader.py +727 -0
  507. sqlspec/migrations/__init__.py +39 -0
  508. sqlspec/migrations/base.cp314-win_amd64.pyd +0 -0
  509. sqlspec/migrations/base.py +862 -0
  510. sqlspec/migrations/commands.py +2151 -0
  511. sqlspec/migrations/context.cp314-win_amd64.pyd +0 -0
  512. sqlspec/migrations/context.py +157 -0
  513. sqlspec/migrations/fix.cp314-win_amd64.pyd +0 -0
  514. sqlspec/migrations/fix.py +204 -0
  515. sqlspec/migrations/loaders.cp314-win_amd64.pyd +0 -0
  516. sqlspec/migrations/loaders.py +443 -0
  517. sqlspec/migrations/runner.cp314-win_amd64.pyd +0 -0
  518. sqlspec/migrations/runner.py +1195 -0
  519. sqlspec/migrations/squash.cp314-win_amd64.pyd +0 -0
  520. sqlspec/migrations/squash.py +490 -0
  521. sqlspec/migrations/templates.cp314-win_amd64.pyd +0 -0
  522. sqlspec/migrations/templates.py +234 -0
  523. sqlspec/migrations/tracker.cp314-win_amd64.pyd +0 -0
  524. sqlspec/migrations/tracker.py +792 -0
  525. sqlspec/migrations/utils.cp314-win_amd64.pyd +0 -0
  526. sqlspec/migrations/utils.py +256 -0
  527. sqlspec/migrations/validation.cp314-win_amd64.pyd +0 -0
  528. sqlspec/migrations/validation.py +359 -0
  529. sqlspec/migrations/version.cp314-win_amd64.pyd +0 -0
  530. sqlspec/migrations/version.py +446 -0
  531. sqlspec/observability/__init__.py +57 -0
  532. sqlspec/observability/_common.cp314-win_amd64.pyd +0 -0
  533. sqlspec/observability/_common.py +77 -0
  534. sqlspec/observability/_config.cp314-win_amd64.pyd +0 -0
  535. sqlspec/observability/_config.py +364 -0
  536. sqlspec/observability/_diagnostics.cp314-win_amd64.pyd +0 -0
  537. sqlspec/observability/_diagnostics.py +74 -0
  538. sqlspec/observability/_dispatcher.cp314-win_amd64.pyd +0 -0
  539. sqlspec/observability/_dispatcher.py +200 -0
  540. sqlspec/observability/_formatters/__init__.py +13 -0
  541. sqlspec/observability/_formatters/_aws.cp314-win_amd64.pyd +0 -0
  542. sqlspec/observability/_formatters/_aws.py +102 -0
  543. sqlspec/observability/_formatters/_azure.cp314-win_amd64.pyd +0 -0
  544. sqlspec/observability/_formatters/_azure.py +96 -0
  545. sqlspec/observability/_formatters/_base.cp314-win_amd64.pyd +0 -0
  546. sqlspec/observability/_formatters/_base.py +57 -0
  547. sqlspec/observability/_formatters/_gcp.cp314-win_amd64.pyd +0 -0
  548. sqlspec/observability/_formatters/_gcp.py +131 -0
  549. sqlspec/observability/_formatting.py +58 -0
  550. sqlspec/observability/_observer.cp314-win_amd64.pyd +0 -0
  551. sqlspec/observability/_observer.py +361 -0
  552. sqlspec/observability/_runtime.cp314-win_amd64.pyd +0 -0
  553. sqlspec/observability/_runtime.py +461 -0
  554. sqlspec/observability/_sampling.cp314-win_amd64.pyd +0 -0
  555. sqlspec/observability/_sampling.py +188 -0
  556. sqlspec/observability/_spans.cp314-win_amd64.pyd +0 -0
  557. sqlspec/observability/_spans.py +161 -0
  558. sqlspec/protocols.py +955 -0
  559. sqlspec/py.typed +0 -0
  560. sqlspec/service.py +433 -0
  561. sqlspec/storage/__init__.py +48 -0
  562. sqlspec/storage/_arrow_payload.py +68 -0
  563. sqlspec/storage/_paths.cp314-win_amd64.pyd +0 -0
  564. sqlspec/storage/_paths.py +58 -0
  565. sqlspec/storage/_utils.py +46 -0
  566. sqlspec/storage/backends/__init__.py +1 -0
  567. sqlspec/storage/backends/base.cp314-win_amd64.pyd +0 -0
  568. sqlspec/storage/backends/base.py +374 -0
  569. sqlspec/storage/backends/fsspec.py +574 -0
  570. sqlspec/storage/backends/local.py +468 -0
  571. sqlspec/storage/backends/obstore.py +956 -0
  572. sqlspec/storage/errors.cp314-win_amd64.pyd +0 -0
  573. sqlspec/storage/errors.py +102 -0
  574. sqlspec/storage/pipeline.cp314-win_amd64.pyd +0 -0
  575. sqlspec/storage/pipeline.py +628 -0
  576. sqlspec/storage/registry.cp314-win_amd64.pyd +0 -0
  577. sqlspec/storage/registry.py +329 -0
  578. sqlspec/typing.py +405 -0
  579. sqlspec/utils/__init__.py +7 -0
  580. sqlspec/utils/arrow_helpers.py +384 -0
  581. sqlspec/utils/config_tools.cp314-win_amd64.pyd +0 -0
  582. sqlspec/utils/config_tools.py +314 -0
  583. sqlspec/utils/correlation.cp314-win_amd64.pyd +0 -0
  584. sqlspec/utils/correlation.py +134 -0
  585. sqlspec/utils/deprecation.cp314-win_amd64.pyd +0 -0
  586. sqlspec/utils/deprecation.py +157 -0
  587. sqlspec/utils/dispatch.cp314-win_amd64.pyd +0 -0
  588. sqlspec/utils/dispatch.py +101 -0
  589. sqlspec/utils/fixtures.cp314-win_amd64.pyd +0 -0
  590. sqlspec/utils/fixtures.py +260 -0
  591. sqlspec/utils/logging.cp314-win_amd64.pyd +0 -0
  592. sqlspec/utils/logging.py +251 -0
  593. sqlspec/utils/module_loader.py +306 -0
  594. sqlspec/utils/portal.cp314-win_amd64.pyd +0 -0
  595. sqlspec/utils/portal.py +377 -0
  596. sqlspec/utils/schema.cp314-win_amd64.pyd +0 -0
  597. sqlspec/utils/schema.py +1040 -0
  598. sqlspec/utils/serializers/__init__.py +30 -0
  599. sqlspec/utils/serializers/_json.cp314-win_amd64.pyd +0 -0
  600. sqlspec/utils/serializers/_json.py +415 -0
  601. sqlspec/utils/serializers/_numpy.cp314-win_amd64.pyd +0 -0
  602. sqlspec/utils/serializers/_numpy.py +65 -0
  603. sqlspec/utils/serializers/_schema.cp314-win_amd64.pyd +0 -0
  604. sqlspec/utils/serializers/_schema.py +285 -0
  605. sqlspec/utils/singleton.cp314-win_amd64.pyd +0 -0
  606. sqlspec/utils/singleton.py +41 -0
  607. sqlspec/utils/sync_tools.cp314-win_amd64.pyd +0 -0
  608. sqlspec/utils/sync_tools.py +316 -0
  609. sqlspec/utils/text.cp314-win_amd64.pyd +0 -0
  610. sqlspec/utils/text.py +109 -0
  611. sqlspec/utils/type_converters.cp314-win_amd64.pyd +0 -0
  612. sqlspec/utils/type_converters.py +216 -0
  613. sqlspec/utils/type_guards.cp314-win_amd64.pyd +0 -0
  614. sqlspec/utils/type_guards.py +1508 -0
  615. sqlspec/utils/uuids.cp314-win_amd64.pyd +0 -0
  616. sqlspec/utils/uuids.py +241 -0
  617. sqlspec-0.47.0.dist-info/METADATA +202 -0
  618. sqlspec-0.47.0.dist-info/RECORD +621 -0
  619. sqlspec-0.47.0.dist-info/WHEEL +4 -0
  620. sqlspec-0.47.0.dist-info/entry_points.txt +6 -0
  621. sqlspec-0.47.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,1040 @@
1
+ """Schema transformation utilities for converting data to various schema types."""
2
+
3
+ import datetime
4
+ from collections.abc import Callable, Sequence
5
+ from decimal import Decimal, InvalidOperation
6
+ from enum import Enum
7
+ from functools import lru_cache, partial
8
+ from pathlib import Path, PurePath
9
+ from typing import Any, Final, TypeGuard, cast, overload
10
+ from uuid import UUID
11
+
12
+ from typing_extensions import TypeVar
13
+
14
+ from sqlspec.exceptions import SQLSpecError
15
+ from sqlspec.typing import (
16
+ CATTRS_INSTALLED,
17
+ NUMPY_INSTALLED,
18
+ SchemaT,
19
+ attrs_asdict,
20
+ cattrs_structure,
21
+ cattrs_unstructure,
22
+ convert,
23
+ get_type_adapter,
24
+ )
25
+ from sqlspec.utils.dispatch import TypeDispatcher
26
+ from sqlspec.utils.logging import get_logger
27
+ from sqlspec.utils.serializers import from_json
28
+ from sqlspec.utils.text import camelize, kebabize, pascalize
29
+ from sqlspec.utils.type_guards import (
30
+ get_msgspec_rename_config,
31
+ is_attrs_instance,
32
+ is_attrs_schema,
33
+ is_dataclass,
34
+ is_dict,
35
+ is_msgspec_struct,
36
+ is_pydantic_model,
37
+ is_typed_dict,
38
+ )
39
+
40
+ __all__ = (
41
+ "_DEFAULT_TYPE_DECODERS",
42
+ "DataT",
43
+ "ValueT",
44
+ "_convert_numpy_recursive",
45
+ "_convert_numpy_to_list",
46
+ "_default_msgspec_deserializer",
47
+ "_is_list_type_target",
48
+ "to_schema",
49
+ "to_value_type",
50
+ "transform_dict_keys",
51
+ )
52
+
53
+ DataT = TypeVar("DataT", default=dict[str, Any])
54
+ ValueT = TypeVar("ValueT")
55
+
56
+ logger = get_logger(__name__)
57
+
58
+ _DATETIME_TYPES: Final[set[type]] = {datetime.datetime, datetime.date, datetime.time}
59
+ _DATETIME_TYPE_TUPLE: Final[tuple[type, ...]] = (datetime.datetime, datetime.date, datetime.time)
60
+ _MSGSPEC_RENAME_CONVERTERS: Final[dict[str, Callable[[str], str]]] = {
61
+ "camel": camelize,
62
+ "kebab": kebabize,
63
+ "pascal": pascalize,
64
+ }
65
+ _NUMPY_RECURSIVE_DISPATCHER: "TypeDispatcher[Callable[[Any], Any]] | None" = None
66
+
67
+
68
+ # =============================================================================
69
+ # Dict Key Transformation
70
+ # =============================================================================
71
+
72
+
73
+ def _safe_convert_key(key: Any, converter: Callable[[str], str]) -> Any:
74
+ """Safely convert a key using the converter function.
75
+
76
+ Args:
77
+ key: Key to convert (may not be a string).
78
+ converter: Function to convert string keys.
79
+
80
+ Returns:
81
+ Converted key if conversion succeeds, original key otherwise.
82
+
83
+ """
84
+ if not isinstance(key, str):
85
+ return key
86
+
87
+ try:
88
+ return converter(key)
89
+ except (TypeError, ValueError, AttributeError):
90
+ return key
91
+
92
+
93
+ def transform_dict_keys(data: dict | list | Any, converter: Callable[[str], str]) -> dict | list | Any:
94
+ """Transform dictionary keys using the provided converter function.
95
+
96
+ Recursively transforms all dictionary keys in a data structure using
97
+ the provided converter function. Handles nested dictionaries, lists
98
+ of dictionaries, and preserves non-dict values unchanged.
99
+
100
+ Args:
101
+ data: The data structure to transform. Can be a dict, list, or any other type.
102
+ converter: Function to convert string keys (e.g., camelize, kebabize).
103
+
104
+ Returns:
105
+ The transformed data structure with converted keys. Non-dict values
106
+ are returned unchanged.
107
+
108
+ Examples:
109
+ Transform snake_case keys to camelCase:
110
+
111
+ >>> from sqlspec.utils.text import camelize
112
+ >>> data = {"user_id": 123, "created_at": "2024-01-01"}
113
+ >>> transform_dict_keys(data, camelize)
114
+ {"userId": 123, "createdAt": "2024-01-01"}
115
+
116
+ Transform nested structures:
117
+
118
+ >>> nested = {
119
+ ... "user_data": {"first_name": "John", "last_name": "Doe"},
120
+ ... "order_items": [
121
+ ... {"item_id": 1, "item_name": "Product A"},
122
+ ... {"item_id": 2, "item_name": "Product B"},
123
+ ... ],
124
+ ... }
125
+ >>> transform_dict_keys(nested, camelize)
126
+ {
127
+ "userData": {
128
+ "firstName": "John",
129
+ "lastName": "Doe"
130
+ },
131
+ "orderItems": [
132
+ {"itemId": 1, "itemName": "Product A"},
133
+ {"itemId": 2, "itemName": "Product B"}
134
+ ]
135
+ }
136
+
137
+ """
138
+ if isinstance(data, dict):
139
+ return _transform_dict(data, converter)
140
+ if isinstance(data, list):
141
+ return _transform_list(data, converter)
142
+ return data
143
+
144
+
145
+ def _transform_dict(data: dict, converter: Callable[[str], str]) -> dict:
146
+ """Transform a dictionary's keys recursively.
147
+
148
+ Args:
149
+ data: Dictionary to transform.
150
+ converter: Function to convert string keys.
151
+
152
+ Returns:
153
+ Dictionary with transformed keys and recursively transformed values.
154
+
155
+ """
156
+ transformed = {}
157
+
158
+ for key, value in data.items():
159
+ converted_key = _safe_convert_key(key, converter)
160
+ transformed_value = transform_dict_keys(value, converter)
161
+ transformed[converted_key] = transformed_value
162
+
163
+ return transformed
164
+
165
+
166
+ def _transform_list(data: list, converter: Callable[[str], str]) -> list:
167
+ """Transform a list's elements recursively.
168
+
169
+ Args:
170
+ data: List to transform.
171
+ converter: Function to convert string keys in nested structures.
172
+
173
+ Returns:
174
+ List with recursively transformed elements.
175
+
176
+ """
177
+ return [transform_dict_keys(item, converter) for item in data]
178
+
179
+
180
+ # =============================================================================
181
+ # Schema Type Detection
182
+ # =============================================================================
183
+
184
+
185
+ def _is_list_type_target(target_type: Any) -> "TypeGuard[list[object]]":
186
+ """Check if target type is a list type (e.g., list[float])."""
187
+ try:
188
+ origin = target_type.__origin__
189
+ except (AttributeError, TypeError):
190
+ return False
191
+ return origin is list
192
+
193
+
194
+ def _convert_numpy_to_list(target_type: Any, value: Any) -> Any:
195
+ """Convert numpy array to list if target is a list type."""
196
+ if not NUMPY_INSTALLED:
197
+ return value
198
+
199
+ import numpy as np
200
+
201
+ if isinstance(value, np.ndarray) and _is_list_type_target(target_type):
202
+ return value.tolist()
203
+
204
+ return value
205
+
206
+
207
+ @lru_cache(maxsize=128)
208
+ def _detect_schema_type(schema_type: type) -> "str | None":
209
+ """Detect schema type with LRU caching.
210
+
211
+ Args:
212
+ schema_type: Type to detect
213
+
214
+ Returns:
215
+ Type identifier string or None if unsupported
216
+
217
+ """
218
+ return (
219
+ "typed_dict"
220
+ if is_typed_dict(schema_type)
221
+ else "dataclass"
222
+ if is_dataclass(schema_type)
223
+ else "msgspec"
224
+ if is_msgspec_struct(schema_type)
225
+ else "pydantic"
226
+ if is_pydantic_model(schema_type)
227
+ else "attrs"
228
+ if is_attrs_schema(schema_type)
229
+ else None
230
+ )
231
+
232
+
233
+ def _is_foreign_key_metadata_type(schema_type: type) -> bool:
234
+ if schema_type.__name__ != "ForeignKeyMetadata":
235
+ return False
236
+
237
+ # Check module for stronger guarantee without importing
238
+ module = getattr(schema_type, "__module__", "")
239
+ if "sqlspec" in module and ("driver" in module or "data_dictionary" in module):
240
+ return True
241
+
242
+ slots = getattr(schema_type, "__slots__", None)
243
+ if not slots:
244
+ return False
245
+ return {"table_name", "column_name", "referenced_table", "referenced_column"}.issubset(set(slots))
246
+
247
+
248
+ def _convert_foreign_key_metadata(data: Any, schema_type: Any) -> Any:
249
+ """Convert data to ForeignKeyMetadata schema type.
250
+
251
+ Handles both single items and lists for consistency with other converters.
252
+ """
253
+ if isinstance(data, list):
254
+ return [_convert_single_foreign_key_metadata(item, schema_type) for item in data]
255
+ return _convert_single_foreign_key_metadata(data, schema_type)
256
+
257
+
258
+ def _convert_single_foreign_key_metadata(data: Any, schema_type: Any) -> Any:
259
+ """Convert a single item to ForeignKeyMetadata."""
260
+ if not is_dict(data):
261
+ return data
262
+ payload = {
263
+ "table_name": data.get("table_name") or data.get("table"),
264
+ "column_name": data.get("column_name") or data.get("column"),
265
+ "referenced_table": data.get("referenced_table") or data.get("referenced_table_name"),
266
+ "referenced_column": data.get("referenced_column") or data.get("referenced_column_name"),
267
+ "constraint_name": data.get("constraint_name"),
268
+ "schema": data.get("schema") or data.get("table_schema"),
269
+ "referenced_schema": data.get("referenced_schema") or data.get("referenced_table_schema"),
270
+ }
271
+ return schema_type(**payload)
272
+
273
+
274
+ def _convert_typed_dict(data: Any, schema_type: Any) -> Any:
275
+ """Convert data to TypedDict."""
276
+ return [item for item in data if is_dict(item)] if isinstance(data, list) else data
277
+
278
+
279
+ def _convert_dataclass(data: Any, schema_type: Any) -> Any:
280
+ """Convert data to dataclass."""
281
+ if isinstance(data, list):
282
+ return [schema_type(**dict(item)) if is_dict(item) else item for item in data]
283
+ return schema_type(**dict(data)) if is_dict(data) else (schema_type(**data) if isinstance(data, dict) else data)
284
+
285
+
286
+ class _IsTypePredicate:
287
+ """Callable predicate to check if a type matches a target type."""
288
+
289
+ __slots__ = ("_type",)
290
+
291
+ def __init__(self, target_type: type) -> None:
292
+ self._type = target_type
293
+
294
+ def __call__(self, x: Any) -> bool:
295
+ return x is self._type
296
+
297
+
298
+ class _UUIDDecoder:
299
+ """Decoder for UUID types."""
300
+
301
+ __slots__ = ()
302
+
303
+ def __call__(self, t: type, v: Any) -> Any:
304
+ return t(v.hex)
305
+
306
+
307
+ class _ISOFormatDecoder:
308
+ """Decoder for types with isoformat() method (datetime, date, time)."""
309
+
310
+ __slots__ = ()
311
+
312
+ def __call__(self, t: type, v: Any) -> Any:
313
+ return t(v.isoformat())
314
+
315
+
316
+ class _EnumDecoder:
317
+ """Decoder for Enum types."""
318
+
319
+ __slots__ = ()
320
+
321
+ def __call__(self, t: type, v: Any) -> Any:
322
+ return t(v.value)
323
+
324
+
325
+ _DEFAULT_TYPE_DECODERS: Final[list[tuple[Callable[[Any], bool], Callable[[Any, Any], Any]]]] = [
326
+ (_IsTypePredicate(UUID), _UUIDDecoder()),
327
+ (_IsTypePredicate(datetime.datetime), _ISOFormatDecoder()),
328
+ (_IsTypePredicate(datetime.date), _ISOFormatDecoder()),
329
+ (_IsTypePredicate(datetime.time), _ISOFormatDecoder()),
330
+ (_IsTypePredicate(Enum), _EnumDecoder()),
331
+ (_is_list_type_target, _convert_numpy_to_list),
332
+ ]
333
+
334
+
335
+ def _default_msgspec_deserializer(
336
+ target_type: Any, value: Any, type_decoders: "Sequence[tuple[Any, Any]] | None" = None
337
+ ) -> Any:
338
+ """Convert msgspec types with type decoder support.
339
+
340
+ Args:
341
+ target_type: Type to convert to
342
+ value: Value to convert
343
+ type_decoders: Optional sequence of (predicate, decoder) pairs
344
+
345
+ Returns:
346
+ Converted value or original value if conversion not applicable
347
+
348
+ """
349
+ if NUMPY_INSTALLED:
350
+ import numpy as np
351
+
352
+ if isinstance(value, np.ndarray) and _is_list_type_target(target_type):
353
+ return value.tolist()
354
+
355
+ if type_decoders:
356
+ for predicate, decoder in type_decoders:
357
+ if predicate(target_type):
358
+ return decoder(target_type, value)
359
+
360
+ if target_type is UUID and isinstance(value, UUID):
361
+ return value.hex
362
+
363
+ if target_type in _DATETIME_TYPES and isinstance(value, _DATETIME_TYPE_TUPLE):
364
+ datetime_value = cast("datetime.datetime | datetime.date | datetime.time", value)
365
+ return datetime_value.isoformat()
366
+
367
+ if isinstance(target_type, type) and issubclass(target_type, Enum) and isinstance(value, Enum):
368
+ return value.value
369
+
370
+ try:
371
+ if isinstance(target_type, type) and isinstance(value, target_type):
372
+ return value
373
+ except TypeError:
374
+ pass
375
+
376
+ if isinstance(target_type, type):
377
+ try:
378
+ if issubclass(target_type, (Path, PurePath)) or issubclass(target_type, UUID):
379
+ return target_type(str(value))
380
+ except (TypeError, ValueError):
381
+ pass
382
+
383
+ return value
384
+
385
+
386
+ _DEFAULT_MSGSPEC_DESERIALIZER: Final[Callable[[Any, Any], Any]] = partial(
387
+ _default_msgspec_deserializer, type_decoders=_DEFAULT_TYPE_DECODERS
388
+ )
389
+
390
+
391
+ def _convert_numpy_recursive(obj: Any) -> Any:
392
+ """Recursively convert numpy arrays to lists.
393
+
394
+ This is a module-level function to avoid nested function definitions
395
+ which are problematic for mypyc compilation.
396
+
397
+ Args:
398
+ obj: Object to convert (may contain numpy arrays nested in dicts/lists)
399
+
400
+ Returns:
401
+ Object with all numpy arrays converted to lists
402
+
403
+ """
404
+ if not NUMPY_INSTALLED:
405
+ return obj
406
+
407
+ handler = _get_numpy_recursive_dispatcher().get(obj)
408
+ if handler is not None:
409
+ return handler(obj)
410
+ return obj
411
+
412
+
413
+ def _convert_numpy_array(obj: Any) -> Any:
414
+ return obj.tolist()
415
+
416
+
417
+ def _convert_numpy_mapping(obj: Any) -> Any:
418
+ return {key: _convert_numpy_recursive(value) for key, value in obj.items()}
419
+
420
+
421
+ def _convert_numpy_sequence(obj: Any) -> Any:
422
+ converted = [_convert_numpy_recursive(item) for item in obj]
423
+ return type(obj)(converted)
424
+
425
+
426
+ def _get_numpy_recursive_dispatcher() -> "TypeDispatcher[Callable[[Any], Any]]":
427
+ global _NUMPY_RECURSIVE_DISPATCHER
428
+ if _NUMPY_RECURSIVE_DISPATCHER is None:
429
+ import numpy as np
430
+
431
+ dispatcher = TypeDispatcher["Callable[[Any], Any]"]()
432
+ dispatcher.register(np.ndarray, _convert_numpy_array)
433
+ dispatcher.register(dict, _convert_numpy_mapping)
434
+ dispatcher.register(list, _convert_numpy_sequence)
435
+ dispatcher.register(tuple, _convert_numpy_sequence)
436
+ _NUMPY_RECURSIVE_DISPATCHER = dispatcher
437
+ return _NUMPY_RECURSIVE_DISPATCHER
438
+
439
+
440
+ def _convert_msgspec(data: Any, schema_type: Any) -> Any:
441
+ """Convert data to msgspec Struct."""
442
+ rename_config = get_msgspec_rename_config(schema_type)
443
+
444
+ transformed_data = data
445
+ if (rename_config and is_dict(data)) or (isinstance(data, Sequence) and data and is_dict(data[0])):
446
+ try:
447
+ converter = _MSGSPEC_RENAME_CONVERTERS.get(rename_config) if rename_config else None
448
+ if converter:
449
+ transformed_data = (
450
+ [transform_dict_keys(item, converter) if is_dict(item) else item for item in data]
451
+ if isinstance(data, Sequence)
452
+ else (transform_dict_keys(data, converter) if is_dict(data) else data)
453
+ )
454
+ except Exception as e:
455
+ logger.debug("Field name transformation failed for msgspec schema: %s", e)
456
+
457
+ if NUMPY_INSTALLED:
458
+ transformed_data = _convert_numpy_recursive(transformed_data)
459
+
460
+ return convert(
461
+ obj=transformed_data,
462
+ type=(list[schema_type] if isinstance(transformed_data, Sequence) else schema_type),
463
+ from_attributes=True,
464
+ dec_hook=_DEFAULT_MSGSPEC_DESERIALIZER,
465
+ )
466
+
467
+
468
+ def _convert_pydantic(data: Any, schema_type: Any) -> Any:
469
+ """Convert data to Pydantic model."""
470
+ if isinstance(data, Sequence):
471
+ return get_type_adapter(list[schema_type]).validate_python(data, from_attributes=True)
472
+ return get_type_adapter(schema_type).validate_python(data, from_attributes=True)
473
+
474
+
475
+ def _convert_attrs(data: Any, schema_type: Any) -> Any:
476
+ """Convert data to attrs class."""
477
+ if CATTRS_INSTALLED:
478
+ if isinstance(data, Sequence):
479
+ return cattrs_structure(data, list[schema_type])
480
+ structured = cattrs_unstructure(data) if is_attrs_instance(data) else data
481
+ return cattrs_structure(structured, schema_type)
482
+
483
+ if isinstance(data, list):
484
+ return [schema_type(**dict(item)) if is_dict(item) else schema_type(**attrs_asdict(item)) for item in data]
485
+ return schema_type(**dict(data)) if is_dict(data) else data
486
+
487
+
488
+ # Cache for schema converters - maps type directly to converter callable (or None if unsupported)
489
+ # Manual dict cache is faster than lru_cache for mypyc: direct dict[type] lookup vs decorated call
490
+ _SCHEMA_CONVERTER_CACHE: "dict[type, Callable[[Any, Any], Any] | None]" = {}
491
+
492
+
493
+ def _get_schema_converter(schema_type: type) -> "Callable[[Any, Any], Any] | None":
494
+ """Get the converter function for a schema type with caching.
495
+
496
+ This is optimized for mypyc: uses a plain dict cache instead of lru_cache,
497
+ and caches the callable directly instead of a string key.
498
+
499
+ Args:
500
+ schema_type: The schema type to get a converter for.
501
+
502
+ Returns:
503
+ Converter function if schema_type is a supported schema, None otherwise.
504
+
505
+ """
506
+ try:
507
+ return _SCHEMA_CONVERTER_CACHE[schema_type]
508
+ except KeyError:
509
+ # Determine converter - order by expected frequency
510
+ if is_typed_dict(schema_type):
511
+ conv: Callable[[Any, Any], Any] | None = _convert_typed_dict
512
+ elif is_dataclass(schema_type):
513
+ conv = _convert_dataclass
514
+ elif is_msgspec_struct(schema_type):
515
+ conv = _convert_msgspec
516
+ elif is_pydantic_model(schema_type):
517
+ conv = _convert_pydantic
518
+ elif is_attrs_schema(schema_type):
519
+ conv = _convert_attrs
520
+ elif _is_foreign_key_metadata_type(schema_type):
521
+ conv = _convert_foreign_key_metadata
522
+ else:
523
+ conv = None
524
+ _SCHEMA_CONVERTER_CACHE[schema_type] = conv # pyright: ignore[reportArgumentType]
525
+ return conv
526
+
527
+
528
+ @overload
529
+ def to_schema(data: "list[DataT]", *, schema_type: "type[SchemaT]") -> "list[SchemaT]": ...
530
+ @overload
531
+ def to_schema(data: "list[DataT]", *, schema_type: None = None) -> "list[DataT]": ...
532
+ @overload
533
+ def to_schema(data: "DataT", *, schema_type: "type[SchemaT]") -> "SchemaT": ...
534
+ @overload
535
+ def to_schema(data: "DataT", *, schema_type: None = None) -> "DataT": ...
536
+
537
+
538
+ def to_schema(data: Any, *, schema_type: Any = None) -> Any:
539
+ """Convert data to a specified schema type.
540
+
541
+ Supports transformation to various schema types including:
542
+ - TypedDict
543
+ - dataclasses
544
+ - msgspec Structs
545
+ - Pydantic models
546
+ - attrs classes
547
+
548
+ Args:
549
+ data: Input data to convert (dict, list of dicts, or other)
550
+ schema_type: Target schema type for conversion. If None, returns data unchanged.
551
+
552
+ Returns:
553
+ Converted data in the specified schema type, or original data if schema_type is None
554
+
555
+ Raises:
556
+ SQLSpecError: If schema_type is not a supported type
557
+
558
+ """
559
+ if schema_type is None:
560
+ return data
561
+
562
+ # Get cached converter - single dict lookup, no string indirection
563
+ conv = _get_schema_converter(schema_type)
564
+ if conv is None:
565
+ msg = "`schema_type` should be a valid Dataclass, Pydantic model, Msgspec struct, Attrs class, or TypedDict"
566
+ raise SQLSpecError(msg)
567
+
568
+ return conv(data, schema_type)
569
+
570
+
571
+ # =============================================================================
572
+ # Scalar Type Conversion
573
+ # =============================================================================
574
+
575
+
576
+ def _ensure_json_parsed(value: Any) -> Any:
577
+ """Parse JSON string if needed, otherwise return as-is.
578
+
579
+ This helper is used when converting database values (potentially JSON strings
580
+ from JSONB columns) to schema types like Pydantic models or dataclasses.
581
+
582
+ Args:
583
+ value: The value to potentially parse. If it's a string, attempts JSON parsing.
584
+
585
+ Returns:
586
+ Parsed JSON object if value was a valid JSON string, otherwise the original value.
587
+
588
+ """
589
+ if isinstance(value, str):
590
+ try:
591
+ return from_json(value)
592
+ except Exception:
593
+ return value
594
+ return value
595
+
596
+
597
+ def _try_parse_json(value: str) -> Any:
598
+ """Attempt to parse a JSON string, returning None on failure.
599
+
600
+ Args:
601
+ value: JSON string to parse.
602
+
603
+ Returns:
604
+ Parsed JSON value, or None if parsing fails.
605
+
606
+ """
607
+ try:
608
+ return from_json(value)
609
+ except Exception:
610
+ return None
611
+
612
+
613
+ # Boolean true values for string conversion
614
+ _BOOL_TRUE_VALUES: Final[frozenset[str]] = frozenset({"true", "1", "yes", "y", "t", "on"})
615
+
616
+ # Types requiring strict type() identity check due to subclass gotchas:
617
+ # - bool is subclass of int (isinstance(True, int) is True)
618
+ # - datetime is subclass of date (isinstance(datetime(...), date) is True)
619
+ _STRICT_IDENTITY_TYPES: Final[tuple[type, ...]] = (int, bool, datetime.date, datetime.time)
620
+
621
+
622
+ def _convert_to_int(value: Any) -> int:
623
+ """Convert a value to int.
624
+
625
+ Args:
626
+ value: Value to convert.
627
+
628
+ Returns:
629
+ Converted integer value.
630
+
631
+ Raises:
632
+ TypeError: If value cannot be converted to int.
633
+
634
+ """
635
+ if isinstance(value, bool):
636
+ return int(value)
637
+ if isinstance(value, (int, float, Decimal)):
638
+ return int(value)
639
+ if isinstance(value, str):
640
+ try:
641
+ return int(value)
642
+ except ValueError:
643
+ # Try parsing as float first for values like "42.0"
644
+ try:
645
+ return int(float(value))
646
+ except ValueError:
647
+ pass
648
+ msg = f"Cannot convert {type(value).__name__} to int"
649
+ raise TypeError(msg)
650
+
651
+
652
+ def _convert_to_float(value: Any) -> float:
653
+ """Convert a value to float.
654
+
655
+ Args:
656
+ value: Value to convert.
657
+
658
+ Returns:
659
+ Converted float value.
660
+
661
+ Raises:
662
+ TypeError: If value cannot be converted to float.
663
+
664
+ """
665
+ if isinstance(value, bool):
666
+ return float(value)
667
+ if isinstance(value, (int, float, Decimal)):
668
+ return float(value)
669
+ if isinstance(value, str):
670
+ try:
671
+ return float(value)
672
+ except ValueError:
673
+ pass
674
+ msg = f"Cannot convert {type(value).__name__} to float"
675
+ raise TypeError(msg)
676
+
677
+
678
+ def _convert_to_bool(value: Any) -> bool:
679
+ """Convert a value to bool.
680
+
681
+ Args:
682
+ value: Value to convert.
683
+
684
+ Returns:
685
+ Converted boolean value.
686
+
687
+ Raises:
688
+ TypeError: If value cannot be converted to bool.
689
+
690
+ """
691
+ if isinstance(value, bool):
692
+ return value
693
+ if isinstance(value, (int, float)):
694
+ return bool(value)
695
+ if isinstance(value, str):
696
+ return value.lower() in _BOOL_TRUE_VALUES
697
+ msg = f"Cannot convert {type(value).__name__} to bool"
698
+ raise TypeError(msg)
699
+
700
+
701
+ def _convert_to_datetime(value: Any) -> datetime.datetime:
702
+ """Convert a value to datetime.
703
+
704
+ Args:
705
+ value: Value to convert.
706
+
707
+ Returns:
708
+ Converted datetime value.
709
+
710
+ Raises:
711
+ TypeError: If value cannot be converted to datetime.
712
+
713
+ """
714
+ if isinstance(value, datetime.datetime):
715
+ return value
716
+ if isinstance(value, str):
717
+ try:
718
+ return datetime.datetime.fromisoformat(value)
719
+ except ValueError:
720
+ pass
721
+ if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime):
722
+ return datetime.datetime.combine(value, datetime.time.min)
723
+ msg = f"Cannot convert {type(value).__name__} to datetime"
724
+ raise TypeError(msg)
725
+
726
+
727
+ def _convert_to_date(value: Any) -> datetime.date:
728
+ """Convert a value to date.
729
+
730
+ Args:
731
+ value: Value to convert.
732
+
733
+ Returns:
734
+ Converted date value.
735
+
736
+ Raises:
737
+ TypeError: If value cannot be converted to date.
738
+
739
+ """
740
+ if isinstance(value, datetime.datetime):
741
+ return value.date()
742
+ if isinstance(value, datetime.date):
743
+ return value
744
+ if isinstance(value, str):
745
+ try:
746
+ # Try ISO format first
747
+ return datetime.date.fromisoformat(value)
748
+ except ValueError:
749
+ # Try parsing as datetime and extracting date
750
+ try:
751
+ return datetime.datetime.fromisoformat(value).date()
752
+ except ValueError:
753
+ pass
754
+ msg = f"Cannot convert {type(value).__name__} to date"
755
+ raise TypeError(msg)
756
+
757
+
758
+ def _convert_to_time(value: Any) -> datetime.time:
759
+ """Convert a value to time.
760
+
761
+ Args:
762
+ value: Value to convert.
763
+
764
+ Returns:
765
+ Converted time value.
766
+
767
+ Raises:
768
+ TypeError: If value cannot be converted to time.
769
+
770
+ """
771
+ if isinstance(value, datetime.datetime):
772
+ return value.time()
773
+ if isinstance(value, datetime.time):
774
+ return value
775
+ if isinstance(value, str):
776
+ try:
777
+ return datetime.time.fromisoformat(value)
778
+ except ValueError:
779
+ pass
780
+ msg = f"Cannot convert {type(value).__name__} to time"
781
+ raise TypeError(msg)
782
+
783
+
784
+ def _convert_to_decimal(value: Any) -> Decimal:
785
+ """Convert a value to Decimal.
786
+
787
+ Args:
788
+ value: Value to convert.
789
+
790
+ Returns:
791
+ Converted Decimal value.
792
+
793
+ Raises:
794
+ TypeError: If value cannot be converted to Decimal.
795
+
796
+ """
797
+ if isinstance(value, Decimal):
798
+ return value
799
+ if isinstance(value, (int, float, str)):
800
+ try:
801
+ return Decimal(str(value))
802
+ except InvalidOperation:
803
+ pass
804
+ msg = f"Cannot convert {type(value).__name__} to Decimal"
805
+ raise TypeError(msg)
806
+
807
+
808
+ def _convert_to_uuid(value: Any) -> UUID:
809
+ """Convert a value to UUID.
810
+
811
+ Args:
812
+ value: Value to convert.
813
+
814
+ Returns:
815
+ Converted UUID value.
816
+
817
+ Raises:
818
+ TypeError: If value cannot be converted to UUID.
819
+
820
+ """
821
+ if isinstance(value, UUID):
822
+ return value
823
+ if isinstance(value, str):
824
+ try:
825
+ return UUID(value)
826
+ except ValueError:
827
+ pass
828
+ if isinstance(value, bytes):
829
+ try:
830
+ return UUID(bytes=value)
831
+ except ValueError:
832
+ pass
833
+ msg = f"Cannot convert {type(value).__name__} to UUID"
834
+ raise TypeError(msg)
835
+
836
+
837
+ def _convert_to_path(value: Any) -> Path:
838
+ """Convert a value to Path.
839
+
840
+ Args:
841
+ value: Value to convert.
842
+
843
+ Returns:
844
+ Converted Path value.
845
+
846
+ Raises:
847
+ TypeError: If value cannot be converted to Path.
848
+
849
+ """
850
+ if isinstance(value, Path):
851
+ return value
852
+ if isinstance(value, (str, PurePath)):
853
+ return Path(value)
854
+ msg = f"Cannot convert {type(value).__name__} to Path"
855
+ raise TypeError(msg)
856
+
857
+
858
+ def _convert_to_dict(value: Any) -> dict[str, Any]:
859
+ """Convert a value to dict.
860
+
861
+ This is useful for JSON/JSONB database columns where the driver may return
862
+ either a dict (already parsed) or a string (needs parsing).
863
+
864
+ Args:
865
+ value: Value to convert.
866
+
867
+ Returns:
868
+ Converted dict value.
869
+
870
+ Raises:
871
+ TypeError: If value cannot be converted to dict.
872
+
873
+ """
874
+ if isinstance(value, dict):
875
+ return value
876
+ if isinstance(value, str):
877
+ parsed = _try_parse_json(value)
878
+ if parsed is not None:
879
+ if isinstance(parsed, dict):
880
+ return parsed
881
+ msg = f"JSON string did not parse to dict, got {type(parsed).__name__}"
882
+ raise TypeError(msg)
883
+ msg = f"Cannot convert {type(value).__name__} to dict"
884
+ raise TypeError(msg)
885
+
886
+
887
+ def _convert_to_list(value: Any) -> list[Any]:
888
+ """Convert a value to list.
889
+
890
+ This is useful for JSON array database columns where the driver may return
891
+ either a list (already parsed) or a string (needs parsing).
892
+
893
+ Args:
894
+ value: Value to convert.
895
+
896
+ Returns:
897
+ Converted list value.
898
+
899
+ Raises:
900
+ TypeError: If value cannot be converted to list.
901
+
902
+ """
903
+ if isinstance(value, list):
904
+ return value
905
+ if isinstance(value, str):
906
+ parsed = _try_parse_json(value)
907
+ if parsed is not None:
908
+ if isinstance(parsed, list):
909
+ return parsed
910
+ msg = f"JSON string did not parse to list, got {type(parsed).__name__}"
911
+ raise TypeError(msg)
912
+ if isinstance(value, (tuple, set, frozenset)):
913
+ return list(value)
914
+ msg = f"Cannot convert {type(value).__name__} to list"
915
+ raise TypeError(msg)
916
+
917
+
918
+ def to_value_type(value: Any, value_type: "type[ValueT]") -> "ValueT":
919
+ """Convert a database value to the specified Python type.
920
+
921
+ This function handles type conversion for common database return values,
922
+ providing runtime type safety for scalar queries. When the value is already
923
+ the correct type, it is returned as-is without conversion overhead.
924
+
925
+ Also supports schema types (Pydantic models, dataclasses, msgspec Structs,
926
+ attrs classes, and TypedDict). For schema types, JSON strings are automatically
927
+ parsed before conversion.
928
+
929
+ Args:
930
+ value: The value to convert.
931
+ value_type: The target Python type. Supported types include:
932
+ - Primitives: int, float, str, bool
933
+ - Temporal: datetime, date, time
934
+ - Numeric: Decimal
935
+ - Identifiers: UUID, Path
936
+ - Collections: dict, list (for JSON/JSONB columns)
937
+ - Schema types: Pydantic models, dataclasses, msgspec Structs,
938
+ attrs classes, TypedDict (for JSONB columns)
939
+
940
+ Returns:
941
+ The converted value of the specified type.
942
+
943
+ Raises:
944
+ TypeError: If the value cannot be converted to the specified type.
945
+
946
+ Examples:
947
+ Convert string to int:
948
+
949
+ >>> to_value_type("42", int)
950
+ 42
951
+
952
+ Convert Decimal to float:
953
+
954
+ >>> from decimal import Decimal
955
+ >>> to_value_type(Decimal("3.14"), float)
956
+ 3.14
957
+
958
+ Convert string to UUID:
959
+
960
+ >>> from uuid import UUID
961
+ >>> to_value_type("550e8400-e29b-41d4-a716-446655440000", UUID)
962
+ UUID('550e8400-e29b-41d4-a716-446655440000')
963
+
964
+ Convert JSON string to dict:
965
+
966
+ >>> to_value_type('{"key": "value"}', dict)
967
+ {'key': 'value'}
968
+
969
+ Convert JSONB to Pydantic model:
970
+
971
+ >>> from pydantic import BaseModel
972
+ >>> class User(BaseModel):
973
+ ... name: str
974
+ ... email: str
975
+ >>> to_value_type(
976
+ ... '{"name": "Alice", "email": "alice@example.com"}', User
977
+ ... )
978
+ User(name='Alice', email='alice@example.com')
979
+
980
+ Identity conversion (no overhead when type matches exactly):
981
+
982
+ >>> value = 42
983
+ >>> result = to_value_type(value, int)
984
+ >>> result is value
985
+ True
986
+
987
+ Bool to int conversion (bool is a subclass of int, but converts correctly):
988
+
989
+ >>> to_value_type(True, int)
990
+ 1
991
+ >>> to_value_type(False, int)
992
+ 0
993
+
994
+ """
995
+ # Fast path: already correct type (handles ~90% of cases)
996
+ # Uses strict type() identity which correctly handles subclass gotchas:
997
+ # - type(True) is int → False (bool is subclass of int)
998
+ # - type(datetime(...)) is date → False (datetime is subclass of date)
999
+ if type(value) is value_type:
1000
+ return value
1001
+
1002
+ # Scalar type conversions - most common cases, fast pointer comparisons under mypyc
1003
+ if value_type is int:
1004
+ return cast("ValueT", _convert_to_int(value))
1005
+ if value_type is str:
1006
+ return cast("ValueT", str(value))
1007
+ if value_type is float:
1008
+ return cast("ValueT", _convert_to_float(value))
1009
+ if value_type is bool:
1010
+ return cast("ValueT", _convert_to_bool(value))
1011
+ if value_type is datetime.datetime:
1012
+ return cast("ValueT", _convert_to_datetime(value))
1013
+ if value_type is datetime.date:
1014
+ return cast("ValueT", _convert_to_date(value))
1015
+ if value_type is datetime.time:
1016
+ return cast("ValueT", _convert_to_time(value))
1017
+ if value_type is Decimal:
1018
+ return cast("ValueT", _convert_to_decimal(value))
1019
+ if value_type is UUID:
1020
+ return cast("ValueT", _convert_to_uuid(value))
1021
+ if value_type is Path:
1022
+ return cast("ValueT", _convert_to_path(value))
1023
+ if value_type is dict:
1024
+ return cast("ValueT", _convert_to_dict(value))
1025
+ if value_type is list:
1026
+ return cast("ValueT", _convert_to_list(value))
1027
+
1028
+ # Schema types (Pydantic, dataclass, msgspec, attrs, TypedDict)
1029
+ # Deferred after scalar checks to avoid overhead for common scalar queries
1030
+ schema_converter = _get_schema_converter(value_type)
1031
+ if schema_converter is not None:
1032
+ parsed = _ensure_json_parsed(value)
1033
+ return cast("ValueT", schema_converter(parsed, value_type))
1034
+
1035
+ # Fallback: try direct construction for custom types
1036
+ try:
1037
+ return value_type(value) # type: ignore[call-arg]
1038
+ except (TypeError, ValueError) as e:
1039
+ msg = f"Cannot convert {type(value).__name__} to {value_type.__name__}"
1040
+ raise TypeError(msg) from e