The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# PODNAME: Prophet::Manual
# ABSTRACT: What Prophet is, how it works and how to use it


12:55 < grink> what is a good word for the datastore in Prophet? database? replica database?
12:55 < Sartak> database is the global state, replica is the local state
12:56 < Sartak> so you probably want just replica :)
12:56 < grink> sweeeeet
12:57  * grink edits out "storage-thingy"
13:15 < obra> local replica == local copy of the database
13:15 < obra> grink: sd is the main app on Prophet we're working on right now
13:17 < grink> isn't local replica redundant then?
13:18 < obra> not really
13:18 < obra> EVERY copy is a replica
13:18 < grink> or are you saying, "Alice's local state" and "Bob's local state"
13:18 < obra> my local replica is the one I'm working from
13:19 < grink> so the database is the theoretical merging of all the replicas, but no one would ever work from the "database"
13:19 < grink> you always interface through a replica
13:20 < obra> there isn't really "the database"
13:20 < obra> database is a word that describes any/all replicas. 
13:20 < obra> every replica shares the same database uuid
13:20 < obra> so you don't merge your replica of the foo database into my replica of the bar database
13:21 < obra> it's kind of like cylons
13:21 < obra> there are many copies.
13:21 < grink> lol
13:21 < obra> they're sort of interchangable
13:21 < obra> but each comes from the same prototype
13:21 < obra> and clones of the same kind can get inside each others' heads much more easily
13:21 < obra> (This is ~why SD's milestones are named for cylons)

__END__

=pod

=head1 NAME

Prophet::Manual - What Prophet is, how it works and how to use it

=head1 VERSION

version 0.751

=head1 Introduction

=head2 What is Prophet?

Prophet is a new kind of database designed for the post Web-2.0 world. It's
made to let you collaborate with your friends and coworkers without needing any
kind of special server or Internet provider.

Prophet's buzzword-laden pitch reads something like this:

    A grounded, semirelational, peer to peer replicated, disconnected, versioned, property database with self-healing conflict resolution. 

Here is a slideshow describing why Prophet came about:
L<http://www.slideshare.net/obrajesse/web-20-is-sharecropping>

=head2 How does it work?

There are two ways to create a Prophet database: cloning and initing

One way is to clone an existing database. When you clone an existing database,
a local replica is created for you with the uuid of the cloned database.

Another way is to init a database. This creates a database with a new uuid.
Anyone who clones from this database will get a replica of the data and share
the database uuid.

Note that Prophet will prevent you from merging databases unless they have the
same database uuid (although you can force the merge of different databases if
you want).

A Prophet database is composed of records, each of which has several
properties. Two core properties are C<type> and C<uuid>. A record's C<type>
indicates the kind of record (comment, ticket, user, etc.) and the C<uuid> of
the record uniquely identifies it so that it can be referenced elsewhere.
Another core property is a record's C<luid>, which is a shorthand identifier
used for local identification. For example:

    # Instead of specifying the uuid
    ticket show e4e5f9d8-ff7a-40c1-8c7f-2d6fcdd859ed

    # ...you can use the luid
    ticket show 9

=head2 Record overview

=head3 The record object (Prophet::Record)

A record object in Prophet is initially an empty husk. First, the record class
is found. The default record class is L<Prophet::Record>, but designating a
custom class, one that extends from L<Prophet::Record> is possible. Once the
record class is found, the object is instantiated and passed the app_handle,
handle, and type of the record. The record is now ready for use.

=head3 Loading a record from the database

Once you have a record object configured with a type and uuid, you can load
data from the replica. This consists of asking the replica (handle) for the
properties corresponding to the given record type and uuid.

Currently, the record object does not actually store any data. Rather, it acts
as a proxy to the replica.

=head3 Saving a record to the database

There is no save method corresponding to load. Properties are immediately saved
to the replica once they are set.

Before properties are sent to the replica, the record object is responsible for
canonicalizing and validating them.

=head2 Definining a property: declaring, defaulting, and recommending

You can declare properties for a record by defining a C<declared_props> routine
for a record. The routine should return a list of properties declared for the
record type. Don't forget to return inherited properties! Here is an example:

    sub declared_props {
        return ('email', shift->SUPER::declared_props(@_))
    }

Prophet knows how to default a property by looking for a C<default_prop_$prop>
method in the record class. If it finds one, it will pass the properties (not
just the property to be defaulted) through in the form of a hashref. The
returned value is the default value for the property. The default method is NOT
triggered if the property value is already defined (not undef)

Generating property defaults takes place during record creation.

You can also recommend values for a property. Recommending values for a
property is mainly used for validation. To recommend values for a property,
define a C<_recommended_values_for_prop_$prop> routine in your record class.
The routine should return a list of which is the range of values for the
property. Here is an example of how SD uses value recommending to validate:

    # A globally defined "statuses" setting is specified in App::SD
    sub database_settings {
        ...
        statuses => ['24183C4D-EFD0-4B16-A207-ED7598E875E6' => qw/new open stalled closed rejected/],
        ...
    }

    ...

    # App::SD::Model::Ticket uses the "statuses" setting for recommended values
    sub _recommended_values_for_prop_status {
       return @{ shift->app_handle->setting( label => 'statuses' )->get() };
    }

    ...

    # App::SD::Model::Ticket uses the recommended values for "status" to validate
    sub validate_prop_status {
        my ( $self, %args ) = @_;
        return $self->validate_prop_from_recommended_values( 'status', \%args );
    }

=head2 Property canonicalization

Property canonicalization makes sure a property is in the right format. It
includes trimmming leading and trailing whitespace, making sure text is in the
right case, and more.

Prophet knows how to canonicalize a property by looking for a
C<canonical_prop_$prop> method in the record class. If it finds one, it will
pass the properties (not just the named property) through in the form of a
hashref to be canonicalized.

=head2 Property validation

Property validation makes sure a property has a valid value before committing
it to the replica.

Prophet knows how to validate a property by looking for a
C<validate_prop_$prop> method in the record class. If it finds one, it will
pass the properties (not just the named property) through in the form of a
hashref to be validated.

If the validation routine makes note of an error, Prophet will abort with an
exception (die).

You can also ask Prophet to validate a property based on recommended values.

=head1 Glossary

=head2 Record

A record is a collection of properties (much like an SQL table is a collection
of columns). A record must have a type and uuid. It may also have an luid,
which is like a uuid but only valid for the local environment/replica.

=head2 Property

A property is a name/value pair associated with a record.

=head2 Collection

A collection is used to search for and operate on records matching certain
criteria.

=head2 Replica (WIP)

The database that a Prophet application works from.  The local state of all the
data. Alice keeps her most recent fetch of the database in her replica. The
global state of all the data. The latest data that Alice and Bob have committed
are in the database.

=head1 FAQ

=head2 Why doesn't Prophet use git or svn to track changes?

The short answer: "The way you want to handle changes in a B<code>base (for
source code) are very different than the way you want to handle changes in a
B<data>base (for records and properties)"

=head2 Does Prophet currently do sub-property (content-level) diffing?

No it does not... yet. However, the conflict resolution in Prophet is
pluggable, so it's a possibility

=head2 What do C<app_handle> and C<handle> refer to? What's the difference between them?

C<app_handle> is a reference to your application object, like an instance of
C<MyApp.pm> that extends from C<Prophet::App>

If you're familliar with Catalyst, you'll recognize it as being similar to the
C<$catalyst> instance

C<handle> is a reference to your repository "database", depending on what kind
of Replica you're using

If you're familliar with DBI, you'll recognize it as the database handle that
is returned when you connect to a database via C<< DBI->connect >>

=head2 How is Prophet different from something like Google Gears or Adobe Air?

While Gears and Air allow you to take cloud applications offline, they don't
solve the data merging/synchronization problem.

<Insert something here about Gears/Air being based in JavaScript/Flash and
Prophet not having that limitation>

=head2 How does Prophet ensure that synchronized/shared data is valid?

=head1 AUTHORS

=over 4

=item *

Jesse Vincent <jesse@bestpractical.com>

=item *

Chia-Liang Kao <clkao@bestpractical.com>

=item *

Christine Spang <christine@spang.cc>

=back

=head1 COPYRIGHT AND LICENSE

This software is Copyright (c) 2009 by Best Practical Solutions.

This is free software, licensed under:

  The MIT (X11) License

=head1 BUGS AND LIMITATIONS

You can make new bug reports, and view existing ones, through the
web interface at L<https://rt.cpan.org/Public/Dist/Display.html?Name=Prophet>.

=head1 CONTRIBUTORS

=over 4

=item *

Alex Vandiver <alexmv@bestpractical.com>

=item *

Casey West <casey@geeknest.com>

=item *

Cyril Brulebois <kibi@debian.org>

=item *

Florian Ragwitz <rafl@debian.org>

=item *

Ioan Rogers <ioanr@cpan.org>

=item *

Jonas Smedegaard <dr@jones.dk>

=item *

Kevin Falcone <falcone@bestpractical.com>

=item *

Lance Wicks <lw@judocoach.com>

=item *

Nelson Elhage <nelhage@mit.edu>

=item *

Pedro Melo <melo@simplicidade.org>

=item *

Rob Hoelz <rob@hoelz.ro>

=item *

Ruslan Zakirov <ruz@bestpractical.com>

=item *

Shawn M Moore <sartak@bestpractical.com>

=item *

Simon Wistow <simon@thegestalt.org>

=item *

Stephane Alnet <stephane@shimaore.net>

=item *

Unknown user <nobody@localhost>

=item *

Yanick Champoux <yanick@babyl.dyndns.org>

=item *

franck cuny <franck@lumberjaph.net>

=item *

robertkrimen <robertkrimen@gmail.com>

=item *

sunnavy <sunnavy@bestpractical.com>

=back

=cut