querysource 4.1.10__tar.gz → 4.1.11__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 (402) hide show
  1. querysource-4.1.11/CHANGES.rst +54 -0
  2. {querysource-4.1.10 → querysource-4.1.11}/Makefile +9 -3
  3. {querysource-4.1.10/querysource.egg-info → querysource-4.1.11}/PKG-INFO +2 -2
  4. {querysource-4.1.10 → querysource-4.1.11}/pyproject.toml +10 -1
  5. {querysource-4.1.10 → querysource-4.1.11}/querysource/_version.py +3 -3
  6. querysource-4.1.11/querysource/handlers/_pagination.py +413 -0
  7. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/manager.py +145 -28
  8. {querysource-4.1.10 → querysource-4.1.11}/querysource/version.py +1 -1
  9. {querysource-4.1.10 → querysource-4.1.11/querysource.egg-info}/PKG-INFO +2 -2
  10. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/SOURCES.txt +5 -1
  11. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/requires.txt +1 -1
  12. querysource-4.1.11/tests/handlers/__init__.py +0 -0
  13. querysource-4.1.11/tests/handlers/conftest.py +173 -0
  14. querysource-4.1.11/tests/handlers/test_querymanager_pagination.py +560 -0
  15. querysource-4.1.10/CHANGES.rst +0 -16
  16. {querysource-4.1.10 → querysource-4.1.11}/.bumpversion.cfg +0 -0
  17. {querysource-4.1.10 → querysource-4.1.11}/.claude/agents/code-reviewer.md +0 -0
  18. {querysource-4.1.10 → querysource-4.1.11}/.claude/agents/sdd-worker.md +0 -0
  19. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/pr-review.md +0 -0
  20. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-brainstorm.md +0 -0
  21. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-codereview.md +0 -0
  22. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-done.md +0 -0
  23. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-fromjira.md +0 -0
  24. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-next.md +0 -0
  25. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-proposal.md +0 -0
  26. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-spec.md +0 -0
  27. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-start.md +0 -0
  28. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-status.md +0 -0
  29. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-task.md +0 -0
  30. {querysource-4.1.10 → querysource-4.1.11}/.claude/commands/sdd-tojira.md +0 -0
  31. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/aws-cost-optimization.md +0 -0
  32. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/code-reviewer.md +0 -0
  33. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/cython-development.md +0 -0
  34. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/python-development.md +0 -0
  35. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/rust-development.md +0 -0
  36. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/using-git-worktrees.md +0 -0
  37. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/worktree-pr-and-clean.md +0 -0
  38. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/worktree-start-feature.md +0 -0
  39. {querysource-4.1.10 → querysource-4.1.11}/.claude/rules/worktree-status.md +0 -0
  40. {querysource-4.1.10 → querysource-4.1.11}/.github/dependabot.yml +0 -0
  41. {querysource-4.1.10 → querysource-4.1.11}/.github/workflows/codeql-analysis.yml +0 -0
  42. {querysource-4.1.10 → querysource-4.1.11}/.github/workflows/release.yml +0 -0
  43. {querysource-4.1.10 → querysource-4.1.11}/.isort.cfg +0 -0
  44. {querysource-4.1.10 → querysource-4.1.11}/.jupyter/jupyter_notebook_config.py +0 -0
  45. {querysource-4.1.10 → querysource-4.1.11}/.pylintrc +0 -0
  46. {querysource-4.1.10 → querysource-4.1.11}/CODE_OF_CONDUCT.md +0 -0
  47. {querysource-4.1.10 → querysource-4.1.11}/CONTRIBUTING.md +0 -0
  48. {querysource-4.1.10 → querysource-4.1.11}/INSTALL +0 -0
  49. {querysource-4.1.10 → querysource-4.1.11}/LICENSE +0 -0
  50. {querysource-4.1.10 → querysource-4.1.11}/MANIFEST.in +0 -0
  51. {querysource-4.1.10 → querysource-4.1.11}/README.md +0 -0
  52. {querysource-4.1.10 → querysource-4.1.11}/app.py +0 -0
  53. {querysource-4.1.10 → querysource-4.1.11}/bin/README.md +0 -0
  54. {querysource-4.1.10 → querysource-4.1.11}/gunicorn_config.py +0 -0
  55. {querysource-4.1.10 → querysource-4.1.11}/mypy.ini +0 -0
  56. {querysource-4.1.10 → querysource-4.1.11}/nav.py +0 -0
  57. {querysource-4.1.10 → querysource-4.1.11}/pytest.ini +0 -0
  58. {querysource-4.1.10 → querysource-4.1.11}/querysource/__cli__.py +0 -0
  59. {querysource-4.1.10 → querysource-4.1.11}/querysource/__init__.py +0 -0
  60. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/__init__.py +0 -0
  61. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/backends/__init__.py +0 -0
  62. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/backends/abstract.py +0 -0
  63. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/backends/memcache.py +0 -0
  64. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/backends/redis.py +0 -0
  65. {querysource-4.1.10 → querysource-4.1.11}/querysource/cache/base.py +0 -0
  66. {querysource-4.1.10 → querysource-4.1.11}/querysource/conf.py +0 -0
  67. {querysource-4.1.10 → querysource-4.1.11}/querysource/connections.py +0 -0
  68. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/__init__.py +0 -0
  69. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/__init__.py +0 -0
  70. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/abstract.py +0 -0
  71. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/arangodb.py +0 -0
  72. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/athena.py +0 -0
  73. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/bigquery.py +0 -0
  74. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/cassandra.py +0 -0
  75. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/clickhouse.py +0 -0
  76. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/cockroachdb.py +0 -0
  77. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/couchbase.py +0 -0
  78. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/couchdb.py +0 -0
  79. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/countries.py +0 -0
  80. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/delta.py +0 -0
  81. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/documentdb.py +0 -0
  82. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/dynamodb.py +0 -0
  83. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/elastic.py +0 -0
  84. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/ga.py +0 -0
  85. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/gcalc.py +0 -0
  86. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/hazel.py +0 -0
  87. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/iceberg.py +0 -0
  88. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/influx.py +0 -0
  89. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/jdbc.py +0 -0
  90. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/jira.py +0 -0
  91. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/mariadb.py +0 -0
  92. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/memcached.py +0 -0
  93. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/mongo.py +0 -0
  94. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/mysql.py +0 -0
  95. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/odbc.py +0 -0
  96. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/openweather.py +0 -0
  97. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/oracle.py +0 -0
  98. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/pg.py +0 -0
  99. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/postgres.py +0 -0
  100. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/py.typed +0 -0
  101. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/qs.py +0 -0
  102. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/redis.py +0 -0
  103. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/rest.py +0 -0
  104. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/rethink.py +0 -0
  105. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/sa.py +0 -0
  106. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/salesforce.py +0 -0
  107. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/scylladb.py +0 -0
  108. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/sqlalchemy.py +0 -0
  109. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/sqlite.py +0 -0
  110. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/sqlserver.py +0 -0
  111. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/upc.py +0 -0
  112. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/drivers/zipcodeapi.py +0 -0
  113. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/handlers/__init__.py +0 -0
  114. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/handlers/datasource.py +0 -0
  115. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/handlers/utils.py +0 -0
  116. {querysource-4.1.10 → querysource-4.1.11}/querysource/datasources/models.py +0 -0
  117. {querysource-4.1.10 → querysource-4.1.11}/querysource/events/__init__.py +0 -0
  118. {querysource-4.1.10 → querysource-4.1.11}/querysource/exceptions.py +0 -0
  119. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/__init__.py +0 -0
  120. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/abstract.py +0 -0
  121. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/executor.py +0 -0
  122. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/log.py +0 -0
  123. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/multi.py +0 -0
  124. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/outputs/__init__.py +0 -0
  125. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/outputs/tableOutput/__init__.py +0 -0
  126. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/outputs/tableOutput/postgres.py +0 -0
  127. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/outputs/tableOutput/table.py +0 -0
  128. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/service.py +0 -0
  129. {querysource-4.1.10 → querysource-4.1.11}/querysource/handlers/variables.py +0 -0
  130. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/__init__.py +0 -0
  131. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/connections.py +0 -0
  132. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/credentials.py +0 -0
  133. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/__init__.py +0 -0
  134. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/abstract.py +0 -0
  135. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/bigquery.py +0 -0
  136. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/db.py +0 -0
  137. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/mongo.py +0 -0
  138. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/databases/rethink.py +0 -0
  139. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/http.py +0 -0
  140. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/playwright_service.py +0 -0
  141. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/queries.py +0 -0
  142. {querysource-4.1.10 → querysource-4.1.11}/querysource/interfaces/selenium_service.py +0 -0
  143. {querysource-4.1.10 → querysource-4.1.11}/querysource/libs/__init__.py +0 -0
  144. {querysource-4.1.10 → querysource-4.1.11}/querysource/libs/encoders.py +0 -0
  145. {querysource-4.1.10 → querysource-4.1.11}/querysource/libs/functions/__init__.py +0 -0
  146. {querysource-4.1.10 → querysource-4.1.11}/querysource/libs/py.typed +0 -0
  147. {querysource-4.1.10 → querysource-4.1.11}/querysource/models.py +0 -0
  148. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/__init__.py +0 -0
  149. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/__init__.py +0 -0
  150. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/abstract.py +0 -0
  151. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/arrow.py +0 -0
  152. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/dt.py +0 -0
  153. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/factory.py +0 -0
  154. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/iter.py +0 -0
  155. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/modin.py +0 -0
  156. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/pandas.py +0 -0
  157. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/dt/polars.py +0 -0
  158. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/output.py +0 -0
  159. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/__init__.py +0 -0
  160. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/abstract.py +0 -0
  161. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/bigquery.py +0 -0
  162. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/documentdb.py +0 -0
  163. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/mongodb.py +0 -0
  164. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/mysql.py +0 -0
  165. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/postgres.py +0 -0
  166. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/rethink.py +0 -0
  167. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/sa.py +0 -0
  168. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/TableOutput/table.py +0 -0
  169. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/tables/__init__.py +0 -0
  170. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/__init__.py +0 -0
  171. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/abstract.py +0 -0
  172. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/bokeh.py +0 -0
  173. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/clustering.py +0 -0
  174. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/csv.py +0 -0
  175. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/describe.py +0 -0
  176. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/eda.py +0 -0
  177. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/excel.py +0 -0
  178. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/html.py +0 -0
  179. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/json.py +0 -0
  180. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/pdf.py +0 -0
  181. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/pickle.py +0 -0
  182. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/plotly.py +0 -0
  183. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/profiling.py +0 -0
  184. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/report.py +0 -0
  185. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/table.py +0 -0
  186. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/tsv.py +0 -0
  187. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/txt.py +0 -0
  188. {querysource-4.1.10 → querysource-4.1.11}/querysource/outputs/writers/xml.py +0 -0
  189. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/__init__.py +0 -0
  190. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/abstract.c +0 -0
  191. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/abstract.pxd +0 -0
  192. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/abstract.pyx +0 -0
  193. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/arangodb.c +0 -0
  194. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/arangodb.pxd +0 -0
  195. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/arangodb.pyx +0 -0
  196. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/bigquery.c +0 -0
  197. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/bigquery.pxd +0 -0
  198. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/bigquery.pyx +0 -0
  199. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/cql.c +0 -0
  200. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/cql.pxd +0 -0
  201. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/cql.pyx +0 -0
  202. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/deltatbl.c +0 -0
  203. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/deltatbl.pxd +0 -0
  204. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/deltatbl.pyx +0 -0
  205. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/elastic.cpp +0 -0
  206. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/elastic.pxd +0 -0
  207. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/elastic.pyx +0 -0
  208. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/iceberg.c +0 -0
  209. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/iceberg.pxd +0 -0
  210. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/iceberg.pyx +0 -0
  211. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/influx.c +0 -0
  212. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/influx.pxd +0 -0
  213. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/influx.pyx +0 -0
  214. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/mongo.cpp +0 -0
  215. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/mongo.pxd +0 -0
  216. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/mongo.pyx +0 -0
  217. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/parser.c +0 -0
  218. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/parser.pxd +0 -0
  219. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/parser.pyx +0 -0
  220. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/pgsql.c +0 -0
  221. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/pgsql.pxd +0 -0
  222. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/pgsql.pyx +0 -0
  223. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/rethink.c +0 -0
  224. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/rethink.pxd +0 -0
  225. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/rethink.pyx +0 -0
  226. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sosql.c +0 -0
  227. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sosql.pxd +0 -0
  228. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sosql.pyx +0 -0
  229. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sql.c +0 -0
  230. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sql.pxd +0 -0
  231. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sql.pyx +0 -0
  232. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sqlserver.c +0 -0
  233. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sqlserver.pxd +0 -0
  234. {querysource-4.1.10 → querysource-4.1.11}/querysource/parsers/sqlserver.pyx +0 -0
  235. {querysource-4.1.10 → querysource-4.1.11}/querysource/plugins/__init__.py +0 -0
  236. {querysource-4.1.10 → querysource-4.1.11}/querysource/plugins/importer.py +0 -0
  237. {querysource-4.1.10 → querysource-4.1.11}/querysource/plugins/sources/__init__.py +0 -0
  238. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/__init__.py +0 -0
  239. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/abstract.py +0 -0
  240. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/arangodb.py +0 -0
  241. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/bigquery.py +0 -0
  242. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/cassandra.py +0 -0
  243. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/db.py +0 -0
  244. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/default.py +0 -0
  245. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/deltatbl.py +0 -0
  246. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/documentdb.py +0 -0
  247. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/dummy.py +0 -0
  248. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/elastic.py +0 -0
  249. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/external.py +0 -0
  250. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/http.py +0 -0
  251. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/iceberg.py +0 -0
  252. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/influx.py +0 -0
  253. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/mysql.py +0 -0
  254. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/pg.py +0 -0
  255. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/py.typed +0 -0
  256. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/rest.py +0 -0
  257. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/rethink.py +0 -0
  258. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/salesforce.py +0 -0
  259. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/scylladb.py +0 -0
  260. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/__init__.py +0 -0
  261. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/abstract.py +0 -0
  262. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/amazon.py +0 -0
  263. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/countries.py +0 -0
  264. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/ga.py +0 -0
  265. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/geofcc.py +0 -0
  266. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/gmaps.py +0 -0
  267. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/graphcountries.py +0 -0
  268. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/graphql.py +0 -0
  269. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/http.py +0 -0
  270. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/hubspot.py +0 -0
  271. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/openweather.py +0 -0
  272. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/parsers/__init__.py +0 -0
  273. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/parsers/amproduct.py +0 -0
  274. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/parsers/xpath.py +0 -0
  275. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/pokemon.py +0 -0
  276. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/populartimes.py +0 -0
  277. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/py.typed +0 -0
  278. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/rest.py +0 -0
  279. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/retailnext.py +0 -0
  280. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/rssapp.py +0 -0
  281. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/salesforce.py +0 -0
  282. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/scrapper.py +0 -0
  283. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/shoppertrack.py +0 -0
  284. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/swop.py +0 -0
  285. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/uap.py +0 -0
  286. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/upc.py +0 -0
  287. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/wm_stores.py +0 -0
  288. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/zammad.py +0 -0
  289. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sources/zipcodeapi.py +0 -0
  290. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sql.py +0 -0
  291. {querysource-4.1.10 → querysource-4.1.11}/querysource/providers/sqlserver.py +0 -0
  292. {querysource-4.1.10 → querysource-4.1.11}/querysource/py.typed +0 -0
  293. {querysource-4.1.10 → querysource-4.1.11}/querysource/qs_parsers/__init__.py +0 -0
  294. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/__init__.py +0 -0
  295. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/base.py +0 -0
  296. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/executor.py +0 -0
  297. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/models.py +0 -0
  298. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/__init__.py +0 -0
  299. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/components/__init__.py +0 -0
  300. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/Concat.py +0 -0
  301. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/GroupBy.py +0 -0
  302. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/Info.py +0 -0
  303. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/Join.py +0 -0
  304. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/Melt.py +0 -0
  305. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/Merge.py +0 -0
  306. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/__init__.py +0 -0
  307. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/abstract.py +0 -0
  308. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/filter/__init__.py +0 -0
  309. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/operators/filter/flt.py +0 -0
  310. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/sources/__init__.py +0 -0
  311. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/sources/file.py +0 -0
  312. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/sources/query.py +0 -0
  313. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/Forecast.py +0 -0
  314. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/Map.py +0 -0
  315. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/__init__.py +0 -0
  316. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/abstract.py +0 -0
  317. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/correlation.py +0 -0
  318. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/crosstab.py +0 -0
  319. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/google/__init__.py +0 -0
  320. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/google/maps.py +0 -0
  321. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/pivot.py +0 -0
  322. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/tOrder.py +0 -0
  323. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/multi/transformations/tPandas.py +0 -0
  324. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/obj.py +0 -0
  325. {querysource-4.1.10 → querysource-4.1.11}/querysource/queries/qs.py +0 -0
  326. {querysource-4.1.10 → querysource-4.1.11}/querysource/scheduler/__init__.py +0 -0
  327. {querysource-4.1.10 → querysource-4.1.11}/querysource/scheduler/jobs.py +0 -0
  328. {querysource-4.1.10 → querysource-4.1.11}/querysource/scheduler/notifications.py +0 -0
  329. {querysource-4.1.10 → querysource-4.1.11}/querysource/scheduler/scheduler.py +0 -0
  330. {querysource-4.1.10 → querysource-4.1.11}/querysource/services.py +0 -0
  331. {querysource-4.1.10 → querysource-4.1.11}/querysource/template/__init__.py +0 -0
  332. {querysource-4.1.10 → querysource-4.1.11}/querysource/template/parser.py +0 -0
  333. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/__init__.py +0 -0
  334. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/converters.cpp +0 -0
  335. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/converters.pyx +0 -0
  336. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/dt/__init__.py +0 -0
  337. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/dt/filters.py +0 -0
  338. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/dt/transforms.py +0 -0
  339. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/py.typed +0 -0
  340. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/typedefs.c +0 -0
  341. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/typedefs.pyx +0 -0
  342. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/validators.cpp +0 -0
  343. {querysource-4.1.10 → querysource-4.1.11}/querysource/types/validators.pyx +0 -0
  344. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/__init__.py +0 -0
  345. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/cache_serialization.py +0 -0
  346. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/events.py +0 -0
  347. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/fn.py +0 -0
  348. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/functions.cpp +0 -0
  349. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/functions.pyx +0 -0
  350. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/getfunc.py +0 -0
  351. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/handlers.py +0 -0
  352. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/parseqs.cpp +0 -0
  353. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/parseqs.pyx +0 -0
  354. {querysource-4.1.10 → querysource-4.1.11}/querysource/utils/validators.py +0 -0
  355. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/dependency_links.txt +0 -0
  356. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/entry_points.txt +0 -0
  357. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/not-zip-safe +0 -0
  358. {querysource-4.1.10 → querysource-4.1.11}/querysource.egg-info/top_level.txt +0 -0
  359. {querysource-4.1.10 → querysource-4.1.11}/run.py +0 -0
  360. {querysource-4.1.10 → querysource-4.1.11}/rust/Cargo.lock +0 -0
  361. {querysource-4.1.10 → querysource-4.1.11}/rust/Cargo.toml +0 -0
  362. {querysource-4.1.10 → querysource-4.1.11}/rust/pyproject.toml +0 -0
  363. {querysource-4.1.10 → querysource-4.1.11}/rust/src/arangodb_parser.rs +0 -0
  364. {querysource-4.1.10 → querysource-4.1.11}/rust/src/bigquery_parser.rs +0 -0
  365. {querysource-4.1.10 → querysource-4.1.11}/rust/src/cql_parser.rs +0 -0
  366. {querysource-4.1.10 → querysource-4.1.11}/rust/src/elastic_parser.rs +0 -0
  367. {querysource-4.1.10 → querysource-4.1.11}/rust/src/filter_common.rs +0 -0
  368. {querysource-4.1.10 → querysource-4.1.11}/rust/src/flux_parser.rs +0 -0
  369. {querysource-4.1.10 → querysource-4.1.11}/rust/src/lib.rs +0 -0
  370. {querysource-4.1.10 → querysource-4.1.11}/rust/src/mongo_parser.rs +0 -0
  371. {querysource-4.1.10 → querysource-4.1.11}/rust/src/mssql_parser.rs +0 -0
  372. {querysource-4.1.10 → querysource-4.1.11}/rust/src/parseqs.rs +0 -0
  373. {querysource-4.1.10 → querysource-4.1.11}/rust/src/pgsql_parser.rs +0 -0
  374. {querysource-4.1.10 → querysource-4.1.11}/rust/src/rethink_parser.rs +0 -0
  375. {querysource-4.1.10 → querysource-4.1.11}/rust/src/safe_dict.rs +0 -0
  376. {querysource-4.1.10 → querysource-4.1.11}/rust/src/soql_parser.rs +0 -0
  377. {querysource-4.1.10 → querysource-4.1.11}/rust/src/sql_parser.rs +0 -0
  378. {querysource-4.1.10 → querysource-4.1.11}/rust/src/validators.rs +0 -0
  379. {querysource-4.1.10 → querysource-4.1.11}/setup.cfg +0 -0
  380. {querysource-4.1.10 → querysource-4.1.11}/setup.py +0 -0
  381. {querysource-4.1.10 → querysource-4.1.11}/static/notebook/bundle.js +0 -0
  382. {querysource-4.1.10 → querysource-4.1.11}/templates/__init__.py +0 -0
  383. {querysource-4.1.10 → querysource-4.1.11}/templates/base.html +0 -0
  384. {querysource-4.1.10 → querysource-4.1.11}/templates/default.html +0 -0
  385. {querysource-4.1.10 → querysource-4.1.11}/templates/default_table.html +0 -0
  386. {querysource-4.1.10 → querysource-4.1.11}/templates/fontlist-v330.json +0 -0
  387. {querysource-4.1.10 → querysource-4.1.11}/templates/fontlist-v390.json +0 -0
  388. {querysource-4.1.10 → querysource-4.1.11}/templates/table_charts.html +0 -0
  389. {querysource-4.1.10 → querysource-4.1.11}/tests/test_api.py +0 -0
  390. {querysource-4.1.10 → querysource-4.1.11}/tests/test_arangodb_parser.py +0 -0
  391. {querysource-4.1.10 → querysource-4.1.11}/tests/test_column_filters.py +0 -0
  392. {querysource-4.1.10 → querysource-4.1.11}/tests/test_elastic_parser.py +0 -0
  393. {querysource-4.1.10 → querysource-4.1.11}/tests/test_eval.py +0 -0
  394. {querysource-4.1.10 → querysource-4.1.11}/tests/test_join_conditions.py +0 -0
  395. {querysource-4.1.10 → querysource-4.1.11}/tests/test_join_with_column_filter.py +0 -0
  396. {querysource-4.1.10 → querysource-4.1.11}/tests/test_rss.py +0 -0
  397. {querysource-4.1.10 → querysource-4.1.11}/tests/test_rust_parsers.py +0 -0
  398. {querysource-4.1.10 → querysource-4.1.11}/tests/test_scheduler_core.py +0 -0
  399. {querysource-4.1.10 → querysource-4.1.11}/tests/test_scheduler_integration.py +0 -0
  400. {querysource-4.1.10 → querysource-4.1.11}/tests/test_scheduler_jobs.py +0 -0
  401. {querysource-4.1.10 → querysource-4.1.11}/tests/test_scheduler_notifications.py +0 -0
  402. {querysource-4.1.10 → querysource-4.1.11}/tox.ini +0 -0
@@ -0,0 +1,54 @@
1
+ Unreleased
2
+ ==========
3
+
4
+ FEAT-090 — Query Slug list pagination
5
+ -------------------------------------
6
+
7
+ **BREAKING**: ``GET /api/v1/management/queries`` now returns a paginated
8
+ envelope (``{"data": [...], "meta": {...}}``) instead of a bare JSON array.
9
+ The response is capped at 200 rows per request (default page size 50).
10
+
11
+ New query parameters on ``GET /api/v1/management/queries``:
12
+
13
+ - ``page`` (int, default ``1``)
14
+ - ``page_size`` (int, default ``50``, max ``200``)
15
+ - ``sort=<field>[:asc|desc]`` — allowlisted columns only
16
+ (``query_slug``, ``description``, ``program_slug``, ``provider``,
17
+ ``is_cached``, ``created_at``, ``updated_at``)
18
+ - ``search=<term>`` — ``ILIKE '%term%'`` across ``query_slug``,
19
+ ``description``, ``program_slug`` and ``source``
20
+ - ``fields=<csv>`` — same allowlist as before, now validated against
21
+ ``QueryModel.columns`` (unknown columns rejected with ``400``)
22
+
23
+ Any remaining query-string key that matches a ``QueryModel`` column is
24
+ still accepted as an equality filter; unknown / unsafe keys are dropped
25
+ rather than forwarded to SQL.
26
+
27
+ New response headers: ``X-Total-Count``, ``X-Page``, ``X-Page-Size``,
28
+ ``X-Total-Pages``. Empty results return ``204 No Content`` with
29
+ ``X-Total-Count: 0`` (same semantics as the previous ``NoDataFound`` path).
30
+
31
+ Unchanged:
32
+
33
+ - ``GET /api/v1/management/queries/{slug}``
34
+ - ``GET /api/v1/management/queries:meta``
35
+ - ``GET /api/v1/management/queries/{slug}:insert``
36
+ - ``PUT`` / ``POST`` / ``PATCH`` / ``DELETE`` verbs
37
+
38
+
39
+ 2.8.0 (2022-09-29)
40
+ ==================
41
+
42
+ - new support for models based on datamodel
43
+ - upgraded version of asyncdb
44
+ - migrated parsers to cython
45
+ - added support for stored procedures in SQL Server driver.
46
+
47
+
48
+ 2.7.7 (2022-08-02)
49
+ ==================
50
+
51
+ - Removing dependency of navigator.conf
52
+ - added new navigator-session dependency
53
+ - security fixes
54
+ - bump version packages.
@@ -1,7 +1,7 @@
1
1
  # QuerySource Makefile
2
2
  # This Makefile provides a set of commands to manage the QuerySource project.
3
3
 
4
- .PHONY: venv install develop setup dev release format lint test clean distclean lock sync
4
+ .PHONY: venv install develop setup dev release format lint test clean distclean lock sync build-rust
5
5
 
6
6
  # Python version to use
7
7
  PYTHON_VERSION := 3.11
@@ -22,7 +22,7 @@ venv:
22
22
  @echo 'run `source .venv/bin/activate` to start develop with QuerySource.'
23
23
 
24
24
  # Install production dependencies using lock file
25
- install:
25
+ install: build-rust
26
26
  uv sync --frozen --no-dev --extra analytics --extra vectors
27
27
  uv pip install navigator-api[uvloop,locale]
28
28
  @echo "Production dependencies installed. Use 'make develop' for development setup."
@@ -36,9 +36,14 @@ else
36
36
  endif
37
37
 
38
38
  # Install all dependencies including dev dependencies
39
- develop:
39
+ develop: build-rust
40
40
  uv sync --frozen --extra analytics --extra dev
41
41
 
42
+ # Build the Rust-accelerated parser extension (querysource.qs_parsers._qs_parsers)
43
+ build-rust:
44
+ @command -v maturin >/dev/null 2>&1 || uv pip install maturin
45
+ maturin develop --release
46
+
42
47
  # Alternative: install without lock file (faster for development)
43
48
  develop-fast:
44
49
  uv pip install -e .[analytics,dev]
@@ -187,5 +192,6 @@ help:
187
192
  @echo " detect-tools - Show detected tools"
188
193
  @echo " install-uv - Install uv"
189
194
  @echo " build-inplace - Build Cython extensions in place"
195
+ @echo " build-rust - Build the Rust parser extension via maturin"
190
196
  @echo ""
191
197
  @echo "Current setup: $(TOOL_INFO)"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: querysource
3
- Version: 4.1.10
3
+ Version: 4.1.11
4
4
  Summary: Aiohttp web service for querying several databases easily
5
5
  Author-email: Jesus Lara <jesuslarag@gmail.com>
6
6
  License: BSD-3-Clause
@@ -55,7 +55,7 @@ Requires-Dist: webdriver-manager>=4.0.2
55
55
  Requires-Dist: playwright==1.52.0
56
56
  Requires-Dist: proxylists>=0.14.0
57
57
  Requires-Dist: async-notify[all]>=1.4.0
58
- Requires-Dist: navconfig[default,uvloop]>=1.7.13
58
+ Requires-Dist: navconfig[default,uvloop]==2.1.3
59
59
  Requires-Dist: navigator-api[locale,uvloop]>=2.12.22
60
60
  Requires-Dist: jsonschema>=4.22.0
61
61
  Requires-Dist: backoff==2.2.1
@@ -68,7 +68,7 @@ dependencies = [
68
68
  # NAV libraries - using compatible versions
69
69
  "proxylists>=0.14.0",
70
70
  "async-notify[all]>=1.4.0",
71
- "navconfig[uvloop,default]>=1.7.13",
71
+ "navconfig[default,uvloop]==2.1.3",
72
72
  "navigator-api[uvloop,locale]>=2.12.22",
73
73
  "jsonschema>=4.22.0",
74
74
  # Backoff Support
@@ -184,3 +184,12 @@ manifest-path = "rust/Cargo.toml"
184
184
  module-name = "querysource.qs_parsers._qs_parsers"
185
185
  bindings = "pyo3"
186
186
  features = ["pyo3/extension-module"]
187
+
188
+ # ---------------------------------------------------------------------------
189
+ # uv install settings
190
+ # ---------------------------------------------------------------------------
191
+ # Force copy mode: hardlink fallback has been observed to leave native
192
+ # extension packages (orjson, pytomlpp, …) without their compiled .so,
193
+ # producing ModuleNotFoundError: No module named '<pkg>.<native>' at import.
194
+ [tool.uv]
195
+ link-mode = "copy"
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '4.1.11.dev0+ge006e1a54.d20260417'
22
- __version_tuple__ = version_tuple = (4, 1, 11, 'dev0', 'ge006e1a54.d20260417')
21
+ __version__ = version = '4.1.12.dev0+g996ef7518.d20260423'
22
+ __version_tuple__ = version_tuple = (4, 1, 12, 'dev0', 'g996ef7518.d20260423')
23
23
 
24
- __commit_id__ = commit_id = 'ge006e1a54'
24
+ __commit_id__ = commit_id = 'g996ef7518'
@@ -0,0 +1,413 @@
1
+ """Pagination helpers for the Query Slug management list endpoint.
2
+
3
+ Pure functions + Pydantic models. No aiohttp, no DB calls — this module is
4
+ unit-testable in isolation.
5
+
6
+ This module provides:
7
+ * Constants (default / max page size, default sort field & direction).
8
+ * Allowlists derived from :class:`querysource.models.QueryModel` so that
9
+ column identifiers interpolated into raw SQL can never come from
10
+ user-controlled strings.
11
+ * Pydantic v2 models :class:`PaginationParams`, :class:`PaginationMeta`
12
+ and :class:`PaginatedResponse`.
13
+ * Pure SQL-builder helpers: :func:`build_where_clause`,
14
+ :func:`build_order_by`, :func:`build_count_sql`, :func:`build_page_sql`.
15
+
16
+ All builders validate every column identifier against a fixed allowlist and
17
+ route scalar values through :class:`querysource.types.validators.Entity`
18
+ (``toSQL`` + ``quoteString``) — the same helpers used by
19
+ ``QueryManager.get_query_insert``. This matches the project's existing
20
+ SQL-safety pattern and provides defence-in-depth against injection.
21
+
22
+ See ``sdd/specs/querysource-slug-list-pagination.spec.md`` §3 Modules 1-2.
23
+ """
24
+ from __future__ import annotations
25
+
26
+ import logging
27
+ from typing import Any, Literal, Optional
28
+
29
+ from pydantic import BaseModel, Field, field_validator
30
+
31
+ from ..models import QueryModel
32
+ from ..types.validators import Entity
33
+
34
+
35
+ logger = logging.getLogger(__name__)
36
+
37
+
38
+ SortDirection = Literal["asc", "desc"]
39
+
40
+ DEFAULT_PAGE_SIZE: int = 50
41
+ MAX_PAGE_SIZE: int = 200
42
+ DEFAULT_SORT_FIELD: str = "updated_at"
43
+ DEFAULT_SORT_DIRECTION: SortDirection = "desc"
44
+
45
+ # Columns allowlisted for WHERE / filter kwargs — every key of the live
46
+ # ``QueryModel.columns()`` dict. Frozen so the set is hashable and immutable.
47
+ _MODEL_COLUMNS: dict = QueryModel.columns(QueryModel)
48
+ FILTERABLE_COLUMNS: frozenset[str] = frozenset(_MODEL_COLUMNS.keys())
49
+
50
+ # Scalar columns that the caller is allowed to sort on. jsonb / array columns
51
+ # are deliberately excluded (see spec §7 "Known Risks / Gotchas").
52
+ SORTABLE_COLUMNS: frozenset[str] = frozenset(
53
+ {
54
+ "query_slug",
55
+ "description",
56
+ "program_slug",
57
+ "provider",
58
+ "is_cached",
59
+ "created_at",
60
+ "updated_at",
61
+ }
62
+ )
63
+
64
+ # Columns matched by the ``search`` query-string param with ``ILIKE '%term%'``.
65
+ SEARCHABLE_COLUMNS: tuple[str, ...] = (
66
+ "query_slug",
67
+ "description",
68
+ "program_slug",
69
+ "source",
70
+ )
71
+
72
+
73
+ class PaginationParams(BaseModel):
74
+ """Validated pagination / sort / search parameters for the slug list endpoint.
75
+
76
+ Attributes:
77
+ page: 1-based page number (``>= 1``).
78
+ page_size: Rows per page. Clamped to ``[1, MAX_PAGE_SIZE]``.
79
+ sort_field: Column to sort on. Must be in :data:`SORTABLE_COLUMNS`.
80
+ sort_direction: ``"asc"`` or ``"desc"``.
81
+ search: Optional free-text search term (max 255 chars). Applied via
82
+ ``ILIKE '%term%'`` across :data:`SEARCHABLE_COLUMNS`.
83
+ fields: Optional list of column names to project. Each element must be
84
+ in :data:`FILTERABLE_COLUMNS`.
85
+ """
86
+
87
+ page: int = Field(default=1, ge=1)
88
+ page_size: int = Field(default=DEFAULT_PAGE_SIZE, ge=1, le=MAX_PAGE_SIZE)
89
+ sort_field: str = Field(default=DEFAULT_SORT_FIELD)
90
+ sort_direction: SortDirection = Field(default=DEFAULT_SORT_DIRECTION)
91
+ search: Optional[str] = Field(default=None, max_length=255)
92
+ fields: Optional[list[str]] = Field(default=None)
93
+
94
+ @field_validator("sort_field")
95
+ @classmethod
96
+ def _validate_sort_field(cls, v: str) -> str:
97
+ """Reject sort fields that are not in :data:`SORTABLE_COLUMNS`."""
98
+ if v not in SORTABLE_COLUMNS:
99
+ raise ValueError(
100
+ f"sort field not allowed: {v!r}. "
101
+ f"Allowed: {sorted(SORTABLE_COLUMNS)}"
102
+ )
103
+ return v
104
+
105
+ @field_validator("fields")
106
+ @classmethod
107
+ def _validate_fields(cls, v: Optional[list[str]]) -> Optional[list[str]]:
108
+ """Reject any field not in :data:`FILTERABLE_COLUMNS`."""
109
+ if v is None:
110
+ return v
111
+ unknown = [c for c in v if c not in FILTERABLE_COLUMNS]
112
+ if unknown:
113
+ raise ValueError(f"unknown field(s): {unknown}")
114
+ return v
115
+
116
+ @property
117
+ def offset(self) -> int:
118
+ """SQL OFFSET computed from ``(page - 1) * page_size``."""
119
+ return (self.page - 1) * self.page_size
120
+
121
+ @classmethod
122
+ def from_query_string(cls, qs: dict) -> "PaginationParams":
123
+ """Parse a flat query-string dict into :class:`PaginationParams`.
124
+
125
+ Understood keys:
126
+ * ``page`` (int)
127
+ * ``page_size`` (int)
128
+ * ``sort`` — either ``"<field>"`` or ``"<field>:<asc|desc>"``
129
+ * ``search`` (str)
130
+ * ``fields`` — either a comma-separated string or a list of strings
131
+
132
+ Unknown keys are simply ignored here — they are handled as filter
133
+ kwargs by ``build_where_clause``.
134
+
135
+ Args:
136
+ qs: Flat query-string mapping (string → string, typically).
137
+
138
+ Returns:
139
+ A validated :class:`PaginationParams` instance.
140
+
141
+ Raises:
142
+ pydantic.ValidationError: On unsafe or out-of-range values.
143
+ ValueError: On malformed ``sort`` direction.
144
+ """
145
+ data: dict[str, Any] = {}
146
+
147
+ try:
148
+ if "page" in qs:
149
+ data["page"] = int(qs["page"])
150
+ if "page_size" in qs:
151
+ data["page_size"] = int(qs["page_size"])
152
+ except (TypeError, ValueError) as exc:
153
+ raise ValueError(
154
+ f"'page' and 'page_size' must be integers: {exc}"
155
+ ) from exc
156
+
157
+ if "sort" in qs and qs["sort"]:
158
+ sort_value = str(qs["sort"]).strip()
159
+ if ":" in sort_value:
160
+ field_part, _, dir_part = sort_value.partition(":")
161
+ field_part = field_part.strip()
162
+ dir_part = dir_part.strip().lower()
163
+ if dir_part not in ("asc", "desc"):
164
+ raise ValueError(
165
+ f"invalid sort direction: {dir_part!r}; "
166
+ "expected 'asc' or 'desc'"
167
+ )
168
+ data["sort_field"] = field_part
169
+ data["sort_direction"] = dir_part
170
+ else:
171
+ data["sort_field"] = sort_value
172
+
173
+ if "search" in qs and qs["search"] not in (None, ""):
174
+ data["search"] = str(qs["search"])
175
+
176
+ if "fields" in qs and qs["fields"] not in (None, ""):
177
+ raw = qs["fields"]
178
+ if isinstance(raw, (list, tuple)):
179
+ data["fields"] = [str(x).strip() for x in raw if str(x).strip()]
180
+ else:
181
+ data["fields"] = [
182
+ s.strip() for s in str(raw).split(",") if s.strip()
183
+ ]
184
+
185
+ return cls(**data)
186
+
187
+
188
+ class PaginationMeta(BaseModel):
189
+ """Metadata block returned inside :class:`PaginatedResponse`."""
190
+
191
+ page: int
192
+ page_size: int
193
+ total: int
194
+ total_pages: int
195
+
196
+
197
+ class PaginatedResponse(BaseModel):
198
+ """Response envelope for paginated list endpoints."""
199
+
200
+ data: list[dict]
201
+ meta: PaginationMeta
202
+
203
+
204
+ # ---------------------------------------------------------------------------
205
+ # SQL builders
206
+ # ---------------------------------------------------------------------------
207
+
208
+
209
+ def _quote_ident(name: str) -> str:
210
+ """Return ``"<name>"`` after allowlist validation.
211
+
212
+ Only identifiers already checked against :data:`FILTERABLE_COLUMNS` reach
213
+ this point — this helper simply adds double quotes so column names that
214
+ happen to collide with Postgres reserved words are still safe.
215
+ """
216
+ if name not in FILTERABLE_COLUMNS:
217
+ raise ValueError(f"column not in allowlist: {name!r}")
218
+ return f'"{name}"'
219
+
220
+
221
+ def _coerce_value(col_name: str, value: Any) -> str:
222
+ """Run ``value`` through ``Entity.toSQL`` + ``Entity.quoteString``.
223
+
224
+ Mirrors the pattern used by ``QueryManager.get_query_insert`` at
225
+ ``querysource/handlers/manager.py:40-49``. The column's datamodel field is
226
+ used to look up the Python type + db_type before conversion.
227
+
228
+ Args:
229
+ col_name: Name of the column (already allowlisted).
230
+ value: Raw value to coerce.
231
+
232
+ Returns:
233
+ A SQL literal (quoted where appropriate) safe to splice into a WHERE
234
+ clause.
235
+ """
236
+ field = _MODEL_COLUMNS.get(col_name)
237
+ if field is None:
238
+ # Should never happen — caller must pre-check the allowlist.
239
+ raise ValueError(f"column not in model: {col_name!r}")
240
+ _type = field.type
241
+ try:
242
+ _dbtype = field.db_type()
243
+ except Exception: # pragma: no cover - defensive
244
+ _dbtype = None
245
+ sql_val = Entity.toSQL(value, _type, dbtype=_dbtype)
246
+ if sql_val == "NULL":
247
+ return "NULL"
248
+ return Entity.quoteString(str(sql_val), no_dblquoting=False)
249
+
250
+
251
+ def build_where_clause(
252
+ params: PaginationParams,
253
+ extra_filters: dict,
254
+ ) -> str:
255
+ """Return a SQL WHERE clause (including the leading ``WHERE``) or ``""``.
256
+
257
+ The clause merges:
258
+ * Equality predicates for every key in ``extra_filters``. Every key
259
+ MUST be in :data:`FILTERABLE_COLUMNS` — unknown keys raise
260
+ ``ValueError`` (callers convert to HTTP 400). This matches the
261
+ spec §7 "kwargs filter passthrough" requirement: "any filter key
262
+ NOT in the QueryModel.columns allowlist MUST be rejected (400)
263
+ rather than silently forwarded".
264
+ * An ``ILIKE '%term%'`` predicate over :data:`SEARCHABLE_COLUMNS`
265
+ when ``params.search`` is set (combined with ``OR`` inside a
266
+ parenthesised group).
267
+
268
+ Args:
269
+ params: Pre-validated :class:`PaginationParams`.
270
+ extra_filters: Additional filter kwargs (typically the leftover
271
+ query-string params).
272
+
273
+ Returns:
274
+ The WHERE clause (possibly empty).
275
+
276
+ Raises:
277
+ ValueError: If any key of ``extra_filters`` is not in
278
+ :data:`FILTERABLE_COLUMNS`.
279
+ """
280
+ predicates: list[str] = []
281
+
282
+ unknown = [k for k in extra_filters if k not in FILTERABLE_COLUMNS]
283
+ if unknown:
284
+ raise ValueError(f"unknown filter column(s): {unknown}")
285
+
286
+ for key, value in extra_filters.items():
287
+ coerced = _coerce_value(key, value)
288
+ if coerced == "NULL":
289
+ predicates.append(f"{_quote_ident(key)} IS NULL")
290
+ else:
291
+ predicates.append(f"{_quote_ident(key)} = {coerced}")
292
+
293
+ if params.search:
294
+ term = params.search.replace("\\", "\\\\").replace("'", "''")
295
+ like_literal = f"'%{term}%'"
296
+ or_terms = [
297
+ f"{_quote_ident(col)}::text ILIKE {like_literal}"
298
+ for col in SEARCHABLE_COLUMNS
299
+ if col in FILTERABLE_COLUMNS
300
+ ]
301
+ if or_terms:
302
+ predicates.append("(" + " OR ".join(or_terms) + ")")
303
+
304
+ if not predicates:
305
+ return ""
306
+ return "WHERE " + " AND ".join(predicates)
307
+
308
+
309
+ def build_order_by(params: PaginationParams) -> str:
310
+ """Return ``ORDER BY "<col>" <DIR>`` with a validated column name.
311
+
312
+ Defence in depth: even though :class:`PaginationParams` already rejects
313
+ unknown sort columns, we re-check here before interpolating.
314
+
315
+ Args:
316
+ params: Pre-validated :class:`PaginationParams`.
317
+
318
+ Returns:
319
+ The ``ORDER BY`` clause.
320
+
321
+ Raises:
322
+ ValueError: If the sort field is not in :data:`SORTABLE_COLUMNS`.
323
+ """
324
+ if params.sort_field not in SORTABLE_COLUMNS:
325
+ raise ValueError(
326
+ f"sort field not allowed: {params.sort_field!r}"
327
+ )
328
+ direction = "ASC" if params.sort_direction == "asc" else "DESC"
329
+ return f'ORDER BY "{params.sort_field}" {direction}'
330
+
331
+
332
+ def build_count_sql(schema: str, table: str, where: str) -> str:
333
+ """Return ``SELECT COUNT(*) FROM "<schema>"."<table>" <where>``.
334
+
335
+ Args:
336
+ schema: Postgres schema name. Must be a bare identifier.
337
+ table: Table name. Must be a bare identifier.
338
+ where: WHERE clause as produced by :func:`build_where_clause`. May be
339
+ empty.
340
+
341
+ Returns:
342
+ A complete ``SELECT COUNT(*)`` statement.
343
+ """
344
+ _validate_bare_identifier(schema, "schema")
345
+ _validate_bare_identifier(table, "table")
346
+ base = f'SELECT COUNT(*) FROM "{schema}"."{table}"'
347
+ if where:
348
+ return f"{base} {where}"
349
+ return base
350
+
351
+
352
+ def build_page_sql(
353
+ schema: str,
354
+ table: str,
355
+ fields: list[str],
356
+ where: str,
357
+ order_by: str,
358
+ limit: int,
359
+ offset: int,
360
+ ) -> str:
361
+ """Return a paged SELECT statement.
362
+
363
+ Args:
364
+ schema: Postgres schema name. Must be a bare identifier.
365
+ table: Table name. Must be a bare identifier.
366
+ fields: List of columns to project. Each must be in
367
+ :data:`FILTERABLE_COLUMNS`. ``[]`` projects all columns (``*``).
368
+ where: Clause from :func:`build_where_clause` (may be empty).
369
+ order_by: Clause from :func:`build_order_by`.
370
+ limit: Non-negative integer used as ``LIMIT``.
371
+ offset: Non-negative integer used as ``OFFSET``.
372
+
373
+ Returns:
374
+ A complete ``SELECT`` statement safe to pass to ``conn.fetch``.
375
+
376
+ Raises:
377
+ ValueError: On unknown columns, non-bare identifiers, or negative
378
+ ``limit`` / ``offset``.
379
+ """
380
+ _validate_bare_identifier(schema, "schema")
381
+ _validate_bare_identifier(table, "table")
382
+ if not isinstance(limit, int) or limit < 0:
383
+ raise ValueError(f"limit must be a non-negative int, got {limit!r}")
384
+ if not isinstance(offset, int) or offset < 0:
385
+ raise ValueError(f"offset must be a non-negative int, got {offset!r}")
386
+
387
+ if fields:
388
+ unknown = [c for c in fields if c not in FILTERABLE_COLUMNS]
389
+ if unknown:
390
+ raise ValueError(f"unknown projection column(s): {unknown}")
391
+ select_list = ", ".join(f'"{c}"' for c in fields)
392
+ else:
393
+ select_list = "*"
394
+
395
+ parts = [f'SELECT {select_list} FROM "{schema}"."{table}"']
396
+ if where:
397
+ parts.append(where)
398
+ if order_by:
399
+ parts.append(order_by)
400
+ parts.append(f"LIMIT {limit} OFFSET {offset}")
401
+ return " ".join(parts)
402
+
403
+
404
+ def _validate_bare_identifier(value: str, kind: str) -> None:
405
+ """Ensure ``value`` contains only ``[A-Za-z0-9_]`` characters.
406
+
407
+ Schema and table names come from ``QueryModel.Meta`` (static config), but
408
+ we still validate to avoid accidental future misuse.
409
+ """
410
+ if not value or not all(
411
+ c.isalnum() or c == "_" for c in value
412
+ ) or value[0].isdigit():
413
+ raise ValueError(f"invalid {kind} identifier: {value!r}")