Skip to main content

A simple ORM cache library for redis

Project description

RORM

基于Redis的结构化存储驱动,使用者只需要定义数据模型,即可实现数据的持久化和缓存

rorm中,ORMModel作为数据模型使用,ORMCache将持有ORMModel的实例,并提供数据的持久化和缓存功能

注意事项与基本原理

  • ORMModel的子类需要实现unique_id方法,以便ORMCache能够正确的管理数据
  • 每个ORMCache实例都会对应redis中的一个hash结构,hash名为ORMCacheunique_id
    • keyORMCache的属性名与对应ORMModel的类型名以及ORMModelunique_id
    • valueORMModeljson序列化结果
  • 在调用ORMCache对象的save_all方法时,会将ORMCache实例中的所有ORMModel的实例保存到redis
    • ORMModel实现的标脏检查,只有数据发生变化时才会序列化并保存,因此不用担心序列化性能和访问redis过于频繁的问题

Example

定义ORMModel和ORMCache

@ORMCache.register
class RoleInfo(ORMModel):
    role_id: int = Field(0, title="角色id")
    role_name: str = Field("", title="角色名")
    role_level: int = Field(0, title="角色等级")

    def __init__(self,  /, **data) -> None:
        super().__init__(**data)

    def unique_id(self) -> str:
        return f"{self.role_id}"


@ORMCache.register
class ItemInfo(ORMModel):
    item_id: int = Field(0, title="物品id")
    item_name: str = Field("", title="物品名")
    item_count: int = Field(0, title="物品数量")

    def __init__(self,  /, **data) -> None:
        super().__init__(**data)

    def unique_id(self) -> str:
        return f"{self.item_id}"


@ORMCache.register
class MailInfo(ORMModel):
    mail_id: int = Field(0, title="邮件id")
    mail_title: str = Field("", title="邮件标题")
    mail_content: str = Field("", title="邮件内容")
    attarchments: list[ItemInfo] = []

    def __init__(self,  /, **data) -> None:
        super().__init__(**data)

    def unique_id(self) -> str:
        return f"{self.mail_id}"

class Player(ORMCache):

    role: RoleInfo = RoleInfo()
    items: dict[str, ItemInfo] = {}
    mails: list[MailInfo] = []
    tmp: list[str] = []

    def __init__(self, client: Redis, user_id: int) -> None:
        super().__init__(client)
        self.__user_id = user_id

    def unique_id(self) -> str:
        return f"{self.__class__.__qualname__}:{self.__user_id}"

存储数据

async def test_save(self):
    client = await Redis.from_url("redis://localhost:6379/0")
    player = Player(client, 10001)
    player.role = RoleInfo(
        role_id=10001, role_name="rorm-py", role_level=1)
    for i in range(1, 6):
        player.items[f"{i}"] = ItemInfo(
            item_id=i, item_name=f"item-{i}", item_count=i)
    for i in range(1, 6):
        player.mails.append(MailInfo(
            mail_id=i,
            mail_title=f"mail-{i}",
            mail_content=f"mail-{i}",
            attarchments=[ItemInfo(
                item_id=i,
                item_name=f"item-{i}",
                item_count=i)]
        ))
    player.tmp.append("not save")
    await player.save_all()
    await client.close()

注意 只有ORMModel类型的数据才会被存储

127.0.0.1:6379> KEYS *
1) "Player:10001"
127.0.0.1:6379> HGETALL Player:10001
 1) "mails:MailInfo:1"
 2) "{\"mail_id\":1,\"mail_title\":\"mail-1\",\"mail_content\":\"mail-1\",\"attarchments\":[{\"item_id\":1,\"item_name\":\"item-1\",\"item_count\":1}]}"
 3) "items:ItemInfo:1"
 4) "{\"item_id\":1,\"item_name\":\"item-1\",\"item_count\":1}"
 5) "items:ItemInfo:3"
 6) "{\"item_id\":3,\"item_name\":\"item-3\",\"item_count\":3}"
 7) "mails:MailInfo:2"
 8) "{\"mail_id\":2,\"mail_title\":\"mail-2\",\"mail_content\":\"mail-2\",\"attarchments\":[{\"item_id\":2,\"item_name\":\"item-2\",\"item_count\":2}]}"
 9) "items:ItemInfo:4"
10) "{\"item_id\":4,\"item_name\":\"item-4\",\"item_count\":4}"
11) "role:RoleInfo:10001"
12) "{\"role_id\":10001,\"role_name\":\"rorm-py\",\"role_level\":1}"
13) "mails:MailInfo:3"
14) "{\"mail_id\":3,\"mail_title\":\"mail-3\",\"mail_content\":\"mail-3\",\"attarchments\":[{\"item_id\":3,\"item_name\":\"item-3\",\"item_count\":3}]}"
15) "mails:MailInfo:4"
16) "{\"mail_id\":4,\"mail_title\":\"mail-4\",\"mail_content\":\"mail-4\",\"attarchments\":[{\"item_id\":4,\"item_name\":\"item-4\",\"item_count\":4}]}"
17) "items:ItemInfo:2"
18) "{\"item_id\":2,\"item_name\":\"item-2\",\"item_count\":2}"
19) "items:ItemInfo:5"
20) "{\"item_id\":5,\"item_name\":\"item-5\",\"item_count\":5}"
21) "mails:MailInfo:5"
22) "{\"mail_id\":5,\"mail_title\":\"mail-5\",\"mail_content\":\"mail-5\",\"attarchments\":[{\"item_id\":5,\"item_name\":\"item-5\",\"item_count\":5}]}"

读取数据

async def test_load(self):
    client = await Redis.from_url("redis://localhost:6379/0")
    player = Player(client, 10001)
    await player.load_from_redis()
    print(player.model_dump_json())
    await client.close()
{
    "role":{"role_id":10001,"role_name":"rorm-py","role_level":1},
    "items":{
        "1":{"item_id":1,"item_name":"item-1","item_count":1},
        "3":{"item_id":3,"item_name":"item-3","item_count":3},
        "4":{"item_id":4,"item_name":"item-4","item_count":4},
        "2":{"item_id":2,"item_name":"item-2","item_count":2},
        "5":{"item_id":5,"item_name":"item-5","item_count":5}
    },
    "mails":[
        {"mail_id":1,"mail_title":"mail-1","mail_content":"mail-1","attarchments":[{"item_id":1,"item_name":"item-1","item_count":1}]},
        {"mail_id":2,"mail_title":"mail-2","mail_content":"mail-2","attarchments":[{"item_id":2,"item_name":"item-2","item_count":2}]},
        {"mail_id":3,"mail_title":"mail-3","mail_content":"mail-3","attarchments":[{"item_id":3,"item_name":"item-3","item_count":3}]},
        {"mail_id":4,"mail_title":"mail-4","mail_content":"mail-4","attarchments":[{"item_id":4,"item_name":"item-4","item_count":4}]},
        {"mail_id":5,"mail_title":"mail-5","mail_content":"mail-5","attarchments":[{"item_id":5,"item_name":"item-5","item_count":5}]}],
    "tmp":[]
}

修改与删除数据

async def test_modify(self):
    client = await Redis.from_url("redis://localhost:6379/0")
    player = Player(client, 10001)
    await player.load_from_redis()

    player.role.role_level = 2
    for item in player.items.values():
        item.item_count += 1

    for mail in player.mails:
        mail.mail_content = "modify"
        for item in mail.attarchments:
            item.item_count += 1

    await player.save_all()

async def test_delete(self):
    client = await Redis.from_url("redis://localhost:6379/0")
    player = Player(client, 10001)
    await player.load_from_redis()

    player.role = RoleInfo()
    for key in list(player.items.keys()):
        if int(key) % 2 == 0:
            del player.items[key]

    for mail in list(player.mails):
        if mail.mail_id % 2 == 0:
            player.mails.remove(mail)

    await player.save_all()
127.0.0.1:6379> HGETALL Player:10001
 1) "role:RoleInfo:10001"
 2) "{\"role_id\":10001,\"role_name\":\"rorm-py\",\"role_level\":2}"
 3) "mails:MailInfo:3"
 4) "{\"mail_id\":3,\"mail_title\":\"mail-3\",\"mail_content\":\"modify\",\"attarchments\":[{\"item_id\":3,\"item_name\":\"item-3\",\"item_count\":4}]}"
 5) "role:RoleInfo:0"
 6) "{\"role_id\":0,\"role_name\":\"\",\"role_level\":0}"
 7) "mails:MailInfo:1"
 8) "{\"mail_id\":1,\"mail_title\":\"mail-1\",\"mail_content\":\"modify\",\"attarchments\":[{\"item_id\":1,\"item_name\":\"item-1\",\"item_count\":2}]}"
 9) "items:ItemInfo:5"
10) "{\"item_id\":5,\"item_name\":\"item-5\",\"item_count\":6}"
11) "items:ItemInfo:3"
12) "{\"item_id\":3,\"item_name\":\"item-3\",\"item_count\":4}"
13) "items:ItemInfo:1"
14) "{\"item_id\":1,\"item_name\":\"item-1\",\"item_count\":2}"
15) "mails:MailInfo:5"
16) "{\"mail_id\":5,\"mail_title\":\"mail-5\",\"mail_content\":\"modify\",\"attarchments\":[{\"item_id\":5,\"item_name\":\"item-5\",\"item_count\":6}]}"

License

This project is licensed under the MIT License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rorm_py-1.0.0.tar.gz (7.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rorm_py-1.0.0-py3-none-any.whl (7.8 kB view details)

Uploaded Python 3

File details

Details for the file rorm_py-1.0.0.tar.gz.

File metadata

  • Download URL: rorm_py-1.0.0.tar.gz
  • Upload date:
  • Size: 7.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.5

File hashes

Hashes for rorm_py-1.0.0.tar.gz
Algorithm Hash digest
SHA256 79a854f77d4f3d1c82fc6a774efc5eec1f2add4221cefd312fa8e5b5cba3589d
MD5 d8cc8d56705da3c1f0ab3f31a4851dbf
BLAKE2b-256 6ee3298139f619b8a4a7b9787a457a0649a6204e6ea850c4cdbdae8bd07fb819

See more details on using hashes here.

File details

Details for the file rorm_py-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: rorm_py-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 7.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.12.5

File hashes

Hashes for rorm_py-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 31ed12fde2d6660903ec85575abb1621cee250f115ab5280da417c89d5711caa
MD5 d43db4ae3bd0231d2a2009a3dcc428f8
BLAKE2b-256 6b1124a9db884e84fd44aa2ac990b6f6d9702269ae47c20c9b1a2f58a6c6eece

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page