Skip to content

Commit 2e52aaa

Browse files
author
Peng Ren
committed
Add views in test dataset and implement get_view_names for sqlalchemy dialect
1 parent 7839c83 commit 2e52aaa

6 files changed

Lines changed: 380 additions & 378 deletions

File tree

pymongosql/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
if TYPE_CHECKING:
77
from .connection import Connection
88

9-
__version__: str = "0.5.0"
9+
__version__: str = "0.6.0"
1010

1111
# Globals https://www.python.org/dev/peps/pep-0249/#globals
1212
apilevel: str = "2.0"

pymongosql/sqlalchemy_mongodb/sqlalchemy_dialect.py

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -300,38 +300,33 @@ def has_table(self, connection, table_name: str, schema: Optional[str] = None, *
300300
return False
301301

302302
def get_table_names(self, connection, schema: Optional[str] = None, **kwargs) -> List[str]:
303-
"""Get list of collections (tables)."""
303+
"""Get list of collections (tables), excluding views."""
304304
try:
305-
# Use MongoDB listCollections command directly
306305
db_connection = connection.connection
307306
if hasattr(db_connection, "_client"):
308307
if schema:
309308
db = db_connection._client[schema]
310309
else:
311310
db = db_connection.database
312311

313-
# Use listCollections command
314-
return db.list_collection_names()
312+
return db.list_collection_names(filter={"type": {"$ne": "view"}})
315313
except Exception as e:
316314
_logger.warning(f"Failed to get table names: {e}")
317315
return []
318316

319317
def get_view_names(self, connection, schema: Optional[str] = None, **kwargs) -> List[str]:
320-
"""Get list of views.
321-
322-
MongoDB doesn't have traditional SQL views like relational databases.
323-
Return empty list to satisfy SQLAlchemy and tools like Superset.
324-
325-
Args:
326-
connection: Database connection
327-
schema: Optional schema/database name
328-
**kwargs: Additional arguments
318+
"""Get list of MongoDB views."""
319+
try:
320+
db_connection = connection.connection
321+
if hasattr(db_connection, "_client"):
322+
if schema:
323+
db = db_connection._client[schema]
324+
else:
325+
db = db_connection.database
329326

330-
Returns:
331-
Empty list as MongoDB doesn't support SQL views
332-
"""
333-
# MongoDB doesn't have traditional SQL views
334-
# Return empty list to avoid NotImplementedError
327+
return db.list_collection_names(filter={"type": "view"})
328+
except Exception as e:
329+
_logger.warning(f"Failed to get view names: {e}")
335330
return []
336331

337332
def get_columns(self, connection, table_name: str, schema: Optional[str] = None, **kwargs) -> List[Dict[str, Any]]:

tests/data/sensor_readings.json

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
[
2+
{
3+
"sensor_id": "sensor_01",
4+
"timestamp": {"$date": "2024-01-15T08:00:00Z"},
5+
"metadata": {"location": "warehouse_A", "type": "temperature"},
6+
"temperature": 22.5,
7+
"humidity": 45.2
8+
},
9+
{
10+
"sensor_id": "sensor_01",
11+
"timestamp": {"$date": "2024-01-15T08:15:00Z"},
12+
"metadata": {"location": "warehouse_A", "type": "temperature"},
13+
"temperature": 22.8,
14+
"humidity": 44.9
15+
},
16+
{
17+
"sensor_id": "sensor_01",
18+
"timestamp": {"$date": "2024-01-15T08:30:00Z"},
19+
"metadata": {"location": "warehouse_A", "type": "temperature"},
20+
"temperature": 23.1,
21+
"humidity": 44.5
22+
},
23+
{
24+
"sensor_id": "sensor_02",
25+
"timestamp": {"$date": "2024-01-15T08:00:00Z"},
26+
"metadata": {"location": "warehouse_B", "type": "temperature"},
27+
"temperature": 19.3,
28+
"humidity": 52.1
29+
},
30+
{
31+
"sensor_id": "sensor_02",
32+
"timestamp": {"$date": "2024-01-15T08:15:00Z"},
33+
"metadata": {"location": "warehouse_B", "type": "temperature"},
34+
"temperature": 19.5,
35+
"humidity": 51.8
36+
},
37+
{
38+
"sensor_id": "sensor_02",
39+
"timestamp": {"$date": "2024-01-15T08:30:00Z"},
40+
"metadata": {"location": "warehouse_B", "type": "temperature"},
41+
"temperature": 19.8,
42+
"humidity": 51.3
43+
},
44+
{
45+
"sensor_id": "sensor_03",
46+
"timestamp": {"$date": "2024-01-15T08:00:00Z"},
47+
"metadata": {"location": "office_1", "type": "environment"},
48+
"temperature": 21.0,
49+
"humidity": 40.0
50+
},
51+
{
52+
"sensor_id": "sensor_03",
53+
"timestamp": {"$date": "2024-01-15T08:15:00Z"},
54+
"metadata": {"location": "office_1", "type": "environment"},
55+
"temperature": 21.3,
56+
"humidity": 39.7
57+
},
58+
{
59+
"sensor_id": "sensor_03",
60+
"timestamp": {"$date": "2024-01-15T08:30:00Z"},
61+
"metadata": {"location": "office_1", "type": "environment"},
62+
"temperature": 21.6,
63+
"humidity": 39.4
64+
},
65+
{
66+
"sensor_id": "sensor_01",
67+
"timestamp": {"$date": "2024-01-15T09:00:00Z"},
68+
"metadata": {"location": "warehouse_A", "type": "temperature"},
69+
"temperature": 23.5,
70+
"humidity": 43.8
71+
},
72+
{
73+
"sensor_id": "sensor_02",
74+
"timestamp": {"$date": "2024-01-15T09:00:00Z"},
75+
"metadata": {"location": "warehouse_B", "type": "temperature"},
76+
"temperature": 20.1,
77+
"humidity": 50.9
78+
},
79+
{
80+
"sensor_id": "sensor_03",
81+
"timestamp": {"$date": "2024-01-15T09:00:00Z"},
82+
"metadata": {"location": "office_1", "type": "environment"},
83+
"temperature": 22.0,
84+
"humidity": 38.9
85+
}
86+
]

tests/run_test_server.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ def load_config():
5858
if "test_data_file" in config and not TEST_DATA_FILES:
5959
TEST_DATA_FILES = {"legacy": config["test_data_file"]}
6060

61+
# Time-series collection definitions
62+
TIMESERIES_COLLECTIONS = config.get("timeseries_collections", {})
63+
6164

6265
def check_docker():
6366
"""Check if Docker is available and running"""
@@ -244,6 +247,82 @@ def load_test_data():
244247
return test_data
245248

246249

250+
def _create_views(db):
251+
"""Create MongoDB views for testing"""
252+
views = [
253+
{
254+
"name": "active_users",
255+
"viewOn": "users",
256+
"pipeline": [
257+
{"$match": {"active": True}},
258+
{"$project": {"_id": 1, "name": 1, "email": 1, "age": 1, "balance": 1}},
259+
],
260+
},
261+
{
262+
"name": "completed_orders",
263+
"viewOn": "orders",
264+
"pipeline": [
265+
{"$match": {"status": "completed"}},
266+
{
267+
"$project": {
268+
"_id": 1,
269+
"user_id": 1,
270+
"order_date": 1,
271+
"total_amount": 1,
272+
"currency": 1,
273+
}
274+
},
275+
],
276+
},
277+
{
278+
"name": "in_stock_products",
279+
"viewOn": "products",
280+
"pipeline": [
281+
{"$match": {"in_stock": True}},
282+
{"$project": {"_id": 1, "name": 1, "price": 1, "category": 1, "quantity": 1}},
283+
],
284+
},
285+
{
286+
"name": "orders_with_users",
287+
"viewOn": "orders",
288+
"pipeline": [
289+
{
290+
"$lookup": {
291+
"from": "users",
292+
"localField": "user_id",
293+
"foreignField": "_id",
294+
"as": "user",
295+
}
296+
},
297+
{"$unwind": "$user"},
298+
{
299+
"$project": {
300+
"_id": 1,
301+
"order_date": 1,
302+
"status": 1,
303+
"total_amount": 1,
304+
"currency": 1,
305+
"user_name": "$user.name",
306+
"user_email": "$user.email",
307+
}
308+
},
309+
],
310+
},
311+
]
312+
313+
for view in views:
314+
# Drop existing view if it exists
315+
db[view["name"]].drop()
316+
db.command(
317+
{
318+
"create": view["name"],
319+
"viewOn": view["viewOn"],
320+
"pipeline": view["pipeline"],
321+
}
322+
)
323+
print(f" Created view '{view['name']}' on '{view['viewOn']}'")
324+
325+
247326
def setup_test_data():
248327
"""Setup test data in MongoDB"""
249328
print("Setting up test data...")
@@ -273,11 +352,23 @@ def setup_test_data():
273352
# Drop existing collection
274353
db[collection_name].drop()
275354

355+
# Create time-series collection if configured
356+
if collection_name in TIMESERIES_COLLECTIONS:
357+
ts_opts = TIMESERIES_COLLECTIONS[collection_name]
358+
db.create_collection(
359+
collection_name,
360+
timeseries=ts_opts,
361+
)
362+
print(f" Created time-series collection '{collection_name}' (timeField={ts_opts['timeField']})")
363+
276364
# Insert new data
277365
db[collection_name].insert_many(test_data[collection_name])
278366
count = db[collection_name].count_documents({})
279367
print(f" Inserted {count} {collection_name}")
280368

369+
# Create MongoDB views
370+
_create_views(db)
371+
281372
print("[SUCCESS] Test data setup completed successfully!")
282373
return True
283374

tests/server_config.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525
"analytics": "data/analytics.json",
2626
"departments": "data/departments.json",
2727
"suppliers": "data/suppliers.json",
28-
"user-orders": "data/user-orders.json"
28+
"user-orders": "data/user-orders.json",
29+
"sensor_readings": "data/sensor_readings.json"
30+
},
31+
"timeseries_collections": {
32+
"sensor_readings": {
33+
"timeField": "timestamp",
34+
"metaField": "metadata",
35+
"granularity": "minutes"
36+
}
2937
}
3038
}

0 commit comments

Comments
 (0)