Skip to main content

Parse URL-style queries into MongoDB filters, sort, projection, and pagination data.

Project description

MoleQL logo

MoleQL

Expressive URL-query to MongoDB query conversion library.

CI License PyPI Python Versions

Overview

MoleQL allows your REST APIs or data layers to accept URL-style query strings (e.g. ?age>30&status=in(active,pending)) and converts them into MongoDB-compatible query dictionaries. It supports filters, sorting, skip/limit, projection and text search.

Example:

from moleql import parse

query = parse("age>30&country=US&name=/^John/i")
# yields:
# {
#   "filter": {"age": {"$gt": 30}, "country": "US", "name": {"$regex": "^John", "$options": "i"}},
#   "sort": None,
#   "skip": 0,
#   "limit": 0,
#   "projection": None
# }

✨ Features

  • 🧠 Intuitive syntax: =, !=, <, <=, >, >=
  • 📋 List operators: in(...), ...
  • 🔍 Regex: /pattern/flags → $regex + $options
  • 🧾 Pagination: skip=10, limit=50
  • ⚙️ Sorting: sort=-created_at,name
  • 🧩 Projection: fields=name,email,age
  • 🔠 Text search: text=free text here or $text=free text here
  • 🧱 Type casters: custom value transformations
  • 🚫 Blacklist: skip parsing of restricted fields
  • 🧪 Tested: full pytest coverage, Ruff linting

🧰 Installation

With uv (recommended):

uv add moleql
pip install moleql

🚀 Quick Start

from moleql import parse

query = parse("age>30&country=US&name=/^John/i")
print(query)

# {
#   "filter": {
#       "age": {"$gt": 30},
#       "country": "US",
#       "name": {"$regex": "^John", "$options": "i"}
#   },
#   "sort": None,
#   "skip": 0,
#   "limit": 0,
#   "projection": None
# }

Extended example

from moleql import parse

query = parse(
    "age>=18&status=in(active,pending)"
    "&sort=-created_at,name"
    "&skip=10&limit=20"
    "&fields=name,email,age"
)

Output:

{
    "filter": {
        "age": {"$gte": 18},
        "status": {"$in": ["active", "pending"]}
    },
    "sort": [("created_at", -1), ("name", 1)],
    "skip": 10,
    "limit": 20,
    "projection": {"name": 1, "email": 1, "age": 1}
}

🔣 Supported Operators

Expression Mongo Operator Example
= direct match age=20{"age": 20}
!= $ne status!=active
> / >= $gt / $gte score>=80
< / <= $lt / $lte price<10
in(...) $in role=in(admin,user)
!=in(...) $nin tier!=in(gold,platinum)
/pattern/flags $regex name=/^Jo/i
text= or $text= $text text=free search text
fields= projection fields=name,email
sort= sort directive sort=-created_at,name

🧱 Quick API Reference

parse(moleql_query: str, blacklist=None, casters=None) -> dict

from moleql import parse

parse("age>25&active=true")

Returns a dictionary with: filter, sort, skip, limit, projection

moleqularize(moleql_query: str, blacklist=None, casters=None) -> MoleQL

Parse a MoleQL string and return the internal MoleQL object for advanced inspection and debugging.

from moleql import moleqularize

m = moleqularize("age>25")
print(m.mongo_query)

🧩 Custom Casters

You can define custom casters to control type conversions.

from moleql import parse, get_casters


def to_bool(value: str) -> bool:
    return value.lower() in ("true", "1", "yes")


custom_casters = {"bool": to_bool}

q = parse("active=bool(true)&age>30", casters=custom_casters)

🧠 Design Philosophy

  • Transparency — The query string is readable and reversible.
  • Safety — No eval, injection-safe parsing.
  • Extensibility — Easy to plug in custom handlers.
  • Predictability — Every operator maps 1:1 to Mongo semantics.
  • Minimal dependencies — Pure Python, no ODM required.

⚙️ Integration Examples

FastAPI

from fastapi import FastAPI, Request
from moleql import parse
from pymongo import MongoClient

db = MongoClient()["app"]
app = FastAPI()


@app.get("/users")
def list_users(request: Request):
    q = parse(request.url.query.lstrip("?"))
    return list(db.users.find(q["filter"]))

Flask

from flask import Flask, request, jsonify
from moleql import parse

app = Flask(__name__)


@app.get("/orders")
def orders():
    q = parse(request.query_string.decode())
    return jsonify(q)

🧪 Testing

Run the full suite using uv:

uv sync --all-extras --dev
uv run pytest -vv --cov=moleql --cov-report=term-missing --cov-fail-under=100

Generate coverage:

uv run pytest --cov=moleql --cov-report=term-missing --cov-fail-under=100

🧹 Code Quality

This repository uses:

  • Ruff — Linting + formatting (UP / pyupgrade rules)
  • pre-commit — automatic checks
  • pytest — testing
  • uv — environment & packaging

Set up hooks:

uv run pre-commit install
uv run pre-commit run --all-files

🧭 Roadmap

  • [] Add exists(field) and between(a,b) operators
  • [] Add optional CLI (moleql "age>20" --as-json)
  • [] Extended docs and tutorials

🤝 Contributing

  1. Fork this repository

  2. Create your feature branch

    git checkout -b feat/awesome-change
    
  3. Run formatting and tests

    uv run pre-commit run --all-files
    uv run pytest
    
  4. Commit and push your changes

  5. Open a Pull Request 🚀

See CODE_OF_CONDUCT.md for details.

🌟 Acknowledgments

Built and maintained by @OneTesseractInMultiverse Inspired by the need for readable, typed, and safe Mongo queries in API environments.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

moleql-0.2.0.tar.gz (12.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

moleql-0.2.0-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file moleql-0.2.0.tar.gz.

File metadata

  • Download URL: moleql-0.2.0.tar.gz
  • Upload date:
  • Size: 12.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for moleql-0.2.0.tar.gz
Algorithm Hash digest
SHA256 e1bea84086e432a7f295473fa0c5ebb3d6806d29c3be6cb1d0f390dac9e2a617
MD5 a68c20ec7b6b4ca63919d99534904fab
BLAKE2b-256 ac3ff85e5cac78f9bf7a01c29c45db640d449f0f1ab831f7accd184abbfe136c

See more details on using hashes here.

Provenance

The following attestation bundles were made for moleql-0.2.0.tar.gz:

Publisher: release.yml on OneTesseractInMultiverse/moleql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file moleql-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: moleql-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for moleql-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dae13a567f61834c7a8c31725adbe7725f0935817502e93fdc4bbc039b960cd7
MD5 09a866db00e14cf06ce38ff75fafd8b3
BLAKE2b-256 cadceed2cbbf2d4cc113ac8fd3b1065548a4c37f8d887b1beaf05af2f0a185bb

See more details on using hashes here.

Provenance

The following attestation bundles were made for moleql-0.2.0-py3-none-any.whl:

Publisher: release.yml on OneTesseractInMultiverse/moleql

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page