microrm 0.6.3

Lightweight ORM using sqlite as a backend
Documentation
Non-API documentation for microrm.

---

## Overview ##

There are several concepts for microrm that are tricky to extract from just the
API documentation; rather than leave users to derive these through trial and
error themselves, this document is an attempt at collecting them in one place.

Broadly speaking, this document covers three major points:

- Schemata design
- Migrations
- 'Gotchas'

## Schemata design ##

While you can -- as present in the examples at the root of the crate -- simply
place your schema types anywhere in your source tree, the use of a separate
crate with a specific structure will aid greatly when dealing with migrations
--- in other words, as your application grows and evolves, you will end up with
something very similar to this, so you may as well get started on the right
foot! The following arises from one very important fact: the SQLite table name
for an Entity is based on the name of the struct that Entity is derived on _at
the definition site_. Thus, multiple versions of an entity can coexist in a
single source tree, so long as they are not used simultaneously! This is the
core fact leveraged by microrm's migrations system.

Everything that follows is convention, not requirement, so take any absolute
statements with appropriate seasoning.

---

Structure your schema crate as:
```ignore
schema/
  src/
    lib.rs
    v1.rs
    v2.rs
    v3.rs
    ...
```

The idea is to create a module for each version of the schema, and to include
previous types as needed in each version. The latest version should be exported
at the root of the crate; any code that accesses e.g. `schema::v2::Foobar`
should be avoided. Instead, you might have something like the following:

- v1.rs:
```rust
use microrm::prelude::*;

/// Initial Foo definition
#[derive(Clone, Entity)]
pub struct Foo {
    #[key]
    pub bar: String,
    pub baz: String,
}

#[derive(Schema)]
pub struct Schema {
    pub foo: microrm::IDMap<Foo>,
}
```
- v2.rs:
```rust
use microrm::prelude::*;

/// New Foo definition with linked Aleph entity
#[derive(Clone, Entity)]
pub struct Foo {
    #[key]
    pub bar: String,
    pub baz: String,
    pub alephs: microrm::RelationMap<Aleph>
}

/// Aleph record
#[derive(Clone, Entity)]
pub struct Aleph {
    pub bet: u64,
    pub dalet: Vec<u8>,
}

#[derive(Schema)]
pub struct Schema {
    pub foo: microrm::IDMap<Foo>,
}
```
- v3.rs:
```compile_fail
use microrm::prelude::*;

pub use crate::v2::Aleph;

#[derive(Clone, Entity)]
pub struct Foo {
   #[key]
   pub bar: String,
   pub baz: String,
   /// We're adding in an extra (nullable) field
   pub quux: Option<f32>,
   /// We aren't changing Aleph at all, so we can reuse the previous definition here.
   pub alephs: microrm::RelationMap<Aleph>,
}

#[derive(Schema)]
pub struct Schema {
    pub foo: microrm::IDMap<Foo>,
}
```
- lib.rs:
```compile_fail
mod v1;
mod v2;
mod v3;

pub use v3::*;

type SchemaList = (v1::Schema, v2::Schema, v3::Schema, );

pub fn apply_migrations(pool: &microrm::ConnectionPool) -> microrm::DBResult<Schema> {
    microrm::migration::run_migration::<SchemaList>(pool)
}
```

As the definition of the entities changes, consumer code only ever sees the
most recent types -- thus functionally the same as changing the definition
in-place -- but the previous schemata are available to microrm for the purposes
of migrating between the different specified versions.

(The above will not actually compile fully, because while the types have been
specified, the actual migration logic has not yet been written; see below for
more details.)

Note that some care must be taken for bidirectional relationships --- in
general, all types that reference an updated entity must also in turn be
re-specified. In larger schemata, the number of types that must be updated can
be reduced by nesting `Schema` instances:
```compile_fail
#[derive(Schema)]
pub struct GroupA {
	pub e1: microrm::IDMap<E1>,
	...
}

#[derive(Schema)]
pub struct Schema {
	pub group_a: GroupA,
	pub e_n: microrm::IDMap<EN>,
}
```

## Migration logic ##

### MigratableItem ###

The [`MigratableItem`](../schema/migration/trait.MigratableItem.html) trait
provides the core logic for schema migrations. Usually, it's implemented for
Schema instances and controls the overarching data flow of the migration ---
microrm handles indicies automatically, so only entity transforms need be
specified.

Actually migrating an entity generally falls into three stages, one or more of
which may not apply:
1. Create a new in-place table via
   [`MigrationContext::in_progress`]../schema/migration/struct.MigrationContext.html#method.in_progress.
2. Populate the new table with equivalent data from old entities.
3. Fixup any relations that changed between the old schema and the new schema.

The `in_progress` function provides an insertion context where data can be
re-added, including a special method that inserts a new entity with the same ID
as an old entity. While the migration is processing, you have access to both
entity versions coexisting in the database at the same time; care must be taken
to not accidentally reference old data when new data is expected (i.e. via a
relation from an unmigrated entity).

### MigratableEntity ###

Much of the time, migrations modify an entity by applying a simple
transformation to each existing instance. Rather than place an iteration loop
and transformation in the schema's MigratableItem implementation, the
transformation can be captured in a `MigratableEntity` implementation instead,
which then allows the use of the
[`migrate_entity`](../schema/migration/struct.MigrationContext.html#method.migrate_entity)
helper method.

### `migratable` attribute ###

Because all types that reference an updated entity must also in turn be
re-specified, there will sometimes be entity definitions that vary only by the
types involved in their relations. You can automatically provide a
`MigratableEntity` implementation for an entity by using the `migratable`
attribute on an entity:
```compile_fail
#[derive(Clone, Entity)]
#[migratable(super::v2::EntityName)]
pub struct EntityName { ... }
```

Note that you can pass multiple names to the attribute, e.g. `#[migratable(path1, path2)]`.

## Gotchas ##

### Indicies ###
When defining indices, using the `index_cols` proc_macro will make your life much easier:
```
# use microrm::prelude::*;

#[derive(Clone, Entity)]
struct IndexExample {
    #[key]
    pub main_key: String,
    pub secondary_key: String,
    pub data: String,
    // ...
}

#[derive(Schema)]
struct Schema {
    example_entities: microrm::IDMap<IndexExample>,
    supplementary_index: microrm::Index<IndexExample, index_cols![IndexExample::secondary_key]>,
}
```