More changes

This commit is contained in:
Andrew Brookins 2021-10-25 14:21:39 -07:00
parent 77030ccaf5
commit 42592013ba
4 changed files with 249 additions and 71 deletions

View file

@ -0,0 +1,45 @@
# Embedded Models
Redis OM can store and query **nested models** like any document database, with the speed and power you get from Redis. Let's see how this works.
In the next example, we'll define a new `Address` model and embed it within the `Customer` model.
```python
import datetime
from typing import Optional
from redis_om.model import (
EmbeddedJsonModel,
JsonModel,
Field,
)
class Address(EmbeddedJsonModel):
address_line_1: str
address_line_2: Optional[str]
city: str = Field(index=True)
state: str = Field(index=True)
country: str
postal_code: str = Field(index=True)
class Customer(JsonModel):
first_name: str = Field(index=True)
last_name: str = Field(index=True)
email: str = Field(index=True)
join_date: datetime.date
age: int = Field(index=True)
bio: Optional[str] = Field(index=True, full_text_search=True,
default="")
# Creates an embedded model.
address: Address
```
With these two models and a Redis deployment with the RedisJSON module installed, we can run queries like the following:
```python
# Find all customers who live in San Antonio, TX
Customer.find(Customer.address.city == "San Antonio",
Customer.address.state == "TX")
```

View file

@ -0,0 +1,64 @@
# Querying
Querying uses a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee.
The example code defines `Address` and `Customer` models for use with a Redis database with the [RedisJSON](redis-json-url) module installed.
With these two classes defined, you can now:
* Validate data based on the model's type annotations using Pydantic
* Persist model instances to Redis as JSON
* Instantiate model instances from Redis by primary key (a client-generated [ULID](ulid-url))
* Query on any indexed fields in the models
```python
import datetime
from typing import Optional
from redis_om.model import (
EmbeddedJsonModel,
JsonModel,
Field,
)
class Address(EmbeddedJsonModel):
address_line_1: str
address_line_2: Optional[str]
city: str = Field(index=True)
state: str = Field(index=True)
country: str
postal_code: str = Field(index=True)
class Customer(JsonModel):
first_name: str = Field(index=True)
last_name: str = Field(index=True)
email: str = Field(index=True)
join_date: datetime.date
age: int = Field(index=True)
bio: Optional[str] = Field(index=True, full_text_search=True,
default="")
# Creates an embedded model.
address: Address
```
Here are a few example queries that use the models we defined earlier:
```python
# Find all customers with the last name "Brookins"
Customer.find(Customer.last_name == "Brookins").all()
# Find all customers that do NOT have the last name "Brookins"
Customer.find(Customer.last_name != "Brookins").all()
# Find all customers whose last name is "Brookins" OR whose age is
# 100 AND whose last name is "Smith"
Customer.find((Customer.last_name == "Brookins") | (
Customer.age == 100
) & (Customer.last_name == "Smith")).all()
# Find all customers who live in San Antonio, TX
Customer.find(Customer.address.city == "San Antonio",
Customer.address.state == "TX")
```

71
docs/validation.md Normal file
View file

@ -0,0 +1,71 @@
# Validation
Redis OM uses [Pydantic](pydantic-url) behind the scenes to validate data at runtime, based on the model's type annotations.
## Basic Type Validation
Validation works for basic type annotations like `str`. Thus, given the following model:
```python
class Customer(HashModel):
first_name: str
last_name: str
email: EmailStr
join_date: datetime.date
age: int
bio: Optional[str]
```
... Redis OM will ensure that `first_name` is always a string.
But every Redis OM model is also a Pydantic model, so you can use existing Pydantic validators like `EmailStr`, `Pattern`, and many more for complex validation!
## Complex Validation
Let's see what happens if we try to create a `Customer` object with an invalid email address.
```python
# We'll get a validation error if we try to use an invalid email address!
Customer(
first_name="Andrew",
last_name="Brookins",
email="Not an email address!",
join_date=datetime.date.today(),
age=38,
bio="Python developer, works at Redis, Inc."
)
```
This code generates the following error:
```
Traceback:
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
email
value is not a valid email address (type=value_error.email)
```
We'll also get a validation error if we change a field on a model instance to an invalid value and then try to save it:
```python
andrew = Customer(
first_name="Andrew",
last_name="Brookins",
email="andrew.brookins@example.com",
join_date=datetime.date.today(),
age=38,
bio="Python developer, works at Redis, Inc."
)
andrew.email = "Not valid"
andrew.save()
```
Once again, we get the valiation error:
```
Traceback:
pydantic.error_wrappers.ValidationError: 1 validation error for Customer
email
value is not a valid email address (type=value_error.email)
```