From: Arthur Axel 'fREW' Schmidt Date: Mon, 22 Feb 2010 00:07:51 +0000 (-0600) Subject: initial commit X-Git-Tag: v0.001000_01~167 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b974984a4aa4db356fe2ebe90fb7e039da71197c;p=dbsrgits%2FDBIx-Class-DeploymentHandler.git initial commit --- b974984a4aa4db356fe2ebe90fb7e039da71197c diff --git a/lib/DBIx/Class/DeploymentHandler.pm b/lib/DBIx/Class/DeploymentHandler.pm new file mode 100644 index 0000000..cc15cdc --- /dev/null +++ b/lib/DBIx/Class/DeploymentHandler.pm @@ -0,0 +1,382 @@ +package DBIx::Class::DeploymentHandler; + +use Moose; +use Method::Signatures::Simple; +require DBIx::Class::Schema; # loaded for type constraint +require DBIx::Class::Storage; # loaded for type constraint +use Carp 'carp'; + +has schema => ( + isa => 'DBIx::Class::Schema', + is => 'ro', + required => 1, +); + +has upgrade_directory => ( + isa => 'Str', + is => 'ro', + required => 1, + default => 'sql', +); + +has backup_directory => ( + isa => 'Str', + is => 'ro', +); + +has storage => ( + isa => 'DBIx::Class::Storage', + is => 'ro', + lazy_build => 1, +); + +has _filedata => ( + is => 'ro', +); + +has do_backup => ( + isa => 'Bool', + is => 'ro', + default => undef, +); + +has do_diff_on_init => ( + isa => 'Bool', + is => 'ro', + default => undef, +); + +method _build_storage { + return $self->schema->storage; +} + +method install($new_version) { + # must be called on a fresh database + if ($self->get_db_version) { + carp 'Install not possible as versions table already exists in database'; + } + + # default to current version if none passed + $new_version ||= $self->schema_version(); + + if ($new_version) { + # create versions table and version row + $self->{vschema}->deploy; + $self->_set_db_version({ version => $new_version }); + } +} + +method deploy { + $self->next::method(@_); + $self->install(); +} + +sub create_upgrade_path { + ## override this method +} + +sub ordered_schema_versions { + ## override this method +} + +method upgrade { + my $db_version = $self->get_db_version(); + + # db unversioned + unless ($db_version) { + carp 'Upgrade not possible as database is unversioned. Please call install first.'; + return; + } + + # db and schema at same version. do nothing + if ( $db_version eq $self->schema_version ) { + carp "Upgrade not necessary\n"; + return; + } + + my @version_list = $self->ordered_schema_versions; + + # if nothing returned then we preload with min/max + @version_list = ( $db_version, $self->schema_version ) + unless ( scalar(@version_list) ); + + # catch the case of someone returning an arrayref + @version_list = @{ $version_list[0] } + if ( ref( $version_list[0] ) eq 'ARRAY' ); + + # remove all versions in list above the required version + while ( scalar(@version_list) + && ( $version_list[-1] ne $self->schema_version ) ) + { + pop @version_list; + } + + # remove all versions in list below the current version + while ( scalar(@version_list) && ( $version_list[0] ne $db_version ) ) { + shift @version_list; + } + + # check we have an appropriate list of versions + if ( scalar(@version_list) < 2 ) { + die; + } + + # do sets of upgrade + while ( scalar(@version_list) >= 2 ) { + $self->upgrade_single_step( $version_list[0], $version_list[1] ); + shift @version_list; + } +} + +method upgrade_single_step($db_version, $target_version) { + # db and schema at same version. do nothing + if ($db_version eq $target_version) { + carp "Upgrade not necessary\n"; + return; + } + + # strangely the first time this is called can + # differ to subsequent times. so we call it + # here to be sure. + # XXX - just fix it + $self->storage->sqlt_type; + + my $upgrade_file = $self->ddl_filename( + $self->storage->sqlt_type, + $target_version, + $self->upgrade_directory, + $db_version, + ); + + $self->create_upgrade_path({ upgrade_file => $upgrade_file }); + + unless (-f $upgrade_file) { + carp "Upgrade not possible, no upgrade file found ($upgrade_file), please create one\n"; + return; + } + + carp "DB version ($db_version) is lower than the schema version (".$self->schema_version."). Attempting upgrade.\n"; + + # backup if necessary then apply upgrade + $self->_filedata($self->_read_sql_file($upgrade_file)); + $self->backup() if($self->do_backup); + $self->txn_do(sub { $self->do_upgrade() }); + + # set row in dbix_class_schema_versions table + $self->_set_db_version({version => $target_version}); +} + +method do_upgrade { + # just run all the commands (including inserts) in order + $self->run_upgrade(qr/.*?/); +} + +method run_upgrade($stm) { + return unless ($self->_filedata); + my @statements = grep { $_ =~ $stm } @{$self->_filedata}; + $self->_filedata([ grep { $_ !~ /$stm/i } @{$self->_filedata} ]); + + for (@statements) { + $self->storage->debugobj->query_start($_) if $self->storage->debug; + $self->apply_statement($_); + $self->storage->debugobj->query_end($_) if $self->storage->debug; + } + + return 1; +} + +method apply_statement($statement) { + $self->storage->dbh->do($_) or carp "SQL was: $_"; +} + +method get_db_version($rs) { + my $vtable = $self->{vschema}->resultset('Table'); + my $version = eval { + $vtable->search({}, { order_by => { -desc => 'installed' }, rows => 1 } ) + ->get_column ('version') + ->next; + }; + return $version || 0; +} + +method schema_version {} + +method backup { + ## Make each ::DBI::Foo do this + $self->storage->backup($self->backup_directory()); +} + +method connection { + $self->next::method(@_); + $self->_on_connect($_[3]); + return $self; +} + +sub _on_connect +{ + my ($self, $args) = @_; + + $args = {} unless $args; + + $self->{vschema} = DBIx::Class::Version->connect(@{$self->storage->connect_info()}); + my $vtable = $self->{vschema}->resultset('Table'); + + # useful when connecting from scripts etc + return if ($args->{ignore_version} || ($ENV{DBIC_NO_VERSION_CHECK} && !exists $args->{ignore_version})); + + # check for legacy versions table and move to new if exists + my $vschema_compat = DBIx::Class::VersionCompat->connect(@{$self->storage->connect_info()}); + unless ($self->_source_exists($vtable)) { + my $vtable_compat = $vschema_compat->resultset('TableCompat'); + if ($self->_source_exists($vtable_compat)) { + $self->{vschema}->deploy; + map { $vtable->create({ installed => $_->Installed, version => $_->Version }) } $vtable_compat->all; + $self->storage->dbh->do("DROP TABLE " . $vtable_compat->result_source->from); + } + } + + my $pversion = $self->get_db_version(); + + if($pversion eq $self->schema_version) + { +# carp "This version is already installed\n"; + return 1; + } + + if(!$pversion) + { + carp "Your DB is currently unversioned. Please call upgrade on your schema to sync the DB.\n"; + return 1; + } + + carp "Versions out of sync. This is " . $self->schema_version . + ", your database contains version $pversion, please call upgrade on your Schema.\n"; +} + +sub _create_db_to_schema_diff { + my $self = shift; + + my %driver_to_db_map = ( + 'mysql' => 'MySQL' + ); + + my $db = $driver_to_db_map{$self->storage->dbh->{Driver}->{Name}}; + unless ($db) { + print "Sorry, this is an unsupported DB\n"; + return; + } + + $self->throw_exception($self->storage->_sqlt_version_error) + if (not $self->storage->_sqlt_version_ok); + + my $db_tr = SQL::Translator->new({ + add_drop_table => 1, + parser => 'DBI', + parser_args => { dbh => $self->storage->dbh } + }); + + $db_tr->producer($db); + my $dbic_tr = SQL::Translator->new; + $dbic_tr->parser('SQL::Translator::Parser::DBIx::Class'); + $dbic_tr->data($self); + $dbic_tr->producer($db); + + $db_tr->schema->name('db_schema'); + $dbic_tr->schema->name('dbic_schema'); + + # is this really necessary? + foreach my $tr ($db_tr, $dbic_tr) { + my $data = $tr->data; + $tr->parser->($tr, $$data); + } + + my $diff = SQL::Translator::Diff::schema_diff($db_tr->schema, $db, + $dbic_tr->schema, $db, + { ignore_constraint_names => 1, ignore_index_names => 1, caseopt => 1 }); + + my $filename = $self->ddl_filename( + $db, + $self->schema_version, + $self->upgrade_directory, + 'PRE', + ); + my $file; + if(!open($file, ">$filename")) + { + $self->throw_exception("Can't open $filename for writing ($!)"); + next; + } + print $file $diff; + close($file); + + carp "WARNING: There may be differences between your DB and your DBIC schema. Please review and if necessary run the SQL in $filename to sync your DB.\n"; +} + + +sub _set_db_version { + my $self = shift; + my ($params) = @_; + $params ||= {}; + + my $version = $params->{version} ? $params->{version} : $self->schema_version; + my $vtable = $self->{vschema}->resultset('Table'); + + ############################################################################## + # !!! NOTE !!! + ############################################################################## + # + # The travesty below replaces the old nice timestamp format of %Y-%m-%d %H:%M:%S + # This is necessary since there are legitimate cases when upgrades can happen + # back to back within the same second. This breaks things since we relay on the + # ability to sort by the 'installed' value. The logical choice of an autoinc + # is not possible, as it will break multiple legacy installations. Also it is + # not possible to format the string sanely, as the column is a varchar(20). + # The 'v' character is added to the front of the string, so that any version + # formatted by this new function will sort _after_ any existing 200... strings. + my @tm = gettimeofday(); + my @dt = gmtime ($tm[0]); + my $o = $vtable->create({ + version => $version, + installed => sprintf("v%04d%02d%02d_%02d%02d%02d.%03.0f", + $dt[5] + 1900, + $dt[4] + 1, + $dt[3], + $dt[2], + $dt[1], + $dt[0], + $tm[1] / 1000, # convert to millisecs, format as up/down rounded int above + ), + }); +} + +sub _read_sql_file { + my $self = shift; + my $file = shift || return; + + open my $fh, '<', $file or carp("Can't open upgrade file, $file ($!)"); + my @data = split /\n/, join '', <$fh>; + close $fh; + + @data = grep { + $_ && + !/^--/ && + !/^(BEGIN|BEGIN TRANSACTION|COMMIT)/m + } split /;/, + join '', @data; + + return \@data; +} + +sub _source_exists +{ + my ($self, $rs) = @_; + + my $c = eval { + $rs->search({ 1, 0 })->count; + }; + return 0 if $@ || !defined $c; + + return 1; +} + +1; diff --git a/t/01-load.t b/t/01-load.t new file mode 100644 index 0000000..8c28e61 --- /dev/null +++ b/t/01-load.t @@ -0,0 +1,8 @@ +#!perl + +use Test::More; +use lib 't/lib'; + +use_ok 'DBIx::Class::DeploymentHandler'; + +done_testing; diff --git a/t/02-instantiation.t b/t/02-instantiation.t new file mode 100644 index 0000000..4943e3c --- /dev/null +++ b/t/02-instantiation.t @@ -0,0 +1,15 @@ +#!perl + +use Test::More; + +use lib 't/lib'; +use DBICTest; +use DBIx::Class::DeploymentHandler; + +my $handler = DBIx::Class::DeploymentHandler->new({ + schema => DBICTest->init_schema() +}); + +ok($handler, 'DBIx::Class::DeploymentHandler instantiates correctly'); + +done_testing; diff --git a/t/lib/DBICTest.pm b/t/lib/DBICTest.pm new file mode 100644 index 0000000..8006961 --- /dev/null +++ b/t/lib/DBICTest.pm @@ -0,0 +1,331 @@ +package # hide from PAUSE + DBICTest; + +use strict; +use warnings; +use DBICTest::AuthorCheck; +use DBICTest::Schema; + +=head1 NAME + +DBICTest - Library to be used by DBIx::Class test scripts. + +=head1 SYNOPSIS + + use lib qw(t/lib); + use DBICTest; + use Test::More; + + my $schema = DBICTest->init_schema(); + +=head1 DESCRIPTION + +This module provides the basic utilities to write tests against +DBIx::Class. + +=head1 METHODS + +=head2 init_schema + + my $schema = DBICTest->init_schema( + no_deploy=>1, + no_populate=>1, + storage_type=>'::DBI::Replicated', + storage_type_args=>{ + balancer_type=>'DBIx::Class::Storage::DBI::Replicated::Balancer::Random' + }, + ); + +This method removes the test SQLite database in t/var/DBIxClass.db +and then creates a new, empty database. + +This method will call deploy_schema() by default, unless the +no_deploy flag is set. + +Also, by default, this method will call populate_schema() by +default, unless the no_deploy or no_populate flags are set. + +=cut + +sub has_custom_dsn { + return $ENV{"DBICTEST_DSN"} ? 1:0; +} + +sub _sqlite_dbfilename { + return "t/var/DBIxClass.db"; +} + +sub _sqlite_dbname { + my $self = shift; + my %args = @_; + return $self->_sqlite_dbfilename if $args{sqlite_use_file} or $ENV{"DBICTEST_SQLITE_USE_FILE"}; + return ":memory:"; +} + +sub _database { + my $self = shift; + my %args = @_; + my $db_file = $self->_sqlite_dbname(%args); + + unlink($db_file) if -e $db_file; + unlink($db_file . "-journal") if -e $db_file . "-journal"; + mkdir("t/var") unless -d "t/var"; + + my $dsn = $ENV{"DBICTEST_DSN"} || "dbi:SQLite:${db_file}"; + my $dbuser = $ENV{"DBICTEST_DBUSER"} || ''; + my $dbpass = $ENV{"DBICTEST_DBPASS"} || ''; + + my @connect_info = ($dsn, $dbuser, $dbpass, { AutoCommit => 1, %args }); + + return @connect_info; +} + +sub init_schema { + my $self = shift; + my %args = @_; + + my $schema; + + if ($args{compose_connection}) { + $schema = DBICTest::Schema->compose_connection( + 'DBICTest', $self->_database(%args) + ); + } else { + $schema = DBICTest::Schema->compose_namespace('DBICTest'); + } + if( $args{storage_type}) { + $schema->storage_type($args{storage_type}); + } + if ( !$args{no_connect} ) { + $schema = $schema->connect($self->_database(%args)); + $schema->storage->on_connect_do(['PRAGMA synchronous = OFF']) + unless $self->has_custom_dsn; + } + if ( !$args{no_deploy} ) { + __PACKAGE__->deploy_schema( $schema, $args{deploy_args} ); + __PACKAGE__->populate_schema( $schema ) + if( !$args{no_populate} ); + } + return $schema; +} + +=head2 deploy_schema + + DBICTest->deploy_schema( $schema ); + +This method does one of two things to the schema. It can either call +the experimental $schema->deploy() if the DBICTEST_SQLT_DEPLOY environment +variable is set, otherwise the default is to read in the t/lib/sqlite.sql +file and execute the SQL within. Either way you end up with a fresh set +of tables for testing. + +=cut + +sub deploy_schema { + my $self = shift; + my $schema = shift; + my $args = shift || {}; + + if ($ENV{"DBICTEST_SQLT_DEPLOY"}) { + $schema->deploy($args); + } else { + open IN, "t/lib/sqlite.sql"; + my $sql; + { local $/ = undef; $sql = ; } + close IN; + for my $chunk ( split (/;\s*\n+/, $sql) ) { + if ( $chunk =~ / ^ (?! --\s* ) \S /xm ) { # there is some real sql in the chunk - a non-space at the start of the string which is not a comment + $schema->storage->dbh_do(sub { $_[1]->do($chunk) }) or print "Error on SQL: $chunk\n"; + } + } + } + return; +} + +=head2 populate_schema + + DBICTest->populate_schema( $schema ); + +After you deploy your schema you can use this method to populate +the tables with test data. + +=cut + +sub populate_schema { + my $self = shift; + my $schema = shift; + + $schema->populate('Genre', [ + [qw/genreid name/], + [qw/1 emo /], + ]); + + $schema->populate('Artist', [ + [ qw/artistid name/ ], + [ 1, 'Caterwauler McCrae' ], + [ 2, 'Random Boy Band' ], + [ 3, 'We Are Goth' ], + ]); + + $schema->populate('CD', [ + [ qw/cdid artist title year genreid/ ], + [ 1, 1, "Spoonful of bees", 1999, 1 ], + [ 2, 1, "Forkful of bees", 2001 ], + [ 3, 1, "Caterwaulin' Blues", 1997 ], + [ 4, 2, "Generic Manufactured Singles", 2001 ], + [ 5, 3, "Come Be Depressed With Us", 1998 ], + ]); + + $schema->populate('LinerNotes', [ + [ qw/liner_id notes/ ], + [ 2, "Buy Whiskey!" ], + [ 4, "Buy Merch!" ], + [ 5, "Kill Yourself!" ], + ]); + + $schema->populate('Tag', [ + [ qw/tagid cd tag/ ], + [ 1, 1, "Blue" ], + [ 2, 2, "Blue" ], + [ 3, 3, "Blue" ], + [ 4, 5, "Blue" ], + [ 5, 2, "Cheesy" ], + [ 6, 4, "Cheesy" ], + [ 7, 5, "Cheesy" ], + [ 8, 2, "Shiny" ], + [ 9, 4, "Shiny" ], + ]); + + $schema->populate('TwoKeys', [ + [ qw/artist cd/ ], + [ 1, 1 ], + [ 1, 2 ], + [ 2, 2 ], + ]); + + $schema->populate('FourKeys', [ + [ qw/foo bar hello goodbye sensors/ ], + [ 1, 2, 3, 4, 'online' ], + [ 5, 4, 3, 6, 'offline' ], + ]); + + $schema->populate('OneKey', [ + [ qw/id artist cd/ ], + [ 1, 1, 1 ], + [ 2, 1, 2 ], + [ 3, 2, 2 ], + ]); + + $schema->populate('SelfRef', [ + [ qw/id name/ ], + [ 1, 'First' ], + [ 2, 'Second' ], + ]); + + $schema->populate('SelfRefAlias', [ + [ qw/self_ref alias/ ], + [ 1, 2 ] + ]); + + $schema->populate('ArtistUndirectedMap', [ + [ qw/id1 id2/ ], + [ 1, 2 ] + ]); + + $schema->populate('Producer', [ + [ qw/producerid name/ ], + [ 1, 'Matt S Trout' ], + [ 2, 'Bob The Builder' ], + [ 3, 'Fred The Phenotype' ], + ]); + + $schema->populate('CD_to_Producer', [ + [ qw/cd producer/ ], + [ 1, 1 ], + [ 1, 2 ], + [ 1, 3 ], + ]); + + $schema->populate('TreeLike', [ + [ qw/id parent name/ ], + [ 1, undef, 'root' ], + [ 2, 1, 'foo' ], + [ 3, 2, 'bar' ], + [ 6, 2, 'blop' ], + [ 4, 3, 'baz' ], + [ 5, 4, 'quux' ], + [ 7, 3, 'fong' ], + ]); + + $schema->populate('Track', [ + [ qw/trackid cd position title/ ], + [ 4, 2, 1, "Stung with Success"], + [ 5, 2, 2, "Stripy"], + [ 6, 2, 3, "Sticky Honey"], + [ 7, 3, 1, "Yowlin"], + [ 8, 3, 2, "Howlin"], + [ 9, 3, 3, "Fowlin"], + [ 10, 4, 1, "Boring Name"], + [ 11, 4, 2, "Boring Song"], + [ 12, 4, 3, "No More Ideas"], + [ 13, 5, 1, "Sad"], + [ 14, 5, 2, "Under The Weather"], + [ 15, 5, 3, "Suicidal"], + [ 16, 1, 1, "The Bees Knees"], + [ 17, 1, 2, "Apiary"], + [ 18, 1, 3, "Beehind You"], + ]); + + $schema->populate('Event', [ + [ qw/id starts_at created_on varchar_date varchar_datetime skip_inflation/ ], + [ 1, '2006-04-25 22:24:33', '2006-06-22 21:00:05', '2006-07-23', '2006-05-22 19:05:07', '2006-04-21 18:04:06'], + ]); + + $schema->populate('Link', [ + [ qw/id url title/ ], + [ 1, '', 'aaa' ] + ]); + + $schema->populate('Bookmark', [ + [ qw/id link/ ], + [ 1, 1 ] + ]); + + $schema->populate('Collection', [ + [ qw/collectionid name/ ], + [ 1, "Tools" ], + [ 2, "Body Parts" ], + ]); + + $schema->populate('TypedObject', [ + [ qw/objectid type value/ ], + [ 1, "pointy", "Awl" ], + [ 2, "round", "Bearing" ], + [ 3, "pointy", "Knife" ], + [ 4, "pointy", "Tooth" ], + [ 5, "round", "Head" ], + ]); + $schema->populate('CollectionObject', [ + [ qw/collection object/ ], + [ 1, 1 ], + [ 1, 2 ], + [ 1, 3 ], + [ 2, 4 ], + [ 2, 5 ], + ]); + + $schema->populate('Owners', [ + [ qw/id name/ ], + [ 1, "Newton" ], + [ 2, "Waltham" ], + ]); + + $schema->populate('BooksInLibrary', [ + [ qw/id owner title source price/ ], + [ 1, 1, "Programming Perl", "Library", 23 ], + [ 2, 1, "Dynamical Systems", "Library", 37 ], + [ 3, 2, "Best Recipe Cookbook", "Library", 65 ], + ]); +} + +1; diff --git a/t/lib/DBICTest/AuthorCheck.pm b/t/lib/DBICTest/AuthorCheck.pm new file mode 100644 index 0000000..f793cf0 --- /dev/null +++ b/t/lib/DBICTest/AuthorCheck.pm @@ -0,0 +1,115 @@ +package # hide from PAUSE + DBICTest::AuthorCheck; + +use strict; +use warnings; + +use Path::Class qw/file dir/; + +_check_author_makefile() unless $ENV{DBICTEST_NO_MAKEFILE_VERIFICATION}; + +# Die if the author did not update his makefile +# +# This is pretty heavy handed, so the check is pretty solid: +# +# 1) Assume that this particular module is loaded from -I <$root>/t/lib +# 2) Make sure <$root>/Makefile.PL exists +# 3) Make sure we can stat() <$root>/Makefile.PL +# +# If all of the above is satisfied +# +# *) die if <$root>/inc does not exist +# *) die if no stat() results for <$root>/Makefile (covers no Makefile) +# *) die if Makefile.PL mtime > Makefile mtime +# +sub _check_author_makefile { + + my $root = _find_co_root() + or return; + + # not using file->stat as it invokes File::stat which in turn breaks stat(_) + my ($mf_pl_mtime, $mf_mtime) = ( map + { (stat ($root->file ($_)) )[9] } + qw/Makefile.PL Makefile/ + ); + + return unless $mf_pl_mtime; # something went wrong during co_root detection ? + + if ( + not -d $root->subdir ('inc') + or + not $mf_mtime + or + $mf_mtime < $mf_pl_mtime + ) { + print STDERR <<'EOE'; + + + + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +======================== FATAL ERROR =========================== +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +We have a number of reasons to believe that this is a development +checkout and that you, the user, did not run `perl Makefile.PL` +before using this code. You absolutely _must_ perform this step, +and ensure you have all required dependencies present. Not doing +so often results in a lot of wasted time for other contributors +trying to assit you with spurious "its broken!" problems. + +If you are seeing this message unexpectedly (i.e. you are in fact +attempting a regular installation be it through CPAN or manually), +please report the situation to either the mailing list or to the +irc channel as described in + +http://search.cpan.org/dist/DBIx-Class/lib/DBIx/Class.pm#GETTING_HELP/SUPPORT + +The DBIC team + + + +EOE + + exit 1; + } +} + +# Mimic $Module::Install::AUTHOR +sub is_author { + + my $root = _find_co_root() + or return undef; + + return ( + ( not -d $root->subdir ('inc') ) + or + ( -e $root->subdir ('inc')->file ($^O eq 'VMS' ? '_author' : '.author') ) + ); +} + +# Try to determine the root of a checkout/untar if possible +# or return undef +sub _find_co_root { + + my @mod_parts = split /::/, (__PACKAGE__ . '.pm'); + my $rel_path = join ('/', @mod_parts); # %INC stores paths with / regardless of OS + + return undef unless ($INC{$rel_path}); + + # a bit convoluted, but what we do here essentially is: + # - get the file name of this particular module + # - do 'cd ..' as many times as necessary to get to t/lib/../.. + + my $root = dir ($INC{$rel_path}); + for (1 .. @mod_parts + 2) { + $root = $root->parent; + } + + return (-f $root->file ('Makefile.PL') ) + ? $root + : undef + ; +} + +1; diff --git a/t/lib/DBICTest/BaseResult.pm b/t/lib/DBICTest/BaseResult.pm new file mode 100644 index 0000000..4f38202 --- /dev/null +++ b/t/lib/DBICTest/BaseResult.pm @@ -0,0 +1,13 @@ +package #hide from pause + DBICTest::BaseResult; + +use strict; +use warnings; + +use base qw/DBIx::Class::Core/; +use DBICTest::BaseResultSet; + +__PACKAGE__->table ('bogus'); +__PACKAGE__->resultset_class ('DBICTest::BaseResultSet'); + +1; diff --git a/t/lib/DBICTest/BaseResultSet.pm b/t/lib/DBICTest/BaseResultSet.pm new file mode 100644 index 0000000..6d9df85 --- /dev/null +++ b/t/lib/DBICTest/BaseResultSet.pm @@ -0,0 +1,13 @@ +package #hide from pause + DBICTest::BaseResultSet; + +use strict; +use warnings; + +use base qw/DBIx::Class::ResultSet/; + +sub hri_dump { + return shift->search ({}, { result_class => 'DBIx::Class::ResultClass::HashRefInflator' }); +} + +1; diff --git a/t/lib/DBICTest/ErrorComponent.pm b/t/lib/DBICTest/ErrorComponent.pm new file mode 100644 index 0000000..67f54e8 --- /dev/null +++ b/t/lib/DBICTest/ErrorComponent.pm @@ -0,0 +1,8 @@ +# belongs to t/run/90ensure_class_loaded.tl +package # hide from PAUSE + DBICTest::ErrorComponent; +use warnings; +use strict; + +# this is missing on purpose +# 1; diff --git a/t/lib/DBICTest/FakeComponent.pm b/t/lib/DBICTest/FakeComponent.pm new file mode 100644 index 0000000..fbe21f0 --- /dev/null +++ b/t/lib/DBICTest/FakeComponent.pm @@ -0,0 +1,7 @@ +# belongs to t/run/90ensure_class_loaded.tl +package # hide from PAUSE + DBICTest::FakeComponent; +use warnings; +use strict; + +1; diff --git a/t/lib/DBICTest/ForeignComponent.pm b/t/lib/DBICTest/ForeignComponent.pm new file mode 100644 index 0000000..333dd26 --- /dev/null +++ b/t/lib/DBICTest/ForeignComponent.pm @@ -0,0 +1,11 @@ +# belongs to t/05components.t +package # hide from PAUSE + DBICTest::ForeignComponent; +use warnings; +use strict; + +use base qw/ DBIx::Class /; + +__PACKAGE__->load_components( qw/ +DBICTest::ForeignComponent::TestComp / ); + +1; diff --git a/t/lib/DBICTest/ForeignComponent/TestComp.pm b/t/lib/DBICTest/ForeignComponent/TestComp.pm new file mode 100644 index 0000000..cc95940 --- /dev/null +++ b/t/lib/DBICTest/ForeignComponent/TestComp.pm @@ -0,0 +1,9 @@ +# belongs to t/05components.t +package # hide from PAUSE + DBICTest::ForeignComponent::TestComp; +use warnings; +use strict; + +sub foreign_test_method { 1 } + +1; diff --git a/t/lib/DBICTest/OptionalComponent.pm b/t/lib/DBICTest/OptionalComponent.pm new file mode 100644 index 0000000..5f0d36a --- /dev/null +++ b/t/lib/DBICTest/OptionalComponent.pm @@ -0,0 +1,7 @@ +# belongs to t/run/90ensure_class_loaded.tl +package # hide from PAUSE + DBICTest::OptionalComponent; +use warnings; +use strict; + +1; diff --git a/t/lib/DBICTest/Plain.pm b/t/lib/DBICTest/Plain.pm new file mode 100644 index 0000000..209cc3e --- /dev/null +++ b/t/lib/DBICTest/Plain.pm @@ -0,0 +1,40 @@ +package # hide from PAUSE + DBICTest::Plain; + +use strict; +use warnings; +use base qw/DBIx::Class::Schema/; +use DBI; + +my $db_file = "t/var/Plain.db"; + +unlink($db_file) if -e $db_file; +unlink($db_file . "-journal") if -e $db_file . "-journal"; +mkdir("t/var") unless -d "t/var"; + +my $dsn = "dbi:SQLite:${db_file}"; + +__PACKAGE__->load_classes("Test"); +my $schema = __PACKAGE__->compose_connection( + __PACKAGE__, + $dsn, + undef, + undef, + { AutoCommit => 1 } +); + +my $dbh = DBI->connect($dsn); + +my $sql = <do($_) for split(/\n\n/, $sql); + +1; diff --git a/t/lib/DBICTest/Plain/Test.pm b/t/lib/DBICTest/Plain/Test.pm new file mode 100644 index 0000000..e950278 --- /dev/null +++ b/t/lib/DBICTest/Plain/Test.pm @@ -0,0 +1,18 @@ +package # hide from PAUSE + DBICTest::Plain::Test; + +use base 'DBIx::Class::Core'; + +__PACKAGE__->table('test'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'name' => { + data_type => 'varchar', + }, +); +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/ResultSetManager.pm b/t/lib/DBICTest/ResultSetManager.pm new file mode 100644 index 0000000..08b3159 --- /dev/null +++ b/t/lib/DBICTest/ResultSetManager.pm @@ -0,0 +1,7 @@ +package # hide from PAUSE + DBICTest::ResultSetManager; +use base 'DBIx::Class::Schema'; + +__PACKAGE__->load_classes("Foo"); + +1; diff --git a/t/lib/DBICTest/ResultSetManager/Foo.pm b/t/lib/DBICTest/ResultSetManager/Foo.pm new file mode 100644 index 0000000..30c1c95 --- /dev/null +++ b/t/lib/DBICTest/ResultSetManager/Foo.pm @@ -0,0 +1,10 @@ +package # hide from PAUSE + DBICTest::ResultSetManager::Foo; +use base 'DBIx::Class::Core'; + +__PACKAGE__->load_components(qw/ ResultSetManager /); +__PACKAGE__->table('foo'); + +sub bar : ResultSet { 'good' } + +1; diff --git a/t/lib/DBICTest/Schema.pm b/t/lib/DBICTest/Schema.pm new file mode 100644 index 0000000..a3e4484 --- /dev/null +++ b/t/lib/DBICTest/Schema.pm @@ -0,0 +1,61 @@ +package # hide from PAUSE + DBICTest::Schema; + +use base qw/DBIx::Class::Schema/; + +no warnings qw/qw/; + +__PACKAGE__->load_classes(qw/ + Artist + SequenceTest + BindType + Employee + CD + FileColumn + Genre + Link + Bookmark + #dummy + Track + Tag + Year2000CDs + Year1999CDs + CustomSql + Money + /, + { 'DBICTest::Schema' => [qw/ + LinerNotes + Artwork + Artwork_to_Artist + Image + Lyrics + LyricVersion + OneKey + #dummy + TwoKeys + Serialized + /]}, + ( + 'FourKeys', + 'FourKeys_to_TwoKeys', + '#dummy', + 'SelfRef', + 'ArtistUndirectedMap', + 'ArtistSourceName', + 'ArtistSubclass', + 'Producer', + 'CD_to_Producer', + 'Dummy', # this is a real result class we remove in the hook below + ), + qw/SelfRefAlias TreeLike TwoKeyTreeLike Event EventTZ NoPrimaryKey/, + qw/Collection CollectionObject TypedObject Owners BooksInLibrary/, + qw/ForceForeign Encoded/, +); + +sub sqlt_deploy_hook { + my ($self, $sqlt_schema) = @_; + + $sqlt_schema->drop_table('dummy'); +} + +1; diff --git a/t/lib/DBICTest/Schema/Artist.pm b/t/lib/DBICTest/Schema/Artist.pm new file mode 100644 index 0000000..dd5028e --- /dev/null +++ b/t/lib/DBICTest/Schema/Artist.pm @@ -0,0 +1,82 @@ +package # hide from PAUSE + DBICTest::Schema::Artist; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('artist'); +__PACKAGE__->source_info({ + "source_info_key_A" => "source_info_value_A", + "source_info_key_B" => "source_info_value_B", + "source_info_key_C" => "source_info_value_C", +}); +__PACKAGE__->add_columns( + 'artistid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'name' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, + rank => { + data_type => 'integer', + default_value => 13, + }, + charfield => { + data_type => 'char', + size => 10, + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('artistid'); +__PACKAGE__->add_unique_constraint(artist => ['artistid']); # do not remove, part of a test + +__PACKAGE__->mk_classdata('field_name_for', { + artistid => 'primary key', + name => 'artist name', +}); + +__PACKAGE__->has_many( + cds => 'DBICTest::Schema::CD', undef, + { order_by => 'year' }, +); +__PACKAGE__->has_many( + cds_unordered => 'DBICTest::Schema::CD' +); +__PACKAGE__->has_many( + cds_very_very_very_long_relationship_name => 'DBICTest::Schema::CD' +); + +__PACKAGE__->has_many( twokeys => 'DBICTest::Schema::TwoKeys' ); +__PACKAGE__->has_many( onekeys => 'DBICTest::Schema::OneKey' ); + +__PACKAGE__->has_many( + artist_undirected_maps => 'DBICTest::Schema::ArtistUndirectedMap', + [ {'foreign.id1' => 'self.artistid'}, {'foreign.id2' => 'self.artistid'} ], + { cascade_copy => 0 } # this would *so* not make sense +); + +__PACKAGE__->has_many( + artwork_to_artist => 'DBICTest::Schema::Artwork_to_Artist' => 'artist_id' +); +__PACKAGE__->many_to_many('artworks', 'artwork_to_artist', 'artwork'); + + +sub sqlt_deploy_hook { + my ($self, $sqlt_table) = @_; + + if ($sqlt_table->schema->translator->producer_type =~ /SQLite$/ ) { + $sqlt_table->add_index( name => 'artist_name_hookidx', fields => ['name'] ) + or die $sqlt_table->error; + } +} + +sub store_column { + my ($self, $name, $value) = @_; + $value = 'X '.$value if ($name eq 'name' && $value && $value =~ /(X )?store_column test/); + $self->next::method($name, $value); +} + + +1; diff --git a/t/lib/DBICTest/Schema/ArtistGUID.pm b/t/lib/DBICTest/Schema/ArtistGUID.pm new file mode 100644 index 0000000..cad8965 --- /dev/null +++ b/t/lib/DBICTest/Schema/ArtistGUID.pm @@ -0,0 +1,35 @@ +package # hide from PAUSE + DBICTest::Schema::ArtistGUID; + +use base qw/DBICTest::BaseResult/; + +# test MSSQL uniqueidentifier type + +__PACKAGE__->table('artist'); +__PACKAGE__->add_columns( + 'artistid' => { + data_type => 'uniqueidentifier' # auto_nextval not necessary for PK + }, + 'name' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, + rank => { + data_type => 'integer', + default_value => 13, + }, + charfield => { + data_type => 'char', + size => 10, + is_nullable => 1, + }, + a_guid => { + data_type => 'uniqueidentifier', + auto_nextval => 1, # necessary here, because not a PK + is_nullable => 1, + } +); +__PACKAGE__->set_primary_key('artistid'); + +1; diff --git a/t/lib/DBICTest/Schema/ArtistSourceName.pm b/t/lib/DBICTest/Schema/ArtistSourceName.pm new file mode 100644 index 0000000..c59bbe5 --- /dev/null +++ b/t/lib/DBICTest/Schema/ArtistSourceName.pm @@ -0,0 +1,8 @@ +package # hide from PAUSE + DBICTest::Schema::ArtistSourceName; + +use base 'DBICTest::Schema::Artist'; +__PACKAGE__->table(__PACKAGE__->table); +__PACKAGE__->source_name('SourceNameArtists'); + +1; diff --git a/t/lib/DBICTest/Schema/ArtistSubclass.pm b/t/lib/DBICTest/Schema/ArtistSubclass.pm new file mode 100644 index 0000000..8dd3f6f --- /dev/null +++ b/t/lib/DBICTest/Schema/ArtistSubclass.pm @@ -0,0 +1,8 @@ +package # hide from PAUSE + DBICTest::Schema::ArtistSubclass; + +use base 'DBICTest::Schema::Artist'; + +__PACKAGE__->table(__PACKAGE__->table); + +1; \ No newline at end of file diff --git a/t/lib/DBICTest/Schema/ArtistUndirectedMap.pm b/t/lib/DBICTest/Schema/ArtistUndirectedMap.pm new file mode 100644 index 0000000..2f4d85f --- /dev/null +++ b/t/lib/DBICTest/Schema/ArtistUndirectedMap.pm @@ -0,0 +1,20 @@ +package # hide from PAUSE + DBICTest::Schema::ArtistUndirectedMap; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('artist_undirected_map'); +__PACKAGE__->add_columns( + 'id1' => { data_type => 'integer' }, + 'id2' => { data_type => 'integer' }, +); +__PACKAGE__->set_primary_key(qw/id1 id2/); + +__PACKAGE__->belongs_to( 'artist1', 'DBICTest::Schema::Artist', 'id1', { on_delete => 'RESTRICT', on_update => 'CASCADE'} ); +__PACKAGE__->belongs_to( 'artist2', 'DBICTest::Schema::Artist', 'id2', { on_delete => undef, on_update => undef} ); +__PACKAGE__->has_many( + 'mapped_artists', 'DBICTest::Schema::Artist', + [ {'foreign.artistid' => 'self.id1'}, {'foreign.artistid' => 'self.id2'} ], +); + +1; diff --git a/t/lib/DBICTest/Schema/Artwork.pm b/t/lib/DBICTest/Schema/Artwork.pm new file mode 100644 index 0000000..4eecef5 --- /dev/null +++ b/t/lib/DBICTest/Schema/Artwork.pm @@ -0,0 +1,20 @@ +package # hide from PAUSE + DBICTest::Schema::Artwork; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('cd_artwork'); +__PACKAGE__->add_columns( + 'cd_id' => { + data_type => 'integer', + is_nullable => 0, + }, +); +__PACKAGE__->set_primary_key('cd_id'); +__PACKAGE__->belongs_to('cd', 'DBICTest::Schema::CD', 'cd_id'); +__PACKAGE__->has_many('images', 'DBICTest::Schema::Image', 'artwork_id'); + +__PACKAGE__->has_many('artwork_to_artist', 'DBICTest::Schema::Artwork_to_Artist', 'artwork_cd_id'); +__PACKAGE__->many_to_many('artists', 'artwork_to_artist', 'artist'); + +1; diff --git a/t/lib/DBICTest/Schema/Artwork_to_Artist.pm b/t/lib/DBICTest/Schema/Artwork_to_Artist.pm new file mode 100644 index 0000000..0859080 --- /dev/null +++ b/t/lib/DBICTest/Schema/Artwork_to_Artist.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::Artwork_to_Artist; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('artwork_to_artist'); +__PACKAGE__->add_columns( + 'artwork_cd_id' => { + data_type => 'integer', + is_foreign_key => 1, + }, + 'artist_id' => { + data_type => 'integer', + is_foreign_key => 1, + }, +); +__PACKAGE__->set_primary_key(qw/artwork_cd_id artist_id/); +__PACKAGE__->belongs_to('artwork', 'DBICTest::Schema::Artwork', 'artwork_cd_id'); +__PACKAGE__->belongs_to('artist', 'DBICTest::Schema::Artist', 'artist_id'); + +1; diff --git a/t/lib/DBICTest/Schema/BindType.pm b/t/lib/DBICTest/Schema/BindType.pm new file mode 100644 index 0000000..5670f2f --- /dev/null +++ b/t/lib/DBICTest/Schema/BindType.pm @@ -0,0 +1,29 @@ +package # hide from PAUSE + DBICTest::Schema::BindType; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('bindtype_test'); + +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'bytea' => { + data_type => 'bytea', + is_nullable => 1, + }, + 'blob' => { + data_type => 'blob', + is_nullable => 1, + }, + 'clob' => { + data_type => 'clob', + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/Bookmark.pm b/t/lib/DBICTest/Schema/Bookmark.pm new file mode 100644 index 0000000..8c2c3b1 --- /dev/null +++ b/t/lib/DBICTest/Schema/Bookmark.pm @@ -0,0 +1,25 @@ +package # hide from PAUSE + DBICTest::Schema::Bookmark; + + use base qw/DBICTest::BaseResult/; + + +use strict; +use warnings; + +__PACKAGE__->table('bookmark'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'link' => { + data_type => 'integer', + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key('id'); +__PACKAGE__->belongs_to(link => 'DBICTest::Schema::Link', 'link', { on_delete => 'SET NULL' } ); + +1; diff --git a/t/lib/DBICTest/Schema/BooksInLibrary.pm b/t/lib/DBICTest/Schema/BooksInLibrary.pm new file mode 100644 index 0000000..8da54e6 --- /dev/null +++ b/t/lib/DBICTest/Schema/BooksInLibrary.pm @@ -0,0 +1,34 @@ +package # hide from PAUSE + DBICTest::Schema::BooksInLibrary; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('books'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'source' => { + data_type => 'varchar', + size => '100', + }, + 'owner' => { + data_type => 'integer', + }, + 'title' => { + data_type => 'varchar', + size => '100', + }, + 'price' => { + data_type => 'integer', + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('id'); + +__PACKAGE__->resultset_attributes({where => { source => "Library" } }); + +__PACKAGE__->belongs_to ( owner => 'DBICTest::Schema::Owners', 'owner' ); + +1; diff --git a/t/lib/DBICTest/Schema/CD.pm b/t/lib/DBICTest/Schema/CD.pm new file mode 100644 index 0000000..fadd539 --- /dev/null +++ b/t/lib/DBICTest/Schema/CD.pm @@ -0,0 +1,92 @@ +package # hide from PAUSE + DBICTest::Schema::CD; + +use base qw/DBICTest::BaseResult/; + +# this tests table name as scalar ref +# DO NOT REMOVE THE \ +__PACKAGE__->table(\'cd'); + +__PACKAGE__->add_columns( + 'cdid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'artist' => { + data_type => 'integer', + }, + 'title' => { + data_type => 'varchar', + size => 100, + }, + 'year' => { + data_type => 'varchar', + size => 100, + }, + 'genreid' => { + data_type => 'integer', + is_nullable => 1, + accessor => undef, + }, + 'single_track' => { + data_type => 'integer', + is_nullable => 1, + is_foreign_key => 1, + } +); +__PACKAGE__->set_primary_key('cdid'); +__PACKAGE__->add_unique_constraint([ qw/artist title/ ]); + +__PACKAGE__->belongs_to( artist => 'DBICTest::Schema::Artist', undef, { + is_deferrable => 1, +}); + +# in case this is a single-cd it promotes a track from another cd +__PACKAGE__->belongs_to( single_track => 'DBICTest::Schema::Track', 'single_track', + { join_type => 'left'} +); + +__PACKAGE__->has_many( tracks => 'DBICTest::Schema::Track' ); +__PACKAGE__->has_many( + tags => 'DBICTest::Schema::Tag', undef, + { order_by => 'tag' }, +); +__PACKAGE__->has_many( + cd_to_producer => 'DBICTest::Schema::CD_to_Producer' => 'cd' +); + +__PACKAGE__->might_have( + liner_notes => 'DBICTest::Schema::LinerNotes', undef, + { proxy => [ qw/notes/ ] }, +); +__PACKAGE__->might_have(artwork => 'DBICTest::Schema::Artwork', 'cd_id'); +__PACKAGE__->has_one(mandatory_artwork => 'DBICTest::Schema::Artwork', 'cd_id'); + +__PACKAGE__->many_to_many( producers => cd_to_producer => 'producer' ); +__PACKAGE__->many_to_many( + producers_sorted => cd_to_producer => 'producer', + { order_by => 'producer.name' }, +); + +__PACKAGE__->belongs_to('genre', 'DBICTest::Schema::Genre', + { 'foreign.genreid' => 'self.genreid' }, + { + join_type => 'left', + on_delete => 'SET NULL', + on_update => 'CASCADE', + }, +); + +#This second relationship was added to test the short-circuiting of pointless +#queries provided by undef_on_null_fk. the relevant test in 66relationship.t +__PACKAGE__->belongs_to('genre_inefficient', 'DBICTest::Schema::Genre', + { 'foreign.genreid' => 'self.genreid' }, + { + join_type => 'left', + on_delete => 'SET NULL', + on_update => 'CASCADE', + undef_on_null_fk => 0, + }, +); + +1; diff --git a/t/lib/DBICTest/Schema/CD_to_Producer.pm b/t/lib/DBICTest/Schema/CD_to_Producer.pm new file mode 100644 index 0000000..f0f14f0 --- /dev/null +++ b/t/lib/DBICTest/Schema/CD_to_Producer.pm @@ -0,0 +1,25 @@ +package # hide from PAUSE + DBICTest::Schema::CD_to_Producer; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('cd_to_producer'); +__PACKAGE__->add_columns( + cd => { data_type => 'integer' }, + producer => { data_type => 'integer' }, + attribute => { data_type => 'integer', is_nullable => 1 }, +); +__PACKAGE__->set_primary_key(qw/cd producer/); + +__PACKAGE__->belongs_to( + 'cd', 'DBICTest::Schema::CD', + { 'foreign.cdid' => 'self.cd' } +); + +__PACKAGE__->belongs_to( + 'producer', 'DBICTest::Schema::Producer', + { 'foreign.producerid' => 'self.producer' }, + { on_delete => undef, on_update => undef }, +); + +1; diff --git a/t/lib/DBICTest/Schema/Collection.pm b/t/lib/DBICTest/Schema/Collection.pm new file mode 100644 index 0000000..96f6399 --- /dev/null +++ b/t/lib/DBICTest/Schema/Collection.pm @@ -0,0 +1,30 @@ +package # hide from PAUSE + DBICTest::Schema::Collection; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('collection'); +__PACKAGE__->add_columns( + 'collectionid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'name' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('collectionid'); + +__PACKAGE__->has_many( collection_object => "DBICTest::Schema::CollectionObject", + { "foreign.collection" => "self.collectionid" } + ); +__PACKAGE__->many_to_many( objects => collection_object => "object" ); +__PACKAGE__->many_to_many( pointy_objects => collection_object => "object", + { where => { "object.type" => "pointy" } } + ); +__PACKAGE__->many_to_many( round_objects => collection_object => "object", + { where => { "object.type" => "round" } } + ); + +1; diff --git a/t/lib/DBICTest/Schema/CollectionObject.pm b/t/lib/DBICTest/Schema/CollectionObject.pm new file mode 100644 index 0000000..446909c --- /dev/null +++ b/t/lib/DBICTest/Schema/CollectionObject.pm @@ -0,0 +1,24 @@ +package # hide from PAUSE + DBICTest::Schema::CollectionObject; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('collection_object'); +__PACKAGE__->add_columns( + 'collection' => { + data_type => 'integer', + }, + 'object' => { + data_type => 'integer', + }, +); +__PACKAGE__->set_primary_key(qw/collection object/); + +__PACKAGE__->belongs_to( collection => "DBICTest::Schema::Collection", + { "foreign.collectionid" => "self.collection" } + ); +__PACKAGE__->belongs_to( object => "DBICTest::Schema::TypedObject", + { "foreign.objectid" => "self.object" } + ); + +1; diff --git a/t/lib/DBICTest/Schema/ComputedColumn.pm b/t/lib/DBICTest/Schema/ComputedColumn.pm new file mode 100644 index 0000000..6832b3e --- /dev/null +++ b/t/lib/DBICTest/Schema/ComputedColumn.pm @@ -0,0 +1,34 @@ +package # hide from PAUSE + DBICTest::Schema::ComputedColumn; + +# for sybase and mssql computed column tests + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('computed_column_test'); + +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'a_computed_column' => { + data_type => undef, + is_nullable => 0, + default_value => \'getdate()', + }, + 'a_timestamp' => { + data_type => 'timestamp', + is_nullable => 0, + }, + 'charfield' => { + data_type => 'varchar', + size => 20, + default_value => 'foo', + is_nullable => 0, + } +); + +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/CustomSql.pm b/t/lib/DBICTest/Schema/CustomSql.pm new file mode 100644 index 0000000..bdad8b8 --- /dev/null +++ b/t/lib/DBICTest/Schema/CustomSql.pm @@ -0,0 +1,17 @@ +package # hide from PAUSE + DBICTest::Schema::CustomSql; + +use base qw/DBICTest::Schema::Artist/; + +__PACKAGE__->table('dummy'); + +__PACKAGE__->result_source_instance->name(\<schema->drop_table($_[1]) } + +1; diff --git a/t/lib/DBICTest/Schema/Dummy.pm b/t/lib/DBICTest/Schema/Dummy.pm new file mode 100644 index 0000000..2a8396d --- /dev/null +++ b/t/lib/DBICTest/Schema/Dummy.pm @@ -0,0 +1,23 @@ +package # hide from PAUSE + DBICTest::Schema::Dummy; + +use base qw/DBICTest::BaseResult/; + +use strict; +use warnings; + +__PACKAGE__->table('dummy'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'gittery' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/Employee.pm b/t/lib/DBICTest/Schema/Employee.pm new file mode 100644 index 0000000..9bf015a --- /dev/null +++ b/t/lib/DBICTest/Schema/Employee.pm @@ -0,0 +1,49 @@ +package # hide from PAUSE + DBICTest::Schema::Employee; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->load_components(qw( Ordered )); + +__PACKAGE__->table('employee'); + +__PACKAGE__->add_columns( + employee_id => { + data_type => 'integer', + is_auto_increment => 1 + }, + position => { + data_type => 'integer', + }, + group_id => { + data_type => 'integer', + is_nullable => 1, + }, + group_id_2 => { + data_type => 'integer', + is_nullable => 1, + }, + group_id_3 => { + data_type => 'integer', + is_nullable => 1, + }, + name => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key('employee_id'); +__PACKAGE__->position_column('position'); + +#__PACKAGE__->add_unique_constraint(position_group => [ qw/position group_id/ ]); + +__PACKAGE__->mk_classdata('field_name_for', { + employee_id => 'primary key', + position => 'list position', + group_id => 'collection column', + name => 'employee name', +}); + +1; diff --git a/t/lib/DBICTest/Schema/Encoded.pm b/t/lib/DBICTest/Schema/Encoded.pm new file mode 100644 index 0000000..7fd77dc --- /dev/null +++ b/t/lib/DBICTest/Schema/Encoded.pm @@ -0,0 +1,39 @@ +package # hide from PAUSE + DBICTest::Schema::Encoded; + +use base qw/DBICTest::BaseResult/; + +use strict; +use warnings; + +__PACKAGE__->table('encoded'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'encoded' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key('id'); + +sub set_column { + my ($self, $col, $value) = @_; + if( $col eq 'encoded' ){ + $value = reverse split '', $value; + } + $self->next::method($col, $value); +} + +sub new { + my($self, $attr, @rest) = @_; + $attr->{encoded} = reverse split '', $attr->{encoded} + if defined $attr->{encoded}; + return $self->next::method($attr, @rest); +} + +1; diff --git a/t/lib/DBICTest/Schema/Event.pm b/t/lib/DBICTest/Schema/Event.pm new file mode 100644 index 0000000..22b655e --- /dev/null +++ b/t/lib/DBICTest/Schema/Event.pm @@ -0,0 +1,23 @@ +package DBICTest::Schema::Event; + +use strict; +use warnings; +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->load_components(qw/InflateColumn::DateTime/); + +__PACKAGE__->table('event'); + +__PACKAGE__->add_columns( + id => { data_type => 'integer', is_auto_increment => 1 }, + starts_at => { data_type => 'datetime' }, + created_on => { data_type => 'timestamp' }, + varchar_date => { data_type => 'varchar', inflate_date => 1, size => 20, is_nullable => 1 }, + varchar_datetime => { data_type => 'varchar', inflate_datetime => 1, size => 20, is_nullable => 1 }, + skip_inflation => { data_type => 'datetime', inflate_datetime => 0, is_nullable => 1 }, + ts_without_tz => { data_type => 'datetime', is_nullable => 1 }, # used in EventTZPg +); + +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/EventTZ.pm b/t/lib/DBICTest/Schema/EventTZ.pm new file mode 100644 index 0000000..2d8df28 --- /dev/null +++ b/t/lib/DBICTest/Schema/EventTZ.pm @@ -0,0 +1,24 @@ +package DBICTest::Schema::EventTZ; + +use strict; +use warnings; +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->load_components(qw/InflateColumn::DateTime/); + +__PACKAGE__->table('event'); + +__PACKAGE__->add_columns( + id => { data_type => 'integer', is_auto_increment => 1 }, + starts_at => { data_type => 'datetime', timezone => "America/Chicago", locale => 'de_DE', datetime_undef_if_invalid => 1 }, + created_on => { data_type => 'timestamp', timezone => "America/Chicago", floating_tz_ok => 1 }, +); + +__PACKAGE__->set_primary_key('id'); + +sub _datetime_parser { + require DateTime::Format::MySQL; + DateTime::Format::MySQL->new(); +} + +1; diff --git a/t/lib/DBICTest/Schema/EventTZDeprecated.pm b/t/lib/DBICTest/Schema/EventTZDeprecated.pm new file mode 100644 index 0000000..a667976 --- /dev/null +++ b/t/lib/DBICTest/Schema/EventTZDeprecated.pm @@ -0,0 +1,25 @@ +package DBICTest::Schema::EventTZDeprecated; + +use strict; +use warnings; +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->load_components(qw/InflateColumn::DateTime/); + +__PACKAGE__->table('event'); + +__PACKAGE__->add_columns( + id => { data_type => 'integer', is_auto_increment => 1 }, + starts_at => { data_type => 'datetime', extra => { timezone => "America/Chicago", locale => 'de_DE' } }, + created_on => { data_type => 'timestamp', extra => { timezone => "America/Chicago", floating_tz_ok => 1 } }, +); + +__PACKAGE__->set_primary_key('id'); + +sub _datetime_parser { + require DateTime::Format::MySQL; + DateTime::Format::MySQL->new(); +} + + +1; diff --git a/t/lib/DBICTest/Schema/EventTZPg.pm b/t/lib/DBICTest/Schema/EventTZPg.pm new file mode 100644 index 0000000..444fe69 --- /dev/null +++ b/t/lib/DBICTest/Schema/EventTZPg.pm @@ -0,0 +1,25 @@ +package DBICTest::Schema::EventTZPg; + +use strict; +use warnings; +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->load_components(qw/InflateColumn::DateTime/); + +__PACKAGE__->table('event'); + +__PACKAGE__->add_columns( + id => { data_type => 'integer', is_auto_increment => 1 }, + starts_at => { data_type => 'datetime', timezone => "America/Chicago", locale => 'de_DE' }, + created_on => { data_type => 'timestamp with time zone', timezone => "America/Chicago" }, + ts_without_tz => { data_type => 'timestamp without time zone' }, +); + +__PACKAGE__->set_primary_key('id'); + +sub _datetime_parser { + require DateTime::Format::Pg; + DateTime::Format::Pg->new(); +} + +1; diff --git a/t/lib/DBICTest/Schema/FileColumn.pm b/t/lib/DBICTest/Schema/FileColumn.pm new file mode 100644 index 0000000..82fcebd --- /dev/null +++ b/t/lib/DBICTest/Schema/FileColumn.pm @@ -0,0 +1,25 @@ +package +DBICTest::Schema::FileColumn; + +use strict; +use warnings; +use base qw/DBICTest::BaseResult/; +use File::Temp qw/tempdir/; + +__PACKAGE__->load_components(qw/InflateColumn::File/); + +__PACKAGE__->table('file_columns'); + +__PACKAGE__->add_columns( + id => { data_type => 'integer', is_auto_increment => 1 }, + file => { + data_type => 'varchar', + is_file_column => 1, + file_column_path => tempdir(CLEANUP => 1), + size => 255 + } +); + +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/ForceForeign.pm b/t/lib/DBICTest/Schema/ForceForeign.pm new file mode 100644 index 0000000..8e2daeb --- /dev/null +++ b/t/lib/DBICTest/Schema/ForceForeign.pm @@ -0,0 +1,41 @@ +package # hide from PAUSE + DBICTest::Schema::ForceForeign; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('forceforeign'); +__PACKAGE__->add_columns( + 'artist' => { data_type => 'integer' }, + 'cd' => { data_type => 'integer' }, +); +__PACKAGE__->set_primary_key(qw/artist/); + +# Normally this would not appear as a FK constraint +# since it uses the PK +__PACKAGE__->might_have( + 'artist_1', 'DBICTest::Schema::Artist', { + 'foreign.artistid' => 'self.artist', + }, { + is_foreign_key_constraint => 1, + }, +); + +# Normally this would appear as a FK constraint +__PACKAGE__->might_have( + 'cd_1', 'DBICTest::Schema::CD', { + 'foreign.cdid' => 'self.cd', + }, { + is_foreign_key_constraint => 0, + }, +); + +# Normally this would appear as a FK constraint +__PACKAGE__->belongs_to( + 'cd_3', 'DBICTest::Schema::CD', { + 'foreign.cdid' => 'self.cd', + }, { + is_foreign_key_constraint => 0, + }, +); + +1; diff --git a/t/lib/DBICTest/Schema/FourKeys.pm b/t/lib/DBICTest/Schema/FourKeys.pm new file mode 100644 index 0000000..9966cfb --- /dev/null +++ b/t/lib/DBICTest/Schema/FourKeys.pm @@ -0,0 +1,29 @@ +package # hide from PAUSE + DBICTest::Schema::FourKeys; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('fourkeys'); +__PACKAGE__->add_columns( + 'foo' => { data_type => 'integer' }, + 'bar' => { data_type => 'integer' }, + 'hello' => { data_type => 'integer' }, + 'goodbye' => { data_type => 'integer' }, + 'sensors' => { data_type => 'character', size => 10 }, + 'read_count' => { data_type => 'integer', is_nullable => 1 }, +); +__PACKAGE__->set_primary_key(qw/foo bar hello goodbye/); + +__PACKAGE__->has_many( + 'fourkeys_to_twokeys', 'DBICTest::Schema::FourKeys_to_TwoKeys', { + 'foreign.f_foo' => 'self.foo', + 'foreign.f_bar' => 'self.bar', + 'foreign.f_hello' => 'self.hello', + 'foreign.f_goodbye' => 'self.goodbye', +}); + +__PACKAGE__->many_to_many( + 'twokeys', 'fourkeys_to_twokeys', 'twokeys', +); + +1; diff --git a/t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm b/t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm new file mode 100644 index 0000000..d95ed6c --- /dev/null +++ b/t/lib/DBICTest/Schema/FourKeys_to_TwoKeys.pm @@ -0,0 +1,33 @@ +package # hide from PAUSE + DBICTest::Schema::FourKeys_to_TwoKeys; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('fourkeys_to_twokeys'); +__PACKAGE__->add_columns( + 'f_foo' => { data_type => 'integer' }, + 'f_bar' => { data_type => 'integer' }, + 'f_hello' => { data_type => 'integer' }, + 'f_goodbye' => { data_type => 'integer' }, + 't_artist' => { data_type => 'integer' }, + 't_cd' => { data_type => 'integer' }, + 'autopilot' => { data_type => 'character' }, + 'pilot_sequence' => { data_type => 'integer', is_nullable => 1 }, +); +__PACKAGE__->set_primary_key( + qw/f_foo f_bar f_hello f_goodbye t_artist t_cd/ +); + +__PACKAGE__->belongs_to('fourkeys', 'DBICTest::Schema::FourKeys', { + 'foreign.foo' => 'self.f_foo', + 'foreign.bar' => 'self.f_bar', + 'foreign.hello' => 'self.f_hello', + 'foreign.goodbye' => 'self.f_goodbye', +}); + +__PACKAGE__->belongs_to('twokeys', 'DBICTest::Schema::TwoKeys', { + 'foreign.artist' => 'self.t_artist', + 'foreign.cd' => 'self.t_cd', +}); + +1; diff --git a/t/lib/DBICTest/Schema/Genre.pm b/t/lib/DBICTest/Schema/Genre.pm new file mode 100644 index 0000000..dceabc9 --- /dev/null +++ b/t/lib/DBICTest/Schema/Genre.pm @@ -0,0 +1,25 @@ +package DBICTest::Schema::Genre; + +use strict; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('genre'); +__PACKAGE__->add_columns( + genreid => { + data_type => 'integer', + is_auto_increment => 1, + }, + name => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('genreid'); +__PACKAGE__->add_unique_constraint ( genre_name => [qw/name/] ); + +__PACKAGE__->has_many (cds => 'DBICTest::Schema::CD', 'genreid'); + +__PACKAGE__->has_one (model_cd => 'DBICTest::Schema::CD', 'genreid'); + +1; diff --git a/t/lib/DBICTest/Schema/Image.pm b/t/lib/DBICTest/Schema/Image.pm new file mode 100644 index 0000000..16f94a9 --- /dev/null +++ b/t/lib/DBICTest/Schema/Image.pm @@ -0,0 +1,28 @@ +package # hide from PAUSE + DBICTest::Schema::Image; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('images'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'artwork_id' => { + data_type => 'integer', + is_foreign_key => 1, + }, + 'name' => { + data_type => 'varchar', + size => 100, + }, + 'data' => { + data_type => 'blob', + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('id'); +__PACKAGE__->belongs_to('artwork', 'DBICTest::Schema::Artwork', 'artwork_id'); + +1; diff --git a/t/lib/DBICTest/Schema/LinerNotes.pm b/t/lib/DBICTest/Schema/LinerNotes.pm new file mode 100644 index 0000000..5675f52 --- /dev/null +++ b/t/lib/DBICTest/Schema/LinerNotes.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::LinerNotes; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('liner_notes'); +__PACKAGE__->add_columns( + 'liner_id' => { + data_type => 'integer', + }, + 'notes' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('liner_id'); +__PACKAGE__->belongs_to( + 'cd', 'DBICTest::Schema::CD', 'liner_id' +); + +1; diff --git a/t/lib/DBICTest/Schema/Link.pm b/t/lib/DBICTest/Schema/Link.pm new file mode 100644 index 0000000..19b7aa0 --- /dev/null +++ b/t/lib/DBICTest/Schema/Link.pm @@ -0,0 +1,32 @@ +package # hide from PAUSE + DBICTest::Schema::Link; + +use base qw/DBICTest::BaseResult/; + +use strict; +use warnings; + +__PACKAGE__->table('link'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'url' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, + 'title' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('id'); + +__PACKAGE__->has_many ( bookmarks => 'DBICTest::Schema::Bookmark', 'link', { cascade_delete => 0 } ); + +use overload '""' => sub { shift->url }, fallback=> 1; + +1; diff --git a/t/lib/DBICTest/Schema/LyricVersion.pm b/t/lib/DBICTest/Schema/LyricVersion.pm new file mode 100644 index 0000000..2a409ab --- /dev/null +++ b/t/lib/DBICTest/Schema/LyricVersion.pm @@ -0,0 +1,24 @@ +package # hide from PAUSE + DBICTest::Schema::LyricVersion; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('lyric_versions'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'lyric_id' => { + data_type => 'integer', + is_foreign_key => 1, + }, + 'text' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('id'); +__PACKAGE__->belongs_to('lyric', 'DBICTest::Schema::Lyrics', 'lyric_id'); + +1; diff --git a/t/lib/DBICTest/Schema/Lyrics.pm b/t/lib/DBICTest/Schema/Lyrics.pm new file mode 100644 index 0000000..268a553 --- /dev/null +++ b/t/lib/DBICTest/Schema/Lyrics.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::Lyrics; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('lyrics'); +__PACKAGE__->add_columns( + 'lyric_id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'track_id' => { + data_type => 'integer', + is_foreign_key => 1, + }, +); +__PACKAGE__->set_primary_key('lyric_id'); +__PACKAGE__->belongs_to('track', 'DBICTest::Schema::Track', 'track_id'); +__PACKAGE__->has_many('lyric_versions', 'DBICTest::Schema::LyricVersion', 'lyric_id'); + +1; diff --git a/t/lib/DBICTest/Schema/Money.pm b/t/lib/DBICTest/Schema/Money.pm new file mode 100644 index 0000000..f4586eb --- /dev/null +++ b/t/lib/DBICTest/Schema/Money.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::Money; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('money_test'); + +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'amount' => { + data_type => 'money', + is_nullable => 1, + }, +); + +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/NoPrimaryKey.pm b/t/lib/DBICTest/Schema/NoPrimaryKey.pm new file mode 100644 index 0000000..cb79178 --- /dev/null +++ b/t/lib/DBICTest/Schema/NoPrimaryKey.pm @@ -0,0 +1,15 @@ +package # hide from PAUSE + DBICTest::Schema::NoPrimaryKey; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('noprimarykey'); +__PACKAGE__->add_columns( + 'foo' => { data_type => 'integer' }, + 'bar' => { data_type => 'integer' }, + 'baz' => { data_type => 'integer' }, +); + +__PACKAGE__->add_unique_constraint(foo_bar => [ qw/foo bar/ ]); + +1; diff --git a/t/lib/DBICTest/Schema/NoSuchClass.pm b/t/lib/DBICTest/Schema/NoSuchClass.pm new file mode 100644 index 0000000..2730b3a --- /dev/null +++ b/t/lib/DBICTest/Schema/NoSuchClass.pm @@ -0,0 +1,6 @@ +package DBICTest::Schema::NoSuchClass; + +## This is purposefully not a real DBIC class +## Used in t/102load_classes.t + +1; diff --git a/t/lib/DBICTest/Schema/OneKey.pm b/t/lib/DBICTest/Schema/OneKey.pm new file mode 100644 index 0000000..bd0e148 --- /dev/null +++ b/t/lib/DBICTest/Schema/OneKey.pm @@ -0,0 +1,22 @@ +package # hide from PAUSE + DBICTest::Schema::OneKey; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('onekey'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'artist' => { + data_type => 'integer', + }, + 'cd' => { + data_type => 'integer', + }, +); +__PACKAGE__->set_primary_key('id'); + + +1; diff --git a/t/lib/DBICTest/Schema/Owners.pm b/t/lib/DBICTest/Schema/Owners.pm new file mode 100644 index 0000000..70af33c --- /dev/null +++ b/t/lib/DBICTest/Schema/Owners.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::Owners; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('owners'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'name' => { + data_type => 'varchar', + size => '100', + }, +); +__PACKAGE__->set_primary_key('id'); + +__PACKAGE__->has_many(books => "DBICTest::Schema::BooksInLibrary", "owner"); + +1; diff --git a/t/lib/DBICTest/Schema/Producer.pm b/t/lib/DBICTest/Schema/Producer.pm new file mode 100644 index 0000000..c2fa611 --- /dev/null +++ b/t/lib/DBICTest/Schema/Producer.pm @@ -0,0 +1,24 @@ +package # hide from PAUSE + DBICTest::Schema::Producer; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('producer'); +__PACKAGE__->add_columns( + 'producerid' => { + data_type => 'integer', + is_auto_increment => 1 + }, + 'name' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('producerid'); +__PACKAGE__->add_unique_constraint(prod_name => [ qw/name/ ]); + +__PACKAGE__->has_many( + producer_to_cd => 'DBICTest::Schema::CD_to_Producer' => 'producer' +); +__PACKAGE__->many_to_many('cds', 'producer_to_cd', 'cd'); +1; diff --git a/t/lib/DBICTest/Schema/SelfRef.pm b/t/lib/DBICTest/Schema/SelfRef.pm new file mode 100644 index 0000000..c0e1476 --- /dev/null +++ b/t/lib/DBICTest/Schema/SelfRef.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::SelfRef; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('self_ref'); +__PACKAGE__->add_columns( + 'id' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'name' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('id'); + +__PACKAGE__->has_many( aliases => 'DBICTest::Schema::SelfRefAlias' => 'self_ref' ); + +1; diff --git a/t/lib/DBICTest/Schema/SelfRefAlias.pm b/t/lib/DBICTest/Schema/SelfRefAlias.pm new file mode 100644 index 0000000..40e181f --- /dev/null +++ b/t/lib/DBICTest/Schema/SelfRefAlias.pm @@ -0,0 +1,20 @@ +package # hide from PAUSE + DBICTest::Schema::SelfRefAlias; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('self_ref_alias'); +__PACKAGE__->add_columns( + 'self_ref' => { + data_type => 'integer', + }, + 'alias' => { + data_type => 'integer', + }, +); +__PACKAGE__->set_primary_key(qw/self_ref alias/); + +__PACKAGE__->belongs_to( self_ref => 'DBICTest::Schema::SelfRef' ); +__PACKAGE__->belongs_to( alias => 'DBICTest::Schema::SelfRef' ); + +1; diff --git a/t/lib/DBICTest/Schema/SequenceTest.pm b/t/lib/DBICTest/Schema/SequenceTest.pm new file mode 100644 index 0000000..b0fa515 --- /dev/null +++ b/t/lib/DBICTest/Schema/SequenceTest.pm @@ -0,0 +1,37 @@ +package # hide from PAUSE + DBICTest::Schema::SequenceTest; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('sequence_test'); +__PACKAGE__->source_info({ + "source_info_key_A" => "source_info_value_A", + "source_info_key_B" => "source_info_value_B", + "source_info_key_C" => "source_info_value_C", + "source_info_key_D" => "source_info_value_D", +}); +__PACKAGE__->add_columns( + 'pkid1' => { + data_type => 'integer', + auto_nextval => 1, + sequence => 'pkid1_seq', + }, + 'pkid2' => { + data_type => 'integer', + auto_nextval => 1, + sequence => 'pkid2_seq', + }, + 'nonpkid' => { + data_type => 'integer', + auto_nextval => 1, + sequence => 'nonpkid_seq', + }, + 'name' => { + data_type => 'varchar', + size => 100, + is_nullable => 1, + }, +); +__PACKAGE__->set_primary_key('pkid1', 'pkid2'); + +1; diff --git a/t/lib/DBICTest/Schema/Serialized.pm b/t/lib/DBICTest/Schema/Serialized.pm new file mode 100644 index 0000000..d7737bd --- /dev/null +++ b/t/lib/DBICTest/Schema/Serialized.pm @@ -0,0 +1,13 @@ +package # hide from PAUSE + DBICTest::Schema::Serialized; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('serialized'); +__PACKAGE__->add_columns( + 'id' => { data_type => 'integer', is_auto_increment => 1 }, + 'serialized' => { data_type => 'text' }, +); +__PACKAGE__->set_primary_key('id'); + +1; diff --git a/t/lib/DBICTest/Schema/Tag.pm b/t/lib/DBICTest/Schema/Tag.pm new file mode 100644 index 0000000..796616e --- /dev/null +++ b/t/lib/DBICTest/Schema/Tag.pm @@ -0,0 +1,24 @@ +package # hide from PAUSE + DBICTest::Schema::Tag; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('tags'); +__PACKAGE__->add_columns( + 'tagid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'cd' => { + data_type => 'integer', + }, + 'tag' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('tagid'); + +__PACKAGE__->belongs_to( cd => 'DBICTest::Schema::CD' ); + +1; diff --git a/t/lib/DBICTest/Schema/Track.pm b/t/lib/DBICTest/Schema/Track.pm new file mode 100644 index 0000000..12f7296 --- /dev/null +++ b/t/lib/DBICTest/Schema/Track.pm @@ -0,0 +1,66 @@ +package # hide from PAUSE + DBICTest::Schema::Track; + +use base qw/DBICTest::BaseResult/; +__PACKAGE__->load_components(qw/InflateColumn::DateTime Ordered/); + +__PACKAGE__->table('track'); +__PACKAGE__->add_columns( + 'trackid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'cd' => { + data_type => 'integer', + }, + 'position' => { + data_type => 'int', + accessor => 'pos', + }, + 'title' => { + data_type => 'varchar', + size => 100, + }, + last_updated_on => { + data_type => 'datetime', + accessor => 'updated_date', + is_nullable => 1 + }, + last_updated_at => { + data_type => 'datetime', + is_nullable => 1 + }, + small_dt => { # for mssql and sybase DT tests + data_type => 'smalldatetime', + is_nullable => 1 + }, +); +__PACKAGE__->set_primary_key('trackid'); + +__PACKAGE__->add_unique_constraint([ qw/cd position/ ]); +__PACKAGE__->add_unique_constraint([ qw/cd title/ ]); + +__PACKAGE__->position_column ('position'); +__PACKAGE__->grouping_column ('cd'); + + +__PACKAGE__->belongs_to( cd => 'DBICTest::Schema::CD' ); +__PACKAGE__->belongs_to( disc => 'DBICTest::Schema::CD' => 'cd'); + +__PACKAGE__->might_have( cd_single => 'DBICTest::Schema::CD', 'single_track' ); +__PACKAGE__->might_have( lyrics => 'DBICTest::Schema::Lyrics', 'track_id' ); + +__PACKAGE__->belongs_to( + "year1999cd", + "DBICTest::Schema::Year1999CDs", + { "foreign.cdid" => "self.cd" }, + { join_type => 'left' }, # the relationship is of course optional +); +__PACKAGE__->belongs_to( + "year2000cd", + "DBICTest::Schema::Year2000CDs", + { "foreign.cdid" => "self.cd" }, + { join_type => 'left' }, +); + +1; diff --git a/t/lib/DBICTest/Schema/TreeLike.pm b/t/lib/DBICTest/Schema/TreeLike.pm new file mode 100644 index 0000000..a5413d1 --- /dev/null +++ b/t/lib/DBICTest/Schema/TreeLike.pm @@ -0,0 +1,28 @@ +package # hide from PAUSE + DBICTest::Schema::TreeLike; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('treelike'); +__PACKAGE__->add_columns( + 'id' => { data_type => 'integer', is_auto_increment => 1 }, + 'parent' => { data_type => 'integer' , is_nullable=>1}, + 'name' => { data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key(qw/id/); +__PACKAGE__->belongs_to('parent', 'TreeLike', + { 'foreign.id' => 'self.parent' }); +__PACKAGE__->has_many('children', 'TreeLike', { 'foreign.parent' => 'self.id' }); + +## since this is a self referential table we need to do a post deploy hook and get +## some data in while constraints are off + + sub sqlt_deploy_hook { + my ($self, $sqlt_table) = @_; + + ## We don't seem to need this anymore, but keeping it for the moment + ## $sqlt_table->add_index(name => 'idx_name', fields => ['name']); + } +1; diff --git a/t/lib/DBICTest/Schema/TwoKeyTreeLike.pm b/t/lib/DBICTest/Schema/TwoKeyTreeLike.pm new file mode 100644 index 0000000..1ee8409 --- /dev/null +++ b/t/lib/DBICTest/Schema/TwoKeyTreeLike.pm @@ -0,0 +1,21 @@ +package # hide from PAUSE + DBICTest::Schema::TwoKeyTreeLike; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('twokeytreelike'); +__PACKAGE__->add_columns( + 'id1' => { data_type => 'integer' }, + 'id2' => { data_type => 'integer' }, + 'parent1' => { data_type => 'integer' }, + 'parent2' => { data_type => 'integer' }, + 'name' => { data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key(qw/id1 id2/); +__PACKAGE__->add_unique_constraint('tktlnameunique' => ['name']); +__PACKAGE__->belongs_to('parent', 'DBICTest::Schema::TwoKeyTreeLike', + { 'foreign.id1' => 'self.parent1', 'foreign.id2' => 'self.parent2'}); + +1; diff --git a/t/lib/DBICTest/Schema/TwoKeys.pm b/t/lib/DBICTest/Schema/TwoKeys.pm new file mode 100644 index 0000000..bfb6c42 --- /dev/null +++ b/t/lib/DBICTest/Schema/TwoKeys.pm @@ -0,0 +1,30 @@ +package # hide from PAUSE + DBICTest::Schema::TwoKeys; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('twokeys'); +__PACKAGE__->add_columns( + 'artist' => { data_type => 'integer' }, + 'cd' => { data_type => 'integer' }, +); +__PACKAGE__->set_primary_key(qw/artist cd/); + +__PACKAGE__->belongs_to( + artist => 'DBICTest::Schema::Artist', + {'foreign.artistid'=>'self.artist'}, +); + +__PACKAGE__->belongs_to( cd => 'DBICTest::Schema::CD', undef, { is_deferrable => 0, add_fk_index => 0 } ); + +__PACKAGE__->has_many( + 'fourkeys_to_twokeys', 'DBICTest::Schema::FourKeys_to_TwoKeys', { + 'foreign.t_artist' => 'self.artist', + 'foreign.t_cd' => 'self.cd', +}); + +__PACKAGE__->many_to_many( + 'fourkeys', 'fourkeys_to_twokeys', 'fourkeys', +); + +1; diff --git a/t/lib/DBICTest/Schema/TypedObject.pm b/t/lib/DBICTest/Schema/TypedObject.pm new file mode 100644 index 0000000..50c5e44 --- /dev/null +++ b/t/lib/DBICTest/Schema/TypedObject.pm @@ -0,0 +1,28 @@ +package # hide from PAUSE + DBICTest::Schema::TypedObject; + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table('typed_object'); +__PACKAGE__->add_columns( + 'objectid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'type' => { + data_type => 'varchar', + size => '100', + }, + 'value' => { + data_type => 'varchar', + size => 100, + }, +); +__PACKAGE__->set_primary_key('objectid'); + +__PACKAGE__->has_many( collection_object => "DBICTest::Schema::CollectionObject", + { "foreign.object" => "self.objectid" } + ); +__PACKAGE__->many_to_many( collections => collection_object => "collection" ); + +1; diff --git a/t/lib/DBICTest/Schema/Year1999CDs.pm b/t/lib/DBICTest/Schema/Year1999CDs.pm new file mode 100644 index 0000000..76606d4 --- /dev/null +++ b/t/lib/DBICTest/Schema/Year1999CDs.pm @@ -0,0 +1,39 @@ +package # hide from PAUSE + DBICTest::Schema::Year1999CDs; +## Used in 104view.t + +use base qw/DBICTest::BaseResult/; + +__PACKAGE__->table_class('DBIx::Class::ResultSource::View'); + +__PACKAGE__->table('year1999cds'); +__PACKAGE__->result_source_instance->is_virtual(1); +__PACKAGE__->result_source_instance->view_definition( + "SELECT cdid, artist, title, single_track FROM cd WHERE year ='1999'" +); +__PACKAGE__->add_columns( + 'cdid' => { + data_type => 'integer', + is_auto_increment => 1, + }, + 'artist' => { + data_type => 'integer', + }, + 'title' => { + data_type => 'varchar', + size => 100, + }, + 'single_track' => { + data_type => 'integer', + is_nullable => 1, + is_foreign_key => 1, + }, +); +__PACKAGE__->set_primary_key('cdid'); +__PACKAGE__->add_unique_constraint([ qw/artist title/ ]); + +__PACKAGE__->belongs_to( artist => 'DBICTest::Schema::Artist' ); +__PACKAGE__->has_many( tracks => 'DBICTest::Schema::Track', + { "foreign.cd" => "self.cdid" }); + +1; diff --git a/t/lib/DBICTest/Schema/Year2000CDs.pm b/t/lib/DBICTest/Schema/Year2000CDs.pm new file mode 100644 index 0000000..2fc30aa --- /dev/null +++ b/t/lib/DBICTest/Schema/Year2000CDs.pm @@ -0,0 +1,19 @@ +package # hide from PAUSE + DBICTest::Schema::Year2000CDs; + +use base qw/DBICTest::Schema::CD/; + +__PACKAGE__->table_class('DBIx::Class::ResultSource::View'); +__PACKAGE__->table('year2000cds'); + +# need to operate on the instance for things to work +__PACKAGE__->result_source_instance->view_definition( sprintf ( + 'SELECT %s FROM cd WHERE year = "2000"', + join (', ', __PACKAGE__->columns), +)); + +__PACKAGE__->belongs_to( artist => 'DBICTest::Schema::Artist' ); +__PACKAGE__->has_many( tracks => 'DBICTest::Schema::Track', + { "foreign.cd" => "self.cdid" }); + +1; diff --git a/t/lib/DBICTest/Stats.pm b/t/lib/DBICTest/Stats.pm new file mode 100644 index 0000000..5a4544f --- /dev/null +++ b/t/lib/DBICTest/Stats.pm @@ -0,0 +1,63 @@ +package DBICTest::Stats; +use strict; +use warnings; + +use base qw/DBIx::Class::Storage::Statistics/; + +sub txn_begin { + my $self = shift; + + $self->{'TXN_BEGIN'}++; + return $self->{'TXN_BEGIN'}; +} + +sub txn_rollback { + my $self = shift; + + $self->{'TXN_ROLLBACK'}++; + return $self->{'TXN_ROLLBACK'}; +} + +sub txn_commit { + my $self = shift; + + $self->{'TXN_COMMIT'}++; + return $self->{'TXN_COMMIT'}; +} + +sub svp_begin { + my ($self, $name) = @_; + + $self->{'SVP_BEGIN'}++; + return $self->{'SVP_BEGIN'}; +} + +sub svp_release { + my ($self, $name) = @_; + + $self->{'SVP_RELEASE'}++; + return $self->{'SVP_RELEASE'}; +} + +sub svp_rollback { + my ($self, $name) = @_; + + $self->{'SVP_ROLLBACK'}++; + return $self->{'SVP_ROLLBACK'}; +} + +sub query_start { + my ($self, $string, @bind) = @_; + + $self->{'QUERY_START'}++; + return $self->{'QUERY_START'}; +} + +sub query_end { + my ($self, $string) = @_; + + $self->{'QUERY_END'}++; + return $self->{'QUERY_START'}; +} + +1; diff --git a/t/lib/DBICTest/SyntaxErrorComponent1.pm b/t/lib/DBICTest/SyntaxErrorComponent1.pm new file mode 100644 index 0000000..3fb5045 --- /dev/null +++ b/t/lib/DBICTest/SyntaxErrorComponent1.pm @@ -0,0 +1,9 @@ +# belongs to t/run/90ensure_class_loaded.tl +package # hide from PAUSE + DBICTest::SyntaxErrorComponent1; +use warnings; +use strict; + +my $str ''; # syntax error + +1; diff --git a/t/lib/DBICTest/SyntaxErrorComponent2.pm b/t/lib/DBICTest/SyntaxErrorComponent2.pm new file mode 100644 index 0000000..ac6cfb8 --- /dev/null +++ b/t/lib/DBICTest/SyntaxErrorComponent2.pm @@ -0,0 +1,9 @@ +# belongs to t/run/90ensure_class_loaded.tl +package # hide from PAUSE + DBICTest::SyntaxErrorComponent2; +use warnings; +use strict; + +my $str ''; # syntax error + +1; diff --git a/t/lib/DBICTest/SyntaxErrorComponent3.pm b/t/lib/DBICTest/SyntaxErrorComponent3.pm new file mode 100644 index 0000000..34f3c3f --- /dev/null +++ b/t/lib/DBICTest/SyntaxErrorComponent3.pm @@ -0,0 +1,5 @@ +package DBICErrorTest::SyntaxError; + +use strict; + +I'm a syntax error! diff --git a/t/lib/DBICTest/Taint/Classes/Auto.pm b/t/lib/DBICTest/Taint/Classes/Auto.pm new file mode 100644 index 0000000..9a30c1a --- /dev/null +++ b/t/lib/DBICTest/Taint/Classes/Auto.pm @@ -0,0 +1,7 @@ +package # hide from PAUSE + DBICTest::Taint::Classes::Auto; + +use base 'DBIx::Class::Core'; +__PACKAGE__->table('test'); + +1; diff --git a/t/lib/DBICTest/Taint/Classes/Manual.pm b/t/lib/DBICTest/Taint/Classes/Manual.pm new file mode 100644 index 0000000..5d2109b --- /dev/null +++ b/t/lib/DBICTest/Taint/Classes/Manual.pm @@ -0,0 +1,7 @@ +package # hide from PAUSE + DBICTest::Taint::Classes::Manual; + +use base 'DBIx::Class::Core'; +__PACKAGE__->table('test'); + +1; diff --git a/t/lib/DBICTest/Taint/Namespaces/Result/Test.pm b/t/lib/DBICTest/Taint/Namespaces/Result/Test.pm new file mode 100644 index 0000000..7d57bb5 --- /dev/null +++ b/t/lib/DBICTest/Taint/Namespaces/Result/Test.pm @@ -0,0 +1,7 @@ +package # hide from PAUSE + DBICTest::Taint::Namespaces::Result::Test; + +use base 'DBIx::Class::Core'; +__PACKAGE__->table('test'); + +1; diff --git a/t/lib/sqlite.sql b/t/lib/sqlite.sql new file mode 100644 index 0000000..4d7905f --- /dev/null +++ b/t/lib/sqlite.sql @@ -0,0 +1,448 @@ +-- +-- Created by SQL::Translator::Producer::SQLite +-- Created on Sat Jan 30 19:18:55 2010 +-- +; + +-- +-- Table: artist +-- +CREATE TABLE artist ( + artistid INTEGER PRIMARY KEY NOT NULL, + name varchar(100), + rank integer NOT NULL DEFAULT '13', + charfield char(10) +); + +CREATE INDEX artist_name_hookidx ON artist (name); + +-- +-- Table: bindtype_test +-- +CREATE TABLE bindtype_test ( + id INTEGER PRIMARY KEY NOT NULL, + bytea blob, + blob blob, + clob clob +); + +-- +-- Table: collection +-- +CREATE TABLE collection ( + collectionid INTEGER PRIMARY KEY NOT NULL, + name varchar(100) NOT NULL +); + +-- +-- Table: employee +-- +CREATE TABLE employee ( + employee_id INTEGER PRIMARY KEY NOT NULL, + position integer NOT NULL, + group_id integer, + group_id_2 integer, + group_id_3 integer, + name varchar(100) +); + +-- +-- Table: encoded +-- +CREATE TABLE encoded ( + id INTEGER PRIMARY KEY NOT NULL, + encoded varchar(100) +); + +-- +-- Table: event +-- +CREATE TABLE event ( + id INTEGER PRIMARY KEY NOT NULL, + starts_at datetime NOT NULL, + created_on timestamp NOT NULL, + varchar_date varchar(20), + varchar_datetime varchar(20), + skip_inflation datetime, + ts_without_tz datetime +); + +-- +-- Table: file_columns +-- +CREATE TABLE file_columns ( + id INTEGER PRIMARY KEY NOT NULL, + file varchar(255) NOT NULL +); + +-- +-- Table: fourkeys +-- +CREATE TABLE fourkeys ( + foo integer NOT NULL, + bar integer NOT NULL, + hello integer NOT NULL, + goodbye integer NOT NULL, + sensors character(10) NOT NULL, + read_count integer, + PRIMARY KEY (foo, bar, hello, goodbye) +); + +-- +-- Table: genre +-- +CREATE TABLE genre ( + genreid INTEGER PRIMARY KEY NOT NULL, + name varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX genre_name ON genre (name); + +-- +-- Table: link +-- +CREATE TABLE link ( + id INTEGER PRIMARY KEY NOT NULL, + url varchar(100), + title varchar(100) +); + +-- +-- Table: money_test +-- +CREATE TABLE money_test ( + id INTEGER PRIMARY KEY NOT NULL, + amount money +); + +-- +-- Table: noprimarykey +-- +CREATE TABLE noprimarykey ( + foo integer NOT NULL, + bar integer NOT NULL, + baz integer NOT NULL +); + +CREATE UNIQUE INDEX foo_bar ON noprimarykey (foo, bar); + +-- +-- Table: onekey +-- +CREATE TABLE onekey ( + id INTEGER PRIMARY KEY NOT NULL, + artist integer NOT NULL, + cd integer NOT NULL +); + +-- +-- Table: owners +-- +CREATE TABLE owners ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(100) NOT NULL +); + +-- +-- Table: producer +-- +CREATE TABLE producer ( + producerid INTEGER PRIMARY KEY NOT NULL, + name varchar(100) NOT NULL +); + +CREATE UNIQUE INDEX prod_name ON producer (name); + +-- +-- Table: self_ref +-- +CREATE TABLE self_ref ( + id INTEGER PRIMARY KEY NOT NULL, + name varchar(100) NOT NULL +); + +-- +-- Table: sequence_test +-- +CREATE TABLE sequence_test ( + pkid1 integer NOT NULL, + pkid2 integer NOT NULL, + nonpkid integer NOT NULL, + name varchar(100), + PRIMARY KEY (pkid1, pkid2) +); + +-- +-- Table: serialized +-- +CREATE TABLE serialized ( + id INTEGER PRIMARY KEY NOT NULL, + serialized text NOT NULL +); + +-- +-- Table: treelike +-- +CREATE TABLE treelike ( + id INTEGER PRIMARY KEY NOT NULL, + parent integer, + name varchar(100) NOT NULL +); + +CREATE INDEX treelike_idx_parent ON treelike (parent); + +-- +-- Table: twokeytreelike +-- +CREATE TABLE twokeytreelike ( + id1 integer NOT NULL, + id2 integer NOT NULL, + parent1 integer NOT NULL, + parent2 integer NOT NULL, + name varchar(100) NOT NULL, + PRIMARY KEY (id1, id2) +); + +CREATE INDEX twokeytreelike_idx_parent1_parent2 ON twokeytreelike (parent1, parent2); + +CREATE UNIQUE INDEX tktlnameunique ON twokeytreelike (name); + +-- +-- Table: typed_object +-- +CREATE TABLE typed_object ( + objectid INTEGER PRIMARY KEY NOT NULL, + type varchar(100) NOT NULL, + value varchar(100) NOT NULL +); + +-- +-- Table: artist_undirected_map +-- +CREATE TABLE artist_undirected_map ( + id1 integer NOT NULL, + id2 integer NOT NULL, + PRIMARY KEY (id1, id2) +); + +CREATE INDEX artist_undirected_map_idx_id1 ON artist_undirected_map (id1); + +CREATE INDEX artist_undirected_map_idx_id2 ON artist_undirected_map (id2); + +-- +-- Table: bookmark +-- +CREATE TABLE bookmark ( + id INTEGER PRIMARY KEY NOT NULL, + link integer +); + +CREATE INDEX bookmark_idx_link ON bookmark (link); + +-- +-- Table: books +-- +CREATE TABLE books ( + id INTEGER PRIMARY KEY NOT NULL, + source varchar(100) NOT NULL, + owner integer NOT NULL, + title varchar(100) NOT NULL, + price integer +); + +CREATE INDEX books_idx_owner ON books (owner); + +-- +-- Table: forceforeign +-- +CREATE TABLE forceforeign ( + artist INTEGER PRIMARY KEY NOT NULL, + cd integer NOT NULL +); + +-- +-- Table: self_ref_alias +-- +CREATE TABLE self_ref_alias ( + self_ref integer NOT NULL, + alias integer NOT NULL, + PRIMARY KEY (self_ref, alias) +); + +CREATE INDEX self_ref_alias_idx_alias ON self_ref_alias (alias); + +CREATE INDEX self_ref_alias_idx_self_ref ON self_ref_alias (self_ref); + +-- +-- Table: track +-- +CREATE TABLE track ( + trackid INTEGER PRIMARY KEY NOT NULL, + cd integer NOT NULL, + position int NOT NULL, + title varchar(100) NOT NULL, + last_updated_on datetime, + last_updated_at datetime, + small_dt smalldatetime +); + +CREATE INDEX track_idx_cd ON track (cd); + +CREATE UNIQUE INDEX track_cd_position ON track (cd, position); + +CREATE UNIQUE INDEX track_cd_title ON track (cd, title); + +-- +-- Table: cd +-- +CREATE TABLE cd ( + cdid INTEGER PRIMARY KEY NOT NULL, + artist integer NOT NULL, + title varchar(100) NOT NULL, + year varchar(100) NOT NULL, + genreid integer, + single_track integer +); + +CREATE INDEX cd_idx_artist ON cd (artist); + +CREATE INDEX cd_idx_genreid ON cd (genreid); + +CREATE INDEX cd_idx_single_track ON cd (single_track); + +CREATE UNIQUE INDEX cd_artist_title ON cd (artist, title); + +-- +-- Table: collection_object +-- +CREATE TABLE collection_object ( + collection integer NOT NULL, + object integer NOT NULL, + PRIMARY KEY (collection, object) +); + +CREATE INDEX collection_object_idx_collection ON collection_object (collection); + +CREATE INDEX collection_object_idx_object ON collection_object (object); + +-- +-- Table: lyrics +-- +CREATE TABLE lyrics ( + lyric_id INTEGER PRIMARY KEY NOT NULL, + track_id integer NOT NULL +); + +CREATE INDEX lyrics_idx_track_id ON lyrics (track_id); + +-- +-- Table: cd_artwork +-- +CREATE TABLE cd_artwork ( + cd_id INTEGER PRIMARY KEY NOT NULL +); + +-- +-- Table: liner_notes +-- +CREATE TABLE liner_notes ( + liner_id INTEGER PRIMARY KEY NOT NULL, + notes varchar(100) NOT NULL +); + +-- +-- Table: lyric_versions +-- +CREATE TABLE lyric_versions ( + id INTEGER PRIMARY KEY NOT NULL, + lyric_id integer NOT NULL, + text varchar(100) NOT NULL +); + +CREATE INDEX lyric_versions_idx_lyric_id ON lyric_versions (lyric_id); + +-- +-- Table: tags +-- +CREATE TABLE tags ( + tagid INTEGER PRIMARY KEY NOT NULL, + cd integer NOT NULL, + tag varchar(100) NOT NULL +); + +CREATE INDEX tags_idx_cd ON tags (cd); + +-- +-- Table: cd_to_producer +-- +CREATE TABLE cd_to_producer ( + cd integer NOT NULL, + producer integer NOT NULL, + attribute integer, + PRIMARY KEY (cd, producer) +); + +CREATE INDEX cd_to_producer_idx_cd ON cd_to_producer (cd); + +CREATE INDEX cd_to_producer_idx_producer ON cd_to_producer (producer); + +-- +-- Table: images +-- +CREATE TABLE images ( + id INTEGER PRIMARY KEY NOT NULL, + artwork_id integer NOT NULL, + name varchar(100) NOT NULL, + data blob +); + +CREATE INDEX images_idx_artwork_id ON images (artwork_id); + +-- +-- Table: twokeys +-- +CREATE TABLE twokeys ( + artist integer NOT NULL, + cd integer NOT NULL, + PRIMARY KEY (artist, cd) +); + +CREATE INDEX twokeys_idx_artist ON twokeys (artist); + +-- +-- Table: artwork_to_artist +-- +CREATE TABLE artwork_to_artist ( + artwork_cd_id integer NOT NULL, + artist_id integer NOT NULL, + PRIMARY KEY (artwork_cd_id, artist_id) +); + +CREATE INDEX artwork_to_artist_idx_artist_id ON artwork_to_artist (artist_id); + +CREATE INDEX artwork_to_artist_idx_artwork_cd_id ON artwork_to_artist (artwork_cd_id); + +-- +-- Table: fourkeys_to_twokeys +-- +CREATE TABLE fourkeys_to_twokeys ( + f_foo integer NOT NULL, + f_bar integer NOT NULL, + f_hello integer NOT NULL, + f_goodbye integer NOT NULL, + t_artist integer NOT NULL, + t_cd integer NOT NULL, + autopilot character NOT NULL, + pilot_sequence integer, + PRIMARY KEY (f_foo, f_bar, f_hello, f_goodbye, t_artist, t_cd) +); + +CREATE INDEX fourkeys_to_twokeys_idx_f_foo_f_bar_f_hello_f_goodbye ON fourkeys_to_twokeys (f_foo, f_bar, f_hello, f_goodbye); + +CREATE INDEX fourkeys_to_twokeys_idx_t_artist_t_cd ON fourkeys_to_twokeys (t_artist, t_cd); + +-- +-- View: year2000cds +-- +CREATE VIEW year2000cds AS + SELECT cdid, artist, title, year, genreid, single_track FROM cd WHERE year = "2000" \ No newline at end of file