All Projects → rickh94 → ODetaM

rickh94 / ODetaM

Licence: MIT License
A simple ODM(Object Document Mapper) for Deta Base based on pydantic

Programming Languages

python
139335 projects - #7 most used programming language

Projects that are alternatives of or similar to ODetaM

lodm
ODM with inheritance and OOP composition for Laravel 5+
Stars: ✭ 22 (+22.22%)
Mutual labels:  odm
smokeshow
create temporary websites
Stars: ✭ 24 (+33.33%)
Mutual labels:  pydantic
goodconf
Transparently load variables from environment or JSON/YAML file.
Stars: ✭ 80 (+344.44%)
Mutual labels:  pydantic
pydbantic
A single model for shaping, creating, accessing, storing data within a Database
Stars: ✭ 137 (+661.11%)
Mutual labels:  pydantic
djantic
Pydantic model support for Django
Stars: ✭ 256 (+1322.22%)
Mutual labels:  pydantic
pydantic-i18n
pydantic-i18n is an extension to support an i18n for the pydantic error messages.
Stars: ✭ 32 (+77.78%)
Mutual labels:  pydantic
spectree
API spec validator and OpenAPI document generator for Python web frameworks.
Stars: ✭ 190 (+955.56%)
Mutual labels:  pydantic
PHES-ODM
Metadata and code to support covid-19 wastewater surveillance and open science.
Stars: ✭ 34 (+88.89%)
Mutual labels:  odm
sap-hana-driver-for-sqltools
A Visual Studio Code extension which extends the SQLTools extension, with a driver to work with the SAP HANA Database. It supports tables and views, as well as running queries on an SAP HANA Database.
Stars: ✭ 17 (-5.56%)
Mutual labels:  database-management
yarc
No description or website provided.
Stars: ✭ 109 (+505.56%)
Mutual labels:  deta
ClusterODM
A NodeODM API compatible autoscalable load balancer and task tracker for easy horizontal scaling ♆
Stars: ✭ 54 (+200%)
Mutual labels:  odm
rivery cli
Rivery CLI
Stars: ✭ 16 (-11.11%)
Mutual labels:  database-management
fastapi-lazy
Lazy package to start your project using FastAPI✨
Stars: ✭ 84 (+366.67%)
Mutual labels:  pydantic
ormsgpack
Msgpack serialization/deserialization library for Python, written in Rust using PyO3 and rust-msgpack. Reboot of orjson. msgpack.org[Python]
Stars: ✭ 88 (+388.89%)
Mutual labels:  pydantic
mongo-migrate
Versioned migrations for MongoDB.
Stars: ✭ 79 (+338.89%)
Mutual labels:  database-management
docker-omnidb
OmniDB installed into a Docker container
Stars: ✭ 30 (+66.67%)
Mutual labels:  database-management
mathesar
Web application providing an intuitive user experience to databases.
Stars: ✭ 95 (+427.78%)
Mutual labels:  database-management
wallpaper-api
An api which can use different sites to scrape images and serve them through API
Stars: ✭ 18 (+0%)
Mutual labels:  deta
cl-migratum
Database Schema Migration System for Common Lisp
Stars: ✭ 29 (+61.11%)
Mutual labels:  database-management
fixCache
Github app that keeps track of bug-prone files from commit history.
Stars: ✭ 82 (+355.56%)
Mutual labels:  deta

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 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.

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 aiodeta, as this is optional functionality, so it does not install automatically. This is the aiodeta package which is unofficial, but seems to work well and enables async support.

Get All

DetaModel.get_all() may be broken for large bases. The main deta python library has implemented some breaking changes (though definite improvements) around the fetching of records from the Base. They have implemented a new automatic pagination system that I have not had time to play with yet. Queries are recommended!

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
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].