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

Sat Dec 22 00:30:00 2012

Slides for the talk linq at yapc-eu-2011

-

WARNING:
incomplete code
discussed within.
If you want stuff
to use today,
please go to a
different talk :)

-

Data::Query
a LINQ's
awakening

-

Origins

-

DBIx::Class

-

Further
back?

-

Class::DBI

-

Simple
->search

-

  ->search(
    name => 'Simpson'
  );

-

Class
based

-

Returned
arrays

-

(or an
iterator
object)

-

Tangram

-

Object
store

-

Required
control of
the schema

-

Interesting
syntax

-

  $storage->select(
    $person,
    $person->{name} eq 'Simpson'
  );

-

Still
returned
arrays

-

Integer
based joins

-

Class::DBI::Sweet

-

"You can't
implement
AR :include"

-

Oh yeah?

-

SQL::Abstract

-

join +
prefetch

-

Still only
arrays or
iterators

-

DBIx::Class

-

Reinvention
of Class::DBI

-

join +
prefetch

-

Arbitrary
equality
joins

-

(only
equality
joins)

-

Originally
class based

-

0.05

-

Giant
refactor

-

search() logic
moved to
iterator class

-

iterator
renamed

-

ResultSet

-

Collection
class

-

Enabled
search
chaining

-

Functional
composition
of queries

-

  method older_than ($age) {
    $self->search({
      age => { '>', $age }
    });
  }

-

  $people->older_than($age)
         ->called($name);

-

Still using
SQL::Abstract

-

join
prefetch
group_by
having

-

All implemented
internally

-

Design
errors

-

Combining
collection
+ iterator

-

  $rs->next

-

Objects
too aware
of their
persistence

-

  $row->update

-

Nowhere to
put logic

-

Storage::DBI

-

Storage::DBI
is a god
object

-

ResultSource

-

Table
metadata

-

No true
understanding
of persistence

-

Logic
spread

-

Logic in
Result
ResultSet

-

Worse
still

-

Unintrospectable
query system

-

Too many
ways to
do it

-

  {
    foo => {
      '>', $x,
      '<', $y
    }
  }

-

  {
    foo => [
      -and,
      { '>', $x },
      { '<', $y }
    ]
  }

-

  {
    -and => [
      { foo => { '>', $x } },
      { foo => { '<', $y } },
    ]
  }

-

-

SQL specific
query system

-

  $rs->set_cache(\@objects);
  $rs->search(...);

-

This should
not hit the
database :(

-

select
join
group_by
having

-

Syntax
evolved

-

Evolved and
inconsistent

-

No consensus
on a real
solution

-

SQL::Abstract::More

-

(I hate modules
called ::More)

-

(but ldami still
wrote something
useful there :)

-

Final
horror

-

  $row->get_column('foo');

-

AAAARGH

-

Why does
this exist?

-

  '+select' =>
  group_by =>

-

Same row
classes

-

No new
accessors

-

Need a way
to get extra
column values

-

This was
the WRONG
way to do it

-

HashRefInflator

-

HashRefInflator
is less wrong

-

Constructing
a new class

-

*optionally*
constructing
a new class

-

But now it's
too late

-

-

Wait.

-

Is it
too late?

-

DBIx::Class::CDBICompat

-

Why does
this exist?

-

Class::DBI
compatibility

-

Never really
got used

-

People just
converted

-

That's
ok ...

-

That's not
why I
wrote it

-

t/cdbi-t/

-

Powered early
DBIC development

-

"If CDBICompat
passes these ..."

-

"... core
probably
works too"

-

Plus: DBIC
API much more
capable

-

Much less
reliance on
internals

-

Much less
dependence
on bugs

-

Can we
do it?

-

I think
we can.

-

But first ...

-

-

First?

-

First fix
the query
system

-

Data::Query

-

Abstract
Query
Tree

-

Original
prototype

-

SQL::Abstract2

-

Spec:
Rob Kinyon

-

Code:
Ash Berlin

-

MooseX::Declare

-

Hopelessly
overengineered

-

Still SQL
specific

-

*throw*

-

Started
again

-

Spec as
rough guide

-

Goal: make
stuff work

-

Nodes are
hashrefs

-

Why not
objects?

-

Multiple
backends

-

Differing
class
hierarchies

-

Even within
SQL variants!

-

MySQL: CONCAT(x, y)
Postgres: x || y

-

MySQL: Function
Postgres: Operator

-

Treat
everything
as 'op'

-

Backends
decide what
to generate

-

Ops are
typed to
storage

-

SQL only
has =

-

Conversion
must be
pluggable

-

Naive code
makes eq
and == =

-

Smarter code
can check
argument types

-

(and apply
casts - e.g.
x::int = y::int)

-

What does
it look like?

-

  {
    foo => {
      '>', $x,
      '<', $y
    }
  }

-

  {
    type => DQ_OPERATOR,
    operator => {
      'SQL.Naive' => 'and'
    },
    args => [
      {
        type => DQ_OPERATOR,
        operator => {
          'SQL.Naive' => '>'
        },
        args => [ ...

-

  {
    type => DQ_VALUE,
    subtype => {
      'Perl' => 'Scalar'
    },
    value => $x
  }

-

Sane.

-

Introspectable.

-

OMG
Verbose!

-

Sugar
Syntax

-

Inspired
by Tangram

-

  expr {
    $_->foo > $x
    &
    $_->foo < $y
  }

-

&?

-

Operator
overloading

-

Can't overload
|| && and or

-

Can overload
& and |

-

Imperfect.

-

Can do
better
with B::

-

DBIx::Perlish
DBIx::StORM

-

(StORM found
only on backpan
now ...)

-

  SELECT { $_ }
  FROM { $_->artists }
  WHERE { $_->age > 30 }

-

Query object
separate from
result object

-

Layering
queries

-

WHERE nodes
can collapse

-

  $rs->set_cache(\@objs)

-

Subsequent
WHEREs can
render
to perl

-

Current
status?

-

SQL::Abstract
'dq' branch
passes all
but one test

-

DBIx::Class::SQLMaker
porting still to come

-

DQ-aware
collection
classes still
to come

-

Lots to do
but this
*will* work

-

A LINQ's
awakening?

-

Well, he's
got one
eye open

-

... now I just
need to feed
him coffee

-

-fx-

-

http://git.shadowcat.co.uk/
git://git.shadowcat.co.uk/dbsrgits/Data-Query.git
git://git.shadowcat.co.uk/dbsrgits/SQL-Abstract.git
-
http://shadowcat.co.uk/blog/matt-s-trout/
irc.perl.org#dbix-class
-
Questions?

-

Thank You
IRC:mst
mst@shadowcat.co.uk
@shadowcat_mst