Skip to main content

Asynchronous library for building and managing a hybrid database, by scheme of key-value.

Project description

Logo

Scruby (small shrub)

Asynchronous library for building and managing a hybrid database,
by scheme of key-value.

Build Status Docs PyPI pyversions PyPI status PyPI version fury.io
Types: Pyrefly Code style: Ruff Format PyPI Downloads License: MIT License: GPL v3

The library uses fractal-tree addressing and
the search for documents based on the effect of a quantum loop.
The database consists of collections.
The maximum size of the one collection is 16**8=4294967296 branches,
each branch can store one or more keys.
The value of any key in collection can be obtained maximum in 8 steps,
thereby achieving high performance.
The effectiveness of the search for documents based on a quantum loop,
requires a large number of processor threads.


List of plugins

Documentation

Requirements

Installation

uv add scruby

Run

# Run Development:
uv run python main.py
# Run Production:
uv run python -OOP main.py

Usage

Examples

"""Working with keys."""

import anyio
from datetime import datetime
from zoneinfo import ZoneInfo
from typing import Annotated
from pydantic import EmailStr, Field
from pydantic_extra_types.phone_numbers import PhoneNumber, PhoneNumberValidator
from scruby import Scruby, ScrubyModel, ScrubySettings
from pprint import pprint as pp


class User(ScrubyModel):
    """User model."""
    first_name: str = Field(strict=True)
    last_name: str = Field(strict=True)
    birthday: datetime = Field(strict=True)
    email: EmailStr = Field(strict=True)
    phone: Annotated[PhoneNumber, PhoneNumberValidator(number_format="E164")] = Field(frozen=True)
    # key is always at bottom
    key: str = Field(
        strict=True,
        frozen=True,
        default_factory=lambda data: data["phone"],
    )


async def main() -> None:
    """Example."""
    # Create/get the `User` collection.
    user_coll = await Scruby.collection(User)

    # Create user
    user = User(
        first_name="John",
        last_name="Smith",
        birthday=datetime(1970, 1, 1, tzinfo=ZoneInfo("UTC")),
        email="John_Smith@gmail.com",
        phone="+447986123456",
    )

    # Add data of user to collection.
    await user_coll.add_doc(user)

    # Update user data in a collection
    await user_coll.update_doc(user)

    # Update user details
    user = await user_coll.get_doc("+447986123456")
    pp(user)

    # Check for the presence of a key in the collection
    await user_coll.has_key("+447986123456")  # => True

    # Delete a document by key
    await user_coll.delete_doc("+447986123456")

    # Full database deletion.
    # Hint: The main purpose is tests.
    Scruby.napalm()


if __name__ == "__main__":
    anyio.run(main)
"""Find one document matching the filter.

The search is based on the effect of a quantum loop.
The search effectiveness depends on the number of processor threads.
"""

import anyio
from pydantic import Field
from scruby import Scruby, ScrubyModel, ScrubySettings
from pprint import pprint as pp


class Phone(ScrubyModel):
    """Phone model."""
    brand: str = Field(strict=True, frozen=True)
    model: str = Field(strict=True, frozen=True)
    screen_diagonal: float = Field(strict=True)
    matrix_type: str = Field(strict=True)
    # key is always at bottom
    key: str = Field(
        strict=True,
        frozen=True,
        default_factory=lambda data: f"{data['brand']}:{data['model']}",
    )


async def main() -> None:
    """Example."""
    # Create/Get collection `Phone`.
    phone_coll = await Scruby.collection(Phone)

    # Create phone.
    phone = Phone(
        brand="Samsung",
        model="Galaxy A26",
        screen_diagonal=6.7,
        matrix_type="Super AMOLED",
    )

    # Add phone to collection.
    await phone_coll.add_doc(phone)

    # Find phone by brand.
    phone_details: Phone | None = await phone_coll.find_one(
        filter_fn=lambda doc: doc.brand == "Samsung",
    )
    if phone_details is not None:
        pp(phone_details)
    else:
        print("No Phone!")

    # Find phone by model.
    phone_details: Phone | None = await phone_coll.find_one(
        filter_fn=lambda doc: doc.model == "Galaxy A26",
    )
    if phone_details is not None:
        pp(phone_details)
    else:
        print("No Phone!")

    # Full database deletion.
    # Hint: The main purpose is tests.
    Scruby.napalm()


if __name__ == "__main__":
    anyio.run(main)
"""Find many documents matching the filter.

The search is based on the effect of a quantum loop.
The search effectiveness depends on the number of processor threads.
"""

import anyio
from pydantic import Field
from scruby import Scruby, ScrubyModel, ScrubySettings
from pprint import pprint as pp


class Car(ScrubyModel):
    """Car model."""
    brand: str = Field(strict=True, frozen=True)
    model: str = Field(strict=True, frozen=True)
    year: int = Field(strict=True)
    power_reserve: int = Field(strict=True)
    # key is always at bottom
    key: str = Field(
        strict=True,
        frozen=True,
        default_factory=lambda data: f"{data['brand']}:{data['model']}",
    )


async def main() -> None:
    """Example."""
    # Get collection `Car`.
    car_coll = await Scruby.collection(Car)

    # Create cars.
    for num in range(1, 10):
        car = Car(
            brand="Mazda",
            model=f"EZ-6 {num}",
            year=2025,
            power_reserve=600,
        )
        await car_coll.add_doc(car)

    # Find cars by brand and year.
    car_list: list[Car] | None = await car_coll.find_many(
        filter_fn=lambda doc: doc.brand == "Mazda" and doc.year == 2025,
    )
    if car_list is not None:
        pp(car_list)
    else:
        print("No cars!")

    # Find all cars.
    car_list: list[Car] | None = await car_coll.find_many()
    if car_list is not None:
        pp(car_list)
    else:
        print("No cars!")

    # For pagination output.
    car_list: list[Car] | None = await car_coll.find_many(
        filter_fn=lambda doc: doc.brand == "Mazda",
        limit_docs=5,
        page_number=2,
    )
    if car_list is not None:
        pp(car_list)
    else:
        print("No cars!")

    # Full database deletion.
    # Hint: The main purpose is tests.
    Scruby.napalm()


if __name__ == "__main__":
    anyio.run(main)

Changelog

MIT

GPL-3.0

Project details


Release history Release notifications | RSS feed

Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

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

scruby-0.36.5-py3-none-any.whl (33.4 kB view details)

Uploaded Python 3

File details

Details for the file scruby-0.36.5-py3-none-any.whl.

File metadata

  • Download URL: scruby-0.36.5-py3-none-any.whl
  • Upload date:
  • Size: 33.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Fedora Linux","version":"43","id":"","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for scruby-0.36.5-py3-none-any.whl
Algorithm Hash digest
SHA256 d3d2377e101bb0db7f5c4fabc0376e797cbae9e895fdc2cb1374ea487d47eaf7
MD5 23a1ae1b31ee7d47798a4b417b49f0ff
BLAKE2b-256 50c615469cbbbc44a755fd62b59ba6cb3fa1cf76f2d1e589b381e1765440a335

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