Skip to main content

ORM for asyncio world by dataclass

Project description

Danio

UnitTest Package version Code coverage

Danio is a ORM for python asyncio world.It is designed to make getting easy and clearly.It builds on python's dataclass and encode's databases

Features

  • keep OOM in mind, custom your Field and Model behavior easily
  • type hints any where, no more need to memorize words your field names any more
  • base CRUD operation, transactions, lock and so on
  • signals like before save, after save and so on
  • complex operation like bulk create, upsert, create or update and so on
  • assist model schema migration
  • support MySQL/PostgreSQL/SQLite
  • hints generation

install

pip install danio

Documents

Danio Document

Glance

db = danio.Database(
    "mysql://root:letmein@server:3306/test",
    maxsize=3,
    charset="utf8mb4",
    use_unicode=True,
    connect_timeout=60,
)

@dataclasses.dataclass
class User(danio.Model):
    # auto generated by danio:
    # --------------------Danio Hints--------------------
    # TABLE NAME: user
    # TABLE IS MIGRATED!
    ID: typing.ClassVar[danio.Field]  # "id" serial PRIMARY KEY NOT NULL
    NAME: typing.ClassVar[danio.Field]  # "name" varchar(255)  NOT NULL
    AGE: typing.ClassVar[danio.Field]  # "age" int  NOT NULL
    CREATED_AT: typing.ClassVar[
        danio.Field
    ]  # "created_at" timestamp without time zone  NOT NULL
    UPDATED_AT: typing.ClassVar[
        danio.Field
    ]  # "updated_at" timestamp without time zone  NOT NULL
    GENDER: typing.ClassVar[danio.Field]  # "gender" int  NOT NULL
    # --------------------Danio Hints--------------------

    class Gender(enum.Enum):
        MALE = 0
        FEMALE = 1
        OTHER = 2

    id: typing.Annotated[int, danio.IntField(primary=True, type="serial")] = 0
    name: typing.Annotated[str, danio.CharField(comment="User name")] = ""
    age: typing.Annotated[int, danio.IntField] = 0
    created_at: typing.Annotated[
        datetime.datetime,
        danio.DateTimeField(type="timestamp without time zone", comment="when created"),
    ] = dataclasses.field(default_factory=datetime.datetime.now)
    updated_at: typing.Annotated[
        datetime.datetime,
        danio.DateTimeField(type="timestamp without time zone", comment="when updated"),
    ] = dataclasses.field(default_factory=datetime.datetime.now)
    gender: typing.Annotated[Gender, danio.IntField(enum=Gender)] = Gender.MALE


    async def before_create(self, validate=True):
        await super().before_create(validate=True)

    async def before_update(self, validate=True):
        self.updated_at = datetime.datetime.now()
        await super().before_update(validate=True)

    async def validate(self):
        await super().validate()
        if not self.name:
            raise danio.ValidateException("Empty name!")

    @classmethod
    def get_database(
        cls, operation: danio.Operation, table: str, *args, **kwargs
    ) -> danio.Database:
        return db

# base CRUD
user = await User(name="batman").save()
user = await User.where(User.NAME == "batman").fetch_one()
user.gender = User.Gender.MALE
await user.save()
await user.delete()
# sql chain
await User.where(User.NAME != "").limit(10).fetch_all()
# multi where condition
await User.where(User.ID != 1, User.NAME != "").fetch_all()
await User.where(User.ID != 1).where(User.NAME != "").fetch_all()
await User.where(User.ID <= 10, User.ID >= 20, is_and=False).fetch_all()
# complicated expression
await User.where(User.ID == 1).update(age=(User.AGE + 1) / (User.AGE / 12) - 2)
await User.where((User.AGE + 1) == 3).fetch_all()
# complicated sql operation
await User.where(User.ID == u.id).update(
    age=User.AGE.case(User.AGE > 10, 1, default=18).case(User.AGE <= 0, 10)
)
created, updated = await UserProfile.upsert(
    [
        dict(id=1, name="upsert"),
    ],
    update_fields=["name"],
)
# bulk operation
await User.bulk_create([User(name=f"user_{i}") for i in range(10)])
await User.bulk_update(await User.fetch_all())
await User.bulk_delete(await User.fetch_all())
# shortcut
user, created = await User(id=1, name="created?").get_or_create(
    key_fields=(User.ID,)
)
user, created, updated = await User(id=2, name="updated?").create_or_update(
    key_fields=(User.ID,)
)

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

danio-0.5.1.tar.gz (19.4 kB view details)

Uploaded Source

Built Distribution

danio-0.5.1-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file danio-0.5.1.tar.gz.

File metadata

  • Download URL: danio-0.5.1.tar.gz
  • Upload date:
  • Size: 19.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.3.2 CPython/3.10.10 Linux/5.15.83-1-pve

File hashes

Hashes for danio-0.5.1.tar.gz
Algorithm Hash digest
SHA256 e1fea3c025f1eb69de74c8fc2429a9edeeefa15d637533bcd7adbedd5d7f14c5
MD5 c3525bbe0d3f66d5ed9e6efc080119f8
BLAKE2b-256 c23c99835f99ec529d110d5075c79cdcd5d903e6b05ff1db24a950ef724d3de7

See more details on using hashes here.

File details

Details for the file danio-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: danio-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.3.2 CPython/3.10.10 Linux/5.15.83-1-pve

File hashes

Hashes for danio-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e8a747c7b9d4e05076bc280ba84f3bc2fdf8214ec86db5b9499f8bb9672d0771
MD5 4aed39d484bff8b84678f54e9226e5ba
BLAKE2b-256 b574618b9014a782e81597dab4b13bf62e30d0ec5abfe83627d9de962e7f82b2

See more details on using hashes here.

Supported by

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