Open-source universal Python connector for APIs - Query any data source with SQL
Project description
WaveQL
The Universal SQL Connector for Modern APIs
Query ServiceNow, Salesforce, Jira, and more using standard SQL.
WaveQL transforms the way you interact with SaaS APIs. Instead of wrestling with complex, proprietary REST endpoints and pagination logic, WaveQL lets you query your business data using the language you already know: SQL.
Built for data engineers and developers, it translates your SQL queries into optimized API calls (pushing down predicates like WHERE and ORDER BY), handles authentications, and returns high-performance Arrow or Pandas dataframes.
🚀 Why WaveQL?
- 🔌 Universal Adapter System: Connect to ServiceNow, Salesforce, Jira, or generic REST APIs with a unified interface.
- ⚡ Intelligent Query Pushdown: We don't just fetch all data.
WHEREclauses are translated into native API filters (e.g., JQL, SOQL) for maximum performance. - 🔄 Cross-Source JOINs: Seamlessly join data between your local CSVs, a Jira backlog, and ServiceNow incidents using our DuckDB-powered engine.
- ⚡ Async Built-in: Built on
httpxandanyiofor high-concurrency, non-blocking applications. - 🐼 Data Science Ready: Native integrations with Pandas, PyArrow, and SQLAlchemy (works with Superset!).
📦 Installation
pip install waveql
Or install from source:
git clone https://github.com/mitayan0/WaveQL.git
cd WaveQL
pip install -e .
⚡ Quick Start
1. Querying ServiceNow
import waveql
# Connect securely
conn = waveql.connect(
"servicenow://instance.service-now.com",
username="admin",
password="your-password"
)
# Execute standard SQL
cursor = conn.cursor()
cursor.execute("""
SELECT number, short_description, priority
FROM incident
WHERE state = 1 AND priority <= 2
ORDER BY number DESC
LIMIT 10
""")
# Work with results
for row in cursor:
print(f"[{row.number}] {row.short_description}")
# Or get a Pandas DataFrame instantly
df = cursor.fetchall().to_df()
print(df.head())
2. Async Support
Building a modern FastAPI or async app? We've got you covered.
import asyncio
from waveql import connect_async
async def main():
conn = await connect_async(
"jira://your-domain.atlassian.net",
username="user@example.com",
password="api-token"
)
cursor = conn.cursor()
# Predicates are pushed down to JQL!
await cursor.execute("SELECT key, summary FROM issues WHERE project = 'PROJ'")
results = await cursor.fetchall()
print(results)
asyncio.run(main())
3. The Power of Cross-Source Joins
Combine data from anywhere.
conn.execute("""
SELECT
sn.number as ticket_id,
jira.key as engineering_task,
sn.short_description
FROM servicenow.incident sn
JOIN jira.issues jira ON sn.correlation_id = jira.key
WHERE sn.priority = 1
""")
🛠 Supported Adapters
| Adapter | URI Scheme | Features |
|---|---|---|
| ServiceNow | servicenow:// |
✅ Table API, ✅ Aggregates, ✅ Write (CRUD) |
| Salesforce | salesforce:// |
✅ SOQL Pushdown, ✅ Bulk API support |
| Jira | jira:// |
✅ JQL Pushdown, ✅ Pagination |
| REST | rest:// |
⚠️ Generic JSON querying |
| File | file:// |
✅ CSV, Parquet, JSON (via DuckDB) |
📝 SQL Syntax Support
WaveQL supports ANSI SQL with full compatibility for schema-qualified and quoted identifiers:
-- All of these are equivalent and fully supported:
SELECT * FROM incident
SELECT * FROM servicenow.incident
SELECT * FROM "servicenow"."incident"
SELECT * FROM servicenow."incident"
Supports: SELECT, INSERT, UPDATE, DELETE, JOIN, GROUP BY, ORDER BY, LIMIT, OFFSET
🔐 Authentication
WaveQL takes the headache out of auth headers.
- Basic Auth: Simple username/password.
- API Key: Custom headers or query params.
- OAuth2: Full flow support including token refresh.
from waveql.auth import AuthManager
# OAuth2 Example
auth = AuthManager(
oauth2_token_url="https://login.salesforce.com/services/oauth2/token",
client_id="your_client_id",
client_secret="your_client_secret"
)
conn = waveql.connect("salesforce://login.salesforce.com", auth_manager=auth)
🤝 Contributing
We love contributions! Whether it's a new adapter, a bug fix, or a docs improvement, please join us.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
Copyright (c) 2026 Mitayan Chakma.
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file waveql-0.1.1.tar.gz.
File metadata
- Download URL: waveql-0.1.1.tar.gz
- Upload date:
- Size: 469.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
474ebf5e96e1c63e7f5c85dc8c916e85bcdcdeb29acd0d36c19c62d80694690c
|
|
| MD5 |
98883a13f50766a6f188a5f22eab4b66
|
|
| BLAKE2b-256 |
2da47291a0b8861521fb69b432da477a3211d7be5c53e45a29de46faaa1dd202
|
File details
Details for the file waveql-0.1.1-py3-none-any.whl.
File metadata
- Download URL: waveql-0.1.1-py3-none-any.whl
- Upload date:
- Size: 61.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
06fe62c285cea6831c3074fd741de7d89a6a3740165580de4ed2ed3ed6404fe9
|
|
| MD5 |
dca2a650ba7322025cd3c9590e81c865
|
|
| BLAKE2b-256 |
4becef6983cc5b25f3a9ec70b32fe91e1d6298963523e1033e542963a8a78bbf
|