Skip to main content

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

Project description

ODetaM

Build Status 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 PROJECT_KEY to your Deta project key so that databases can be accessed/created. This is a secret key, so handle it appropriately (hence the environment variable). Intended for use with FastAPI, but the Deta API is not asynchronous, so any framework could potentially be used.

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.

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...
  • NoProjectKey: PROJECT_KEY env var has not been set correctly. See Deta documentation.
  • 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.0.3.tar.gz (6.8 kB view details)

Uploaded Source

Built Distribution

ODetaM-1.0.3-py3-none-any.whl (6.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ODetaM-1.0.3.tar.gz
  • Upload date:
  • Size: 6.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.9.6 Linux/5.13.4-arch2-1

File hashes

Hashes for ODetaM-1.0.3.tar.gz
Algorithm Hash digest
SHA256 36000a4f5d945200272868cdc2593c511c5f74a5bf8328d4397b35270566c072
MD5 710d01d0a4b8cfad70d5d8eba67f6da5
BLAKE2b-256 2fb9fff2dd75ff129f2ef17b6ef986052b24f2883e7934de9e001d2dfa9815ff

See more details on using hashes here.

File details

Details for the file ODetaM-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: ODetaM-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 6.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/1.1.4 CPython/3.9.6 Linux/5.13.4-arch2-1

File hashes

Hashes for ODetaM-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d2ed659906b06dd4a6aacc66461f6635a96bb7eb2a7d3823ed68182f537b2e15
MD5 951d645d63985749b5400cc233a7c00e
BLAKE2b-256 611bd162b1b89b514bb2070a5b087dfd1fc93b8a6a61da181c8ee5a328e11e03

See more details on using hashes here.

Supported by

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