Expressive URL-query to MongoDB query conversion library.
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
# }- 🧠 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 hereor$text=free text here - 🧱 Type casters:
custom value transformations - 🚫 Blacklist: skip parsing of restricted fields
- 🧪 Tested: full pytest coverage, Ruff linting
With uv (recommended):
uv add moleqlpip install moleqlfrom 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}
}| 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 |
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)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)- 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.
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)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
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- [] Add exists(field) and between(a,b) operators
- [] Add optional CLI (moleql "age>20" --as-json)
- [] Extended docs and tutorials
🤝 Contributing
-
Fork this repository
-
Create your feature branch
git checkout -b feat/awesome-change
-
Run formatting and tests
uv run pre-commit run --all-files uv run pytest
-
Commit and push your changes
-
Open a Pull Request 🚀
See CODE_OF_CONDUCT.md for details.
Built and maintained by @OneTesseractInMultiverse Inspired by the need for readable, typed, and safe Mongo queries in API environments.
