Dance like NoSQL is watching

April 15th, 2017

Dance like NoSQL is watching

Here come a fast one that I have to get out of my head.

First, there was DBIx::NoSQL

Lately I've returned to DBIx::NoSQL, which provides a simple, easy way to create key/value stores. Simple? Yes, really dead simple. Like that kind of simple:

use DBIx::NoSQL;

my $store = DBIx::NoSQL->connect( 'store.sqlite' );

        #     model    id  
$store->set( Player => yenzie => {
    name => 'yenzie',
    alliance => 'Nefarious Coallition',
});

$store->set( Ship => enkidu => {
    name   => 'Enkidu',
    hull   => 10,
    coords => [ 10, 10 ],
});

In the background, DBIx::NoSQL creates a DBIx::Class schema. All data structures are serialized and dumped in a big happy table, while their ids are saved in per-model tables. Indexes can also be added to models whenever we want

$store->model('Player')->index('alliance');

When new indexes are created, DBIx::NoSQL alters the schema dynamically in consequence. And since the schema is DBIx::Class-based, its power is there for searches when needed.

my @players = $store->search('Player')->where({ 
    # needs to be the id or an indexed field
    alliance => { like => qr/evil/ }
)->order_by( 'name DESC' )->all;

In a nutshell, it's a decent tool when setting up a MongoDB or CouchDB instance -- let alone a full relational schema -- sounds like too much work.

Then came along DBIx::NoSQL::Store::Manager

When I originally played with it I upped the antes and wrote DBIx::NoSQL::Store::Manager, which uses Moose objects as models. Which let you create the class MyStore::Model::Player, and the system will figure it out from there.

package MyStore::Model::Player;

use Moose;
use MooseX::MungeHas 'is_ro';

with 'DBIx::NoSQL::Store::Manager::Model';

has name     => ( traits  => [ 'StoreKey' ] );
has alliance => ( traits  => [ 'StoreIndex' ] );

1;

And now... lights on the dancefloor...

And so last week I was musing on how easy this allows to set up a quick'n'dirty NoSQL backend. Then I thought... and what if we push that DWIMery all the way to a REST interface?

So I fired up the ol' Dancer environment, hacked for an hour or two, and now I have... no, let's show, not tell.

I'm skipping the non-important parts of the config.yml. All that matter for us right now is that we serialize using JSON, and set a database and store manager class for the store plugin.

As you can see, the main store class is straightforward.

Mind you, in a future iteration I might streamline things further and just build the class automatically if no customization is required. But that's a yak for a different day.

Model class. Still short and sweet.

The Dancer app. All of it.

No, really, that's all of it.

And we DANCE!

Player creation.

By the by, I'm using HTTP Pie as my REST tool. It's really nice.

Yup, it's there.

Updates work.

... but not on ready-only values.

Right now the exception value is an ugly trace. It'll eventually get prettier.

... or unknown attributes.

We can delete too, natch.

C'mon. You have to admit. It's all pretty sweet, isn't?

Last notes

The code for the plugin can be found on GitHub, although it's still purely in its Proof-of-Concept stage. I'll try to groom it for CPAN if there is a demand.

I'm also in the midst of updating DBIx::NoSQL::Store::Manager itself, and I'm also making inquiries about DBIx::NoSQL, which would need to have a few things updated (mostly, it's using Any::Moose, which has been deprecated since). I would also love to see DBIx::NoSQL adopting more backends. I heard smashing recommendations for Postgres and its JSON support, so the mix of the two could be interesting (well, to me, at least).

Seen a typo or an error? Submit an edit on GitHub!