Build status - Master:
Build status - Dev:
RethinkORM is a small wrapper class to help make working with documents in RethinkDB easier, and in a more Pythonic way.
I recently found RethinkDB and was amazed at how easy everything seemed to be, however one thing that I’ve missed is how the data is just a Python List or Dict rather than a full wrapper class. So I figured a good way to learn the general use of the Python RethinkDB driver was to write a general wrapper class that functioned a bit like an ORM, providing some easier to work with data and objects.
Unittests are included, and the code should be PEP8 compliant. The tests are automatically ran each commit, thanks to travis-ci.org and this documentation is kindly hosted and automatically rebuilt by readthedocs.org.
Gittip if you like the work I do and would consider a small donation to help fund me and this project:
This package is kindly hosted on the Python Package Index making it as easy as a simple pip command to install.
pip install RethinkORM
There are currently two main modules to this package, Models and Collections.
The core of RethinkORM, models are the main unit of code you’ll probably be use from this package.
New in v0.2.0 are collections. These are containers for interacting with sets of documents. Collections provide an easy way to gather up just the documents you need, and have them automatically wrapped with the ORM RethinkModel object.
You can read more about collections here.
All code for this can be found online at github. If something is broken, or a feature is missing, please submit a pull request or open an issue. Most things I probably won’t have time to get around to looking at too deeply, so if you want it fixed, a pull request is the way to go. Besides that, I’m releasing this under the GPLv3 License as found in the LICENSE.txt file. Enjoy!
The model is the core of everything RethinkORM deals with. All data returned from RethinkDB is eventually wrapped in the model before being returned to the end user. It provides an pythonic, object style interface for the data, exposing methods to save and update documents along with creating new ones.
pip install RethinkORM
First we need to make an object which will represent all of our data in a specific table, along with getting a connection to RethinkDB started.
import rethinkdb as r
from rethinkORM import RethinkModel
r.connect(db="props").repl()
class tvProps(RethinkModel):
table = "stargate_props"
For more information on what class properties are available to change, see rethinkORM
dhdProp = tvProps(what="DHD", planet="P3X-439", description="Dial HomeDevice")
dhdProp.id="DHD_P3X_439"
dhdProp.save()
updatedProp = tvProps("DHD_P3X_439")
updatedProp.description="""Dial Home Device from the planel P3X-439, where an
Ancient Repository of Knowledge was found, and interfaced with by Colonel
Jack."""
updatedProp.save()
oldProp = tvProps("DHD_P3X_439")
oldProp.delete()
Emulates a python object for the data which is returned from rethinkdb and the official Python client driver. Raw data from the database is stored in _data to keep the objects namespace clean. For more information look at how _get() and _set() function in order to keep the namespace cleaner but still provide easy access to data.
This object has a __repr__ method which can be used with print or logging statements. It will give the id and a representation of the internal _data dict for debugging purposes.
The table which this document object will be stored in
The current primary key of the table
Can either be Hard or Soft, and is passed to RethinkDB
Determins if the transaction can be non atomic or not
Will either update, or create a new object if true and a primary key is given.
Initializes the main object, if id is in kwargs, then we assume this is already in the database, and will try to pull its data, if not, then we assume this is a new entry that will be inserted.
(Optional, only if not using .repl()) conn or connection can also be passed, which will be used in all the .run() clauses.
A hook called at the end of the main __init__ to allow for custom inherited classes to customize their init process without having to redo all of the existing int. This should accept nothing besides self and nothing should be returned.
Deletes the given item from the objects _data dict, or if from the objects namespace, if it does not exist in _data.
Allows for the use of syntax similar to:
if "blah" in model:
This only works with the internal _data, and does not include other properties in the objects namepsace.
Creates a new instance, filling out the models data with the keyword arguments passed, so long as those keywords are not in the protected items array.
Similar to new() however this calls save() on the object before returning it.
Loads an existing entry if one can be found, otherwise an exception is raised.
Parameters: | id (Str) – The id of the given entry |
---|---|
Returns: | cls instance of the given id entry |
If an id exists in the database, we assume we’ll update it, and if not then we’ll insert it. This could be a problem with creating your own id’s on new objects, however luckily, we keep track of if this is a new object through a private _new variable, and use that to determine if we insert or update.
Deletes the current instance. This assumes that we know what we’re doing, and have a primary key in our data already. If this is a new instance, then we’ll let the user know with an Exception
Allows for the representation of the object, for debugging purposes
Provides a cleaner interface to dynamically add items to the models list of protected functions to not store in the database
Collections provide a quick and easy way to interact with many documents of the same type all at once. They also provide a mechanism for basic joins across one addition table (due to current limitations of RethinkDB and how it handles joins). Collections act like Lists of RethinkModel objects, but provide an interface to order the results, and optionally, eqJoin across one other table, along with filtering of results.
Optionally you can also pass a dictionary which will be used as a filter. For more information on how filters work, please see the RethinkDB docs
collection = RethinkCollection(gateModel)
collection.joinOn(episodeModel, "episodes")
collection.orderBy("episodes", "ASC")
result = collection.fetch()
Result acts like a List, containing all of the Documents which are part of the collection, all pre wrapped in a RethinkModel object.
A way to fetch groupings of documents that meet a criteria and have them in an iterable storage object, with each document represented by RethinkModel objects
Instantiates a new collection, using the given models table, and wrapping all documents with the given model.
Filter can be a dictionary or lambda, similar to the filters for the RethinkDB drivers filters.
Performs an eqJoin on with the given model. The resulting join will be accessible through the models name.
Like joinOn but allows setting the joined results name to access it from.
Performs an eqJoin on with the given model. The resulting join will be accessible through the given name.
Allows for the results to be ordered by a specific field. If given, direction can be set with passing an additional argument in the form of “asc” or “desc”
Fetches the query and then tries to wrap the data in the model, joining as needed, if applicable.
To get started and make sure this all works, please make sure you have Python nose installed.
nosetests rethinkORM -v -s
This will run the all the tests, not capturing stdout and being verbose, in case anything goes wrong, or if you modify the tests. Please note, tests are subject to a lot of changes, and this may not always be the same command.
If you want to also check the PEP8 validity of the code, you can run:
pep8 rethinkORM
or, if you have tissue installed you can run a PEP8 check with the rest of the test suite like so:
nosetests rethinkORM -v -s --with-tissue
There is a setup fixture that creates a database called model and within that creates a table stargate. Then each test works on entries which get stored in this database and table. When everything is done, the teardown fixture is ran to clean up and delete the whole database model. Each test should be broken down into basic actions, for example there are currently tests for:
- inserting a new entry
- modifying that entry
- deleting that entry
- inserting an entry where the primary key is None or a null value.
Test suite for the model
Bases: object
Base test object to help automate some of the repetitive work of reloading a document to ensure the model matches the test data. Also takes care of deleting the document if cleanupAfter is True
Should the document created by this test be deleted when over?
Should the document be reloaded and have all it’s data checked against?
If loadCheck is true, fill this out with strings of the data keys to check the model against.
The model being used for this test
The data being used for this test. Please at least include an ID
Override this to do a custom load check. This should find the key you created or modified in action() and check it’s values to ensure everything was set correctly. By default this loads the model with the test objects data[“id”] and uses whatToLoad to run checks against the data and the model.
Bases: rethinkORM.tests.test_model.base
Tests the basic ability to make a new model instance, and save it to the Database
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the ability to load, modify and save a model correctly
alias of gateModel
Here we test to make sure that if we give a primary key of type None that we are raising an exception, if we don’t get an exception then something is wrong since the primary key shouldn’t be allowed to be None
Make sure that the model raises an Exception when a key and data are provided
Bases: rethinkORM.tests.test_model.base
Tests the new() classmethod of the model
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the create() classmethod of the model
Same as the new() classmethod test however we don’t have to explicitly tell the model to save
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the find() classmethod of the model
alias of gateModel
To get started and make sure this all works, please make sure you have Python nose installed.
nosetests rethinkORM -v -s
This will run the all the tests, not capturing stdout and being verbose, in case anything goes wrong, or if you modify the tests. Please note, tests are subject to a lot of changes, and this may not always be the same command.
If you want to also check the PEP8 validity of the code, you can run:
pep8 rethinkORM
or, if you have tissue installed you can run a PEP8 check with the rest of the test suite like so:
nosetests rethinkORM -v -s --with-tissue
There is a setup fixture that creates a database called model and within that creates a table stargate. Then each test works on entries which get stored in this database and table. When everything is done, the teardown fixture is ran to clean up and delete the whole database model. Each test should be broken down into basic actions, for example there are currently tests for:
- inserting a new entry
- modifying that entry
- deleting that entry
- inserting an entry where the primary key is None or a null value.
Test suite for the model
Bases: object
Base test object to help automate some of the repetitive work of reloading a document to ensure the model matches the test data. Also takes care of deleting the document if cleanupAfter is True
Should the document created by this test be deleted when over?
Should the document be reloaded and have all it’s data checked against?
If loadCheck is true, fill this out with strings of the data keys to check the model against.
The model being used for this test
The data being used for this test. Please at least include an ID
Override this to do a custom load check. This should find the key you created or modified in action() and check it’s values to ensure everything was set correctly. By default this loads the model with the test objects data[“id”] and uses whatToLoad to run checks against the data and the model.
Bases: rethinkORM.tests.test_model.base
Tests the basic ability to make a new model instance, and save it to the Database
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the ability to load, modify and save a model correctly
alias of gateModel
Here we test to make sure that if we give a primary key of type None that we are raising an exception, if we don’t get an exception then something is wrong since the primary key shouldn’t be allowed to be None
Make sure that the model raises an Exception when a key and data are provided
Bases: rethinkORM.tests.test_model.base
Tests the new() classmethod of the model
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the create() classmethod of the model
Same as the new() classmethod test however we don’t have to explicitly tell the model to save
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the find() classmethod of the model
alias of gateModel
Emulates a python object for the data which is returned from rethinkdb and the official Python client driver. Raw data from the database is stored in _data to keep the objects namespace clean. For more information look at how _get() and _set() function in order to keep the namespace cleaner but still provide easy access to data.
This object has a __repr__ method which can be used with print or logging statements. It will give the id and a representation of the internal _data dict for debugging purposes.
The table which this document object will be stored in
The current primary key of the table
Can either be Hard or Soft, and is passed to RethinkDB
Determins if the transaction can be non atomic or not
Will either update, or create a new object if true and a primary key is given.
Initializes the main object, if id is in kwargs, then we assume this is already in the database, and will try to pull its data, if not, then we assume this is a new entry that will be inserted.
(Optional, only if not using .repl()) conn or connection can also be passed, which will be used in all the .run() clauses.
A hook called at the end of the main __init__ to allow for custom inherited classes to customize their init process without having to redo all of the existing int. This should accept nothing besides self and nothing should be returned.
Deletes the given item from the objects _data dict, or if from the objects namespace, if it does not exist in _data.
Allows for the use of syntax similar to:
if "blah" in model:
This only works with the internal _data, and does not include other properties in the objects namepsace.
Creates a new instance, filling out the models data with the keyword arguments passed, so long as those keywords are not in the protected items array.
Similar to new() however this calls save() on the object before returning it.
Loads an existing entry if one can be found, otherwise an exception is raised.
Parameters: | id (Str) – The id of the given entry |
---|---|
Returns: | cls instance of the given id entry |
If an id exists in the database, we assume we’ll update it, and if not then we’ll insert it. This could be a problem with creating your own id’s on new objects, however luckily, we keep track of if this is a new object through a private _new variable, and use that to determine if we insert or update.
A way to fetch groupings of documents that meet a criteria and have them in an iterable storage object, with each document represented by RethinkModel objects
Instantiates a new collection, using the given models table, and wrapping all documents with the given model.
Filter can be a dictionary or lambda, similar to the filters for the RethinkDB drivers filters.
Performs an eqJoin on with the given model. The resulting join will be accessible through the models name.
Like joinOn but allows setting the joined results name to access it from.
Performs an eqJoin on with the given model. The resulting join will be accessible through the given name.
To get started and make sure this all works, please make sure you have Python nose installed.
nosetests rethinkORM -v -s
This will run the all the tests, not capturing stdout and being verbose, in case anything goes wrong, or if you modify the tests. Please note, tests are subject to a lot of changes, and this may not always be the same command.
If you want to also check the PEP8 validity of the code, you can run:
pep8 rethinkORM
or, if you have tissue installed you can run a PEP8 check with the rest of the test suite like so:
nosetests rethinkORM -v -s --with-tissue
There is a setup fixture that creates a database called model and within that creates a table stargate. Then each test works on entries which get stored in this database and table. When everything is done, the teardown fixture is ran to clean up and delete the whole database model. Each test should be broken down into basic actions, for example there are currently tests for:
- inserting a new entry
- modifying that entry
- deleting that entry
- inserting an entry where the primary key is None or a null value.
Test suite for the model
Bases: object
Base test object to help automate some of the repetitive work of reloading a document to ensure the model matches the test data. Also takes care of deleting the document if cleanupAfter is True
Should the document created by this test be deleted when over?
Should the document be reloaded and have all it’s data checked against?
If loadCheck is true, fill this out with strings of the data keys to check the model against.
The model being used for this test
The data being used for this test. Please at least include an ID
Override this to do a custom load check. This should find the key you created or modified in action() and check it’s values to ensure everything was set correctly. By default this loads the model with the test objects data[“id”] and uses whatToLoad to run checks against the data and the model.
Bases: rethinkORM.tests.test_model.base
Tests the basic ability to make a new model instance, and save it to the Database
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the ability to load, modify and save a model correctly
alias of gateModel
Here we test to make sure that if we give a primary key of type None that we are raising an exception, if we don’t get an exception then something is wrong since the primary key shouldn’t be allowed to be None
Make sure that the model raises an Exception when a key and data are provided
Bases: rethinkORM.tests.test_model.base
Tests the new() classmethod of the model
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the create() classmethod of the model
Same as the new() classmethod test however we don’t have to explicitly tell the model to save
alias of gateModel
Bases: rethinkORM.tests.test_model.base
Tests the find() classmethod of the model
alias of gateModel