Source code for simstack.util.mock_db
import asyncio
from typing import Type, TypeVar, Dict, List, Optional
from odmantic import Model, ObjectId
T = TypeVar("T", bound=Model)
[docs]
class InMemoryCollection:
def __init__(self, engine: "InMemoryAIOEngine"):
self._engine = engine
self._store: List[Dict] = []
def __getitem__(self, index: int) -> Dict:
return self._store[index]
def __setitem__(self, index: int, value: Dict):
self._store[index] = value
def __iter__(self):
return iter(self._store)
[docs]
class InMemoryAIOEngine:
def __init__(self):
# Stores data as {collection_name: [documents]}
self._store: Dict[str, InMemoryCollection] = {}
[docs]
async def save(self, instance: T) -> T:
collection_name = (
instance.__collection__
if hasattr(instance, "__collection__")
else instance.__class__.__name__.lower()
)
obj_dict = instance.model_dump()
# Ensure the instance has an ObjectId assigned
if not instance.id:
instance.id = ObjectId()
obj_dict["id"] = instance.id
# Initialize collection if it doesn't exist
if collection_name not in self._store:
self._store[collection_name] = InMemoryCollection(self)
# Update if already exists
existing_index = next(
(
i
for i, obj in enumerate(self._store[collection_name])
if obj["id"] == instance.id
),
None,
)
if existing_index is not None:
self._store[collection_name][existing_index] = obj_dict
else:
self._store[collection_name].append(obj_dict)
return instance
[docs]
async def find(self, model: Type[T], **query) -> List[T]:
collection_name = (
model.__collection__
if hasattr(model, "__collection__")
else model.__name__.lower()
)
all_objects = self._store.get(collection_name, [])
results = []
for obj_dict in all_objects:
if all(obj_dict.get(k) == v for k, v in query.items()):
results.append(model.model_validate(obj_dict))
return results
[docs]
async def find_one(self, model: Type[T], condition=None, **query) -> Optional[T]:
# Handle both keyword arguments and condition objects
if condition is not None:
# For conditions like ModelMapping.name == class_name
# This is a more robust approach to extract field name and value
condition_str = str(condition)
# Look for the pattern: field_name == value or field_name: {$eq: value}
if "==" in condition_str:
# Handle direct comparison like ModelMapping.name == 'TestClass'
parts = condition_str.split("==")
if len(parts) == 2:
field_name = parts[0].strip().split(".")[-1]
value = parts[1].strip().strip("'\"")
query[field_name] = value
elif "$eq" in condition_str:
# Handle MongoDB-style query like {'mapping': {'$eq': 'tests.core.test_import_class.TestClass'}}
import re
# Extract field name and value using regex
field_match = re.search(
r"'(\w+)':\s*\{'?\$eq'?:\s*'([^']+)'", condition_str
)
if field_match:
field_name = field_match.group(1)
value = field_match.group(2)
query[field_name] = value
else:
# Fallback - try to extract from the string representation
# Look for pattern like "ModelMapping.field_name"
field_match = re.search(r"(\w+)\.(\w+)", condition_str)
if field_match:
field_name = field_match.group(2)
# Try to extract the value (this is still a fallback)
value_match = re.search(r"'([^']+)'(?:[^']*$)", condition_str)
if value_match:
value = value_match.group(1)
query[field_name] = value
found = await self.find(model, **query)
return found[0] if found else None
# Example Usage:
if __name__ == "__main__":
from odmantic import Model
class BinaryOperationInput(Model):
arg1: int
arg2: int
async def test_engine():
engine = InMemoryAIOEngine()
obj = BinaryOperationInput(arg1=1, arg2=2)
# Saving object
await engine.save(obj)
# Finding objects
found_objs = await engine.find(BinaryOperationInput, arg1=1)
print("Found objects:", found_objs)
# Find one object
found_one = await engine.find_one(BinaryOperationInput, arg2=2)
print("Found single object:", found_one)
asyncio.run(test_engine())