pyrsql 0.0.1__tar.gz → 0.0.2__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 (235) hide show
  1. pyrsql-0.0.2/PKG-INFO +225 -0
  2. pyrsql-0.0.2/README.md +190 -0
  3. pyrsql-0.0.2/docs/contributing.md +49 -0
  4. pyrsql-0.0.2/docs/explanation/architecture.md +352 -0
  5. pyrsql-0.0.2/docs/explanation/extensibility.md +72 -0
  6. pyrsql-0.0.2/docs/index.md +36 -0
  7. pyrsql-0.0.2/docs/quickstart.md +71 -0
  8. pyrsql-0.0.2/docs/reference/api.md +43 -0
  9. pyrsql-0.0.2/docs/reference/operators.md +37 -0
  10. pyrsql-0.0.2/docs/reference/options.md +66 -0
  11. pyrsql-0.0.2/docs/testing.md +152 -0
  12. pyrsql-0.0.2/docs/usage/custom-predicates.md +53 -0
  13. pyrsql-0.0.2/docs/usage/fastapi-sqlalchemy.md +85 -0
  14. pyrsql-0.0.2/docs/usage/fastapi.md +86 -0
  15. pyrsql-0.0.2/docs/usage/field-policies.md +46 -0
  16. pyrsql-0.0.2/docs/usage/join-hints.md +20 -0
  17. pyrsql-0.0.2/docs/usage/json.md +87 -0
  18. pyrsql-0.0.2/docs/usage/page.md +31 -0
  19. pyrsql-0.0.2/docs/usage/query.md +125 -0
  20. pyrsql-0.0.2/docs/usage/sort.md +42 -0
  21. pyrsql-0.0.2/docs/usage/value-conversion.md +44 -0
  22. pyrsql-0.0.2/pyproject.toml +225 -0
  23. pyrsql-0.0.2/src/pyrsql/__init__.py +55 -0
  24. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/adapters/__init__.py +1 -1
  25. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/adapters/fastapi/__init__.py +2 -2
  26. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/adapters/fastapi/config.py +62 -8
  27. pyrsql-0.0.2/src/pyrsql/adapters/fastapi/criteria.py +94 -0
  28. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/adapters/fastapi/dependency.py +64 -22
  29. pyrsql-0.0.2/src/pyrsql/adapters/fastapi/errors.py +218 -0
  30. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/api.py +15 -14
  31. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/__init__.py +7 -1
  32. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/compiler.py +58 -12
  33. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/conversion.py +153 -47
  34. pyrsql-0.0.2/src/pyrsql/core/custom.py +22 -0
  35. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/field_policy.py +18 -4
  36. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/json/__init__.py +7 -1
  37. pyrsql-0.0.2/src/pyrsql/core/json/options.py +107 -0
  38. pyrsql-0.0.2/src/pyrsql/core/json/path.py +85 -0
  39. pyrsql-0.0.2/src/pyrsql/core/json/query.py +68 -0
  40. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/json/values.py +37 -16
  41. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/options.py +275 -143
  42. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/page.py +51 -14
  43. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/procedure_policy.py +37 -9
  44. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/query.py +47 -28
  45. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/sort.py +47 -26
  46. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/integrations/__init__.py +6 -1
  47. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/integrations/fastapi/__init__.py +6 -1
  48. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/__init__.py +11 -0
  49. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/examples.py +114 -0
  50. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/helpers.py +83 -0
  51. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/integration.py +409 -0
  52. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/payloads.py +29 -0
  53. pyrsql-0.0.2/src/pyrsql/integrations/fastapi/sqlalchemy/resource.py +326 -0
  54. pyrsql-0.0.2/src/pyrsql/ir/__init__.py +28 -0
  55. pyrsql-0.0.2/src/pyrsql/ir/page.py +40 -0
  56. pyrsql-0.0.2/src/pyrsql/ir/query.py +181 -0
  57. pyrsql-0.0.2/src/pyrsql/ir/sort.py +50 -0
  58. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/base.py +17 -8
  59. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/coercion.py +27 -10
  60. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/compiled.py +19 -9
  61. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/compiled_page.py +18 -10
  62. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/compiled_sort.py +22 -10
  63. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/custom.py +12 -5
  64. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/errors.py +1 -1
  65. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/introspection.py +77 -30
  66. pyrsql-0.0.2/src/pyrsql/orms/sqlalchemy/json_path.py +655 -0
  67. pyrsql-0.0.2/src/pyrsql/orms/sqlalchemy/orm.py +98 -0
  68. pyrsql-0.0.2/src/pyrsql/orms/sqlalchemy/resolver.py +251 -0
  69. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/sorter.py +112 -57
  70. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/statement.py +28 -5
  71. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/translator.py +268 -195
  72. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/type_inference.py +10 -2
  73. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/types.py +26 -10
  74. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/parsing/__init__.py +6 -1
  75. pyrsql-0.0.2/src/pyrsql/parsing/ast.py +123 -0
  76. pyrsql-0.0.2/src/pyrsql/parsing/diagnostics.py +29 -0
  77. pyrsql-0.0.2/src/pyrsql/parsing/errors.py +47 -0
  78. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/parsing/lexer.py +112 -44
  79. pyrsql-0.0.2/src/pyrsql/parsing/limits.py +36 -0
  80. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/parsing/operators.py +58 -10
  81. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/parsing/parser.py +139 -37
  82. pyrsql-0.0.2/src/pyrsql/parsing/source.py +83 -0
  83. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/parsing/tokens.py +8 -4
  84. pyrsql-0.0.2/src/pyrsql/selector/__init__.py +25 -0
  85. pyrsql-0.0.2/src/pyrsql/selector/ast.py +86 -0
  86. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/selector/parser.py +70 -22
  87. pyrsql-0.0.2/src/pyrsql/semantic/__init__.py +21 -0
  88. pyrsql-0.0.2/src/pyrsql/semantic/binder.py +237 -0
  89. pyrsql-0.0.2/src/pyrsql/semantic/diagnostics.py +29 -0
  90. pyrsql-0.0.2/src/pyrsql/semantic/errors.py +69 -0
  91. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/sorting/__init__.py +6 -2
  92. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/sorting/ast.py +22 -7
  93. pyrsql-0.0.2/src/pyrsql/sorting/binder.py +184 -0
  94. pyrsql-0.0.2/src/pyrsql/sorting/diagnostics.py +18 -0
  95. pyrsql-0.0.2/src/pyrsql/sorting/errors.py +66 -0
  96. pyrsql-0.0.2/src/pyrsql/sorting/limits.py +27 -0
  97. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/sorting/parser.py +68 -21
  98. pyrsql-0.0.2/tests/conftest.py +1 -0
  99. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/functional/fastapi_adapter/test_dependency.py +81 -7
  100. pyrsql-0.0.2/tests/functional/fastapi_sqlalchemy/conftest.py +24 -0
  101. pyrsql-0.0.2/tests/functional/fastapi_sqlalchemy/test_integration.py +249 -0
  102. pyrsql-0.0.2/tests/functional/test_public_api.py +175 -0
  103. pyrsql-0.0.2/tests/integration/sqlalchemy/conftest.py +122 -0
  104. pyrsql-0.0.2/tests/integration/sqlalchemy/test_page_pipeline.py +37 -0
  105. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/integration/sqlalchemy/test_query_pipeline.py +120 -201
  106. pyrsql-0.0.2/tests/integration/sqlalchemy/test_sort_pipeline.py +185 -0
  107. pyrsql-0.0.2/tests/performance/conftest.py +67 -0
  108. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/test_conversion_bench.py +7 -7
  109. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/test_json_bench.py +7 -7
  110. pyrsql-0.0.2/tests/performance/test_json_path_builder_bench.py +72 -0
  111. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/test_parser_bench.py +4 -8
  112. pyrsql-0.0.2/tests/performance/test_path_resolver_bench.py +70 -0
  113. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/test_selector_bench.py +3 -3
  114. pyrsql-0.0.2/tests/performance/test_semantic_bench.py +35 -0
  115. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/test_sqlalchemy_translation_bench.py +17 -30
  116. pyrsql-0.0.2/tests/unit/__init__.py +1 -0
  117. pyrsql-0.0.2/tests/unit/adapters/__init__.py +1 -0
  118. pyrsql-0.0.2/tests/unit/adapters/fastapi_adapter/conftest.py +70 -0
  119. pyrsql-0.0.2/tests/unit/adapters/fastapi_adapter/test_config.py +109 -0
  120. pyrsql-0.0.2/tests/unit/adapters/fastapi_adapter/test_criteria.py +143 -0
  121. pyrsql-0.0.2/tests/unit/conftest.py +12 -0
  122. pyrsql-0.0.2/tests/unit/core/conftest.py +97 -0
  123. pyrsql-0.0.2/tests/unit/core/json/test_options.py +98 -0
  124. pyrsql-0.0.2/tests/unit/core/json/test_path.py +42 -0
  125. pyrsql-0.0.2/tests/unit/core/json/test_query.py +82 -0
  126. pyrsql-0.0.2/tests/unit/core/json/test_values.py +31 -0
  127. pyrsql-0.0.2/tests/unit/core/test_conversion.py +169 -0
  128. pyrsql-0.0.2/tests/unit/core/test_options.py +245 -0
  129. pyrsql-0.0.2/tests/unit/core/test_page.py +91 -0
  130. pyrsql-0.0.2/tests/unit/core/test_query.py +103 -0
  131. pyrsql-0.0.2/tests/unit/core/test_sort.py +89 -0
  132. pyrsql-0.0.2/tests/unit/integrations/fastapi_sqlalchemy/conftest.py +82 -0
  133. pyrsql-0.0.2/tests/unit/integrations/fastapi_sqlalchemy/test_integration.py +481 -0
  134. pyrsql-0.0.2/tests/unit/ir/__init__.py +1 -0
  135. pyrsql-0.0.2/tests/unit/ir/test_page.py +32 -0
  136. pyrsql-0.0.2/tests/unit/ir/test_query.py +124 -0
  137. pyrsql-0.0.2/tests/unit/ir/test_sort.py +72 -0
  138. pyrsql-0.0.2/tests/unit/orms/sqlalchemy/conftest.py +83 -0
  139. pyrsql-0.0.2/tests/unit/orms/sqlalchemy/test_coercion.py +81 -0
  140. pyrsql-0.0.2/tests/unit/orms/sqlalchemy/test_json_path_builder.py +97 -0
  141. pyrsql-0.0.2/tests/unit/orms/sqlalchemy/test_orm.py +26 -0
  142. pyrsql-0.0.2/tests/unit/orms/sqlalchemy/test_resolver.py +223 -0
  143. pyrsql-0.0.2/tests/unit/parsing/test_lexer.py +136 -0
  144. pyrsql-0.0.2/tests/unit/parsing/test_parser.py +174 -0
  145. pyrsql-0.0.2/tests/unit/selector/test_parser.py +124 -0
  146. pyrsql-0.0.2/tests/unit/semantic/test_binder.py +192 -0
  147. pyrsql-0.0.2/tests/unit/sorting/test_binder.py +157 -0
  148. pyrsql-0.0.2/tests/unit/sorting/test_parser.py +136 -0
  149. pyrsql-0.0.1/PKG-INFO +0 -72
  150. pyrsql-0.0.1/README.md +0 -43
  151. pyrsql-0.0.1/docs/architecture.md +0 -461
  152. pyrsql-0.0.1/docs/pyguide.md +0 -3709
  153. pyrsql-0.0.1/docs/quality.md +0 -94
  154. pyrsql-0.0.1/docs/reference.md +0 -199
  155. pyrsql-0.0.1/docs/testing.md +0 -228
  156. pyrsql-0.0.1/docs/usage.md +0 -631
  157. pyrsql-0.0.1/pyproject.toml +0 -117
  158. pyrsql-0.0.1/src/pyrsql/__init__.py +0 -63
  159. pyrsql-0.0.1/src/pyrsql/adapters/fastapi/criteria.py +0 -56
  160. pyrsql-0.0.1/src/pyrsql/adapters/fastapi/errors.py +0 -107
  161. pyrsql-0.0.1/src/pyrsql/core/custom.py +0 -14
  162. pyrsql-0.0.1/src/pyrsql/core/json/options.py +0 -31
  163. pyrsql-0.0.1/src/pyrsql/core/json/path.py +0 -35
  164. pyrsql-0.0.1/src/pyrsql/core/json/query.py +0 -39
  165. pyrsql-0.0.1/src/pyrsql/integrations/fastapi/sqlalchemy.py +0 -251
  166. pyrsql-0.0.1/src/pyrsql/orms/sqlalchemy/json_path.py +0 -351
  167. pyrsql-0.0.1/src/pyrsql/orms/sqlalchemy/orm.py +0 -65
  168. pyrsql-0.0.1/src/pyrsql/orms/sqlalchemy/resolver.py +0 -202
  169. pyrsql-0.0.1/src/pyrsql/parsing/ast.py +0 -61
  170. pyrsql-0.0.1/src/pyrsql/parsing/errors.py +0 -25
  171. pyrsql-0.0.1/src/pyrsql/parsing/limits.py +0 -15
  172. pyrsql-0.0.1/src/pyrsql/parsing/source.py +0 -48
  173. pyrsql-0.0.1/src/pyrsql/selector/__init__.py +0 -30
  174. pyrsql-0.0.1/src/pyrsql/selector/analyzer.py +0 -58
  175. pyrsql-0.0.1/src/pyrsql/selector/ast.py +0 -31
  176. pyrsql-0.0.1/src/pyrsql/selector/semantic.py +0 -34
  177. pyrsql-0.0.1/src/pyrsql/semantic/__init__.py +0 -23
  178. pyrsql-0.0.1/src/pyrsql/semantic/analyzer.py +0 -116
  179. pyrsql-0.0.1/src/pyrsql/semantic/ast.py +0 -35
  180. pyrsql-0.0.1/src/pyrsql/semantic/errors.py +0 -40
  181. pyrsql-0.0.1/src/pyrsql/sorting/analyzer.py +0 -74
  182. pyrsql-0.0.1/src/pyrsql/sorting/errors.py +0 -21
  183. pyrsql-0.0.1/src/pyrsql/sorting/limits.py +0 -15
  184. pyrsql-0.0.1/src/pyrsql/sorting/semantic.py +0 -15
  185. pyrsql-0.0.1/tests/conftest.py +0 -31
  186. pyrsql-0.0.1/tests/fixtures/__init__.py +0 -1
  187. pyrsql-0.0.1/tests/fixtures/orms.py +0 -1
  188. pyrsql-0.0.1/tests/fixtures/query_samples.py +0 -1
  189. pyrsql-0.0.1/tests/fixtures/sqlalchemy_models.py +0 -1
  190. pyrsql-0.0.1/tests/functional/fastapi_sqlalchemy/test_integration.py +0 -126
  191. pyrsql-0.0.1/tests/functional/test_public_api.py +0 -80
  192. pyrsql-0.0.1/tests/integration/sqlalchemy/test_page_pipeline.py +0 -65
  193. pyrsql-0.0.1/tests/integration/sqlalchemy/test_sort_pipeline.py +0 -177
  194. pyrsql-0.0.1/tests/performance/test_semantic_bench.py +0 -36
  195. pyrsql-0.0.1/tests/unit/adapters/fastapi_adapter/test_config.py +0 -40
  196. pyrsql-0.0.1/tests/unit/adapters/fastapi_adapter/test_criteria.py +0 -83
  197. pyrsql-0.0.1/tests/unit/core/json/test_options.py +0 -32
  198. pyrsql-0.0.1/tests/unit/core/json/test_path.py +0 -20
  199. pyrsql-0.0.1/tests/unit/core/json/test_query.py +0 -28
  200. pyrsql-0.0.1/tests/unit/core/json/test_values.py +0 -21
  201. pyrsql-0.0.1/tests/unit/core/test_conversion.py +0 -109
  202. pyrsql-0.0.1/tests/unit/core/test_options.py +0 -160
  203. pyrsql-0.0.1/tests/unit/core/test_page.py +0 -99
  204. pyrsql-0.0.1/tests/unit/core/test_query.py +0 -87
  205. pyrsql-0.0.1/tests/unit/core/test_sort.py +0 -62
  206. pyrsql-0.0.1/tests/unit/integrations/fastapi_sqlalchemy/test_integration.py +0 -136
  207. pyrsql-0.0.1/tests/unit/orms/sqlalchemy/test_resolver.py +0 -187
  208. pyrsql-0.0.1/tests/unit/parsing/test_lexer.py +0 -78
  209. pyrsql-0.0.1/tests/unit/parsing/test_parser.py +0 -108
  210. pyrsql-0.0.1/tests/unit/selector/test_parser.py +0 -13
  211. pyrsql-0.0.1/tests/unit/semantic/test_analyzer.py +0 -93
  212. pyrsql-0.0.1/tests/unit/sorting/test_analyzer.py +0 -80
  213. pyrsql-0.0.1/tests/unit/sorting/test_parser.py +0 -81
  214. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/core/joins.py +0 -0
  215. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/__init__.py +0 -0
  216. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/orms/sqlalchemy/__init__.py +4 -4
  217. {pyrsql-0.0.1 → pyrsql-0.0.2}/src/pyrsql/py.typed +0 -0
  218. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/functional/__init__.py +0 -0
  219. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/functional/fastapi_adapter/__init__.py +0 -0
  220. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/functional/fastapi_sqlalchemy/__init__.py +0 -0
  221. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/integration/__init__.py +0 -0
  222. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/integration/sqlalchemy/__init__.py +0 -0
  223. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/performance/__init__.py +0 -0
  224. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/adapters/fastapi_adapter/__init__.py +0 -0
  225. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/core/__init__.py +0 -0
  226. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/core/json/__init__.py +0 -0
  227. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/integrations/__init__.py +0 -0
  228. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/integrations/fastapi/__init__.py +0 -0
  229. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/integrations/fastapi_sqlalchemy/__init__.py +0 -0
  230. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/orms/__init__.py +0 -0
  231. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/orms/sqlalchemy/__init__.py +0 -0
  232. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/parsing/__init__.py +0 -0
  233. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/selector/__init__.py +0 -0
  234. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/semantic/__init__.py +0 -0
  235. {pyrsql-0.0.1 → pyrsql-0.0.2}/tests/unit/sorting/__init__.py +0 -0
pyrsql-0.0.2/PKG-INFO ADDED
@@ -0,0 +1,225 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyrsql
3
+ Version: 0.0.2
4
+ Summary: Compiler-oriented RSQL query engine for safe, typed, and extensible Python ORM-backed APIs.
5
+ Keywords: rsql,orm,filter,pagination,sort,sqlalchemy,fastapi,rest
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Environment :: Web Environment
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Information Technology
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Framework :: FastAPI
18
+ Classifier: Topic :: Database
19
+ Classifier: Topic :: Software Development :: Compilers
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Classifier: Typing :: Typed
22
+ Requires-Dist: ciso8601>=2.3,<3.0
23
+ Requires-Dist: msgspec>=0.18,<1.0
24
+ Requires-Dist: typing-extensions>=4.10.0 ; python_full_version < '3.11'
25
+ Requires-Dist: fastapi>=0.110,<1.0 ; extra == 'fastapi'
26
+ Requires-Dist: sqlalchemy>=2.0,<3.0 ; extra == 'sqlalchemy'
27
+ Requires-Python: >=3.10
28
+ Project-URL: Homepage, https://github.com/wskr00/pyrsql
29
+ Project-URL: Repository, https://github.com/wskr00/pyrsql
30
+ Project-URL: Issues, https://github.com/wskr00/pyrsql/issues
31
+ Project-URL: Documentation, https://wskr00.github.io/pyrsql/
32
+ Provides-Extra: fastapi
33
+ Provides-Extra: sqlalchemy
34
+ Description-Content-Type: text/markdown
35
+
36
+ # pyrsql
37
+
38
+ A compiler-oriented RSQL query engine for safe, typed, and extensible
39
+ filtering, sorting, and pagination in Python APIs.
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/)
42
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
43
+
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.
48
+
49
+ **Current backends:** SQLAlchemy 2.0
50
+ **Current framework adapters:** FastAPI
51
+ **Planned:** Django ORM, SQLModel, Flask
52
+
53
+ ## Why pyrsql?
54
+
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.
59
+
60
+ - **ORM-neutral core** - `Query`, `Sort`, `PageRequest` have zero ORM dependencies
61
+ - **Pluggable backends** - implement `compile_query` / `compile_sort` /
62
+ `compile_page_request` for any ORM
63
+ - **Pluggable framework adapters** - FastAPI today, Flask/Django tomorrow
64
+ - **Custom operators** - define your own RSQL operators with per-ORM lowering
65
+ - **Field policies** - whitelist, blacklist, aliases at global and per-model level
66
+ - **Type-safe** - strict mypy, Google-style docstrings, immutable value objects
67
+
68
+ ## Quickstart
69
+
70
+ ```bash
71
+ pip install pyrsql[sqlalchemy]
72
+ ```
73
+
74
+ ```python
75
+ import pyrsql
76
+ from sqlalchemy import select
77
+ from pyrsql.orms.sqlalchemy import SQLAlchemyORM
78
+
79
+ orm = SQLAlchemyORM()
80
+ stmt = select(User)
81
+
82
+ # Filter: name equals "demo", company name contains "acme"
83
+ stmt = pyrsql.parse("name==demo;company.name==acme*").apply(stmt, User, orm=orm)
84
+
85
+ # Sort: by name ascending, then company name descending
86
+ stmt = pyrsql.Sort.parse("name,asc;company.name,desc").apply(stmt, User, orm=orm)
87
+
88
+ # Paginate: page 0, 25 items per page
89
+ stmt = pyrsql.PageRequest.of(0, 25).apply(stmt, User, orm=orm)
90
+ ```
91
+
92
+ ## Features
93
+
94
+ ### Query (filter)
95
+
96
+ - 20+ built-in operators: `==`, `!=`, `=gt=`, `=ge=`, `=lt=`, `=le=`, `=in=`, `=out=`, `=like=`, `=ilike=`, `=bt=`, `=na=`, `=nn=`, etc.
97
+ - Logical composition: `;` (AND), `,` (OR)
98
+ - Grouping with parentheses
99
+ - Wildcard matching (`*demo*`) and case-insensitive markers (`^demo`)
100
+ - Strict equality mode (literal `*` and `^`)
101
+ - Configurable `LIKE` escape character
102
+ - `SELECT DISTINCT` support
103
+ - Configurable parser limits (query length, depth, argument count)
104
+
105
+ ### Sort
106
+
107
+ - Multi-field: `name,asc;company.name,desc,ic`
108
+ - Ignore-case modifier (`ic`)
109
+ - Function selectors: `@upper[name],asc`
110
+
111
+ ### Pagination
112
+
113
+ - Page-number + page-size API: `PageRequest.of(0, 25)`
114
+ - Offset + limit API: `PageRequest.from_offset(offset=50, limit=25)`
115
+ - Configurable max page size
116
+
117
+ ### Field Mapping & Access Control
118
+
119
+ - Aliases: `field_mapping={"username": "user.name"}`
120
+ - Whitelist/blacklist: `field_whitelist`, `field_blacklist`
121
+ - Per-model policies: `model_field_mapping`, `model_field_whitelist`, `model_field_blacklist`
122
+
123
+ ### Custom Predicates
124
+
125
+ Define custom operators with ORM-specific lowering:
126
+
127
+ ```python
128
+ from pyrsql import CustomPredicateDefinition, QueryOptions
129
+ from pyrsql.parsing.operators import ComparisonOperator
130
+
131
+ all_match = ComparisonOperator(name="all_match", spellings=("=all=",), ...)
132
+ options = QueryOptions(
133
+ custom_predicates={
134
+ "all_match": CustomPredicateDefinition(operator=all_match, argument_type=str),
135
+ },
136
+ )
137
+ ```
138
+
139
+ ### Value Conversion
140
+
141
+ - Built-in: `bool`, `int`, `float`, `Decimal`, `UUID`, `date`, `time`, `datetime`, `enum`
142
+ - Custom converters: `ValueConverterRegistry` + `with_converter`
143
+ - Field-scoped: `field_value_converters={"created_at": my_converter}`
144
+ - Model-scoped: `model_field_value_converters={MyModel: {"field": my_converter}}`
145
+
146
+ ### Join Hints
147
+
148
+ ```python
149
+ from pyrsql import QueryOptions
150
+ from pyrsql.core.joins import JoinHint
151
+
152
+ options = QueryOptions(join_hints={"User.company": JoinHint.LEFT})
153
+ ```
154
+
155
+ ### PostgreSQL JSON / JSONB
156
+
157
+ - **Whole-document**: direct `==`, `!=`, `=in=`, `=out=`, `=na=`, `=nn=` against JSONB columns
158
+ - **Nested path**: `jsonb_path_exists` via PostgreSQL `jsonpath`
159
+ - **Structured values**: arrays and objects passed as `jsonpath` vars
160
+ - **Temporal**: `JSONOptions(use_datetime=True)` for datetime-aware `jsonpath`
161
+ - **JSON sort**: text, integer, float, numeric, boolean, date, time, datetime
162
+ - **Custom function names**: `JSONOptions(path_exists_function=...)`
163
+
164
+ ### FastAPI Integration
165
+
166
+ ```python
167
+ from fastapi import Depends, FastAPI
168
+ from pyrsql.adapters.fastapi import criteria_dependency
169
+
170
+ app = FastAPI()
171
+ dependency = criteria_dependency()
172
+
173
+ @app.get("/items")
174
+ def list_items(criteria = Depends(dependency)):
175
+ ...
176
+ ```
177
+
178
+ - Auto-extracts `filter`, `sort`, `page`, `size` from query params
179
+ - `HTTP 422` with structured diagnostics on parse/semantic errors
180
+ - OpenAPI examples from configuration
181
+ - One-based paging support
182
+ - Custom query parameter names
183
+
184
+ ### FastAPI + SQLAlchemy Integration
185
+
186
+ ```python
187
+ from pyrsql.integrations.fastapi import FastAPISQLAlchemyIntegration
188
+
189
+ integration = FastAPISQLAlchemyIntegration()
190
+
191
+ @app.get("/users")
192
+ def list_users(stmt = Depends(integration.select_dependency(User))):
193
+ return {"sql": str(stmt)}
194
+ ```
195
+
196
+ - `select_dependency`, `count_select_dependency`, `paginated_select_dependency`
197
+ - Declarative `resource()` with auto-generated OpenAPI examples
198
+ - `applier_dependency` for custom base statements
199
+
200
+ ## Documentation
201
+
202
+ Full documentation at **[wskr00.github.io/pyrsql](https://wskr00.github.io/pyrsql/)**.
203
+
204
+ | Section | Description |
205
+ |---------|-------------|
206
+ | [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 |
208
+ | [API Reference](https://wskr00.github.io/pyrsql/reference/api/) | Auto-generated from docstrings |
209
+ | [Operators](https://wskr00.github.io/pyrsql/reference/operators/) | Complete operator table |
210
+ | [Options](https://wskr00.github.io/pyrsql/reference/options/) | QueryOptions, SortOptions, JSONOptions |
211
+ | [Architecture](https://wskr00.github.io/pyrsql/explanation/architecture/) | Pipeline, modules, design |
212
+ | [Extensibility](https://wskr00.github.io/pyrsql/explanation/extensibility/) | Adding backends and adapters |
213
+ | [Contributing](https://wskr00.github.io/pyrsql/contributing/) | Setup, workflow, standards |
214
+
215
+ ## Development Principles
216
+
217
+ - Object-oriented design
218
+ - SOLID principles
219
+ - Google Python Style Guide
220
+ - Strong typing
221
+ - ORM-neutral public API
222
+
223
+ ## License
224
+
225
+ [MIT](LICENSE).
pyrsql-0.0.2/README.md ADDED
@@ -0,0 +1,190 @@
1
+ # pyrsql
2
+
3
+ A compiler-oriented RSQL query engine for safe, typed, and extensible
4
+ filtering, sorting, and pagination in Python APIs.
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/)
7
+ [![License](https://img.shields.io/badge/license-MIT-green)](LICENSE)
8
+
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.
13
+
14
+ **Current backends:** SQLAlchemy 2.0
15
+ **Current framework adapters:** FastAPI
16
+ **Planned:** Django ORM, SQLModel, Flask
17
+
18
+ ## Why pyrsql?
19
+
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.
24
+
25
+ - **ORM-neutral core** - `Query`, `Sort`, `PageRequest` have zero ORM dependencies
26
+ - **Pluggable backends** - implement `compile_query` / `compile_sort` /
27
+ `compile_page_request` for any ORM
28
+ - **Pluggable framework adapters** - FastAPI today, Flask/Django tomorrow
29
+ - **Custom operators** - define your own RSQL operators with per-ORM lowering
30
+ - **Field policies** - whitelist, blacklist, aliases at global and per-model level
31
+ - **Type-safe** - strict mypy, Google-style docstrings, immutable value objects
32
+
33
+ ## Quickstart
34
+
35
+ ```bash
36
+ pip install pyrsql[sqlalchemy]
37
+ ```
38
+
39
+ ```python
40
+ import pyrsql
41
+ from sqlalchemy import select
42
+ from pyrsql.orms.sqlalchemy import SQLAlchemyORM
43
+
44
+ orm = SQLAlchemyORM()
45
+ stmt = select(User)
46
+
47
+ # Filter: name equals "demo", company name contains "acme"
48
+ stmt = pyrsql.parse("name==demo;company.name==acme*").apply(stmt, User, orm=orm)
49
+
50
+ # Sort: by name ascending, then company name descending
51
+ stmt = pyrsql.Sort.parse("name,asc;company.name,desc").apply(stmt, User, orm=orm)
52
+
53
+ # Paginate: page 0, 25 items per page
54
+ stmt = pyrsql.PageRequest.of(0, 25).apply(stmt, User, orm=orm)
55
+ ```
56
+
57
+ ## Features
58
+
59
+ ### Query (filter)
60
+
61
+ - 20+ built-in operators: `==`, `!=`, `=gt=`, `=ge=`, `=lt=`, `=le=`, `=in=`, `=out=`, `=like=`, `=ilike=`, `=bt=`, `=na=`, `=nn=`, etc.
62
+ - Logical composition: `;` (AND), `,` (OR)
63
+ - Grouping with parentheses
64
+ - Wildcard matching (`*demo*`) and case-insensitive markers (`^demo`)
65
+ - Strict equality mode (literal `*` and `^`)
66
+ - Configurable `LIKE` escape character
67
+ - `SELECT DISTINCT` support
68
+ - Configurable parser limits (query length, depth, argument count)
69
+
70
+ ### Sort
71
+
72
+ - Multi-field: `name,asc;company.name,desc,ic`
73
+ - Ignore-case modifier (`ic`)
74
+ - Function selectors: `@upper[name],asc`
75
+
76
+ ### Pagination
77
+
78
+ - Page-number + page-size API: `PageRequest.of(0, 25)`
79
+ - Offset + limit API: `PageRequest.from_offset(offset=50, limit=25)`
80
+ - Configurable max page size
81
+
82
+ ### Field Mapping & Access Control
83
+
84
+ - Aliases: `field_mapping={"username": "user.name"}`
85
+ - Whitelist/blacklist: `field_whitelist`, `field_blacklist`
86
+ - Per-model policies: `model_field_mapping`, `model_field_whitelist`, `model_field_blacklist`
87
+
88
+ ### Custom Predicates
89
+
90
+ Define custom operators with ORM-specific lowering:
91
+
92
+ ```python
93
+ from pyrsql import CustomPredicateDefinition, QueryOptions
94
+ from pyrsql.parsing.operators import ComparisonOperator
95
+
96
+ all_match = ComparisonOperator(name="all_match", spellings=("=all=",), ...)
97
+ options = QueryOptions(
98
+ custom_predicates={
99
+ "all_match": CustomPredicateDefinition(operator=all_match, argument_type=str),
100
+ },
101
+ )
102
+ ```
103
+
104
+ ### Value Conversion
105
+
106
+ - Built-in: `bool`, `int`, `float`, `Decimal`, `UUID`, `date`, `time`, `datetime`, `enum`
107
+ - Custom converters: `ValueConverterRegistry` + `with_converter`
108
+ - Field-scoped: `field_value_converters={"created_at": my_converter}`
109
+ - Model-scoped: `model_field_value_converters={MyModel: {"field": my_converter}}`
110
+
111
+ ### Join Hints
112
+
113
+ ```python
114
+ from pyrsql import QueryOptions
115
+ from pyrsql.core.joins import JoinHint
116
+
117
+ options = QueryOptions(join_hints={"User.company": JoinHint.LEFT})
118
+ ```
119
+
120
+ ### PostgreSQL JSON / JSONB
121
+
122
+ - **Whole-document**: direct `==`, `!=`, `=in=`, `=out=`, `=na=`, `=nn=` against JSONB columns
123
+ - **Nested path**: `jsonb_path_exists` via PostgreSQL `jsonpath`
124
+ - **Structured values**: arrays and objects passed as `jsonpath` vars
125
+ - **Temporal**: `JSONOptions(use_datetime=True)` for datetime-aware `jsonpath`
126
+ - **JSON sort**: text, integer, float, numeric, boolean, date, time, datetime
127
+ - **Custom function names**: `JSONOptions(path_exists_function=...)`
128
+
129
+ ### FastAPI Integration
130
+
131
+ ```python
132
+ from fastapi import Depends, FastAPI
133
+ from pyrsql.adapters.fastapi import criteria_dependency
134
+
135
+ app = FastAPI()
136
+ dependency = criteria_dependency()
137
+
138
+ @app.get("/items")
139
+ def list_items(criteria = Depends(dependency)):
140
+ ...
141
+ ```
142
+
143
+ - Auto-extracts `filter`, `sort`, `page`, `size` from query params
144
+ - `HTTP 422` with structured diagnostics on parse/semantic errors
145
+ - OpenAPI examples from configuration
146
+ - One-based paging support
147
+ - Custom query parameter names
148
+
149
+ ### FastAPI + SQLAlchemy Integration
150
+
151
+ ```python
152
+ from pyrsql.integrations.fastapi import FastAPISQLAlchemyIntegration
153
+
154
+ integration = FastAPISQLAlchemyIntegration()
155
+
156
+ @app.get("/users")
157
+ def list_users(stmt = Depends(integration.select_dependency(User))):
158
+ return {"sql": str(stmt)}
159
+ ```
160
+
161
+ - `select_dependency`, `count_select_dependency`, `paginated_select_dependency`
162
+ - Declarative `resource()` with auto-generated OpenAPI examples
163
+ - `applier_dependency` for custom base statements
164
+
165
+ ## Documentation
166
+
167
+ Full documentation at **[wskr00.github.io/pyrsql](https://wskr00.github.io/pyrsql/)**.
168
+
169
+ | Section | Description |
170
+ |---------|-------------|
171
+ | [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 |
173
+ | [API Reference](https://wskr00.github.io/pyrsql/reference/api/) | Auto-generated from docstrings |
174
+ | [Operators](https://wskr00.github.io/pyrsql/reference/operators/) | Complete operator table |
175
+ | [Options](https://wskr00.github.io/pyrsql/reference/options/) | QueryOptions, SortOptions, JSONOptions |
176
+ | [Architecture](https://wskr00.github.io/pyrsql/explanation/architecture/) | Pipeline, modules, design |
177
+ | [Extensibility](https://wskr00.github.io/pyrsql/explanation/extensibility/) | Adding backends and adapters |
178
+ | [Contributing](https://wskr00.github.io/pyrsql/contributing/) | Setup, workflow, standards |
179
+
180
+ ## Development Principles
181
+
182
+ - Object-oriented design
183
+ - SOLID principles
184
+ - Google Python Style Guide
185
+ - Strong typing
186
+ - ORM-neutral public API
187
+
188
+ ## License
189
+
190
+ [MIT](LICENSE).
@@ -0,0 +1,49 @@
1
+ # Contributing
2
+
3
+ ## Setup
4
+
5
+ ```bash
6
+ git clone https://github.com/wskr00/pyrsql.git
7
+ cd pyrsql
8
+ uv sync --all-extras
9
+ ```
10
+
11
+ ## Development workflow
12
+
13
+ ```bash
14
+ uv run ruff check . # lint
15
+ uv run ruff format . # format
16
+ uv run mypy # type check
17
+ uv run pytest # tests
18
+ ```
19
+
20
+ ## Project standards
21
+
22
+ - Google Python Style Guide
23
+ - strict mypy type checking
24
+ - ruff for linting and formatting
25
+ - pytest with `unit`, `integration`, `functional`, `performance` layers
26
+ - ORM-neutral core - zero ORM imports in `pyrsql.core`, `pyrsql.ir`, `pyrsql.parsing`, `pyrsql.semantic`
27
+
28
+ ## Test layers
29
+
30
+ | Layer | Purpose | Run with |
31
+ |-------|---------|----------|
32
+ | `unit` | Isolated module/class tests | `pytest tests/unit/` |
33
+ | `integration` | Cross-component pipelines | `pytest tests/integration/` |
34
+ | `functional` | Public API behavior | `pytest tests/functional/` |
35
+ | `performance` | Hotspot benchmarks | `pytest tests/performance/` |
36
+
37
+ ## Docs
38
+
39
+ ```bash
40
+ uv run mkdocs serve # live preview at http://localhost:8000
41
+ uv run mkdocs build # build static site
42
+ ```
43
+
44
+ ## Pull requests
45
+
46
+ - Keep PRs focused - one feature or fix per PR
47
+ - Update docs if the public API changes
48
+ - Run `ruff check . && mypy && pytest` before pushing
49
+ - Performance PRs should include benchmark results