Skip to main content

A simple ODM (Object Document Mapper) for Deta Base, based on pydantic.

Project description

ODetaM

Test codecov

A simple ODM (Object Document Mapper) for Deta Base base on pydantic.

Installation

pip install odetam

Usage

Create pydantic models as normal, but inherit from DetaModel instead of pydantic BaseModel. You will need to set the environment variable DETA_PROJECT_KEY to your Deta project key so that databases can be accessed/created, instead you are working under deta initialized project. This is a secret key, so handle it appropriately (hence the environment variable).

Bases will be automatically created based on model names (changed from PascalCase/CamelCase case to snake_case). A key field (Deta's unique id) will be automatically added to any model. You can supply the key on creation, or Deta will generate one automatically and it will be added to the object when it is saved.

Async Support

Async/await is now supported! As of version 1.2.0, you can now from odetam.async_model import AsyncDetaModel, inherit from that, and run all the examples below just the same, but with await in front of the calls.

You must pip install deta[async], to use asynchronous base.

Get All

DetaModel.get_all() should handle large bases better now, but you should consider querying instead of getting everything if possible, because it is unlikely to perform well on large bases.

Example

import datetime
from typing import List

from odetam import DetaModel


class Captain(DetaModel):
    name: str
    joined: datetime.date
    ships: List[str]


# create
    kirk = Captain(
            name="James T. Kirk",
            joined=datetime.date(2252, 1, 1),
            ships=["Enterprise"],
            )

    sisko = Captain(
            name="Benjamin Sisko",
            joined=datetime.date(2350, 1, 1),
            ships=["Deep Space 9", "Defiant"],
            )

# initial save, key is now set
kirk.save()

# update the object
    kirk.ships.append("Enterprise-A")

# save again, this will be an update
kirk.save()

sisko.save()

Captain.get_all()
# [
#     Captain(
#         name="James T. Kirk", 
#         joined=datetime.date(2252, 01, 01), 
#         ships=["Enterprise", "Enterprise-A"],
#         key="key1",
#     ),
#     Captain(
#         name="Benjamin Sisko",
#         joined=datetime.date(2350, 01, 01), 
#         ships=["Deep Space 9", "Defiant"],
#         key="key2",
#     ),
# ]

    Captain.get("key1")
# Captain(
#     name="James T. Kirk", 
#     joined=datetime.date(2252, 01, 01), 
#     ships=["Enterprise", "Enterprise-A"],
#     key="key1",
# )

    Captain.query(Captain.name == "James T. Kirk")
# Captain(
#     name="James T. Kirk", 
#     joined=datetime.date(2252, 01, 01), 
#     ships=["Enterprise", "Enterprise-A"],
#     key="key1",
# )

    Captain.query(Captain.ships.contains("Defiant"))
# Captain(
#     name="Benjamin Sisko",
#     joined=datetime.date(2350, 01, 01),
#     ships=["Deep Space 9", "Defiant"],
# )

    Captain.query(Captain.name.prefix("Ben"))
# Captain(
#     name="Benjamin Sisko",
#     joined=datetime.date(2350, 01, 01),
#     ships=["Deep Space 9", "Defiant"],
# )

kirk.delete()
    Captain.delete_key("key2")

Captain.get_all()
# []

# you can also save several at once for better speed
Captain.put_many([kirk, sisko])
# [
#     Captain(
#         name="James T. Kirk", 
#         joined=datetime.date(2252, 01, 01), 
#         ships=["Enterprise", "Enterprise-A"],
#         key="key1",
#     ),
#     Captain(
#         name="Benjamin Sisko",
#         joined=datetime.date(2350, 01, 01), 
#         ships=["Deep Space 9", "Defiant"],
#         key="key2",
#     ),
# ]

    ```

## Save

Models have the `.save()` method which will always behave as an upsert, 
updating a record if it has a key, otherwise creating it and setting a key. 
Deta has pure insert behavior, but it's less performant. If you need it, please 
open a pull request.

## Querying

All basic comparison operators are implemented to map to their equivalents as 
`(Model.field >= comparison_value)`. There is also a `.contains()` and 
`.not_contains()` method for strings and lists of strings, as well as a 
`.prefix()` method for strings. There is also a `.range()` for number types 
that takes a lower and upper bound. You can also use `&`  as AND and `|` as OR. 
ORs cannot be nested within ands, use a list of options as comparison instead. 
You can use as many ORs as you want, as long as they execute after the ANDs in 
the order of operations. This is due to how the Deta Base api works.

## Deta Base

Direct access to the base is available in the dunder attribute `__db__`, though 
the point is to avoid that.

## Exceptions

 - `DetaError`: Base exception when anything goes wrong.
 - `ItemNotFound`: Fairly self-explanatory...
 - `InvalidDetaQuery`: Something is wrong with queries. Make sure you aren't using
 queries with unsupported types

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

ODetaM-1.3.0.tar.gz (9.4 kB view details)

Uploaded Source

Built Distribution

odetam-1.3.0-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file ODetaM-1.3.0.tar.gz.

File metadata

  • Download URL: ODetaM-1.3.0.tar.gz
  • Upload date:
  • Size: 9.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.1 CPython/3.10.7 Darwin/22.1.0

File hashes

Hashes for ODetaM-1.3.0.tar.gz
Algorithm Hash digest
SHA256 cacad78d66897574b4fbcb5e78a870a55441fbd78b00b92167241de82f91221d
MD5 c336c3cc9b02bb538eec46dd998fabba
BLAKE2b-256 b976d7ae1bbe616176438605d705ec94d3e9018260f1aa1a5f50ce0430b5a433

See more details on using hashes here.

Provenance

File details

Details for the file odetam-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: odetam-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.2.1 CPython/3.10.7 Darwin/22.1.0

File hashes

Hashes for odetam-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7d8332b4a673bb302cc2efcb21ac928cad4263c3cb5e0e69ca23a1f293c23fde
MD5 2b1a59fda40ba9d65d901d8bceb9854b
BLAKE2b-256 fee6df82f635f7680a4e1941e940d4f7d1c19e8583358fd1504c2a3bbf8b327c

See more details on using hashes here.

Provenance

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