Skip to content

albertgoss/urm.py

 
 

Repository files navigation

urm.py Unlicensed work

wheel (GitLab) wheel (GHA via nightly.link) GitLab Build Status GitLab Coverage Coveralls Coverage GitHub Actions Libraries.io Status

Unrelational mapper.

Sometimes you need to store some data somewhen and lazily retrieve as class fields and we don't want to write lot of boilerplate code and maintain this piece of shit. Object-relational mappers solve this problem by mapping classes to database tables, objects - to rows, object hierarchy to public and foreign keys.

But sometimes we don't need to store the data in relational databases. We need to store data in entities like files, archives, remote servers using REST/GraphQL API, etc. So we generalize a bit.

This stuff utilizes my other library transformerz of composable 2-way transformations.

Tutorial

It is strongly recommended to read the tutorial before using the lib. tutorial.ipynb (NBViewer)

TL;DR. Data model

We tie stored entities not to objects, but properties in classes. Entities are stored in underlying key-value storage.

  • When we first time access a property in the class, it is loaded into a cache and then returned.
  • subsequent accesses return the stuff from the cache.
  • we can save the stuff from the cache to the storage explicitly.
  • to create a storage from scratch, we put the data into a cache and then save it.

Then we heavily abstrage the stuff.

A key is a tuple of strings and numbers. It is an unique identifier of a piece of data. It is decoupled from the actual storage implementation. We address data by keys.

To define the way we are going to store data we need to answer to the following "orthogonal" questions:

  • WHERE are we going to store it? Saver object is an answer. Mapper.saver answers the question.
  • WHAT is the mapping between our internal keys and keys in the storage of this piece of data? A key is an answer. Mapper.key answers this question.

For cold storage we need to answer an additional question:

  • HOW are we going to serialize the data? transformerz.Transformer object is an answer. ColdMapper.serializer answers this question.

So Mapper object answers the questions related to storage of values.

To create a bidirectional mapping between class properties, we need to answer the following questions:

  • What pattern of access to the data should be optimized for? FieldStrategy subclasses are the answers.
    • ColdStrategy optimizes for frequent rather cheap accesses to volatile data.
      • Requires to know how we STORE the data. ColdMapper object is an answer. FieldStrategy.cold answers this question.
    • CachedStrategy optimizes for frequent rather expensive accesses to not very volatile data.
      • Additionally requires to know how we CACHE the data? HotMapper object is an answer. FieldStrategy.hot answers this question.
    • How do we create our internal keys? Field subclasses contain the answers.

About

Unrelational mapper

Resources

License

Code of conduct

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Jupyter Notebook 51.7%
  • Python 48.3%