noccylabs/tinydata

$ git tag
0.1.0
0.1.1
0.1.2
0.1.3
0.1.4
0.1.4.1
0.2.0
0.2.1
0.2.2

$ git branch
* master

TinyData DBAL

This is a lightweight abstraction layer for SQLite intended for use in local applications. The idea is to have a minimal setup and a flexible API to store and access table data, key-value pairs (configuration), and documents (arrays/objects).

Features

Planned features

Using TinyData

To use TinyData all you really need to do is create a new instance of the main TinyData\DataStore class. You can provide a filename to the constructor to specify where the SQLite database is stored, but if this is omitted the filename will default to the full name of invoked script with a .db suffix appended.

$ds = new DataStore(__DIR__."/app.db");

Creating schemas

You can create schemas in two ways: Either create an instance of the schema class, or use the helper methods on the DataStore

$t = new TableSchema("foo", 1);

...is functionally identical to...

$t = $ds->createTableSchema("foo", 1);

Mapping schemas

Schemas are mapped to the DataStore using the map() method, or by using the magic setter method to specify the schema. Both methods let you name the schema, so the same schema instance can be added multiple times to the datastore using different names. These two statements are thus identical:

$ds->map($mySchema, "my_schema");
$ds->my_schema = $mySchema;

You can also map the schema using the name defined using the schema constructor by calling map without the second parameter.

Table schemas

Table schemas are versioned, and as long as you increase the schema version whenever you make changes to the structure, the upgrade process will be automatic.

// version 1 of the table 'users'
$usertable = new TableSchema("users", 1);
// add 2 fields
$usertable->setColumn("username", "text");
$usertable->setColumn("email", "text");
// map and make sure the database is up to date
$ds->map($usertable);

To insert data, use insert:

$ds->users->insert(['username'=>'bob', 'email'=>'bob@domain.com']);

Accessing data is a bit closer to the metal:

$user = $ds->users->findOne(['username'=>'bob']);
echo "E-mail: ".$user['email']."\n";

In the same way you can replace(), update(), find(), findAll(), delete() and deleteAll(). Note that replace requires you to create a unique index when creating the schema:

$mySchema = new TableSchema("my_schema",1);
$mySchema
    ->setColumn('foo','TEXT')
    ->setColumn('bar','TEXT')
    ->setIndex('foo',['foo'],true)  // true = unique index
    ;

KeyValue schemas

KeyValue schemas is even easier:

$ds->config = new KeyValueSchema("config");

Get and set works as you would expect it to:

$ds->config->set("username", "bob");
echo $ds->config->get("username");

And You can be even more lazy:

$ds->config->created = new DateTime();
echo $ds->config->created->format(DateTime::RFC822)."\n";

Document schemas

Document schemas need to be versioned, in order to maintain the indexed fields:

$ds->resources = new DocumentSchema("resources", 1, [ 
    "/id", 
    "/creator/name" 
]);

You can provide hints in the constructor or when using setIndexedField on unique indexes and field types:

[
    "/path/to/field*",          // unique text field named 'field'
    "/path/to/field:INT"=>"x",  // int field named 'x'
    "/path/to/field:INT*"=>"y", // unique int field named 'y'
]

Indexed fields are extracted into separate columns, and can be used for finding and deleting documents.

$ds->resources->insert([
    'id' => 123,
    'creator' => [
        'name' => 'bob'
    ],
    'type' => 'foo',
    'resource' => new MyCustomResource()
]);

$ds->resources->find(['id'=>123]);

$ds->resources->delete(['id'=>123]);

Cache Schemas

$cache_ds->images = new CacheSchema();

Comparisons

You can match values in the usual ways.

 Type        Key     Comparison
----------- ------- -----------------------------
 Numeric     'x'     Equals
             'x =='
             'x eq'
             'x >'   Greater than
             'x gt'
             'x >='  Greater than or equal
             'x gte'
             'x <'   Less than
             'x lt'
             'x <='  Less than or equal
             'x lte'

Debugging

To enable debugging, set up the DEBUG envvar to contain tinydata:

export DEBUG=tinydata