During this tutorial we will be using the DBI backend for two reasons. The first is DBI's ubiquity. The second is the possibility of easily looking behind the scenes, to more clearly demonstrate what KiokuDB is doing.

This is very trivial use of KiokuDB, but it illustrates a few important things.

First, no schema is necessary. KiokuDB uses Moose to introspect your object without needing to predefine anything like tables.

Second, every object in the database has an ID. If you don't choose an ID for an object, KiokuDB will assign a UUID instead.

This ID is like a primary key in a relational database.

You can also specify an ID instead of letting one be generated:

$dir->store( homer => $obj );

Third, all KiokuDB operations need to be performed within a scope. The scope is not really doing anything important in this simple example, but becomes necessary when cycles and weak references are in use. We will look into that in more detail later.

When KiokuDB is loading the initial object, all the objects the object depends on will also be loaded. The spouse attribute contains a reference to another object (by ID), and this link is resolved at inflation time.

The set convenience function creates a new KiokuDB::Set::Transient object. A transient set is one which started its life in memory space (as opposed to a set that was loaded from the database).

The weak_set convenience function also exists, creating a transient set with Set::Object::Weak used internally to help avoid circular structures (for instance if setting a parent attribute in our example).

The main difference is that sets coming from the database are deferred by default, that is the objects in @kids are not loaded until they are actually needed.

This allows large object graphs to exist in the database, while only being partially loaded, without breaking the encapsulation of user objects. This behavior is implemented in KiokuDB::Set::Deferred and KiokuDB::Set::Loaded.

This set object is optimized to make most operations defer loading. For instance, if you intersect two deferred sets, only the members of the intersection set will need to be loaded.

The collapser uses a KiokuDB::TypeMap object that tells it how objects of each type should be collapsed.

During retrieval of objects the same typemap is used to reinflate objects back into working objects.

Trying to store an object that is not in the typemap is an error. The reason behind this is that it doesn't make sense to store every type of object (for instance DBI handles need a socket, objects based on XS modules have an internal pointer as an integer, whose address won't be valid the next time it's loaded), and even though the majority of objects are safe to serialize, even a small bit of unreported fragility is usually enough to create large, hard to debug problems.

An exception to this rule is Moose based objects, because they have sufficient meta information available through Moose's powerful reflection support in order to be safely serialized.

Additionally, the standard backends provide a default typemap for common objects (DateTime, Path::Class, etc), which by default is merged with any custom typemap you pass to KiokuDB.

So, in order to actually get KiokuDB to store things like Class::Accessor based objects, you can do something like this:

When the collapser encounters an object it will ask KiokuDB::TypeMap::Resolver for a collapsing routine based on the class of the object.

This lookup is typically performed by ref $object, not using inheritance, because a typemap entry that is safe to use with a superclass isn't necessarily safe to use with a subclass. If you do want inherited entries, specify isa_entries:

If no normal (ref keyed) entry is found for an object, the isa entries are searched for a superclass of that object. Subclass entries are tried before superclass entries. The result of this lookup is cached, so it only happens once per class.

In KiokuDB every object is normally assigned an ID, and if the object is shared by several objects this relationship will be preserved.

However, for some objects this is not the desired behavior. These are objects that represent values, like DateTime, Path::Class entries, URI objects, etc.

KiokuDB can be asked to collapse such objects intrinsicly, that is instead of creating a new KiokuDB::Entry with its own ID for the object, the object gets collapsed directly into its parent's structures.

This means that shared references that are collapsed intrinsically will be loaded back from the database as two distinct copies, so updates to one will not affect the other.

Most backends support an inefficient but convenient simple search, which scans the entries and matches fields.

If you want to make use of this API we suggest using KiokuDB::Backend::DBI since simple searching is implemented using an SQL where clause, which is much more efficient (you do have to set up the column manually though).

Calling the search method with a hash reference as the only argument invokes the simple search functionality, returning a Data::Stream::Bulk with the results:

The most mature backend for KiokuDB is KiokuDB::Backend::BDB. It performs very well, and supports many features, like Search::GIN integration to provide customized indexing of your objects and transactions.