NAME
    Mad::Mapper - Map Perl objects to MySQL or PostgreSQL row data

VERSION
    0.05

DESCRIPTION
    Mad::Mapper is base class for objects that should be stored to the a
    persistent SQL database. Currently the supported backends are Mojo::Pg
    Mojo::mysql and Mojo::SQLite. These backends need to be installed
    separately.

      $ cpanm Mad::Mapper
      $ cpanm Mojo::Pg # Mad::Mapper now support postgres!

    THIS MODULE IS EXPERIMENTAL. It is in use in production though, so big
    changes will not be made without extreme consideration.

SYNOPSIS
    The synopsis is split into three parts: The two first is for model
    developers, and the last is for the developer using the models.

  Simple
      package MyApp::Model::User;
      use Mad::Mapper -base;

      # Class attributes
      col id => undef;
      col email => '';

  Complex
    Instead of using the automatic generated methods from simple SQL
    statements, it is possible to do the complete query yourself. Below is
    the example of how the simple "_insert()" method above can be done
    complex:

      package MyApp::Model::User;
      use Mad::Mapper -base;

      sub _insert {
        my ($self, $cb) = @_;

        Mojo::IOLoop->delay(
          sub {
            my ($delay) = @_;
            $self->db->query("INSERT INTO users (email) VALUES (?)", $self->email, $delay->begin);
          },
          sub {
            my ($delay, $err, $res) = @_;
            return $self->$cb($err) if $err;
            $self->in_storage(1);
            $self->id($db->dbh->last_insert_id(undef, undef, $self->table, $self->pk));
            $self->$cb("");
          },
        );
      }

  High level usage
      use Mojolicious::Lite;
      use MyApp::Model::User;
      use Mojo::Pg;

      my $pg = Mojo::Pg->new;

      helper model => sub {
        my $c = shift;
        my $model = "MyApp::Model::" .shift;
        return $model->new(db => $pg->db, @_);
      };

      get "/profile" => sub {
        my $c    = shift;
        my $user = $c->model(User => id => $c->session("uid"));

        $c->delay(
          sub {
            my ($delay) = @_;
            $user->load($delay->begin);
          },
          sub {
            my ($delay, $err) = @_;
            return $self->render_exception($err) if $err;
            return $self->render(user => $user);
          },
        );
      };

      post "/profile" => sub {
        my $c    = shift;
        my $user = $c->model(User => id => $c->session("uid"));

        $c->delay(
          sub {
            my ($delay) = @_;
            $user->email($self->param("email"));
            $user->save($delay->begin);
          },
          sub {
            my ($delay, $err) = @_;
            return $self->render_exception($err) if $err;
            return $self->render(user => $user);
          },
        );
      };

RELATIONSHIPS
    Currently one a basic "has_many" relationship is supported.

    TODO: "belongs_to()" to and maybe "has_one()".

  Has many
    Define a relationship:

      package MyApp::Model::User;
      use Mad::Mapper -base;
      has_many groups => "MyApp::Model::Group", "id_user";

    Here "id_user" in the "groups" table should reference back to the
    primary key in the current table.

    Return Mojo::Collection of "MyApp::Model::Group" objects:

      $groups = $self->groups;

    Same, but async:

      $self = $self->groups(sub { my ($self, $err, $groups) = @_; ... });

    Create a new "MyApp::Model::Group" object:

      $group = $self->add_group(\%constructor_args);
      $group->save;

SUGAR
  col
    Used to define a column. Follow the same rules as "has".

  has
      has name => "Bruce";
      has [qw(name email)];
      has pet => sub { Cat->new };

    Same as "has" in Mojo::Base.

  pk
    Used to define a primary key. Follow the same rules as "has".

    The primary key is used by default in "load" and "update" to update the
    correct row. If omitted, the first "col" will act as primary key.

    Note that "pk" is not returned by "columns".

  table
    Used to define a table name. The default is to use the last part of the
    class name and add "s" at the end, unless it already has "s" at the end.
    Examples:

      .----------------------------.
      | Class name        | table  |
      |-------------------|--------|
      | App::Model::User  | users  |
      | App::Model::Users | users  |
      | App::Model::Group | groups |
      '----------------------------'

ATTRIBUTES
  db
      $db = $self->db;
      $self->db($db_obj);

    Need to hold either a Mojo::Pg::Database or Mojo::mysql::Database
    object.

  in_storage
      $bool = $self->in_storage;
      $self = $self->in_storage($bool);

METHODS
  expand_sst
      ($sst, @args) = $self->expand_sst($sst, @args);

    Used to expand a given $sst with variables defined by helpers.

    *   %t

        Will be replaced by </table>. Example: "SELECT * FROM %t" becomes
        "SELECT * FROM users".

    *   %c

        Will be replaced by "columns". Example: "name,email".

    *   %c=

        Will be replaced by "columns" assignment. Example: "name=?,email=?"

    *   %c?

        Will be replaced by "columns" placeholders. Example: "?,?,?"

    *   %pc

        Include "pk" in list of columns. Example: "id,name,email".

    *   \%c

        Becomes a literal "%c".

  columns
      @str = $self->columns;

    Returns a list of columns, defined by "col".

  delete
      $self = $self->delete;
      $self = $self->delete(sub { my ($self, $err) = @_, ... });

    Will delete the object from database if "in_storage".

  fresh
      $self = $self->fresh;

    Will mark the next relationship accessor to fetch new data from
    database, instead of using the cached data on $self.

  load
      $self = $self->load;
      $self = $class->load(sub { my ($self, $err) = @_; });

    Used to fetch data from storage and update the object attributes.

  save
      $self = $self->save;
      $self = $self->save(sub { my ($self, $err) = @_, ... });

    Will update the object in database if "in_storage" or insert it if not.

  import
    Will set up the caller class with Mad::Mapper functionality if "-base"
    is given as argument. See "SYNOPSIS" for example.

COPYRIGHT AND LICENSE
    Copyright (C) 2014, Jan Henning Thorsen

    This program is free software, you can redistribute it and/or modify it
    under the terms of the Artistic License version 2.0.

AUTHOR
    Jan Henning Thorsen - "jhthorsen@cpan.org"

