diff --git a/README.md b/README.md index 4bc1405..a1dcb7f 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ pip install pymongosql Or install from source: ```bash -git clone https://github.com/your-username/PyMongoSQL.git +git clone https://github.com/passren/PyMongoSQL.git cd PyMongoSQL pip install -e . ``` @@ -90,6 +90,7 @@ pip install -e . - [UPDATE Statements](#update-statements) - [DELETE Statements](#delete-statements) - [Transaction Support](#transaction-support) +- [SQL to MongoDB Mapping](#sql-to-mongodb-mapping) - [Apache Superset Integration](#apache-superset-integration) - [Limitations & Roadmap](#limitations--roadmap) - [Contributing](#contributing) @@ -534,6 +535,76 @@ finally: **Note:** MongoDB requires a replica set or sharded cluster for transaction support. Standalone MongoDB servers do not support ACID transactions at the server level. +## SQL to MongoDB Mapping + +The table below shows how PyMongoSQL translates SQL operations into MongoDB commands. + +### SQL Operations to MongoDB Commands + +| SQL Operation | MongoDB Command | Equivalent PyMongo Method | +|---|---|---| +| `SELECT ... FROM col` | `{find: col, projection: {...}}` | `db.command("find", ...)` | +| `SELECT ... FROM col WHERE ...` | `{find: col, filter: {...}}` | `db.command("find", ...)` | +| `SELECT ... ORDER BY col ASC/DESC` | `{find: ..., sort: {col: 1/-1}}` | `db.command("find", ...)` | +| `SELECT ... LIMIT n` | `{find: ..., limit: n}` | `db.command("find", ...)` | +| `SELECT ... OFFSET n` | `{find: ..., skip: n}` | `db.command("find", ...)` | +| `SELECT * FROM col.aggregate(...)` | `collection.aggregate(pipeline)` | `collection.aggregate()` | +| `INSERT INTO col ...` | `{insert: col, documents: [...]}` | `db.command("insert", ...)` | +| `UPDATE col SET ... WHERE ...` | `{update: col, updates: [{q: filter, u: {$set: {...}}, multi: true}]}` | `db.command("update", ...)` | +| `DELETE FROM col WHERE ...` | `{delete: col, deletes: [{q: filter, limit: 0}]}` | `db.command("delete", ...)` | + +### SQL Clauses to MongoDB Query Components + +| SQL Clause | MongoDB Equivalent | Example | +|---|---|---| +| `SELECT col1, col2` | `projection: {col1: 1, col2: 1}` | Fields to include | +| `SELECT *` | _(no projection)_ | Returns all fields | +| `SELECT col AS alias` | Column alias applied in result set | Post-processing rename | +| `FROM collection` | `find: "collection"` | Target collection | +| `ORDER BY col ASC` | `sort: {col: 1}` | Ascending sort | +| `ORDER BY col DESC` | `sort: {col: -1}` | Descending sort | +| `LIMIT n` | `limit: n` | Restrict result count | +| `OFFSET n` | `skip: n` | Skip first n results | + +### WHERE Operators to MongoDB Filter Operators + +| SQL WHERE Clause | MongoDB Filter | Notes | +|---|---|---| +| `field = value` | `{field: value}` | Equality shorthand | +| `field != value` | `{field: {$ne: value}}` | Not equal | +| `field > value` | `{field: {$gt: value}}` | Greater than | +| `field >= value` | `{field: {$gte: value}}` | Greater than or equal | +| `field < value` | `{field: {$lt: value}}` | Less than | +| `field <= value` | `{field: {$lte: value}}` | Less than or equal | +| `field LIKE 'pat%'` | `{field: {$regex: "pat.*"}}` | `%` → `.*`, `_` → `.` | +| `field IN (a, b, c)` | `{field: {$in: [a, b, c]}}` | Match any value in list | +| `field NOT IN (a, b)` | `{field: {$nin: [a, b]}}` | Exclude values in list | +| `field BETWEEN a AND b` | `{$and: [{field: {$gte: a}}, {field: {$lte: b}}]}` | Range filter | +| `field IS NULL` | `{field: {$eq: null}}` | Null check | +| `field IS NOT NULL` | `{field: {$ne: null}}` | Not null check | +| `cond1 AND cond2` | `{$and: [filter1, filter2]}` | Logical AND | +| `cond1 OR cond2` | `{$or: [filter1, filter2]}` | Logical OR | +| `NOT cond` | `{$not: filter}` | Logical NOT | + +### Nested Field and Array Access + +| SQL Syntax | MongoDB Dot Notation | Example | +|---|---|---| +| `profile.name` | `profile.name` | Single-level nesting | +| `account.profile.name` | `account.profile.name` | Multi-level nesting | +| `items[0].name` | `items.0.name` | Array index access | + +### DML Mapping Details + +| SQL DML | MongoDB Behavior | Notes | +|---|---|---| +| `INSERT INTO col VALUE {...}` | Single document insert | PartiQL object literal | +| `INSERT INTO col VALUE << {...}, {...} >>` | Multi-document insert | PartiQL bag syntax | +| `INSERT INTO col (c1, c2) VALUES (v1, v2)` | Columns and values zipped into document | Standard SQL syntax | +| `UPDATE col SET f1 = v1` | `{$set: {f1: v1}}` with `multi: true` | Updates all matching docs | +| `DELETE FROM col` | `{q: {}, limit: 0}` | Deletes all documents | +| `DELETE FROM col WHERE ...` | `{q: filter, limit: 0}` | Deletes all matching docs | + ## Apache Superset Integration PyMongoSQL can be used as a database driver in Apache Superset for querying and visualizing MongoDB data: diff --git a/pymongosql/__init__.py b/pymongosql/__init__.py index 4b73cce..1b444f7 100644 --- a/pymongosql/__init__.py +++ b/pymongosql/__init__.py @@ -6,7 +6,7 @@ if TYPE_CHECKING: from .connection import Connection -__version__: str = "0.4.7" +__version__: str = "0.4.8" # Globals https://www.python.org/dev/peps/pep-0249/#globals apilevel: str = "2.0" diff --git a/pymongosql/connection.py b/pymongosql/connection.py index 4a56062..4bfba6d 100644 --- a/pymongosql/connection.py +++ b/pymongosql/connection.py @@ -11,18 +11,20 @@ from pymongo.driver_info import DriverInfo from pymongo.errors import ConnectionFailure +from . import __version__ +from .common import BaseCursor +from .cursor import Cursor +from .error import DatabaseError, OperationalError +from .helper import ConnectionHelper +from .retry import RetryConfig, execute_with_retry + try: _VERSION = _get_version("pymongosql") except Exception: - _VERSION = None + _VERSION = __version__ _DRIVER_INFO = DriverInfo(name="PyMongoSQL", version=_VERSION) -from .common import BaseCursor -from .cursor import Cursor -from .error import DatabaseError, OperationalError -from .helper import ConnectionHelper -from .retry import RetryConfig, execute_with_retry _logger = logging.getLogger(__name__) diff --git a/tests/run_test_server.py b/tests/run_test_server.py index 31e23f8..4c527be 100644 --- a/tests/run_test_server.py +++ b/tests/run_test_server.py @@ -5,6 +5,7 @@ This script helps manage MongoDB instances for testing PyMongoSQL. """ + import json import os import subprocess diff --git a/tests/test_connection.py b/tests/test_connection.py index 3cc8788..48d01f9 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- import pytest -from pymongosql.connection import Connection +from pymongosql.connection import _VERSION, Connection from pymongosql.cursor import Cursor from pymongosql.error import OperationalError from tests.conftest import TEST_DB, TEST_URI @@ -26,6 +26,12 @@ def test_connection_init_with_basic_params(self, conn): assert conn.port == 27017 assert conn.database_name == "test_db" assert conn.is_connected + + # Verify driver name and version are correctly configured + assert _VERSION is not None + assert conn._pymongo_params.get("driver").name == "PyMongoSQL" + assert conn._pymongo_params.get("driver").version == _VERSION + conn.close() def test_connection_with_connect_false(self):