Datastore¶
Datastore is a highly scalable NoSQL database for your applications. The datastore
module in gcp-pilot provides an ORM-like interface for interacting with Google Cloud Datastore.
Installation¶
To use the Datastore functionality, you need to install gcp-pilot with the datastore extra:
pip install gcp-pilot[datastore]
Usage¶
The datastore
module provides a way to define document classes and perform CRUD operations on them.
Defining Document Classes¶
To define a document class, you need to inherit from the Document
class:
from gcp_pilot.datastore import Document, EmbeddedDocument
from datetime import datetime
from typing import List, Optional
# Define an embedded document class
class Address(EmbeddedDocument):
street: str
city: str
state: str
zip_code: str
# You can customize the kind name (collection name)
class Config:
kind = "addresses"
# Define a document class
class User(Document):
name: str
email: str
age: int
created_at: datetime = datetime.now()
address: Optional[Address] = None
tags: List[str] = []
# You can customize the kind name (collection name)
# and exclude fields from indexing
class Config:
kind = "users"
exclude_from_indexes = ["address"]
Creating Documents¶
# Create a new user
user = User(
name="John Doe",
email="john@example.com",
age=30,
address=Address(
street="123 Main St",
city="Anytown",
state="CA",
zip_code="12345"
),
tags=["customer", "premium"]
)
# Save the user to Datastore
user.save()
print(f"User created with ID: {user.pk}")
# You can also create a document using the Manager
from gcp_pilot.datastore import Manager
# Create a manager for the User class
user_manager = Manager(User)
# Create a user using the manager
user = user_manager.create(
name="Jane Smith",
email="jane@example.com",
age=25,
address=Address(
street="456 Oak St",
city="Othertown",
state="NY",
zip_code="67890"
),
tags=["customer"]
)
print(f"User created with ID: {user.pk}")
Querying Documents¶
from gcp_pilot.datastore import Manager, DoesNotExist, MultipleObjectsFound
# Create a manager for the User class
user_manager = Manager(User)
# Get a user by primary key
user = user_manager.get(pk="user_id_here")
print(f"User: {user.name}, Email: {user.email}")
# Get a user by a field value
try:
user = user_manager.get(email="john@example.com")
print(f"User: {user.name}, Email: {user.email}")
except DoesNotExist:
print("User not found")
except MultipleObjectsFound:
print("Multiple users found with the same email")
# Query users with filters
users = user_manager.filter(age__gt=25) # Users older than 25
for user in users:
print(f"User: {user.name}, Age: {user.age}")
# Query with multiple filters
users = user_manager.filter(age__gt=25, tags__contains="premium")
for user in users:
print(f"User: {user.name}, Age: {user.age}, Tags: {user.tags}")
# Query with ordering
users = user_manager.query(order_by="age") # Order by age ascending
for user in users:
print(f"User: {user.name}, Age: {user.age}")
users = user_manager.query(order_by="-age") # Order by age descending
for user in users:
print(f"User: {user.name}, Age: {user.age}")
# Query with pagination
users = user_manager.query(page_size=10) # Get 10 users per page
for user in users:
print(f"User: {user.name}")
# Query with distinct values
users = user_manager.query(distinct_on="age")
for user in users:
print(f"User: {user.name}, Age: {user.age}")
Updating Documents¶
# Update a user by primary key
user_manager.update(
pk="user_id_here",
name="John Smith",
age=31
)
# Update a user object
user = user_manager.get(pk="user_id_here")
user.name = "John Smith"
user.age = 31
user.save()
Deleting Documents¶
# Delete a user by primary key
user_manager.delete(pk="user_id_here")
# Delete a user object
user = user_manager.get(pk="user_id_here")
user.delete()
Advanced Usage¶
Custom Managers¶
You can create custom managers for your document classes to add specialized query methods:
from gcp_pilot.datastore import Manager, Document
class UserManager(Manager):
def get_premium_users(self):
return self.filter(tags__contains="premium")
def get_users_by_age_range(self, min_age, max_age):
return self.filter(age__gte=min_age, age__lte=max_age)
class User(Document):
name: str
email: str
age: int
tags: list = []
# Attach the custom manager
objects = UserManager()
class Config:
kind = "users"
# Use the custom manager
premium_users = User.objects.get_premium_users()
for user in premium_users:
print(f"Premium user: {user.name}")
# Get users in an age range
users_25_to_35 = User.objects.get_users_by_age_range(25, 35)
for user in users_25_to_35:
print(f"User: {user.name}, Age: {user.age}")
Query Operators¶
The Datastore module supports various query operators:
__eq
: Equal to (default if no operator is specified)__ne
: Not equal to__lt
: Less than__lte
: Less than or equal to__gt
: Greater than__gte
: Greater than or equal to__in
: In a list of values__contains
: Contains a value (for lists)__startswith
: Starts with a value (for strings)__endswith
: Ends with a value (for strings)
# Examples of query operators
users = user_manager.filter(age__lt=30) # Users younger than 30
users = user_manager.filter(name__startswith="J") # Users whose name starts with J
users = user_manager.filter(tags__contains="premium") # Users with the premium tag
users = user_manager.filter(age__in=[25, 30, 35]) # Users of specific ages
Embedded Documents¶
Embedded documents are stored as part of their parent document:
from gcp_pilot.datastore import Document, EmbeddedDocument
from typing import List, Optional
class Address(EmbeddedDocument):
street: str
city: str
state: str
zip_code: str
class Contact(EmbeddedDocument):
phone: str
email: str
class User(Document):
name: str
address: Optional[Address] = None
contacts: List[Contact] = []
class Config:
kind = "users"
# Create a user with embedded documents
user = User(
name="John Doe",
address=Address(
street="123 Main St",
city="Anytown",
state="CA",
zip_code="12345"
),
contacts=[
Contact(phone="555-1234", email="john@example.com"),
Contact(phone="555-5678", email="john@work.com")
]
)
# Save the user
user.save()
# Query users by embedded document fields
user_manager = Manager(User)
users = user_manager.filter(**{"address.city": "Anytown"})
for user in users:
print(f"User: {user.name}, City: {user.address.city}")
Error Handling¶
The Datastore module provides custom exceptions for handling common errors:
from gcp_pilot.datastore import Manager, DoesNotExist, MultipleObjectsFound
user_manager = Manager(User)
try:
# Try to get a user that doesn't exist
user = user_manager.get(email="nonexistent@example.com")
except DoesNotExist:
print("User not found")
try:
# Try to get a user when multiple users have the same email
user = user_manager.get(age=30) # Multiple users might be 30 years old
except MultipleObjectsFound:
print("Multiple users found")