From a36e74fb1f7e67d038dd1c6c6e4a8ca642f225f9 Mon Sep 17 00:00:00 2001 From: Alex Beamish Date: Wed, 4 Sep 2013 13:45:39 -0400 Subject: [PATCH 1/3] Documentation update and cleanup This update removes 'year' from the CD table definition in both the SQL and in the class definition, since it wasn't being used. The directory MyApp/Schema/ResultSet was also removed since the supplied code never used it. The results that the sample code produces have been expanded a little so that they provide answers to the questions asked by the subroutine calls. A new section has been added that briefly discusses the results and explains the techniques that could be used when writing this type of a programmatic query. --- lib/DBIx/Class/Manual/Example.pod | 108 ++++++++++++++++++------------ 1 file changed, 66 insertions(+), 42 deletions(-) diff --git a/lib/DBIx/Class/Manual/Example.pod b/lib/DBIx/Class/Manual/Example.pod index 59b114e80..05db57bd0 100644 --- a/lib/DBIx/Class/Manual/Example.pod +++ b/lib/DBIx/Class/Manual/Example.pod @@ -11,7 +11,7 @@ as the database frontend. The database consists of the following: table 'artist' with columns: artistid, name - table 'cd' with columns: cdid, artist, title, year + table 'cd' with columns: cdid, artist, title table 'track' with columns: trackid, cd, title @@ -25,21 +25,22 @@ And these rules exists: =head2 Installation -Install DBIx::Class via CPAN should be sufficient. +You'll need to install DBIx::Class via CPAN, and you'll also need to +install sqlite3 (not sqlite) if it's not already intalled. =head3 Create the database/tables -First make and change the directory: +First, create the database directory, then get into that directory, as +we'll create the database there: mkdir app - cd app - mkdir db - cd db + mkdir app/db + cd app/db This example uses SQLite which is a dependency of DBIx::Class, so you shouldn't have to install extra software. -Save the following into a example.sql in the directory db +Save the following into a example.sql in the directory app/db CREATE TABLE artist ( artistid INTEGER PRIMARY KEY, @@ -68,14 +69,13 @@ Change directory back from db to the directory app: cd ../ -Now create some more directories: +Now we'll create some more directories for the classes: mkdir MyApp mkdir MyApp/Schema mkdir MyApp/Schema/Result - mkdir MyApp/Schema/ResultSet -Then, create the following DBIx::Class::Schema classes: +Create the following DBIx::Class::Schema classes: MyApp/Schema.pm: @@ -104,7 +104,7 @@ MyApp/Schema/Result/Cd.pm: use base qw/DBIx::Class::Core/; __PACKAGE__->load_components(qw/InflateColumn::DateTime/); __PACKAGE__->table('cd'); - __PACKAGE__->add_columns(qw/ cdid artist title year/); + __PACKAGE__->add_columns(qw/ cdid artist title /); __PACKAGE__->set_primary_key('cdid'); __PACKAGE__->belongs_to('artist' => 'MyApp::Schema::Result::Artist'); __PACKAGE__->has_many('tracks' => 'MyApp::Schema::Result::Track'); @@ -126,7 +126,10 @@ MyApp/Schema/Result/Track.pm: =head3 Write a script to insert some records -insertdb.pl +This script should be created in the app/ directory, since it access the +database in the app/db directory. + +insertdb.pl: #!/usr/bin/perl @@ -186,8 +189,14 @@ insertdb.pl @tracks, ]); +Once created, this script should be run once to fill the database with +the required data for the following test script. + =head3 Create and run the test scripts +Like the previous script, this script should also be create in the app/ +directory. + testdb.pl: #!/usr/bin/perl @@ -242,7 +251,8 @@ testdb.pl: } ); while (my $track = $rs->next) { - print $track->title . "\n"; + print $track->title . " (from the CD '" . $track->cd->title + . "')\n"; } print "\n"; } @@ -260,7 +270,7 @@ testdb.pl: } ); my $cd = $rs->first; - print $cd->title . "\n\n"; + print $cd->title . " has the track '$tracktitle'.\n\n"; } sub get_cds_by_artist { @@ -296,7 +306,7 @@ testdb.pl: } ); my $artist = $rs->first; - print $artist->name . "\n\n"; + print $artist->name . " recorded the track '$tracktitle'.\n\n"; } sub get_artist_by_cd { @@ -311,37 +321,51 @@ testdb.pl: } ); my $artist = $rs->first; - print $artist->name . "\n\n"; + print $artist->name . " recorded the CD '$cdtitle'.\n\n"; } -It should output: - - get_tracks_by_cd(Bad): - Dirty Diana - Smooth Criminal - Leave Me Alone - - get_tracks_by_artist(Michael Jackson): - Beat it - Billie Jean - Dirty Diana - Smooth Criminal - Leave Me Alone - - get_cd_by_track(Stan): - The Marshall Mathers LP - - get_cds_by_artist(Michael Jackson): - Thriller - Bad - - get_artist_by_track(Dirty Diana): - Michael Jackson - - get_artist_by_cd(The Marshall Mathers LP): - Eminem +When this script is run, it should output the following: + + get_tracks_by_cd(Bad): + Leave Me Alone + Smooth Criminal + Dirty Diana + + get_tracks_by_artist(Michael Jackson): + Billie Jean (from the CD 'Thriller') + Leave Me Alone (from the CD 'Bad') + Smooth Criminal (from the CD 'Bad') + Beat It (from the CD 'Thriller') + Dirty Diana (from the CD 'Bad') + + get_cd_by_track(Stan): + The Marshall Mathers LP has the track 'Stan'. + + get_cds_by_artist(Michael Jackson): + Thriller + Bad + + get_artist_by_track(Dirty Diana): + Michael Jackson recorded the track 'Dirty Diana'. + + get_artist_by_cd(The Marshall Mathers LP): + Eminem recorded the CD 'The Marshall Mathers LP'. + +=head3 Discussion about the results + +The data model defined in this example has an artist with multiple CDs, +and a CD with multiple tracks; thus, it's simple to traverse from a +track back to a CD, and from there back to an artist. This is +demonstrated in the get_tracks_by_artist routine, where we easily walk +from the individual track back to the title of the CD that the track +came from ($track->cd->title). + +Note also that in the get_tracks_by_cd and get_tracks_by_artist +routines, the result set is called multiple times with the 'next' +iterator. In contrast, get_cd_by_track uses the 'first' result set +method, since only one CD is expected to have a specific track. =head1 Notes From 243b826f48baeafe3a48cbd4098a6d4527835c4b Mon Sep 17 00:00:00 2001 From: Alex Beamish Date: Fri, 6 Sep 2013 17:39:18 -0400 Subject: [PATCH 2/3] Remove source code from POD, docs cleanup Some cleanup and simplification in the documentation. --- lib/DBIx/Class/Manual/Example.pod | 308 +++--------------------------- 1 file changed, 30 insertions(+), 278 deletions(-) diff --git a/lib/DBIx/Class/Manual/Example.pod b/lib/DBIx/Class/Manual/Example.pod index 05db57bd0..baf6294d8 100644 --- a/lib/DBIx/Class/Manual/Example.pod +++ b/lib/DBIx/Class/Manual/Example.pod @@ -8,20 +8,19 @@ This tutorial will guide you through the process of setting up and testing a very basic CD database using SQLite, with DBIx::Class::Schema as the database frontend. -The database consists of the following: - - table 'artist' with columns: artistid, name - table 'cd' with columns: cdid, artist, title - table 'track' with columns: trackid, cd, title +The database structure is based on the following rules: + An artist can have many cds, and each cd belongs to just one artist. + A cd can have many tracks, and each track belongs to just one cd. -And these rules exists: +The database is implemented with the following: - one artist can have many cds - one cd belongs to one artist - one cd can have many tracks - one track belongs to one cd + table 'artist' with columns: artistid, name + table 'cd' with columns: cdid, artistid, title, year + table 'track' with columns: trackid, cdid, title +Each of the table's first columns is the primary key; any subsequent +keys are foreign keys. =head2 Installation @@ -30,17 +29,14 @@ install sqlite3 (not sqlite) if it's not already intalled. =head3 Create the database/tables -First, create the database directory, then get into that directory, as -we'll create the database there: +First, create the database directory under the application directory, +then get into that directory, as we'll create the database there: mkdir app mkdir app/db cd app/db -This example uses SQLite which is a dependency of DBIx::Class, so you -shouldn't have to install extra software. - -Save the following into a example.sql in the directory app/db +Save the following into a file called example.sql: CREATE TABLE artist ( artistid INTEGER PRIMARY KEY, @@ -50,7 +46,8 @@ Save the following into a example.sql in the directory app/db CREATE TABLE cd ( cdid INTEGER PRIMARY KEY, artist INTEGER NOT NULL REFERENCES artist(artistid), - title TEXT NOT NULL + title TEXT NOT NULL, + year TEXT ); CREATE TABLE track ( @@ -59,272 +56,27 @@ Save the following into a example.sql in the directory app/db title TEXT NOT NULL ); -and create the SQLite database file: +Now create the SQLite database using that file: sqlite3 example.db < example.sql =head3 Set up DBIx::Class::Schema -Change directory back from db to the directory app: +Go back to the app/ directory: cd ../ -Now we'll create some more directories for the classes: - - mkdir MyApp - mkdir MyApp/Schema - mkdir MyApp/Schema/Result - -Create the following DBIx::Class::Schema classes: - -MyApp/Schema.pm: - - package MyApp::Schema; - use base qw/DBIx::Class::Schema/; - __PACKAGE__->load_namespaces; - - 1; - - -MyApp/Schema/Result/Artist.pm: - - package MyApp::Schema::Result::Artist; - use base qw/DBIx::Class::Core/; - __PACKAGE__->table('artist'); - __PACKAGE__->add_columns(qw/ artistid name /); - __PACKAGE__->set_primary_key('artistid'); - __PACKAGE__->has_many('cds' => 'MyApp::Schema::Result::Cd'); - - 1; - - -MyApp/Schema/Result/Cd.pm: - - package MyApp::Schema::Result::Cd; - use base qw/DBIx::Class::Core/; - __PACKAGE__->load_components(qw/InflateColumn::DateTime/); - __PACKAGE__->table('cd'); - __PACKAGE__->add_columns(qw/ cdid artist title /); - __PACKAGE__->set_primary_key('cdid'); - __PACKAGE__->belongs_to('artist' => 'MyApp::Schema::Result::Artist'); - __PACKAGE__->has_many('tracks' => 'MyApp::Schema::Result::Track'); - - 1; - - -MyApp/Schema/Result/Track.pm: - - package MyApp::Schema::Result::Track; - use base qw/DBIx::Class::Core/; - __PACKAGE__->table('track'); - __PACKAGE__->add_columns(qw/ trackid cd title /); - __PACKAGE__->set_primary_key('trackid'); - __PACKAGE__->belongs_to('cd' => 'MyApp::Schema::Result::Cd'); +Now copy the examples/Schema/MyApp directory to this directory. - 1; +=head3 Populate the database - -=head3 Write a script to insert some records - -This script should be created in the app/ directory, since it access the -database in the app/db directory. - -insertdb.pl: - - #!/usr/bin/perl - - use strict; - use warnings; - - use MyApp::Schema; - - my $schema = MyApp::Schema->connect('dbi:SQLite:db/example.db'); - - my @artists = (['Michael Jackson'], ['Eminem']); - $schema->populate('Artist', [ - [qw/name/], - @artists, - ]); - - my %albums = ( - 'Thriller' => 'Michael Jackson', - 'Bad' => 'Michael Jackson', - 'The Marshall Mathers LP' => 'Eminem', - ); - - my @cds; - foreach my $lp (keys %albums) { - my $artist = $schema->resultset('Artist')->find({ - name => $albums{$lp} - }); - push @cds, [$lp, $artist->id]; - } - - $schema->populate('Cd', [ - [qw/title artist/], - @cds, - ]); - - - my %tracks = ( - 'Beat It' => 'Thriller', - 'Billie Jean' => 'Thriller', - 'Dirty Diana' => 'Bad', - 'Smooth Criminal' => 'Bad', - 'Leave Me Alone' => 'Bad', - 'Stan' => 'The Marshall Mathers LP', - 'The Way I Am' => 'The Marshall Mathers LP', - ); - - my @tracks; - foreach my $track (keys %tracks) { - my $cdname = $schema->resultset('Cd')->find({ - title => $tracks{$track}, - }); - push @tracks, [$cdname->id, $track]; - } - - $schema->populate('Track',[ - [qw/cd title/], - @tracks, - ]); - -Once created, this script should be run once to fill the database with -the required data for the following test script. +Run the script insertdb.pl, which will fill the database with the +required data for the following test script. =head3 Create and run the test scripts -Like the previous script, this script should also be create in the app/ -directory. - -testdb.pl: - - #!/usr/bin/perl - - use strict; - use warnings; - - use MyApp::Schema; - - my $schema = MyApp::Schema->connect('dbi:SQLite:db/example.db'); - # for other DSNs, e.g. MySQL, see the perldoc for the relevant dbd - # driver, e.g perldoc L. - - get_tracks_by_cd('Bad'); - get_tracks_by_artist('Michael Jackson'); - - get_cd_by_track('Stan'); - get_cds_by_artist('Michael Jackson'); - - get_artist_by_track('Dirty Diana'); - get_artist_by_cd('The Marshall Mathers LP'); - - - sub get_tracks_by_cd { - my $cdtitle = shift; - print "get_tracks_by_cd($cdtitle):\n"; - my $rs = $schema->resultset('Track')->search( - { - 'cd.title' => $cdtitle - }, - { - join => [qw/ cd /], - } - ); - while (my $track = $rs->next) { - print $track->title . "\n"; - } - print "\n"; - } - - sub get_tracks_by_artist { - my $artistname = shift; - print "get_tracks_by_artist($artistname):\n"; - my $rs = $schema->resultset('Track')->search( - { - 'artist.name' => $artistname - }, - { - join => { - 'cd' => 'artist' - }, - } - ); - while (my $track = $rs->next) { - print $track->title . " (from the CD '" . $track->cd->title - . "')\n"; - } - print "\n"; - } - - - sub get_cd_by_track { - my $tracktitle = shift; - print "get_cd_by_track($tracktitle):\n"; - my $rs = $schema->resultset('Cd')->search( - { - 'tracks.title' => $tracktitle - }, - { - join => [qw/ tracks /], - } - ); - my $cd = $rs->first; - print $cd->title . " has the track '$tracktitle'.\n\n"; - } - - sub get_cds_by_artist { - my $artistname = shift; - print "get_cds_by_artist($artistname):\n"; - my $rs = $schema->resultset('Cd')->search( - { - 'artist.name' => $artistname - }, - { - join => [qw/ artist /], - } - ); - while (my $cd = $rs->next) { - print $cd->title . "\n"; - } - print "\n"; - } - - - - sub get_artist_by_track { - my $tracktitle = shift; - print "get_artist_by_track($tracktitle):\n"; - my $rs = $schema->resultset('Artist')->search( - { - 'tracks.title' => $tracktitle - }, - { - join => { - 'cds' => 'tracks' - } - } - ); - my $artist = $rs->first; - print $artist->name . " recorded the track '$tracktitle'.\n\n"; - } - - sub get_artist_by_cd { - my $cdtitle = shift; - print "get_artist_by_cd($cdtitle):\n"; - my $rs = $schema->resultset('Artist')->search( - { - 'cds.title' => $cdtitle - }, - { - join => [qw/ cds /], - } - ); - my $artist = $rs->first; - print $artist->name . " recorded the CD '$cdtitle'.\n\n"; - } - - +Run the script testdb.pl, which will test that the database has +successfully been filled. When this script is run, it should output the following: @@ -334,24 +86,24 @@ When this script is run, it should output the following: Dirty Diana get_tracks_by_artist(Michael Jackson): - Billie Jean (from the CD 'Thriller') - Leave Me Alone (from the CD 'Bad') - Smooth Criminal (from the CD 'Bad') - Beat It (from the CD 'Thriller') - Dirty Diana (from the CD 'Bad') + Billie Jean + Leave Me Alone + Smooth Criminal + Beat It + Dirty Diana get_cd_by_track(Stan): - The Marshall Mathers LP has the track 'Stan'. + The Marshall Mathers LP get_cds_by_artist(Michael Jackson): Thriller Bad get_artist_by_track(Dirty Diana): - Michael Jackson recorded the track 'Dirty Diana'. + Michael Jackson get_artist_by_cd(The Marshall Mathers LP): - Eminem recorded the CD 'The Marshall Mathers LP'. + Eminem =head3 Discussion about the results From d53746106ebddecc73d39f9817a5a9e45b7ef4b4 Mon Sep 17 00:00:00 2001 From: Alex Beamish Date: Mon, 9 Sep 2013 10:30:32 -0400 Subject: [PATCH 3/3] Update test script This version just updates the original version with slightly more information so that more DBIx::Class functionality is revealed. --- examples/Schema/testdb.pl | 9 +++++---- lib/DBIx/Class/Manual/Example.pod | 17 +++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/examples/Schema/testdb.pl b/examples/Schema/testdb.pl index 2a1061a51..32cbd6daf 100755 --- a/examples/Schema/testdb.pl +++ b/examples/Schema/testdb.pl @@ -53,7 +53,8 @@ sub get_tracks_by_artist { } ); while (my $track = $rs->next) { - print $track->title . "\n"; + print $track->title . " (from the CD '" . $track->cd->title + . "')\n"; } print "\n"; } @@ -70,7 +71,7 @@ sub get_cd_by_track { } ); my $cd = $rs->first; - print $cd->title . "\n\n"; + print $cd->title . " has the track '$tracktitle'.\n\n"; } sub get_cds_by_artist { @@ -104,7 +105,7 @@ sub get_artist_by_track { } ); my $artist = $rs->first; - print $artist->name . "\n\n"; + print $artist->name . " recorded the track '$tracktitle'.\n\n"; } sub get_artist_by_cd { @@ -119,5 +120,5 @@ sub get_artist_by_cd { } ); my $artist = $rs->first; - print $artist->name . "\n\n"; + print $artist->name . " recorded the CD '$cdtitle'.\n\n"; } diff --git a/lib/DBIx/Class/Manual/Example.pod b/lib/DBIx/Class/Manual/Example.pod index baf6294d8..2659083b8 100644 --- a/lib/DBIx/Class/Manual/Example.pod +++ b/lib/DBIx/Class/Manual/Example.pod @@ -86,24 +86,25 @@ When this script is run, it should output the following: Dirty Diana get_tracks_by_artist(Michael Jackson): - Billie Jean - Leave Me Alone - Smooth Criminal - Beat It - Dirty Diana + Billie Jean (from the CD 'Thriller') + Leave Me Alone (from the CD 'Bad') + Smooth Criminal (from the CD 'Bad') + Beat It (from the CD 'Thriller') + Dirty Diana (from the CD 'Bad') get_cd_by_track(Stan): - The Marshall Mathers LP + The Marshall Mathers LP has the track 'Stan'. get_cds_by_artist(Michael Jackson): Thriller Bad get_artist_by_track(Dirty Diana): - Michael Jackson + Michael Jackson recorded the track 'Dirty Diana'. get_artist_by_cd(The Marshall Mathers LP): - Eminem + Eminem recorded the CD 'The Marshall Mathers LP'. + =head3 Discussion about the results