Skip to content

Overview

Rapyer Logo

Pydantic models with Redis as the storage backend

Python 3.10+ License: MIT Redis codecov PyPI version Downloads Redis

๐Ÿš€ Why Redis?

Redis is an in-memory key-value store designed for fast caching, queues, and real-time data processing. It offers high speed, atomic operations, and excellent scalability, making it ideal for low-latency applications.

Performance Benefits

Redis provides microsecond-level latency and can handle millions of operations per second, making it perfect for real-time applications.

โšก The Power of Pydantic

Pydantic has revolutionized Python data validation and serialization. There are already many libraries that use Pydantic for ORM: Beanie (MongoDB), FastAPI (HTTP server), etc. However, the current packages to support Redis are somewhat lacking.

Type Safety

Pydantic's strength lies in its automatic validation, type safety, and developer-friendly API that makes working with complex data structures intuitive and safe.

๐ŸŽฏ Introducing Rapyer

Rapyer bridges the gap between Redis's performance and Pydantic's type safety, creating a powerful combination optimized for real-world applications.

๐Ÿ”ง Wide Variety of Field Support

Rapyer supports a wide variety of field types and offers users the ability to perform complex atomic actions on these fields:

  • Strings - Optimized Redis string storage
  • Integers - Native Redis number handling
  • Floats - Precise decimal operations
  • Booleans - Efficient boolean storage
  • Lists - Full atomic list operations
  • Dictionaries - Atomic dict updates and lookups
  • Sets - Redis set operations with Python interface
  • RedisStr - Enhanced string type with IDE autocomplete
  • RedisList - List type with atomic operations
  • RedisDict - Dictionary type with atomic operations

Custom Types

You can also create your own custom types or decide how to save the data in Redis. Other types are also supported - essentially we support any type that can be serialized to pickle, however, they can be used to perform atomic operations.

โš›๏ธ Atomic Operations for Race Condition Prevention

Every operation in Rapyer is designed to be atomic and safe in concurrent environments:

Atomic Operations Example
# All operations are atomic - no race conditions possible
await user.tags.aappend("python")          # Atomic list append
await user.metadata.aupdate(role="dev")    # Atomic dict update
user.score += 10
await user.score.asave()                   # Atomic increment

Concurrency Safe

For complex multi-field operations, Rapyer provides lock context managers and pipeline operations that ensure consistency across multiple changes.

๐Ÿš€ Quick Example

Complete Rapyer Example
import asyncio
from rapyer import AtomicRedisModel
from typing import List, Dict


class User(AtomicRedisModel):
    name: str
    age: int
    tags: List[str] = []
    metadata: Dict[str, str] = {}


async def main():
    # Create and save
    user = User(name="Alice", age=25)
    await user.asave()

    # Atomic operations
    await user.tags.aappend("developer")                    # (1)!
    await user.tags.aextend(["python", "redis"])           # (2)!
    await user.metadata.aupdate(team="backend", level="senior")  # (3)!

    # Load and verify
    loaded = await User.aget(user.key)
    print(f"User: {loaded.name}, Tags: {loaded.tags}")     # (4)!


if __name__ == "__main__":
    asyncio.run(main())
  1. Add a single tag atomically
  2. Extend with multiple tags in one operation
  3. Update multiple metadata fields atomically
  4. Load the complete model from Redis

Core Philosophy

This example demonstrates Rapyer's core philosophy: combine Redis performance with Pydantic safety, all while maintaining atomic operations that prevent data corruption in concurrent applications.

Why Choose Rapyer?

Comparison with Other Redis ORMs

Feature Rapyer Redis OM pydantic-redis orredis
๐Ÿš€ Atomic Operations โœ… Built-in for all operations โŒ Manual transactions only โŒ Manual transactions only โŒ Manual transactions only
๐Ÿ”’ Lock Context Manager โœ… Automatic with async with model.alock() โŒ Manual implementation required โŒ Manual implementation required โŒ Manual implementation required
โšก Pipeline Operations โœ… True atomic batching with model.apipeline() โš ๏ธ Basic pipeline support โŒ No pipeline support โŒ No pipeline support
๐ŸŒ Universal Type Support โœ… Native + automatic serialization for any type โš ๏ธ HashModel vs JsonModel limitations โš ๏ธ Limited complex types โš ๏ธ Limited complex types
๐Ÿ”„ Race Condition Safe โœ… Built-in prevention with Lua scripts โŒ Manual implementation required โŒ Manual implementation required โŒ Manual implementation required
๐Ÿ“ฆ Redis JSON Native โœ… Optimized JSON operations โœ… Via JsonModel only โŒ Hash-based โŒ Hash-based
โš™๏ธ Pydantic v2 Support โœ… Full compatibility โœ… Recent support โš ๏ธ Limited support โš ๏ธ Basic support
๐ŸŽฏ Type Safety โœ… Complete validation โœ… Good validation โœ… Good validation โš ๏ธ Basic validation
โšก Performance โœ… Optimized operations โœ… Good performance โœ… Standard โœ… Rust-optimized
๐Ÿ”ง Nested Model Support โœ… Full Redis functionality preserved โš ๏ธ Limited nesting โœ… Advanced relationships โš ๏ธ Basic support
๐ŸŽ›๏ธ Custom Primary Keys โœ… Field annotations โŒ ULIDs only โœ… Custom fields โœ… Custom fields
๐Ÿงช Extensive Test Coverage โœ… 90%+ comprehensive tests with CI โš ๏ธ Basic testing with CI โš ๏ธ Limited test coverage โš ๏ธ Basic test suite