Telephone +44(0)1524 64544
Email: info@shadowcat.co.uk

mkpm-july-2009 - future-of-dbix-class

Sat Dec 22 00:30:00 2012

Slides for the talk future-of-dbix-class at mkpm-july-2009

The future of
DBIx::Class

-

-

Conference
Driven Development

-

Conference
Driven Design

-

works if they
tell me they
accepted
the talk ...

-

-

The past of
DBIx::Class

-

Class::DBI

-

the "classic"
perl ORM

-

Schwern

-

Tony
Bowden

-

Class::DBI::Sweet

-

Christian
Hansen

-

ActiveRecord
:include

-

"you can't
do that in
Class::DBI"

-

two days
later ...

-

fighting the
superclass

-

backwards
compatibility

-

bugwards
compatibility

-

unrefactorable

-

new research
project

-

DBIx::Class

-

start from
scratch

-

Class::DBI
test suite

-

composite
keys

-

join and
prefetch

-

component
system
via MI

-

very
experimental

-

then people
deployed it!

-

they deployed
our trunk to
production!

-

AAARGH!

-

stable
release
cycle

-

never
finished
researching

-

lots of
design
mistakes

-

lots of
new tools
available

-

time for
a rethink

-

this one -is-
refactorable

-

-

The present of
DBIx::Class

-

What did we
get right?

-

making
everything
objects

-

Schema
object

-

Storage
and Cursor
objects

-

hides away
backend
specifics

-

auto-increment
limit syntaxes
DBD weirdnesses

-

(even DBI)

-

ResultSource
object

-

table/view
metadata

-

not tied to
the class

-

relationships

-

near side
far side
join condition

-

no single
column
assumptions
for keys

-

Result
Class

-

inflate_result

-

minimal
protocol

-

don't even
need objects

-

ResultSet

-

virtual
view

-

lazy
persistence
backed
collection

-

pure
functional

-

(sort of)

-

chainable
updatable
cacheable

-

EXTENSIBLE

-

-

digression

-

ResultSets
fucking
rock

-

ResultSets
were an
accident

-

trying to
factor things
out cleanly

-

need an 'aha'
moment to
use them right

-

I don't like
aha moments

-

they remind
me of failing
to learn lisp

-

they remind
me of failing
to learn monads

-

they remind
me of failing
to learn git

-

"learning this
will make you
a better
programmer"

-

great

-

what about
being done and
down the pub?

-

Result Class
vs.
ResultSource
object

-

inflate_column
vs.
add_relationship

-

list context
vs.
scalar context

-

search() args
vs.
find() args

-

aha moments
indicate
conceptual
inconsistency

-

sometimes that means
UR CONCEPTUALISIN
IT COMPLETELY WRONG

-

(so you should
still learn lisp
for that aha)

-

usually it just
means the UI
is retarded

-

(see git)

-

DBIx::Class
sucks

-

because it
raised our
expectations

-

understand
(ab)use
hate
improve

-

-

The present of
DBIx::Class

-

What did we
get wrong?

-

... most
things ...

-

lots of
details

-

details?

-

underlying
design
mistakes

-

persistent
vs.
non persistent

-

why should
"in the same
database"
be special?

-

query
handling

-

SQL::Abstract
AST has too
much DWIM

-

too much
DWIM?!

-

hard to
introspect

-

can't do
inference

-

objects know
too much

-

->insert

-

why should it
care it's
persisted?

-

$rs->next

-

stupid
stupid
STUPID

-

implicit
iterators
are BAD

-

each %hash
anyone?

-

(even 5.8.8's
Data::Dumper
gets it wrong)

-

ORM

-

O/R
Mapper

-

where's the
mapper?

-

one class
<->
one table

-

one class
<->
one view

-

we can fake
it with
delegation

-

search() doesn't
understand
that though

-

-

so, are we
fucked?

-

NO

-

(because we
didn't get to
the pub in time
to pull ...)

-

designed
to be
refactored

-

lots of
tests

-

(CDBICompat
has better
tests than
Class::DBI)

-

rebuild
refactor
re-use
rebase

-

-

The future of
DBIx::Class

-

uniform
data APIs

-

a collection is
a collection is
a collection ...

-

perl array
directory
database table

-

we shouldn't
care about what
data -is-

-

we should care
about what it
can -do-

-

Data::CapabilityBased

-

capability?

-

a role with
a default
implementation

-

and a
validation
test suite

-

Data::Collection::Capability::Mappable

-

  $coll->map(sub {
    ...
  });

-

  $coll->map_by('title');

-

  method map_by ($attr) {
    $self->map(sub ($x) {
      $x->$attr;
    });
  }

-

  class DBIx::Class::ResultSet;

  method map_by ($attr) {
    if ($self->_has_relationship($attr)) {
      return $self->search_related($attr);
    }
    ...
  }

-

-

semantic
queries

-

  use Data::Query qw(expr);

  $coll->grep(expr {
    $_->name eq 'Bob'
  });

-

  array?
  grep { $_->name eq 'Bob' } @array

-

  resultset?
  WHERE name = 'Bob'

-

SQL::Abstract 2
provides an
explicit AST

-

Data::Query
backend generates
to the AST

-

expr {} is
just one
front end

-

introspectable
means
transformable

-

  $_->city eq 'Pittsburgh'

-

  WHERE city = ?

-

  JOIN cities city ON
  city.id = tbl.city_id
  WHERE city.name = ?

-

-this- is
the M in
ORM

-

-

streams

-

  my $stream = $rs->as_stream;
  while (my $obj = $stream->next) {
    ...
  }

-

compatibility?

-

  class DBIx::Class::ResultSet;

  method next {
    $self->_implicit_stream
         ->next;
  }

-

-

store !=
connection

-

default
connection
object

-

dynamically
scoped

-

composite
connections

-

sharding
balancing
query slaves

-

-

observability

-

$foo->bar($baz);

-

how do we
track this?

-

Variable::Magic?

-

tie on
perl5 v8

-

adopt the
objects?

-

subclasses
everywhere

-

  method update (...) {
    store_for($self)
      ->update(...);
  }

-

can't build
it the other
way around

-

-

scoped
flushing

-

  $obj->foo($foo);
  $obj->bar($bar);
  $obj->baz($baz);

-

when do I
UPDATE?

-

  UPDATE tbl SET foo = ?
  UPDATE tbl SET bar = ?
  UPDATE tbl SET baz = ?

-

  $obj->update; # :)

-

  $store->flush;

-

  flush_at_end {
    ...
  }

-

  $obj->foo($foo);
  $obj->bar($bar);
  $obj2->baz($baz);

-

  UPDATE tbl SET
  foo = ?, bar = ?

-

-

What would
it look
like then?

-

  subtype CD
    as Record[
      id => PositiveInt,
      title => Str[255],
      published => DateTime
    ];

-

  subtype CDSet
    as Set[CD, 'id']
    where Unique['title'];

-

  subtype CDProto
    as Record[
      title => Str,
      published => DateTime
    ];

-

  table cds {
    column id => unsigned int(8),
      auto_increment, primary key;
    column title => varchar(255), unique;
    column published => datetime;
  }

-

  my $cd_table = Data::Store::DBI::Table->new(
    database => $music_db,
    schema => $cd_schema,
    type => CD,
    insert_type => CDProto,
  );

-

  my $conn =
    Data::Store::Connection::DBI
      ->new(dsn => $dsn);

-

  $cd_table->add_using($conn, $cd);
  $cd_table->update_using(
    $conn,
    $query_spec,
    $update_spec
  );

-

  $conn->add_to($cd_table, $cd);
  $conn->update_in(
    $cd_table,
    $query_spec,
    $update_spec
  );

-

Update
specification

-

  HashRef[Data::Query::Expr]

-

doesn't
cover
SELECT

-

stores need
capabilities
as well

-

API
TBD

-

i.e. I'll have
to try and
implement it

-

-

Data::CapabilityBased
design sketch
is on CPAN

-

discussion will
happen on the
dbix-class list
and channel

-

these slides
will be on
http://shadowcat.co.uk/

-

Any
Questions?

-

Thank
You

-

irc.perl.org #dbix-class
http://lists.scsys.co.uk/
these slides will be on
http://shadowcat.co.uk/