██╗ ██╗███╗ ██╗██╗██╗ ██╗██╗██████╗ ███████╗
██║ ██║████╗ ██║██║██║ ██║██║██╔══██╗██╔════╝
██║ ██║██╔██╗ ██║██║██║ █╗ ██║██║██████╔╝█████╗
██║ ██║██║╚██╗██║██║██║███╗██║██║██╔══██╗██╔══╝
╚██████╔╝██║ ╚████║██║╚███╔███╔╝██║██║ ██║███████╗
╚═════╝ ╚═╝ ╚═══╝╚═╝ ╚══╝╚══╝ ╚═╝╚═╝ ╚═╝╚══════╝
Use psql to query MongoDB. Browse Redis with DBeaver. Connect any PostgreSQL client to any database.
# Query MongoDB using psql. Yes, really.
psql -h localhost -p 5433 -U uniwire -d my_mongo -c "SELECT * FROM users WHERE age > 25;"UniWire is a Universal Wire Protocol Proxy that sits between your PostgreSQL client and any backend database. It speaks the PostgreSQL wire protocol v3 on its frontend, meaning any tool that can connect to PostgreSQL can now connect to anything.
psql ──────┐ ┌──→ 🍃 MongoDB
mysql CLI ─┤ ├──→ 🔴 Redis
JDBC ──────┤──→ UniWire Proxy (TCP :5433) ───────┤──→ 🐬 MySQL
pgcli ─────┤ ┌─────────────────────────┐ ├──→ 🐘 PostgreSQL
DBeaver ───┘ │ PG Wire Protocol Server │ ├──→ 📦 SQLite
│ SQL Parser (AST) │ └──→ ...
│ Query Router + RBAC │
│ Backend Adapters │
└─────────────────────────┘
git clone https://github.com/sbalavignesh/uniwire.git
cd uniwire
npm installnpm startYou'll see:
██╗ ██╗███╗ ██╗██╗██╗ ██╗██╗██████╗ ███████╗
...
⬡ Backends
──────────────────────────────────────────────────
✓ 📦 demo_sqlite (sqlite) (default)
⬡ Server
──────────────────────────────────────────────────
● Listening on 0.0.0.0:5433
# Connect with psql
psql -h localhost -p 5433 -U uniwire -d demo_sqlite
# Create and query a table
CREATE TABLE users (id INT, name TEXT, age INT);
INSERT INTO users VALUES (1, 'Alice', 30), (2, 'Bob', 25), (3, 'Charlie', 35);
SELECT * FROM users WHERE age > 25;UniWire transparently translates SQL to native MongoDB operations:
| SQL | MongoDB Equivalent |
|---|---|
SELECT * FROM users |
db.users.find({}) |
SELECT name FROM users WHERE age > 25 |
db.users.find({age: {$gt: 25}}, {projection: {name: 1}}) |
SELECT status, COUNT(*) FROM orders GROUP BY status |
db.orders.aggregate([{$group: {_id: "$status", count: {$sum: 1}}}]) |
INSERT INTO users (name, age) VALUES ('John', 30) |
db.users.insertOne({name: 'John', age: 30}) |
UPDATE users SET age = 31 WHERE name = 'John' |
db.users.updateMany({name: 'John'}, {$set: {age: 31}}) |
DELETE FROM users WHERE age < 18 |
db.users.deleteMany({age: {$lt: 18}}) |
UniWire exposes Redis through virtual SQL tables:
-- List all keys
SELECT * FROM keys;
-- Get a value
SELECT value FROM cache WHERE key = 'session:abc';
-- Set a value
INSERT INTO cache (key, value) VALUES ('greeting', 'hello world');
-- Get hash fields
SELECT * FROM hash WHERE key = 'user:1';
-- Delete a key
DELETE FROM cache WHERE key = 'temp:data';Create uniwire.config.yaml:
server:
host: 0.0.0.0
port: 5433
default_backend: my_mongo
backends:
# MongoDB
my_mongo:
type: mongodb
uri: mongodb://localhost:27017
database: myapp
# Redis
my_redis:
type: redis
host: localhost
port: 6379
# MySQL
my_mysql:
type: mysql
host: localhost
port: 3306
user: root
password: secret
database: myapp
# PostgreSQL (proxy pass-through)
my_pg:
type: postgresql
host: localhost
port: 5432
user: postgres
password: secret
database: myapp
# SQLite (zero-config)
my_sqlite:
type: sqlite
path: ./data/myapp.dbThen connect to any backend by name:
psql -d my_mongo # → MongoDB
psql -d my_redis # → Redis
psql -d my_mysql # → MySQL
psql -d my_sqlite # → SQLite| Backend | Status | SQL Support |
|---|---|---|
| 📦 SQLite | ✅ Ready | Full SQL (native) |
| 🍃 MongoDB | ✅ Ready | SELECT, INSERT, UPDATE, DELETE, GROUP BY, ORDER BY, LIMIT |
| 🔴 Redis | ✅ Ready | Virtual tables: keys, cache, hash |
| 🐬 MySQL | ✅ Ready | Full SQL (pass-through with syntax translation) |
| 🐘 PostgreSQL | ✅ Ready | Full SQL (pure pass-through) |
UniWire supports common psql meta-commands:
| Command | Description |
|---|---|
\dt |
List tables/collections |
\d tablename |
Describe table/collection schema |
\l |
List all configured backends |
\conninfo |
Show current connection info |
uniwire/
├── src/
│ ├── cli.ts # CLI with ASCII art banner
│ ├── index.ts # Main proxy orchestrator + metrics hooks
│ ├── config.ts # YAML config loader with env expansion
│ ├── logger.ts # Structured JSON logging
│ ├── metrics.ts # Prometheus-format self-observability
│ ├── shutdown.ts # Graceful shutdown with drain timeout
│ ├── protocol/
│ │ ├── pg-server.ts # PG wire protocol v3 (Simple + Extended)
│ │ ├── pg-messages.ts # Message parsers & builders (24 message types)
│ │ └── pg-types.ts # PG type system & OIDs
│ ├── parser/
│ │ └── sql-parser.ts # SQL → AST parser (PG + MySQL dialects)
│ ├── router/
│ │ └── query-router.ts # Query routing & backend dispatch
│ └── backends/
│ ├── base-adapter.ts # Abstract adapter interface
│ ├── sqlite-adapter.ts # SQLite adapter (sql.js, zero native deps)
│ ├── mongodb-adapter.ts # MongoDB SQL→MQL translator ⭐
│ ├── redis-adapter.ts # Redis virtual table adapter
│ ├── mysql-adapter.ts # MySQL pass-through adapter
│ └── postgresql-adapter.ts # PostgreSQL pass-through adapter
├── test/
│ └── unit.test.ts # 277 unit tests (real module imports)
├── web/
│ └── index.html # Landing page
├── uniwire.config.yaml # Example config
└── package.json
| Module | File | Purpose |
|---|---|---|
| SCRAM-SHA-256 | src/auth.ts |
Full SASL authentication with PBKDF2 key derivation |
| Circuit Breaker | src/circuit-breaker.ts |
CLOSED→OPEN→HALF_OPEN resilience pattern |
| Connection Pool | src/pool.ts |
Generic pool with FIFO queue, idle eviction, health checks |
| Query Timeout | src/timeout.ts |
Configurable per-backend deadline enforcement |
| RBAC | src/rbac.ts |
Role-based per-user, per-backend, per-operation access control |
| HTTP Control Plane | src/http-server.ts |
/healthz, /readyz, /metrics, /backends, /connections, /drain |
| Metrics | src/metrics.ts |
21 Prometheus counters/gauges/histograms |
| Structured Logging | src/logger.ts |
JSON-structured production logging |
| Protocol | Status | Details |
|---|---|---|
Simple Query (Q) |
✅ | Full support — psql, pgcli, CLI tools |
Extended Query (P/B/D/E/S) |
✅ | Parse, Bind, Describe, Execute, Sync — JDBC, ORMs, psycopg |
| SSL Negotiation | ✅ | Responds with N (not supported) — works with sslmode=prefer |
| Cancel Request | ✅ | Detects and handles gracefully |
| Startup Parameters | ✅ | server_version, encoding, timezone, etc. |
| Feature | Status | Details |
|---|---|---|
| SCRAM-SHA-256 Auth | ✅ | Full SASL challenge-response per RFC 7677 |
| RBAC Access Control | ✅ | Per-user, per-backend, per-operation permissions |
| Circuit Breaker | ✅ | CLOSED→OPEN→HALF_OPEN with configurable thresholds |
| Connection Pooling | ✅ | FIFO queue, idle eviction, health-check validation |
| Query Timeout | ✅ | Per-backend configurable deadlines (default 30s) |
| HTTP Control Plane | ✅ | /healthz, /readyz, /metrics, /backends, /drain |
| Prometheus Metrics | ✅ | 21 counters/gauges/histograms for full observability |
| Structured Logging | ✅ | JSON-structured logs for production log aggregation |
| Graceful Shutdown | ✅ | 10s drain timeout with signal handlers (SIGTERM/SIGINT) |
Contributions are welcome! Here are some areas to explore:
- New backends: DuckDB, ClickHouse, CockroachDB, Cassandra
- Web dashboard: Real-time query monitoring UI using Prometheus metrics
- TLS termination: In-process TLS for encrypted client connections
- Query caching: LRU cache for repeated read queries
MIT License — see LICENSE for details.
If this project helped you, consider giving it a ⭐