A Foolish Manifesto

fREWdiculous!

Weekly Status Report 3

I don’t feel great about this past week, but I was really busy with wedding planning stuff. I barely made either of my two main goals (2 blog posts and 2 patches/releases a week.)

Last week I:

I have high hopes for the coming week, that I can get more important releases and more interesting blog posts written. Stay tuned!

  • 0 Comments
  • Filed under: Uncategorized
  • Thanks to some idle chatting in the #dbix-class channel on irc.perl.org I came up with DBIx::Class::Helper::Row::RelationshipDWIM. The gist of it is that you get to type

    1
    __PACKAGE__->has_many(addresses => '::Address', 'person_id' )

    instead of

    1
    __PACKAGE__->has_many(addresses => 'MyApp::Schema::Result::Address', 'person_id' )

    That yields a total sugar (with candy) of the following:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    package Lynx::SMS::Schema::Result::MessageParent;

    use Lynx::SMS::Schema::Candy;

    primary_column id => {
       data_type         => 'int',
       is_auto_increment => 1,
    };

    column account_id => { data_type => 'int' };
    column type_id => { data_type => 'int' };

    column caller_id => {
       data_type => 'int',
       size      => 11,
       is_nullable => 1,
    };

    column message => {
       data_type => 'nvarchar',
       size => 1000,
    };

    column when_created => {
       data_type     => 'datetime',
       set_on_create => 1,
    };

    column voice_id => {
       data_type     => 'int',
       is_nullable   => 1,
    };

    belongs_to account => '::Account', 'account_id';
    belongs_to voice => '::Voice', 'voice_id';
    belongs_to type => '::Type', 'type_id';
    has_many children => '::MessageChild', 'message_parent_id';

    1;

    Pretty nice.

  • 0 Comments
  • Filed under: Uncategorized
  • New stuff in DBIx::Class::Helpers

    I just released a new version of DBIx::Class::Helpers and it has two new components: DBIx::Class::Helper::ResultSet::ResultClassDWIM and DBIx::Class::Helper::Schema::GenerateSource.

    Helper::ResultSet::ResultClassDWIM

    This component solves an issue I’ve seen both by myself and with my coworkers; it’s too hard to remember/type the following:

    1
    2
    3
    my $rs = $schema->resultset('Foo')->search($q, {
       result_class => 'DBIx::Class::ResultClass::HashRefInflator',
    });

    So I wrote this component which will let you generically write:

    1
    2
    3
    my $rs = $schema->resultset('Foo')->search($q, {
       result_class => '::HashRefInflator',
    });

    or use the specially hardcoded:

    1
    2
    3
    my $rs = $schema->resultset('Foo')->search($q, {
       result_class => '::HRI',
    });

    Handy right?

    Helper::Schema::GenerateSource

    This component is a little more unusual. The idea is to take care of some of the issues I mentioned here. It doesn’t solve everything due to some design issues in DBIx::Class, which I hope to take care of soon. Basically the idea is that instead of the boilerplate files that you get when you use DBIx::Class::Helper::Row::SubClass, you can instead just do the following in your schema:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package Foo::Schema;

    __PACKAGE__->load_components('Helper::Schema::GenerateSource');

    # ...

    __PACKAGE->generate_source(User => 'MyCompany::Result::User');

    1;

    The main issue is that even though this correctly associates a new source to the schema, you cannot currently add relationships to the source. I’ll make another post when I fix that, but I doubt I’ll get it into the next release of DBIx::Class.

    In other news I’m doing some pretty sweet stuff with the SQL generation code in DBIx::Class and I hope it will be ready for the next release. I’ll post more when that’s released.

  • 2 Comments
  • Filed under: Uncategorized
  • I am proud to announce a new release of DBIx::Class::Helpers. There are five major changes in this release.

    First off, the latest release adds DBIx::Class::Candy exports. So if you are using DBIx::Class::Candy to define a result, certain methods will be imported into your namespace. For example, DBIx::Class::Helper::Row::SubClass will export a subclass subroutine into your module. Not huge but nice nonetheless.

    Next up, we have four shiny new components. Two are ResultSet components and two are Result components. One of the two ResultSet components was originally going to be in the core of DBIx::Class, but I decided to make a helper first to ensure that we iron out the details before we release it in core. That component is DBIx::Class::Helper::ResultSet::RemoveColumns. It does exactly what it sounds like. With it you can do

    1
    2
    3
    $resultset->search(undef, {
       remove_columns => ['id']
    })

    and the id column will no longer be selected in your ResultSet. I am sure that it has some quirks, but I am not sure what they would be till people use this. So have at it!

    The next component, DBIx::Class::Helper::ResultSet::AutoRemoveColumns, is based upon RemoveColumns. Again, the name should make it clear what it does. Currently it removes typically large columns by default, like text, blob, and the like. See the docs for exactly what it removes. (Note: later on I hope to add a component that adds lazy columns as detailed in ovid’s post here. Ovid if you are reading this I can’t comment on your blog.)

    Next up is a fairly simple component, DBIx::Class::Helper::Row::StorageValues. It gives you access to the last known stored value of a column. For example:

    1
    2
    3
    4
    5
    my $foo = $resultset->search({ name => 'frew'})
       ->next;
    $foo->name('frioux');
    # prints "frew"
    say $foo->get_storage_value('name');

    Building upon that we have my favorite new component: DBIx::Class::Helper::Row::OnColumnChange. This module adds powerful hooks for calling methods when a column has been modified. If you enable StorageValues for the column you hook into you get to look at the old value and the new value, which is pretty cool. There are three hooks: before_column_change, around_column_change, and after_column_change. It automatically takes into account values changing because of accessors as well as by the arguments passed to update. Also note that it allows you to tell it to wrap the call to update and the column change method in a transaction so that you can safely do things to other tables in the method. Anyway, enough talk, here’s a small example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    __PACKAGE__->add_column(relationship_status => {
       data_type               => 'varchar',
       length                  => 30,
       keep_storage_value      => 1,
    });

    __PACKAGE->before_column_change(relationship_status => {
       method    => 'happy_times',
       txn_wrap  => 1,
    });

    sub happy_times {
       my ($self, $old, $new) = @_;
       $self->significant_other->update({ feelings => 'happy' })
          if $new eq 'together' && $old eq 'apart'
    }

    So basically if relationship status changes from apart to togehter the significant other gets marked as happy, and all of this is done in a transaction, which is pretty awesome.

    Anyway, hopefully this makes your job easier. Have a good Friday!

  • 1 Comment
  • Filed under: Uncategorized
  • New stuff in DBIx::Class::Helpers 2.00200

    A new release of the resplendent Perl ORM DBIx::Class means new release of DBIx::Class::Helpers

    The ResultSet::Random helper had the wrong function used for MySQL. That was fixed thanks to an RT from pldoh.

    get_namespace_parts from the util package was unnecessarily strict. Thanks to melo for the prodding to do that.

    I refactored some of the code in core DBIx::Class so that I can more easily detect is_numeric with Row::NumifyGet, instead of requiring the user to specify it. Normally DBIx::Class autodetects it based on column type, but that code wasn’t quite generic enough until now. Nice!

    And then the most exciting bit is a new helper entirely for the suite: Row::ToJSON. Basically I was sick of doing this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package ACD::Schema::Result::Foo;

    # regular package stuff here

    sub TO_JSON {
      my $self = shift;
      return {
        id => $self->id,
        foo => $self->foo,
        # etc etc ad nausium
      }
    }

    "distraction";

    Of course that can be shortened to:

    1
    2
    3
    4
    sub TO_JSON {
      my $self = shift;
      return { map +( $_ => $self->$_), qw{id foo ...} }
    }

    But I still have to make that stupid columns list! This shiny new helper makes a TO_JSON method that will simply include all of your columns except for the “heavy” ones like TEXT, NTEXT, or BLOB. Of course you can have finer-grained control than that by explicitly saying to include (or not) a column in it’s configuration. See the docs for all the nitty gritty details.

  • 0 Comments
  • Filed under: Uncategorized
  • Latest additions to DBIC::Helpers

    Yesterday I added a basic but really nice helper to DBIx::Class::Helpers. Say hello to DBIx::Class::Helper::Row::NumifyGet. The reasoning is that often we have bit fields in our database and when we serialize them with JSON we get something like the following:

    1
    { 'bit_field':'0'}

    JavaScript has the whole truthy concept like Perl except that in JavaScript “0″ is true, while 0 is false. So NumifyGet will automatically “numify” columns with the is_numeric field set to true. After doing that the json above would become:

    1
    { 'bit_field':0}

    Much nicer. Also I added some good docs to DBIx::Class::Helper::ResultSet::Union as well as fixing some latent bugs that were in it.

    Enjoy!

  • 1 Comment
  • Filed under: Uncategorized
  • New stuff in DBIx::Class::Helpers

    If I were to pick one of the modules that I’ve written so far to be my legacy DBIx::Class::Helpers would be it. Maybe later it will be DBIx::Exceptions, but as of now that’s technically vaporware.

    So over the Christmas break I’ve been working on updating it a bit. First and foremost I added the exciting DBIx::Class::Helper::ResultSet::Union helper. The best use case (I can think of) for a union is when you want to get data from multiple tables as if they were one table. Here is how one might do something like that with the new module (example ripped from wikipedia):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
       my $sales_2006 = $schema->resultset('Sales2006')->search(undef, {
          columns => [qw{sales_person_id amount}]
       });
       my $sales_2007 = $schema->resultset('Sales2007')->search(undef, {
          columns => [qw{sales_person_id amount}]
       });
       $sales_2006->result_class('DBIx::Class::ResultClass::HashRefInflator');
       $sales_2007->result_class('DBIx::Class::ResultClass::HashRefInflator');

       my @sales = $sales_2006->union($sales_2007)->all;

    I’d argue that if you have tables like the above you are Doin it Rong, but there are other times when it might make more sense, like if you wanted to maybe have some kind of autocompleter that works for more than one table (Artist, Album, Track) where all of the things have names and ids.

    As you should be able to see from the name of the Component I have gone from naming things DBIx::Class::Helper::* to DBIx::Class::Helper::$namespace::*. Mostly that was because my esteemed DBIx::Class janitor, ribasushi, suggested it. I almost had done it before, but his asking for it was enough to get me to do it. The old names will be available for all of the 2.* series and the 3.* series with a warning. After that they will be removed.

    Speaking of version numbers, I have also switched from using RJBS versions to using a more normal versioning scheme. Again, I wouldn’t take the credit for this one as it is mostly due to mst and ribasushi’s prodding. Basically the deal is that although RJBS versions make it dead easy for me to release code, they make it hard for the user to see what’s going on. How much has changed between releases? All a user knows is if a release breaks backcompat or not. So I’ll be using the more normal x.yyyzzw where x breaks backcompat, y means major new features, z means bugfixes, and w means minor fixes like pod or dist fixes. I imagine that even that could be automated by looking at current and previous release… Maybe next time :-)

    Next up is a much more complete DBIx::Class::Helper::ResultSet::Random which allows the selection of an arbitrary amount of rows, instead of just one. As mentioned in the POD I’ve only tested it on a large table with SQL Server (2005.) To be more explicit, if you are using mysql and it is as slow as people always say, show me a benchmark and we can work together to make it fast. The only thing I can think of to make it fast is to use RowNumberOver and do an IN for a list of shuffled numbers generated with perl. We’ll see though. It works fine for me right now so I don’t care :-)

    While I was updating all these little bits I went ahead and pregenerated the DDL for the schema, so I no longer depend on SQLT, which is actually surprisingly heavy. So that’s pretty sweet.

    Lastly, String::CamelCase had a new release that no longer fails tests! So I’ve added it as a dep and removed the conditional load code. This isn’t as big a deal as most of the other stuff, but it is certainly a nice change.

    Because of all of the major changes I’ve released the new version to cpan as a developer version, so please check it out. At the very least if someone finds a missing dep or something that would be good. If I somehow messed up the doc or something that would be good to find out as well. I plan on releasing for realz before (or on?) New years.

  • 1 Comment
  • Filed under: Uncategorized