Persist Store

MV3D's datastorage system is called Persist. It handles storing Python objects. In order to use a class with Persist, it must inherit from mv3d.util.persist.Persistable and any attributes that need to be stored should be identified. Here's an example:

from mv3d.util.persist import Persistable, Integer, Text

class StoreMe(Persistable):
    number = Integer()
    string = Text()

This defines a new persistable class called StoreMe which has two persisted attributes. number is defined as an integer, and string is a bit of text. In order to save this, we'll need a store. The main type of store is the mv3d.server.persist.SQLiteStore.

from mv3d.server.persist import SQLiteStore

store = SQLiteStore()
store.create()
storeMe = StoreMe()
storeMe.number = 42
storeMe.string = "The Answer"
iid = storeMe.save(store)

That will create a new in memory store and then save the StoreMe instance in it. We could later load that instance back out using the following:

retrieved = StoreMe.load(iid)

Every python object stored in the store has a unique id. You can use this to retrieve it out of the store. It's also possible to get the object back by querying the store.

results = StoreMe.query(StoreMe.number == 42)
results = StoreMe.query((StoreMe.number == 42) & (StoreMe.string == "The Answer"))

Now, many times, when an attribute is changed on a Persistable object, it will be beneficial to store the object right away. For this, there's autoSave, which is a parameter to persistable attributes.

from mv3d.util.persist import Persistable, Integer, Text

class StoreMe(Persistable):
    number = Integer(autoSave=True)
    string = Text(autoSave=True, savePartial=True)

This will cause the StoreMe to be persisted whenever number changes. In this case, the whole object will be saved. If instead, you only want the changed attribute to be stored, then the savePartial keyword can be used.

Retrieving and Deleting Items

Items can be deleted from the store using the delete method. This will remove the item from the store. There are also several ways of to retrieve to retrieve items.

storeMe.delete() # deletes it from the store

StoreMe.get(StoreMe.number == 42) # retrieve the item that matches the query and assert if more than one matches
StoreMe.first(StoreMe.number == 42) # retrieve the first item that matches the query
StoreMe.query() # with no paremeters will retrieve all items, but with a query will return all items matchine the query.
StoreMe.count(StoreMe.number == 42)  # returns the number of items that match the query
StoreMe.load(itemID) # retrieve an item by its id

Versioning

At some point, we may want to add or remove fields from the StoreMe object. When that happens, we will need to take advantage of the automatic upgrading mechanism in Perist. Here's an example:

class StoreMe(Persistable):
    # set the schema version
    _schemaVersion = 2

    number = Integer()
    string = Text()
    # add new attribute
    floaty = Float()

    @classmethod
    def upgrade(cls, oldData):
        newData = dict(oldData)
        if oldData["_schemaVersion"] == 1:
            newData["floaty"] = 0.0
        return newData

This will cause StoreMe? to be upgraded whenever it is loaded.