{"id":50140340,"url":"https://github.com/ehsanahmadzadeh/paramora","last_synced_at":"2026-05-24T01:01:36.083Z","repository":{"id":355099730,"uuid":"1226662925","full_name":"EhsanAhmadzadeh/Paramora","owner":"EhsanAhmadzadeh","description":"Safe typed query compilation for FastAPI.","archived":false,"fork":false,"pushed_at":"2026-05-24T00:16:59.000Z","size":490,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-24T00:17:21.254Z","etag":null,"topics":["fastapi","mongodb","odm","postgresql","query-compiler","sqlmodel","type-safe","validation"],"latest_commit_sha":null,"homepage":"https://ehsanahmadzadeh.github.io/Paramora/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EhsanAhmadzadeh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-01T17:23:59.000Z","updated_at":"2026-05-24T00:14:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/EhsanAhmadzadeh/Paramora","commit_stats":null,"previous_names":["ehsanahmadzadeh/paramora"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/EhsanAhmadzadeh/Paramora","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EhsanAhmadzadeh%2FParamora","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EhsanAhmadzadeh%2FParamora/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EhsanAhmadzadeh%2FParamora/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EhsanAhmadzadeh%2FParamora/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EhsanAhmadzadeh","download_url":"https://codeload.github.com/EhsanAhmadzadeh/Paramora/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EhsanAhmadzadeh%2FParamora/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33417489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-23T22:14:44.296Z","status":"ssl_error","status_checked_at":"2026-05-23T22:14:43.778Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fastapi","mongodb","odm","postgresql","query-compiler","sqlmodel","type-safe","validation"],"created_at":"2026-05-24T01:01:33.701Z","updated_at":"2026-05-24T01:01:36.053Z","avatar_url":"https://github.com/EhsanAhmadzadeh.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://ehsanahmadzadeh.github.io/Paramora/\"\u003e\n    \u003cimg\n      src=\"https://raw.githubusercontent.com/EhsanAhmadzadeh/Paramora/main/docs/assets/paramora-logo.png\"\n      alt=\"Paramora\"\n      width=\"360\"\n    \u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cem\u003eSafe typed filtering for FastAPI, MongoDB, SQL, SQLAlchemy, SQLModel, and ODMs.\u003c/em\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/EhsanAhmadzadeh/Paramora/actions/workflows/ci.yml\"\u003e\n    \u003cimg src=\"https://github.com/EhsanAhmadzadeh/Paramora/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/EhsanAhmadzadeh/Paramora/actions/workflows/pages.yml\"\u003e\n    \u003cimg src=\"https://github.com/EhsanAhmadzadeh/Paramora/actions/workflows/pages.yml/badge.svg\" alt=\"Docs\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://codecov.io/gh/EhsanAhmadzadeh/Paramora\"\u003e\n    \u003cimg src=\"https://codecov.io/gh/EhsanAhmadzadeh/Paramora/branch/main/graph/badge.svg\" alt=\"Coverage\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/paramora/\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/v/paramora?color=%2334D058\u0026label=pypi\" alt=\"PyPI\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://pypi.org/project/paramora/\"\u003e\n    \u003cimg src=\"https://img.shields.io/pypi/pyversions/paramora.svg?color=%2334D058\" alt=\"Python versions\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/EhsanAhmadzadeh/Paramora/blob/main/LICENSE\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/EhsanAhmadzadeh/Paramora\" alt=\"License\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/EhsanAhmadzadeh/Paramora\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/typing-pyright%20strict-blue\" alt=\"Pyright strict\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n**Paramora** turns user-controlled HTTP query parameters like:\n\n```http\n/items?price__gte=10\u0026status__in=free,busy\u0026sort=-created_at\u0026limit=20\n```\n\ninto safe, typed backend query outputs for MongoDB, raw SQL, SQLAlchemy,\nSQLModel, and Mongo ODM adapters.\n\nIt helps FastAPI teams avoid hand-written filtering code, unsafe raw backend\nquery exposure, inconsistent validation, and repeated pagination/sorting logic.\n\n\u003e **Status:** Paramora is alpha software. Public APIs, backend emitter contracts,\n\u003e AST details, and error shapes may change before `1.0`.\n\n## Why Paramora?\n\nFastAPI makes endpoint code ergonomic, but filtering APIs often grow into messy\nmanual parsing:\n\n```python\nprice = request.query_params.get(\"price__gte\")\nstatus = request.query_params.get(\"status__in\")\n\nquery = {}\nif price:\n    query[\"price\"] = {\"$gte\": float(price)}\nif status:\n    query[\"status\"] = {\"$in\": status.split(\",\")}\n```\n\nParamora lets you declare the query surface once:\n\n```python\nfrom datetime import datetime\nfrom typing import Annotated\n\nfrom paramora import Query, QueryContract, query_field\n\n\nclass ItemQuery(QueryContract):\n    status: Annotated[str, query_field(\"eq\", \"in\")]\n    active: bool\n    created_at: Annotated[datetime, query_field(\"gte\", \"lte\", sortable=True)]\n    price: Annotated[float, query_field(\"eq\", \"gte\", \"lte\")]\n\n\nitem_query = Query(ItemQuery)\n```\n\nThen Paramora handles:\n\n- allowed fields and operators\n- type coercion for `str`, `int`, `float`, `bool`, `datetime`, and `Enum`\n- strict vs loose validation\n- sorting and pagination\n- structured FastAPI `422` errors\n- MongoDB, raw SQL, SQLAlchemy, SQLModel, and ODM emitter outputs\n\n## Install\n\n```bash\nuv add paramora\n```\n\nor:\n\n```bash\npip install paramora\n```\n\nOptional backend extras:\n\n```bash\nuv add \"paramora[sqlalchemy]\"\nuv add \"paramora[sqlmodel]\"\nuv add \"paramora[postgres]\"\nuv add \"paramora[odm]\"\nuv add \"paramora[all]\"\n```\n\n## Requirements\n\nParamora supports **Python 3.10+** and FastAPI `0.115+`.\n\nPython 3.10 is the compatibility baseline. Runtime code intentionally avoids\nPython 3.11+/3.12+ only syntax so a wide range of FastAPI applications can adopt\nParamora.\n\n## MongoDB quickstart\n\n```python\nfrom datetime import datetime\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom paramora import CompiledQuery, MongoQuery, Query, QueryContract, query_field\n\napp = FastAPI()\n\n\nclass ItemQuery(QueryContract):\n    status: Annotated[str, query_field(\"eq\", \"in\")]\n    active: bool\n    created_at: Annotated[datetime, query_field(\"gte\", \"lte\", sortable=True)]\n    price: Annotated[float, query_field(\"eq\", \"gt\", \"gte\", \"lt\", \"lte\")]\n\n\nitem_query: Query[MongoQuery] = Query(ItemQuery, default_limit=20, max_limit=100)\n\n\n@app.get(\"/items\")\ndef list_items(query: CompiledQuery[MongoQuery] = Depends(item_query)):\n    mongo = query.output\n\n    docs = (\n        collection\n        .find(mongo.filter)\n        .sort(mongo.sort)\n        .skip(mongo.offset)\n        .limit(mongo.limit)\n    )\n\n    return list(docs)\n```\n\n## Raw SQL quickstart\n\n```python\nfrom datetime import datetime\nfrom typing import Annotated\n\nfrom fastapi import Depends, FastAPI\nfrom paramora import (\n    CompiledQuery,\n    Query,\n    QueryContract,\n    SqlQuery,\n    SqliteEmitter,\n    query_field,\n)\n\napp = FastAPI()\n\n\nclass ItemQuery(QueryContract):\n    status: Annotated[str, query_field(\"eq\", \"in\")]\n    created_at: Annotated[datetime, query_field(\"gte\", \"lte\", sortable=True)]\n    price: Annotated[float, query_field(\"eq\", \"gte\", \"lte\")]\n\n\nitem_query: Query[SqlQuery] = Query(ItemQuery, emitter=SqliteEmitter())\n\n\n@app.get(\"/items\")\ndef list_items(query: CompiledQuery[SqlQuery] = Depends(item_query)):\n    sql = query.output\n    statement = sql.select_statement(\"items\", columns=(\"id\", \"status\", \"price\"))\n    rows = connection.execute(statement.text, statement.params).fetchall()\n    return [dict(row) for row in rows]\n```\n\nValues are always returned as bound parameters. Paramora does not interpolate\nuser values into SQL strings.\n\n## SQLAlchemy / SQLModel quickstart\n\n```python\nfrom datetime import datetime\nfrom typing import Annotated\n\nimport sqlalchemy as sa\nfrom fastapi import Depends, FastAPI\nfrom paramora import CompiledQuery, Query, QueryContract, query_field\nfrom paramora.emitters.sqlalchemy import SqlAlchemyEmitter, SqlAlchemyQuery\n\nmetadata = sa.MetaData()\nitems = sa.Table(\n    \"items\",\n    metadata,\n    sa.Column(\"id\", sa.Integer, primary_key=True),\n    sa.Column(\"status\", sa.String),\n    sa.Column(\"price\", sa.Float),\n    sa.Column(\"created_at\", sa.DateTime),\n)\n\n\nclass ItemQuery(QueryContract):\n    status: Annotated[str, query_field(\"eq\", \"in\")]\n    price: Annotated[float, query_field(\"gte\", \"lte\")]\n    created_at: Annotated[datetime, query_field(\"gte\", \"lte\", sortable=True)]\n\n\nitem_query: Query[SqlAlchemyQuery] = Query(\n    ItemQuery,\n    emitter=SqlAlchemyEmitter.from_table(items),\n)\n\napp = FastAPI()\n\n\n@app.get(\"/items\")\ndef list_items(query: CompiledQuery[SqlAlchemyQuery] = Depends(item_query)):\n    statement = query.output.apply(sa.select(items))\n    return {\"sql\": str(statement)}\n```\n\n## Strict mode and loose mode\n\n- `Query(MyContract)` enables **strict mode**. It rejects unknown fields,\n  unsupported operators, invalid values, unsafe sorting, and oversized limits.\n- `Query()` enables **loose mode**. It accepts unknown fields for trusted tools\n  and prototypes, while still rejecting raw backend operator injection and unsafe\n  SQL identifiers.\n\nUse strict mode for public APIs.\n\n## Documentation\n\nThe full documentation site is available at:\n\n**\u003chttps://ehsanahmadzadeh.github.io/Paramora/\u003e**\n\nUseful pages:\n\n- [Quickstart](https://ehsanahmadzadeh.github.io/Paramora/quickstart/)\n- [Usage guide](https://ehsanahmadzadeh.github.io/Paramora/usage/)\n- [How-to guides](https://ehsanahmadzadeh.github.io/Paramora/how-to/)\n- [MongoDB backend](https://ehsanahmadzadeh.github.io/Paramora/mongodb/)\n- [Raw SQL backend](https://ehsanahmadzadeh.github.io/Paramora/sql/)\n- [SQLAlchemy and SQLModel](https://ehsanahmadzadeh.github.io/Paramora/sqlalchemy/)\n- [Mongo ODM adapters](https://ehsanahmadzadeh.github.io/Paramora/odms/)\n- [Testing strategy](https://ehsanahmadzadeh.github.io/Paramora/testing/)\n- [Continuous Integration](https://ehsanahmadzadeh.github.io/Paramora/ci/)\n- [Benchmarking](https://ehsanahmadzadeh.github.io/Paramora/benchmarking/)\n\n## Development\n\nInstall the full development environment:\n\n```bash\nuv sync --group dev --group docs\n```\n\nRun the same local quality gate that CI expects:\n\n```bash\nscripts/check.sh\n```\n\nIndividual helper scripts are also available:\n\n```bash\nscripts/format.sh       # Format and apply safe lint fixes\nscripts/test.sh         # Run pytest, forwarding any extra arguments\nscripts/docs.sh serve   # Serve the documentation site locally\nscripts/docs.sh build   # Build docs with MkDocs strict mode\nscripts/benchmark.sh    # Run benchmark scenarios\n```\n\nThe CI pipeline runs quality gates and the full test suite across every supported\nPython version: **3.10, 3.11, 3.12, 3.13, and 3.14**. Coverage is generated on\neach Python version and uploaded to Codecov so regressions are visible from the\nREADME badge and pull requests.\n\nThe development environment installs optional backend test dependencies so\nSQLAlchemy, SQLModel, MongoDB-compatible `mongomock`, and ODM-related tests can\nrun when possible.\n\n## Contributing\n\nParamora is early and contributor-friendly. Good first contributions include:\n\n- improving examples\n- adding backend edge-case tests\n- improving documentation recipes\n- expanding SQLAlchemy / SQLModel coverage\n- improving benchmarks and profiling scripts\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## License\n\nParamora is released under the MIT License.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehsanahmadzadeh%2Fparamora","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fehsanahmadzadeh%2Fparamora","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fehsanahmadzadeh%2Fparamora/lists"}