Redis OM

Objecting mapping and more, for Redis.

--- [![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Build Status][ci-svg]][ci-url] Redis OM is a library that helps you build modern Python applications with Redis. **Redis OM Python** | [Redis OM Node.js][redis-om-js] | [Redis OM Spring][redis-om-spring] | [Redis OM .NET][redis-om-dotnet]
Table of contents - [Why Redis OM?](#why) - [Getting started](#getting-started) - [Installation](#installation) - [Documentation](#documentation) - [Troubleshooting](#troubleshooting) - [Contributing](#contributing) - [License](#license)
## ➡ Why Redis OM? Redis OM is a library of high-level tools that help you build modern Python applications with Redis. This *preview release* includes our first major component: a **declarative model class** backed by Redis. ## 🏁 Getting started ### Object Mapping With Redis OM, you get powerful data modeling, extensible data validation with [Pydantic](pydantic-url), and rich query expressions with a small amount of code. Check out this example of data modeling and validation. First, we're going to create a `Customer` model that we can use to save data to Redis. ```python import datetime from typing import Optional from pydantic import EmailStr from redis_om.model import ( HashModel, ) class Customer(HashModel): first_name: str last_name: str email: EmailStr join_date: datetime.date age: int bio: Optional[str] ``` Here, we've defined a `Customer` model with the `HashModel` class from redis-om. This model will save data in Redis as a [Redis Hash](https://redis.io/topics/data-types). Next, let's see how Redis OM makes it easy to save and retrieve `Customer` data in Redis. ```python # We can create a new Customer object: 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." ) # The model generates a globally unique primary key automatically without # needing to talk to Redis. print(andrew.pk) # '01FJM6PH661HCNNRC884H6K30C' # We can save the model to Redis. andrew.save() # Now, we can retrieve this customer with its primary key: other_andrew = Customer.get('01FJM6PH661HCNNRC884H6K30C') # The original model and this one pass an equality check. assert other_andrew == andrew ``` Now, let's talk about **validation**. Did you notice the type annotation for the `email` field was `EmailStr`? `EmailStr` is a [Pydantic field validator](https://pydantic-docs.helpmanual.io/usage/types/). Because every Redis OM model is also a Pydantic model, you can use Pydantic validators like `EmailStr`, `Pattern`, and many more! Let's see what happens if we try to instantiate our `Customer` class 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." ) # 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 try to save a model # instance with an invalid email. 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." ) # Sometime later... andrew.email = "Not valid" andrew.save() # Traceback: # pydantic.error_wrappers.ValidationError: 1 validation error for Customer # email # value is not a valid email address (type=value_error.email) ``` Data modeling, validation, and persistent to Redis all work regardless of where you run Redis. But can we do more? Yes, we can! Next, we'll talk about the **rich query expressions** and **embedded models** that Redis OM gives you when you're using the RediSearch and RedisJSON Redis modules. ### 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") ``` Ready to learn more? Read the [getting started](docs/getting_started.md) guide or check out how to [add Redis OM to your FastAPI project](docs/integrating.md). ## 💻 Installation Installation is simple with `pip`, Poetry, or Pipenv. ```sh # With pip $ pip install redis-om # Or, using Poetry $ poetry add redis-om ``` ## 📚 Documentation Documentation is available [here](docs/index.md). ## ⛏️ Troubleshooting If you run into trouble or have any questions, we're here to help! First, check the [FAQ](docs/faq.md). If you don't find the answer there, hit us up on the [Redis Discord Server](http://discord.gg/redis). ## ✨ RediSearch and RedisJSON Some advanced features of Redis OM rely on core features from two source available Redis modules: **RediSearch** and **RedisJSON**. To learn more, read [our documentation](docs/redis_modules.md). ## ❤️ Contributing We'd love your contributions! **Bug reports** are especially helpful at this stage of the project. [You can open a bug report on GitHub](https://github.com/redis-om/redis-om-python/issues/new). You can also **contribute documentation** -- or just let us know if something needs more detail. [Open an issue on GitHub](https://github.com/redis-om/redis-om-python/issues/new) to get started. ## License Redis OM uses the [BSD 3-Clause license][license-url]. [version-svg]: https://img.shields.io/pypi/v/redis-om?style=flat-square [package-url]: https://pypi.org/project/redis-om/ [ci-svg]: https://img.shields.io/github/workflow/status/redis-om/redis-om-python/python?style=flat-square [ci-url]: https://github.com/redis-om/redis-om-python/actions/workflows/build.yml [license-image]: http://img.shields.io/badge/license-MIT-green.svg?style=flat-square [license-url]: LICENSE [redis-om-website]: https://developer.redis.com [redis-om-js]: https://github.com/redis-om/redis-om-js [redis-om-dotnet]: https://github.com/redis-om/redis-om-dotnet [redis-om-spring]: https://github.com/redis-om/redis-om-spring [redisearch-url]: https://oss.redis.com/redisearch/ [redis-json-url]: https://oss.redis.com/redisjson/ [pydantic-url]: https://github.com/samuelcolvin/pydantic [ulid-url]: https://github.com/ulid/spec