WIP on README - first draft
This commit is contained in:
parent
703be3e0fa
commit
62240723ca
17 changed files with 197 additions and 21 deletions
204
README.md
204
README.md
|
@ -1,23 +1,193 @@
|
||||||
# Redis Developer Python
|
<h1 align="center">Redis Velvet</h1>
|
||||||
|
<p align="center">
|
||||||
|
<p align="center">
|
||||||
|
Objecting mapping and more, for Redis.
|
||||||
|
</p>
|
||||||
|
</p>
|
||||||
|
|
||||||
redis-developer-python is a high-level library containing useful Redis
|
---
|
||||||
abstractions, like an ORM, rate limiter, and leaderboard.
|
|
||||||
|
[![Version][version-svg]][package-url]
|
||||||
|
[![License][license-image]][license-url]
|
||||||
|
[![Build Status][ci-svg]][ci-url]
|
||||||
|
|
||||||
|
Redis Velvet is a library that helps you build modern Python applications with Redis.
|
||||||
|
|
||||||
|
**Redis Velvet Python** | [Redis Velvet Node.js][redis-velvet-js] | [Redis Velvet Spring][redis-velvet-spring] | [Redis Velvet .NET][redis-velvet-dotnet]
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><strong>Table of contents</strong></summary>
|
||||||
|
|
||||||
|
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||||
|
|
||||||
|
|
||||||
## ORM
|
- [Why Redis Velvet?](#why)
|
||||||
|
- [Getting started](#getting-started)
|
||||||
|
- [Installation](#installation)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Troubleshooting](#troubleshooting)
|
||||||
|
- [Contributing](#contributing)
|
||||||
|
- [License](#license)
|
||||||
|
|
||||||
redis-developer-python includes an Object Redis Mapper.
|
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## ➡ Why Redis Velvet?
|
||||||
|
|
||||||
|
Redis Velvet 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 Velvet, you get powerful data modeling, validation, and query expressions with a small amount of code. Check out this example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
import datetime
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from redis_developer.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)
|
||||||
|
|
||||||
|
|
||||||
### Declarative model classes
|
class Customer(JsonModel):
|
||||||
### Serialization and validation based on model classes
|
first_name: str = Field(index=True)
|
||||||
### Save a model instance to Redis
|
last_name: str = Field(index=True)
|
||||||
### Get a single model instance from Redis
|
email: str = Field(index=True)
|
||||||
### Update a model instance in Redis
|
join_date: datetime.date
|
||||||
### Batch/bulk insert and updates
|
age: int = Field(index=True)
|
||||||
### Declarative “primary key”
|
bio: Optional[str] = Field(index=True, full_text_search=True,
|
||||||
### Embedded models (JSON)
|
default="")
|
||||||
### Exact-value queries on indexed fields
|
|
||||||
### Declarative index creation and automatic index management (RediSearch)
|
# Creates an embedded model.
|
||||||
### Ad-hoc numeric range and full-text queries (RediSearch)
|
address: Address
|
||||||
### Aggregations (RediSearch)
|
```
|
||||||
|
|
||||||
|
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](pydantic-url)
|
||||||
|
* 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
|
||||||
|
|
||||||
|
### Querying
|
||||||
|
Querying uses a rich expression syntax inspired by the Django ORM, SQLAlchemy, and Peewee.
|
||||||
|
|
||||||
|
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 Velvet to your FastAPI project](docs/integrating.md).
|
||||||
|
|
||||||
|
### RediSearch and RediJSON
|
||||||
|
|
||||||
|
Redis Velvet relies on core features from two source available Redis modules: **RediSearch** and **RedisJSON**.
|
||||||
|
|
||||||
|
RediSearch is a module that adds querying and full-text search to Redis, while RedisJSON adds support for the JSON data type to Redis.
|
||||||
|
|
||||||
|
#### Why this is important
|
||||||
|
|
||||||
|
Without RediSearch or RedisJSON installed, you can still use Redis Velvet to create declarative models backed by Redis. We'll store your model data in Redis as Hashes, and you can retrieve models using their primary keys. You'll also get all the validation features from Pydantic.
|
||||||
|
|
||||||
|
So, what won't work without these modules?
|
||||||
|
|
||||||
|
1. Without RedisJSON, you won't be able to nest models inside each other, like we did with the example model of a `Customer` model that has an `Address` embedded inside it. This is because Redis Velvet will store your models in Redis as Hashes, which can't contain other container types like Lists or Hashes.
|
||||||
|
2. Without RediSearch, you won't be able to use our expressive queries to find models -- just the primary key.
|
||||||
|
|
||||||
|
#### So how do you get RediSearch and RedisJSON?
|
||||||
|
|
||||||
|
You can use RediSearch and RedisJSON with your self-hosted Redis deployment. Just follow the instructions on installing the binary versions of the modules in their Quick Start Guides:
|
||||||
|
|
||||||
|
- [RedisJSON](https://oss.redis.com/redisjson/#download-and-running-binaries)
|
||||||
|
- [RediSearch](https://oss.redis.com/redisearch/Quick_Start/#download_and_running_binaries)
|
||||||
|
|
||||||
|
RediSearch and RedisJSON are also available on all Redis Cloud managed services. [Get started here.](https://redis.com/try-free/)
|
||||||
|
|
||||||
|
## 💻 Installation
|
||||||
|
|
||||||
|
Installation is simple with `pip`, Poetry, or Pipenv.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
$ pip install redis-velvet
|
||||||
|
|
||||||
|
# Or, using Poetry
|
||||||
|
$ poetry add redis-velvet
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📚 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).
|
||||||
|
|
||||||
|
|
||||||
|
## ❤️ Contributing
|
||||||
|
|
||||||
|
We'd love your contributions!
|
||||||
|
|
||||||
|
**Bug reports** are especially helpful at this stage of the project. [You can open a big report on GitHub](https://github.com/redis-developer/redis-developer-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-developer/redis-developer-python/issues/new) to get started.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
Redis Velvet is [MIT licensed][license-url].
|
||||||
|
|
||||||
|
<!-- Badges -->
|
||||||
|
|
||||||
|
[version-svg]: https://img.shields.io/pypi/v/redis-velvet?style=flat-square
|
||||||
|
[package-url]: https://pypi.org/project/redis-velvet/
|
||||||
|
[ci-svg]: https://img.shields.io/github/workflow/status/redis-developer/redis-developer-python/python?style=flat-square
|
||||||
|
[ci-url]: https://github.com/redis-developer/redis-developer-python/actions/workflows/build.yml
|
||||||
|
[license-image]: http://img.shields.io/badge/license-MIT-green.svg?style=flat-square
|
||||||
|
[license-url]: LICENSE
|
||||||
|
|
||||||
|
<!-- Links -->
|
||||||
|
|
||||||
|
[redis-developer-website]: https://developer.redis.com
|
||||||
|
[redis-velvet-js]: https://github.com/redis-developer/redis-velvet-js
|
||||||
|
[redis-velvet-dotnet]: https://github.com/redis-developer/redis-velvet-dotnet
|
||||||
|
[redis-velvet-spring]: https://github.com/redis-developer/redis-velvet-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
|
||||||
|
|
||||||
|
|
0
docs/getting_started.md
Normal file
0
docs/getting_started.md
Normal file
0
docs/index.md
Normal file
0
docs/index.md
Normal file
0
docs/integrating.md
Normal file
0
docs/integrating.md
Normal file
|
@ -2,5 +2,6 @@ from .model import (
|
||||||
RedisModel,
|
RedisModel,
|
||||||
HashModel,
|
HashModel,
|
||||||
JsonModel,
|
JsonModel,
|
||||||
|
EmbeddedJsonModel,
|
||||||
Field
|
Field
|
||||||
)
|
)
|
0
redis_developer/model/cli/__init__.py
Normal file
0
redis_developer/model/cli/__init__.py
Normal file
|
@ -1,5 +1,5 @@
|
||||||
import click
|
import click
|
||||||
from redis_developer.orm.migrations.migrator import Migrator
|
from redis_developer.om.migrations.migrator import Migrator
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
0
redis_developer/model/migrations/__init__.py
Normal file
0
redis_developer/model/migrations/__init__.py
Normal file
|
@ -7,7 +7,7 @@ from typing import Optional
|
||||||
from redis import ResponseError
|
from redis import ResponseError
|
||||||
|
|
||||||
from redis_developer.connections import get_redis_connection
|
from redis_developer.connections import get_redis_connection
|
||||||
from redis_developer.orm.model import model_registry
|
from redis_developer.om.model import model_registry
|
||||||
|
|
||||||
redis = get_redis_connection()
|
redis = get_redis_connection()
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
|
@ -1331,3 +1331,8 @@ class JsonModel(RedisModel, abc.ABC):
|
||||||
raise sortable_tag_error
|
raise sortable_tag_error
|
||||||
return schema
|
return schema
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
|
class EmbeddedJsonModel(JsonModel, abc.ABC):
|
||||||
|
class Meta:
|
||||||
|
embedded = True
|
|
@ -1,7 +1,7 @@
|
||||||
import abc
|
import abc
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from redis_developer.orm.model import JsonModel, HashModel
|
from redis_developer.om.model import JsonModel, HashModel
|
||||||
|
|
||||||
|
|
||||||
class BaseJsonModel(JsonModel, abc.ABC):
|
class BaseJsonModel(JsonModel, abc.ABC):
|
|
@ -1,7 +1,7 @@
|
||||||
from collections import Sequence
|
from collections import Sequence
|
||||||
from typing import Any, Dict, Mapping, Union, List
|
from typing import Any, Dict, Mapping, Union, List
|
||||||
|
|
||||||
from redis_developer.orm.model import Expression
|
from redis_developer.om.model import Expression
|
||||||
|
|
||||||
|
|
||||||
class LogicalOperatorForListOfExpressions(Expression):
|
class LogicalOperatorForListOfExpressions(Expression):
|
Loading…
Reference in a new issue