pyrsql 0.0.2__tar.gz → 0.0.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. {pyrsql-0.0.2 → pyrsql-0.0.3}/PKG-INFO +25 -10
  2. {pyrsql-0.0.2 → pyrsql-0.0.3}/README.md +23 -8
  3. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/contributing.md +1 -1
  4. pyrsql-0.0.3/docs/explanation/architecture.md +245 -0
  5. pyrsql-0.0.3/docs/explanation/extensibility.md +90 -0
  6. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/index.md +22 -0
  7. pyrsql-0.0.3/docs/quickstart.md +143 -0
  8. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/reference/api.md +0 -1
  9. pyrsql-0.0.3/docs/reference/options.md +107 -0
  10. pyrsql-0.0.3/docs/testing.md +185 -0
  11. pyrsql-0.0.3/docs/usage/async.md +138 -0
  12. pyrsql-0.0.3/docs/usage/errors.md +213 -0
  13. pyrsql-0.0.3/docs/usage/fastapi-sqlalchemy.md +150 -0
  14. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/fastapi.md +26 -4
  15. {pyrsql-0.0.2 → pyrsql-0.0.3}/pyproject.toml +8 -13
  16. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/__init__.py +2 -0
  17. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/adapters/fastapi/config.py +82 -43
  18. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/adapters/fastapi/criteria.py +5 -22
  19. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/adapters/fastapi/dependency.py +26 -28
  20. pyrsql-0.0.3/src/pyrsql/adapters/fastapi/errors.py +347 -0
  21. pyrsql-0.0.3/src/pyrsql/core/binding_policy.py +78 -0
  22. pyrsql-0.0.3/src/pyrsql/core/compiler.py +45 -0
  23. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/conversion.py +185 -92
  24. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/custom.py +10 -2
  25. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/field_policy.py +67 -21
  26. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/json/__init__.py +1 -6
  27. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/json/options.py +62 -25
  28. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/json/path.py +28 -21
  29. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/json/query.py +7 -16
  30. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/json/values.py +27 -6
  31. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/options.py +196 -158
  32. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/page.py +27 -29
  33. pyrsql-0.0.3/src/pyrsql/core/procedure_policy.py +173 -0
  34. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/query.py +17 -53
  35. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/sort.py +16 -54
  36. pyrsql-0.0.3/src/pyrsql/core/source_issues.py +64 -0
  37. pyrsql-0.0.3/src/pyrsql/core/validation.py +16 -0
  38. pyrsql-0.0.3/src/pyrsql/integrations/fastapi/sqlalchemy/__init__.py +17 -0
  39. pyrsql-0.0.3/src/pyrsql/integrations/fastapi/sqlalchemy/examples.py +215 -0
  40. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/fastapi/sqlalchemy/helpers.py +79 -0
  41. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/fastapi/sqlalchemy/integration.py +132 -84
  42. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/fastapi/sqlalchemy/payloads.py +0 -7
  43. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/fastapi/sqlalchemy/resource.py +134 -101
  44. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/__init__.py +2 -0
  45. pyrsql-0.0.3/src/pyrsql/orms/base.py +72 -0
  46. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/__init__.py +1 -1
  47. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/coercion.py +53 -13
  48. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/compiled_page.py +6 -4
  49. pyrsql-0.0.2/src/pyrsql/orms/sqlalchemy/compiled.py → pyrsql-0.0.3/src/pyrsql/orms/sqlalchemy/compiled_query.py +3 -3
  50. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/compiled_sort.py +5 -5
  51. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/errors.py +13 -1
  52. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/introspection.py +87 -54
  53. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/json_path.py +57 -59
  54. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/orm.py +34 -13
  55. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/resolver.py +117 -46
  56. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/sorter.py +47 -37
  57. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/statement.py +35 -13
  58. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/translator.py +69 -51
  59. pyrsql-0.0.3/src/pyrsql/orms/sqlalchemy/type_inference.py +59 -0
  60. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/types.py +5 -6
  61. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/__init__.py +1 -4
  62. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/ast.py +1 -35
  63. pyrsql-0.0.3/src/pyrsql/parsing/diagnostics.py +9 -0
  64. pyrsql-0.0.3/src/pyrsql/parsing/errors.py +21 -0
  65. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/lexer.py +54 -37
  66. pyrsql-0.0.3/src/pyrsql/parsing/limits.py +48 -0
  67. pyrsql-0.0.3/src/pyrsql/parsing/normalization.py +51 -0
  68. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/operators.py +78 -36
  69. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/parser.py +29 -14
  70. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/source.py +0 -31
  71. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/selector/__init__.py +1 -6
  72. pyrsql-0.0.3/src/pyrsql/selector/ast.py +45 -0
  73. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/selector/parser.py +120 -22
  74. pyrsql-0.0.3/src/pyrsql/semantic/binder.py +155 -0
  75. pyrsql-0.0.3/src/pyrsql/semantic/diagnostics.py +9 -0
  76. pyrsql-0.0.3/src/pyrsql/semantic/errors.py +39 -0
  77. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/sorting/ast.py +4 -14
  78. pyrsql-0.0.3/src/pyrsql/sorting/binder.py +118 -0
  79. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/sorting/diagnostics.py +2 -0
  80. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/sorting/errors.py +3 -1
  81. pyrsql-0.0.3/src/pyrsql/sorting/limits.py +33 -0
  82. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/sorting/parser.py +66 -12
  83. pyrsql-0.0.3/tests/__init__.py +1 -0
  84. pyrsql-0.0.3/tests/functional/fastapi_adapter/test_async_dependency.py +114 -0
  85. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/fastapi_adapter/test_dependency.py +6 -5
  86. pyrsql-0.0.3/tests/functional/fastapi_sqlalchemy/test_async_integration.py +234 -0
  87. pyrsql-0.0.3/tests/integration/sqlalchemy/test_async_pipeline.py +104 -0
  88. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/sqlalchemy/test_query_pipeline.py +49 -0
  89. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/sqlalchemy/test_sort_pipeline.py +27 -0
  90. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_path_resolver_bench.py +0 -1
  91. pyrsql-0.0.3/tests/security/__init__.py +1 -0
  92. pyrsql-0.0.3/tests/security/conftest.py +109 -0
  93. pyrsql-0.0.3/tests/security/test_configuration_hardening.py +30 -0
  94. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_error_sanitization.py +101 -0
  95. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_hpp.py +86 -0
  96. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_injection.py +49 -0
  97. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_limits.py +215 -0
  98. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_policies.py +183 -0
  99. pyrsql-0.0.3/tests/security/test_fastapi_sqlalchemy_resource_security.py +54 -0
  100. pyrsql-0.0.3/tests/security/test_sqlalchemy_injection.py +77 -0
  101. pyrsql-0.0.3/tests/security/test_sqlalchemy_jsonpath_security.py +70 -0
  102. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/adapters/fastapi_adapter/conftest.py +11 -16
  103. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/adapters/fastapi_adapter/test_config.py +11 -9
  104. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/adapters/fastapi_adapter/test_criteria.py +1 -22
  105. pyrsql-0.0.3/tests/unit/adapters/fastapi_adapter/test_errors.py +30 -0
  106. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/json/test_options.py +14 -0
  107. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/json/test_path.py +7 -18
  108. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/json/test_query.py +13 -22
  109. pyrsql-0.0.3/tests/unit/core/json/test_values.py +72 -0
  110. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/test_conversion.py +82 -0
  111. pyrsql-0.0.3/tests/unit/core/test_custom.py +22 -0
  112. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/test_options.py +79 -2
  113. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/test_page.py +0 -2
  114. pyrsql-0.0.3/tests/unit/integrations/fastapi_sqlalchemy/test_examples.py +97 -0
  115. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/integrations/fastapi_sqlalchemy/test_integration.py +184 -51
  116. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/test_resolver.py +115 -8
  117. pyrsql-0.0.3/tests/unit/orms/sqlalchemy/test_statement.py +61 -0
  118. pyrsql-0.0.3/tests/unit/parsing/test_ast.py +66 -0
  119. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/parsing/test_lexer.py +32 -0
  120. pyrsql-0.0.3/tests/unit/parsing/test_operators.py +105 -0
  121. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/parsing/test_parser.py +83 -10
  122. pyrsql-0.0.3/tests/unit/parsing/test_source.py +27 -0
  123. pyrsql-0.0.3/tests/unit/selector/test_ast.py +30 -0
  124. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/selector/test_parser.py +100 -1
  125. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/semantic/test_binder.py +39 -18
  126. pyrsql-0.0.3/tests/unit/sorting/test_ast.py +26 -0
  127. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/sorting/test_binder.py +32 -9
  128. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/sorting/test_parser.py +74 -0
  129. pyrsql-0.0.2/docs/explanation/architecture.md +0 -352
  130. pyrsql-0.0.2/docs/explanation/extensibility.md +0 -72
  131. pyrsql-0.0.2/docs/quickstart.md +0 -71
  132. pyrsql-0.0.2/docs/reference/options.md +0 -66
  133. pyrsql-0.0.2/docs/testing.md +0 -152
  134. pyrsql-0.0.2/docs/usage/fastapi-sqlalchemy.md +0 -85
  135. pyrsql-0.0.2/src/pyrsql/adapters/fastapi/errors.py +0 -218
  136. pyrsql-0.0.2/src/pyrsql/core/compiler.py +0 -127
  137. pyrsql-0.0.2/src/pyrsql/core/procedure_policy.py +0 -89
  138. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/__init__.py +0 -11
  139. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/examples.py +0 -114
  140. pyrsql-0.0.2/src/pyrsql/ir/__init__.py +0 -28
  141. pyrsql-0.0.2/src/pyrsql/ir/page.py +0 -40
  142. pyrsql-0.0.2/src/pyrsql/ir/query.py +0 -181
  143. pyrsql-0.0.2/src/pyrsql/ir/sort.py +0 -50
  144. pyrsql-0.0.2/src/pyrsql/orms/base.py +0 -108
  145. pyrsql-0.0.2/src/pyrsql/orms/sqlalchemy/type_inference.py +0 -35
  146. pyrsql-0.0.2/src/pyrsql/parsing/diagnostics.py +0 -29
  147. pyrsql-0.0.2/src/pyrsql/parsing/errors.py +0 -47
  148. pyrsql-0.0.2/src/pyrsql/parsing/limits.py +0 -36
  149. pyrsql-0.0.2/src/pyrsql/selector/ast.py +0 -86
  150. pyrsql-0.0.2/src/pyrsql/semantic/binder.py +0 -237
  151. pyrsql-0.0.2/src/pyrsql/semantic/diagnostics.py +0 -29
  152. pyrsql-0.0.2/src/pyrsql/semantic/errors.py +0 -69
  153. pyrsql-0.0.2/src/pyrsql/sorting/binder.py +0 -184
  154. pyrsql-0.0.2/src/pyrsql/sorting/limits.py +0 -27
  155. pyrsql-0.0.2/tests/unit/core/json/test_values.py +0 -31
  156. pyrsql-0.0.2/tests/unit/ir/__init__.py +0 -1
  157. pyrsql-0.0.2/tests/unit/ir/test_page.py +0 -32
  158. pyrsql-0.0.2/tests/unit/ir/test_query.py +0 -124
  159. pyrsql-0.0.2/tests/unit/ir/test_sort.py +0 -72
  160. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/reference/operators.md +0 -0
  161. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/custom-predicates.md +0 -0
  162. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/field-policies.md +0 -0
  163. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/join-hints.md +0 -0
  164. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/json.md +0 -0
  165. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/page.md +0 -0
  166. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/query.md +0 -0
  167. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/sort.md +0 -0
  168. {pyrsql-0.0.2 → pyrsql-0.0.3}/docs/usage/value-conversion.md +0 -0
  169. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/adapters/__init__.py +0 -0
  170. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/adapters/fastapi/__init__.py +0 -0
  171. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/api.py +0 -0
  172. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/__init__.py +0 -0
  173. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/core/joins.py +0 -0
  174. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/__init__.py +0 -0
  175. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/integrations/fastapi/__init__.py +0 -0
  176. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/orms/sqlalchemy/custom.py +0 -0
  177. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/parsing/tokens.py +0 -0
  178. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/py.typed +0 -0
  179. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/semantic/__init__.py +0 -0
  180. {pyrsql-0.0.2 → pyrsql-0.0.3}/src/pyrsql/sorting/__init__.py +0 -0
  181. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/conftest.py +0 -0
  182. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/__init__.py +0 -0
  183. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/fastapi_adapter/__init__.py +0 -0
  184. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/fastapi_sqlalchemy/__init__.py +0 -0
  185. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/fastapi_sqlalchemy/conftest.py +0 -0
  186. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/fastapi_sqlalchemy/test_integration.py +0 -0
  187. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/functional/test_public_api.py +0 -0
  188. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/__init__.py +0 -0
  189. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/sqlalchemy/__init__.py +0 -0
  190. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/sqlalchemy/conftest.py +0 -0
  191. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/integration/sqlalchemy/test_page_pipeline.py +0 -0
  192. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/__init__.py +0 -0
  193. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/conftest.py +0 -0
  194. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_conversion_bench.py +0 -0
  195. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_json_bench.py +0 -0
  196. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_json_path_builder_bench.py +0 -0
  197. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_parser_bench.py +0 -0
  198. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_selector_bench.py +0 -0
  199. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_semantic_bench.py +0 -0
  200. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/performance/test_sqlalchemy_translation_bench.py +0 -0
  201. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/__init__.py +0 -0
  202. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/adapters/__init__.py +0 -0
  203. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/adapters/fastapi_adapter/__init__.py +0 -0
  204. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/conftest.py +0 -0
  205. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/__init__.py +0 -0
  206. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/conftest.py +0 -0
  207. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/json/__init__.py +0 -0
  208. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/test_query.py +0 -0
  209. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/core/test_sort.py +0 -0
  210. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/integrations/__init__.py +0 -0
  211. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/integrations/fastapi/__init__.py +0 -0
  212. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/integrations/fastapi_sqlalchemy/__init__.py +0 -0
  213. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/integrations/fastapi_sqlalchemy/conftest.py +0 -0
  214. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/__init__.py +0 -0
  215. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/__init__.py +0 -0
  216. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/conftest.py +0 -0
  217. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/test_coercion.py +0 -0
  218. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/test_json_path_builder.py +0 -0
  219. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/orms/sqlalchemy/test_orm.py +0 -0
  220. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/parsing/__init__.py +0 -0
  221. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/selector/__init__.py +0 -0
  222. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/semantic/__init__.py +0 -0
  223. {pyrsql-0.0.2 → pyrsql-0.0.3}/tests/unit/sorting/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyrsql
3
- Version: 0.0.2
3
+ Version: 0.0.3
4
4
  Summary: Compiler-oriented RSQL query engine for safe, typed, and extensible Python ORM-backed APIs.
5
5
  Keywords: rsql,orm,filter,pagination,sort,sqlalchemy,fastapi,rest
6
6
  License-Expression: MIT
@@ -14,12 +14,12 @@ Classifier: Programming Language :: Python :: 3.11
14
14
  Classifier: Programming Language :: Python :: 3.12
15
15
  Classifier: Programming Language :: Python :: 3.13
16
16
  Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: Free Threading
17
18
  Classifier: Framework :: FastAPI
18
19
  Classifier: Topic :: Database
19
20
  Classifier: Topic :: Software Development :: Compilers
20
21
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
22
  Classifier: Typing :: Typed
22
- Requires-Dist: ciso8601>=2.3,<3.0
23
23
  Requires-Dist: msgspec>=0.18,<1.0
24
24
  Requires-Dist: typing-extensions>=4.10.0 ; python_full_version < '3.11'
25
25
  Requires-Dist: fastapi>=0.110,<1.0 ; extra == 'fastapi'
@@ -38,13 +38,13 @@ Description-Content-Type: text/markdown
38
38
  A compiler-oriented RSQL query engine for safe, typed, and extensible
39
39
  filtering, sorting, and pagination in Python APIs.
40
40
 
41
- [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue?logo=python)](https://pypi.org/project/pyrsql/)
41
+ [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14%20%7C%203.14t-blue?logo=python)](https://pypi.org/project/pyrsql/)
42
42
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
43
43
 
44
44
  pyrsql compiles RSQL query strings into ORM-specific statement objects
45
- through a language frontend, semantic binder, logical IR, and pluggable
46
- backend lowering - making it easy to expose complex query capabilities in
47
- your API without coupling to a specific ORM or framework.
45
+ through a language frontend, semantic binding, and pluggable backend
46
+ lowering - making it easy to expose complex query capabilities in your API
47
+ without coupling to a specific ORM or framework.
48
48
 
49
49
  **Current backends:** SQLAlchemy 2.0
50
50
  **Current framework adapters:** FastAPI
@@ -53,9 +53,10 @@ your API without coupling to a specific ORM or framework.
53
53
  ## Why pyrsql?
54
54
 
55
55
  Most API filtering libraries are tightly coupled to one ORM or one framework.
56
- pyrsql is built as a **compiler pipeline** - parsing, semantic analysis, and
57
- IR lowering are separate stages. Adding a new ORM backend means implementing
58
- one interface (`ORM`), not rewriting the parser or query language.
56
+ pyrsql is built as a **compiler pipeline**. Parsing, semantic analysis, and
57
+ backend lowering are separate stages. Adding a new ORM backend means
58
+ implementing one interface (`ORM`), not rewriting the parser or query
59
+ language.
59
60
 
60
61
  - **ORM-neutral core** - `Query`, `Sort`, `PageRequest` have zero ORM dependencies
61
62
  - **Pluggable backends** - implement `compile_query` / `compile_sort` /
@@ -64,6 +65,10 @@ one interface (`ORM`), not rewriting the parser or query language.
64
65
  - **Custom operators** - define your own RSQL operators with per-ORM lowering
65
66
  - **Field policies** - whitelist, blacklist, aliases at global and per-model level
66
67
  - **Type-safe** - strict mypy, Google-style docstrings, immutable value objects
68
+ - **Performance-oriented internals** - immutable `msgspec` models across the
69
+ core pipeline and configuration objects
70
+ - **Security-oriented request handling** - parser/sort limits, structural
71
+ allowlists/blocklists, sanitized FastAPI error payloads
67
72
 
68
73
  ## Quickstart
69
74
 
@@ -196,6 +201,15 @@ def list_users(stmt = Depends(integration.select_dependency(User))):
196
201
  - `select_dependency`, `count_select_dependency`, `paginated_select_dependency`
197
202
  - Declarative `resource()` with auto-generated OpenAPI examples
198
203
  - `applier_dependency` for custom base statements
204
+ - Compatible with both sync `Session` and async `AsyncSession` execution
205
+ - FastAPI parse and page-validation failures become structured `HTTP 400` payloads
206
+ - FastAPI semantic and backend integration failures become structured `HTTP 422` payloads
207
+
208
+ ### Concurrency and Validation
209
+
210
+ - Shared integration and ORM metadata caches are protected for free-threaded execution
211
+ - Async support is validated for adapter, ORM, and integration flows
212
+ - Dedicated async, free-threaded, and security test suites validate these flows
199
213
 
200
214
  ## Documentation
201
215
 
@@ -204,12 +218,13 @@ Full documentation at **[wskr00.github.io/pyrsql](https://wskr00.github.io/pyrsq
204
218
  | Section | Description |
205
219
  |---------|-------------|
206
220
  | [Quickstart](https://wskr00.github.io/pyrsql/quickstart/) | One-minute primer |
207
- | [Usage](https://wskr00.github.io/pyrsql/usage/query/) | Filter, sort, page, JSON, FastAPI, custom predicates |
221
+ | [Usage](https://wskr00.github.io/pyrsql/usage/query/) | Filter, sort, page, JSON, FastAPI, async flows, custom predicates |
208
222
  | [API Reference](https://wskr00.github.io/pyrsql/reference/api/) | Auto-generated from docstrings |
209
223
  | [Operators](https://wskr00.github.io/pyrsql/reference/operators/) | Complete operator table |
210
224
  | [Options](https://wskr00.github.io/pyrsql/reference/options/) | QueryOptions, SortOptions, JSONOptions |
211
225
  | [Architecture](https://wskr00.github.io/pyrsql/explanation/architecture/) | Pipeline, modules, design |
212
226
  | [Extensibility](https://wskr00.github.io/pyrsql/explanation/extensibility/) | Adding backends and adapters |
227
+ | [Testing](https://wskr00.github.io/pyrsql/testing/) | Test layers, async, security, free-threaded validation |
213
228
  | [Contributing](https://wskr00.github.io/pyrsql/contributing/) | Setup, workflow, standards |
214
229
 
215
230
  ## Development Principles
@@ -3,13 +3,13 @@
3
3
  A compiler-oriented RSQL query engine for safe, typed, and extensible
4
4
  filtering, sorting, and pagination in Python APIs.
5
5
 
6
- [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue?logo=python)](https://pypi.org/project/pyrsql/)
6
+ [![Python](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14%20%7C%203.14t-blue?logo=python)](https://pypi.org/project/pyrsql/)
7
7
  [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
8
8
 
9
9
  pyrsql compiles RSQL query strings into ORM-specific statement objects
10
- through a language frontend, semantic binder, logical IR, and pluggable
11
- backend lowering - making it easy to expose complex query capabilities in
12
- your API without coupling to a specific ORM or framework.
10
+ through a language frontend, semantic binding, and pluggable backend
11
+ lowering - making it easy to expose complex query capabilities in your API
12
+ without coupling to a specific ORM or framework.
13
13
 
14
14
  **Current backends:** SQLAlchemy 2.0
15
15
  **Current framework adapters:** FastAPI
@@ -18,9 +18,10 @@ your API without coupling to a specific ORM or framework.
18
18
  ## Why pyrsql?
19
19
 
20
20
  Most API filtering libraries are tightly coupled to one ORM or one framework.
21
- pyrsql is built as a **compiler pipeline** - parsing, semantic analysis, and
22
- IR lowering are separate stages. Adding a new ORM backend means implementing
23
- one interface (`ORM`), not rewriting the parser or query language.
21
+ pyrsql is built as a **compiler pipeline**. Parsing, semantic analysis, and
22
+ backend lowering are separate stages. Adding a new ORM backend means
23
+ implementing one interface (`ORM`), not rewriting the parser or query
24
+ language.
24
25
 
25
26
  - **ORM-neutral core** - `Query`, `Sort`, `PageRequest` have zero ORM dependencies
26
27
  - **Pluggable backends** - implement `compile_query` / `compile_sort` /
@@ -29,6 +30,10 @@ one interface (`ORM`), not rewriting the parser or query language.
29
30
  - **Custom operators** - define your own RSQL operators with per-ORM lowering
30
31
  - **Field policies** - whitelist, blacklist, aliases at global and per-model level
31
32
  - **Type-safe** - strict mypy, Google-style docstrings, immutable value objects
33
+ - **Performance-oriented internals** - immutable `msgspec` models across the
34
+ core pipeline and configuration objects
35
+ - **Security-oriented request handling** - parser/sort limits, structural
36
+ allowlists/blocklists, sanitized FastAPI error payloads
32
37
 
33
38
  ## Quickstart
34
39
 
@@ -161,6 +166,15 @@ def list_users(stmt = Depends(integration.select_dependency(User))):
161
166
  - `select_dependency`, `count_select_dependency`, `paginated_select_dependency`
162
167
  - Declarative `resource()` with auto-generated OpenAPI examples
163
168
  - `applier_dependency` for custom base statements
169
+ - Compatible with both sync `Session` and async `AsyncSession` execution
170
+ - FastAPI parse and page-validation failures become structured `HTTP 400` payloads
171
+ - FastAPI semantic and backend integration failures become structured `HTTP 422` payloads
172
+
173
+ ### Concurrency and Validation
174
+
175
+ - Shared integration and ORM metadata caches are protected for free-threaded execution
176
+ - Async support is validated for adapter, ORM, and integration flows
177
+ - Dedicated async, free-threaded, and security test suites validate these flows
164
178
 
165
179
  ## Documentation
166
180
 
@@ -169,12 +183,13 @@ Full documentation at **[wskr00.github.io/pyrsql](https://wskr00.github.io/pyrsq
169
183
  | Section | Description |
170
184
  |---------|-------------|
171
185
  | [Quickstart](https://wskr00.github.io/pyrsql/quickstart/) | One-minute primer |
172
- | [Usage](https://wskr00.github.io/pyrsql/usage/query/) | Filter, sort, page, JSON, FastAPI, custom predicates |
186
+ | [Usage](https://wskr00.github.io/pyrsql/usage/query/) | Filter, sort, page, JSON, FastAPI, async flows, custom predicates |
173
187
  | [API Reference](https://wskr00.github.io/pyrsql/reference/api/) | Auto-generated from docstrings |
174
188
  | [Operators](https://wskr00.github.io/pyrsql/reference/operators/) | Complete operator table |
175
189
  | [Options](https://wskr00.github.io/pyrsql/reference/options/) | QueryOptions, SortOptions, JSONOptions |
176
190
  | [Architecture](https://wskr00.github.io/pyrsql/explanation/architecture/) | Pipeline, modules, design |
177
191
  | [Extensibility](https://wskr00.github.io/pyrsql/explanation/extensibility/) | Adding backends and adapters |
192
+ | [Testing](https://wskr00.github.io/pyrsql/testing/) | Test layers, async, security, free-threaded validation |
178
193
  | [Contributing](https://wskr00.github.io/pyrsql/contributing/) | Setup, workflow, standards |
179
194
 
180
195
  ## Development Principles
@@ -23,7 +23,7 @@ uv run pytest # tests
23
23
  - strict mypy type checking
24
24
  - ruff for linting and formatting
25
25
  - pytest with `unit`, `integration`, `functional`, `performance` layers
26
- - ORM-neutral core - zero ORM imports in `pyrsql.core`, `pyrsql.ir`, `pyrsql.parsing`, `pyrsql.semantic`
26
+ - ORM-neutral core - zero ORM imports in `pyrsql.core`, `pyrsql.parsing`, `pyrsql.semantic`, `pyrsql.sorting`
27
27
 
28
28
  ## Test layers
29
29
 
@@ -0,0 +1,245 @@
1
+ # pyrsql Architecture
2
+
3
+ ## Identity
4
+
5
+ `pyrsql` is a compiler-oriented RSQL query engine. It turns RSQL-like filter
6
+ and sort expressions into ORM-specific statement updates through a staged
7
+ pipeline:
8
+
9
+ ```text
10
+ query text
11
+ -> parsing
12
+ -> selector AST
13
+ -> semantic binding
14
+ -> backend lowering
15
+ -> ORM-specific statement
16
+ ```
17
+
18
+ The core is deliberately ORM-neutral. Adding a new backend means implementing
19
+ the `ORM` interface, not rewriting the parser, selector grammar, or semantic
20
+ rules.
21
+
22
+ ## Purpose
23
+
24
+ The project is designed around four major responsibilities:
25
+
26
+ - language frontend: parse text into syntax trees
27
+ - semantic binding: resolve fields, functions, and access policies
28
+ - backend lowering: turn validated query objects into ORM-specific statements
29
+ - optional framework adapters and integrations: expose the core in HTTP stacks
30
+
31
+ The current production backend is SQLAlchemy 2.0. The current framework
32
+ adapter is FastAPI.
33
+
34
+ ## Current Pipeline
35
+
36
+ More concretely, the runtime flow looks like this:
37
+
38
+ ```text
39
+ RSQL string
40
+ -> parsing AST
41
+ -> selector nodes
42
+ -> SemanticBinder / SortBinder
43
+ -> Query / Sort / PageRequest application
44
+ -> SQLAlchemyORM lowering
45
+ -> SQLAlchemy Select
46
+ ```
47
+
48
+ For pagination-only flows, `PageRequest` goes directly to backend lowering.
49
+
50
+ ## Module Boundaries
51
+
52
+ The project is split into these main modules:
53
+
54
+ - `parsing`
55
+ - `selector`
56
+ - `semantic`
57
+ - `sorting`
58
+ - `core`
59
+ - `orms`
60
+ - `adapters`
61
+ - `integrations`
62
+ - `api`
63
+
64
+ ### `parsing`
65
+
66
+ Owns:
67
+
68
+ - source spans
69
+ - tokens
70
+ - parser AST
71
+ - parser limits
72
+ - parse diagnostics and errors
73
+
74
+ ### `selector`
75
+
76
+ Owns selector syntax only:
77
+
78
+ - `FieldSelector`
79
+ - `LiteralSelector`
80
+ - `FunctionSelector`
81
+
82
+ It does not own semantic meaning.
83
+
84
+ ### `semantic`
85
+
86
+ Owns semantic binding:
87
+
88
+ - field policy checks
89
+ - function policy checks
90
+ - field mapping
91
+ - semantic diagnostics and errors
92
+ - normalization for backend lowering
93
+
94
+ ### `sorting`
95
+
96
+ Owns sort syntax and sort binding.
97
+
98
+ ### `core`
99
+
100
+ Owns user-facing ORM-agnostic objects:
101
+
102
+ - `Query`, `Sort`, `PageRequest`
103
+ - `QueryOptions`, `SortOptions`
104
+ - `FieldPolicySet`, `ProcedureAccessPolicy`
105
+ - `CustomPredicateDefinition`
106
+ - `ValueConverterRegistry`, `FieldValueConverterSet`
107
+ - `JSONOptions`, `JSONSortScalarType`
108
+ - `JSONPath`, `JSONPathComparison`
109
+ - `JSONScalarNormalizer`, `JSONScalarValue`
110
+ - `JoinHint`
111
+ - `CompilationResult`, `SortCompilationResult`, `PageCompilationResult`
112
+
113
+ The `core/json/` package owns JSON-aware comparison models and value
114
+ normalization, keeping JSON semantics ORM-neutral.
115
+
116
+ ### `orms`
117
+
118
+ Owns backend lowering.
119
+
120
+ Current production backend:
121
+
122
+ - `orms.sqlalchemy`
123
+
124
+ Its job is:
125
+
126
+ - consume normalized query, sort, and page objects
127
+ - resolve model metadata
128
+ - coerce values
129
+ - lower to SQLAlchemy statements
130
+
131
+ It should not redo semantic interpretation already handled upstream.
132
+
133
+ For PostgreSQL JSON/JSONB lowering, the current design separates:
134
+
135
+ - whole-document JSON predicates
136
+ - nested JSON path predicates
137
+ - JSON sort extraction rules
138
+
139
+ This keeps the backend close to SQLAlchemy and PostgreSQL primitives instead of
140
+ forcing every JSON case through one generic lowering path.
141
+
142
+ ### `adapters`
143
+
144
+ Own framework-level request and error adaptation.
145
+
146
+ Current adapter:
147
+
148
+ - `adapters.fastapi`
149
+
150
+ It is responsible for:
151
+
152
+ - extracting query params
153
+ - building `RequestCriteria`
154
+ - translating pyrsql failures into framework-native HTTP errors
155
+ - adding OpenAPI metadata
156
+
157
+ ### `integrations`
158
+
159
+ Own stack-specific orchestration across adapter + backend.
160
+
161
+ Current integration:
162
+
163
+ - `integrations.fastapi.sqlalchemy`
164
+
165
+ It is responsible for:
166
+
167
+ - request criteria application helpers
168
+ - route-ready dependencies
169
+ - declarative resource configuration
170
+ - stack-specific DX
171
+
172
+ ### `api`
173
+
174
+ Owns the smallest public helper surface:
175
+
176
+ - `parse(...)`
177
+ - `compile(...)`
178
+ - `apply(...)`
179
+
180
+ ## Extensibility
181
+
182
+ ### Adding a new ORM backend
183
+
184
+ Implement `pyrsql.orms.base.ORM`:
185
+
186
+ ```python
187
+ class ORM(ABC):
188
+ def compile_query(self, query: Query) -> CompiledQuery: ...
189
+ def compile_sort(self, sort: Sort) -> CompiledSort: ...
190
+ def compile_page_request(self, page_request: PageRequest) -> CompiledPageRequest: ...
191
+ ```
192
+
193
+ Each method receives one ORM-neutral core object and returns a compiled object
194
+ with an `apply(target, model)` method.
195
+
196
+ ### Adding a new framework adapter
197
+
198
+ Implement `pyrsql.adapters.*` to extract query parameters from requests and
199
+ translate pyrsql failures into framework-native HTTP responses.
200
+
201
+ The FastAPI adapter is the reference implementation.
202
+
203
+ ## Design Principles
204
+
205
+ The project follows:
206
+
207
+ - object-oriented design
208
+ - SOLID
209
+ - strong typing
210
+ - backend-independent core semantics
211
+ - performance-oriented data modeling
212
+ - explicit concurrency boundaries
213
+
214
+ ### Practical interpretation
215
+
216
+ - semantic work should happen before the ORM backend
217
+ - ORMs should do lowering, not semantic analysis
218
+ - adapters should do transport adaptation, not query semantics
219
+ - integrations should provide DX, not execution frameworks
220
+
221
+ ## Performance Direction
222
+
223
+ The project uses `msgspec` where it improves compactness and immutable data
224
+ modeling:
225
+
226
+ - diagnostics
227
+ - parser/source structures
228
+ - adapter and integration payloads
229
+ - core query/sort/options/value-policy models
230
+
231
+ Other performance principles:
232
+
233
+ - cache repeated base statements when safe
234
+ - avoid repeating semantic work in the ORM backend
235
+ - keep shared cache lock scope small in concurrency-sensitive paths
236
+
237
+ ## Async and Free-Threaded Support
238
+
239
+ These are related but separate concerns:
240
+
241
+ - async support means generated SQLAlchemy statements work with both `Session`
242
+ and `AsyncSession`
243
+ - free-threaded support means shared mutable caches are synchronized explicitly
244
+
245
+ The core query pipeline stays synchronous and ORM-neutral in both cases.
@@ -0,0 +1,90 @@
1
+ # Extensibility
2
+
3
+ `pyrsql` is designed to support multiple ORM backends and framework adapters.
4
+ The core (`pyrsql.core`, `pyrsql.parsing`, `pyrsql.semantic`,
5
+ `pyrsql.sorting`) has zero dependencies on any ORM or framework.
6
+
7
+ ## Adding a new ORM backend
8
+
9
+ Implement the `ORM` abstract base class:
10
+
11
+ ```python
12
+ from pyrsql.orms.base import ORM, CompiledPageRequest, CompiledQuery, CompiledSort
13
+
14
+ class MyORM(ORM):
15
+ @property
16
+ def name(self) -> str:
17
+ return "my-orm"
18
+
19
+ def compile_query(self, query: Query) -> CompiledQuery:
20
+ ...
21
+
22
+ def compile_sort(self, sort: Sort) -> CompiledSort:
23
+ ...
24
+
25
+ def compile_page_request(self, page_request: PageRequest) -> CompiledPageRequest:
26
+ ...
27
+ ```
28
+
29
+ Each `compile_*` method receives one ORM-neutral core object (`Query`, `Sort`,
30
+ or `PageRequest`) and returns a compiled object with an `apply(target, model)`
31
+ method.
32
+
33
+ The current reference implementation is `SQLAlchemyORM` in
34
+ `pyrsql.orms.sqlalchemy`.
35
+
36
+ ## Adding a new framework adapter
37
+
38
+ Create a module under `pyrsql.adapters` that:
39
+
40
+ 1. extracts query parameters from requests
41
+ 2. builds `RequestCriteria`
42
+ 3. translates parse, semantic, and page-validation failures into
43
+ framework-appropriate error responses
44
+
45
+ The FastAPI adapter (`pyrsql.adapters.fastapi`) is the reference:
46
+
47
+ - `FastAPICriteriaConfig` holds public parameter names and defaults
48
+ - `criteria_dependency()` returns a FastAPI dependency callable
49
+
50
+ ## Backend contract in detail
51
+
52
+ ### `CompiledQuery`
53
+
54
+ ```python
55
+ class CompiledQuery(Protocol):
56
+ def apply(self, target: _TargetT, model: type[_ModelT]) -> _TargetT: ...
57
+ ```
58
+
59
+ Receives an ORM-specific target and model class, then returns the modified
60
+ target with query conditions applied.
61
+
62
+ ### `CompiledSort`
63
+
64
+ Same contract as `CompiledQuery`, but applies sort ordering.
65
+
66
+ ### `CompiledPageRequest`
67
+
68
+ Same contract, but applies pagination semantics such as `LIMIT` and `OFFSET`.
69
+
70
+ ## Integration layer
71
+
72
+ Adapters and ORMs can stay independent. The `integrations/` package is where
73
+ stack-specific DX belongs.
74
+
75
+ For example, `integrations.fastapi.sqlalchemy` is allowed to know both:
76
+
77
+ - the FastAPI adapter contract
78
+ - the SQLAlchemy backend contract
79
+
80
+ That is the right place for:
81
+
82
+ - route-ready dependencies
83
+ - paginated statement bundles
84
+ - OpenAPI example generation tied to SQLAlchemy model metadata
85
+
86
+ ## Planned backends and adapters
87
+
88
+ - **Django ORM** - compile to Django `QuerySet`
89
+ - **SQLModel** - likely reuse most SQLAlchemy lowering
90
+ - **Flask** - request adapter for `request.args`
@@ -34,3 +34,25 @@ stmt = pyrsql.parse("name==demo;age=gt=18").apply(select(User), User, orm=orm)
34
34
  - **Field policies** - whitelist, blacklist, aliases (global + per-model)
35
35
  - **JSON / JSONB** - PostgreSQL `jsonpath` with structured values and datetime support
36
36
  - **Type-safe** - strict mypy, Google-style docstrings, immutable value objects
37
+ - **Async-compatible execution** - generated SQLAlchemy statements work with
38
+ both `Session` and `AsyncSession`
39
+ - **Free-threaded-safe shared caches** - integration and ORM helper caches are
40
+ guarded for concurrent access
41
+ - **Security-oriented request handling** - parser/sort limits, structural
42
+ allowlists/blocklists, and sanitized FastAPI error payloads
43
+
44
+ ## Integration options
45
+
46
+ - **FastAPI adapter** - parse `filter`, `sort`, `page`, and `size` into
47
+ `RequestCriteria`
48
+ - **FastAPI + SQLAlchemy integration** - route-ready dependencies,
49
+ declarative `resource()` helpers, count/paginated bundles, and normalized
50
+ backend error translation
51
+
52
+ ## Next steps
53
+
54
+ - [Quickstart](quickstart.md)
55
+ - [FastAPI Adapter](usage/fastapi.md)
56
+ - [FastAPI + SQLAlchemy](usage/fastapi-sqlalchemy.md)
57
+ - [Async Flows](usage/async.md)
58
+ - [Architecture](explanation/architecture.md)
@@ -0,0 +1,143 @@
1
+ # Quickstart
2
+
3
+ ## Install
4
+
5
+ ```bash
6
+ pip install pyrsql # core only
7
+ pip install pyrsql[sqlalchemy] # with SQLAlchemy
8
+ pip install pyrsql[fastapi] # with FastAPI
9
+ pip install pyrsql[fastapi,sqlalchemy] # both
10
+ ```
11
+
12
+ ## Filter
13
+
14
+ ```python
15
+ from pyrsql import Query
16
+
17
+ Query.parse("name==demo") # equal
18
+ Query.parse("age=gt=18") # greater than
19
+ Query.parse("id=in=(1,2,3)") # IN
20
+ Query.parse("name=like=demo*") # LIKE
21
+ Query.parse("score=bt=(10,20)") # BETWEEN
22
+ Query.parse("name==demo;age=gt=18") # AND
23
+ Query.parse("name==demo,age=gt=18") # OR
24
+ ```
25
+
26
+ ## Sort
27
+
28
+ ```python
29
+ from pyrsql import Sort
30
+
31
+ Sort.parse("name") # ascending
32
+ Sort.parse("name,desc") # descending
33
+ Sort.parse("name,asc;company.name,desc") # multi-field
34
+ ```
35
+
36
+ ## Paginate
37
+
38
+ ```python
39
+ from pyrsql import PageRequest
40
+
41
+ PageRequest.of(0, 25) # first page, 25 items
42
+ PageRequest.of(2, 25) # third page, 25 items
43
+ ```
44
+
45
+ ## SQLAlchemy
46
+
47
+ ```python
48
+ from pyrsql import PageRequest, Query, Sort
49
+ from pyrsql.orms.sqlalchemy import SQLAlchemyORM
50
+ from sqlalchemy import select
51
+
52
+ orm = SQLAlchemyORM()
53
+
54
+ stmt = select(User)
55
+ stmt = Query.parse("name==demo;company.name==acme*").apply(
56
+ stmt,
57
+ User,
58
+ orm=orm,
59
+ )
60
+ stmt = Sort.parse("name,asc;company.name,desc").apply(stmt, User, orm=orm)
61
+ stmt = PageRequest.of(0, 25).apply(stmt, User, orm=orm)
62
+ ```
63
+
64
+ ## FastAPI
65
+
66
+ ```python
67
+ from typing import Annotated
68
+
69
+ from fastapi import Depends, FastAPI
70
+ from pyrsql.adapters.fastapi import RequestCriteria, criteria_dependency
71
+
72
+ app = FastAPI()
73
+
74
+ @app.get("/items")
75
+ def list_items(
76
+ criteria: Annotated[RequestCriteria, Depends(criteria_dependency())],
77
+ ):
78
+ return {"is_empty": criteria.is_empty}
79
+ ```
80
+
81
+ Query params `filter`, `sort`, `page`, `size` are extracted automatically.
82
+ Parse and page-validation errors become structured `HTTP 400` responses.
83
+ Semantic and backend integration errors become structured `HTTP 422`
84
+ responses.
85
+
86
+ ## FastAPI + SQLAlchemy
87
+
88
+ ```python
89
+ from typing import Annotated, Any
90
+
91
+ from fastapi import Depends, FastAPI
92
+
93
+ from pyrsql.integrations.fastapi import FastAPISQLAlchemyIntegration
94
+
95
+ app = FastAPI()
96
+ integration = FastAPISQLAlchemyIntegration()
97
+
98
+ @app.get("/users")
99
+ def list_users(
100
+ stmt: Annotated[Any, Depends(integration.select_dependency(User))],
101
+ ):
102
+ return {"sql": str(stmt)}
103
+ ```
104
+
105
+ Also available:
106
+
107
+ - `count_select_dependency(...)`
108
+ - `paginated_select_dependency(...)`
109
+ - declarative `resource(...)`
110
+
111
+ ## Async execution
112
+
113
+ ```python
114
+ from typing import Annotated, Any
115
+
116
+ from fastapi import Depends, FastAPI
117
+ from sqlalchemy.ext.asyncio import AsyncSession
118
+
119
+ from pyrsql.integrations.fastapi import FastAPISQLAlchemyIntegration
120
+
121
+ app = FastAPI()
122
+ integration = FastAPISQLAlchemyIntegration()
123
+
124
+ @app.get("/users")
125
+ async def list_users(
126
+ stmt: Annotated[Any, Depends(integration.select_dependency(User))],
127
+ session: Annotated[AsyncSession, Depends(get_async_session)],
128
+ ):
129
+ result = await session.scalars(stmt)
130
+ return result.all()
131
+ ```
132
+
133
+ `pyrsql` builds statements only; your application decides whether to execute
134
+ them through sync or async SQLAlchemy sessions.
135
+
136
+ ## Notes
137
+
138
+ - `pyrsql` builds statements and criteria objects only. Your application
139
+ decides whether execution happens through sync or async SQLAlchemy sessions.
140
+ - Shared integration and ORM metadata caches are validated for free-threaded
141
+ execution.
142
+ - Dedicated async, free-threaded, and security suites are documented in
143
+ [Testing](testing.md).
@@ -36,7 +36,6 @@
36
36
  - `pyrsql.integrations.fastapi` - FastAPI + SQLAlchemy (FastAPISQLAlchemyIntegration, FastAPISQLAlchemyResource)
37
37
  - `pyrsql.orms.sqlalchemy` - SQLAlchemy backend (SQLAlchemyORM)
38
38
  - `pyrsql.core` - ORM-neutral core types and options
39
- - `pyrsql.ir` - Logical intermediate representation
40
39
  - `pyrsql.parsing` - Lexer, parser, operators, limits
41
40
  - `pyrsql.selector` - Selector syntax
42
41
  - `pyrsql.semantic` - Semantic binding