X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FSchema.pm;h=2c68cf1a891f4fb0c35505095ac1e9592dfff70a;hb=93405cf0;hp=a2842be19867b8d2e1ba8c09297fb2f01433c1c3;hpb=bc577afb73970b01932a45d79590721e7b399846;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Schema.pm b/lib/DBIx/Class/Schema.pm index a2842be..2c68cf1 100644 --- a/lib/DBIx/Class/Schema.pm +++ b/lib/DBIx/Class/Schema.pm @@ -5,6 +5,7 @@ use warnings; use Carp::Clan qw/^DBIx::Class/; use Scalar::Util qw/weaken/; +use File::Spec; require Module::Find; use base qw/DBIx::Class/; @@ -93,10 +94,15 @@ moniker. sub register_source { my ($self, $moniker, $source) = @_; + + %$source = %{ $source->new( { %$source, source_name => $moniker }) }; + my %reg = %{$self->source_registrations}; $reg{$moniker} = $source; $self->source_registrations(\%reg); + $source->schema($self); + weaken($source->{schema}) if ref($self); if ($source->result_class) { my %map = %{$self->class_mappings}; @@ -105,6 +111,19 @@ sub register_source { } } +sub _unregister_source { + my ($self, $moniker) = @_; + my %reg = %{$self->source_registrations}; + + my $source = delete $reg{$moniker}; + $self->source_registrations(\%reg); + if ($source->result_class) { + my %map = %{$self->class_mappings}; + delete $map{$source->result_class}; + $self->class_mappings(\%map); + } +} + =head2 class =over 4 @@ -267,10 +286,18 @@ sub load_classes { foreach my $prefix (keys %comps_for) { foreach my $comp (@{$comps_for{$prefix}||[]}) { my $comp_class = "${prefix}::${comp}"; + { # try to untaint module name. mods where this fails + # are left alone so we don't have to change the old behavior + no locale; # localized \w doesn't untaint expression + if ( $comp_class =~ m/^( (?:\w+::)* \w+ )$/x ) { + $comp_class = $1; + } + } $class->ensure_class_loaded($comp_class); - $comp_class->source_name($comp) unless $comp_class->source_name; - push(@to_register, [ $comp_class->source_name, $comp_class ]); + $comp = $comp_class->source_name || $comp; +# $DB::single = 1; + push(@to_register, [ $comp, $comp_class ]); } } } @@ -440,7 +467,7 @@ sub load_namespaces { return; } -=head2 compose_connection +=head2 compose_connection (DEPRECATED) =over 4 @@ -450,6 +477,12 @@ sub load_namespaces { =back +DEPRECATED. You probably wanted compose_namespace. + +Actually, you probably just wanted to call connect. + +=for hidden due to deprecation + Calls L to the target namespace, calls L with @db_info on the new schema, then injects the L component and a @@ -464,43 +497,50 @@ more information. =cut -sub compose_connection { - my ($self, $target, @info) = @_; - my $base = 'DBIx::Class::ResultSetProxy'; - eval "require ${base};"; - $self->throw_exception - ("No arguments to load_classes and couldn't load ${base} ($@)") - if $@; - - if ($self eq $target) { - # Pathological case, largely caused by the docs on early C::M::DBIC::Plain - foreach my $moniker ($self->sources) { - my $source = $self->source($moniker); +{ + my $warn; + + sub compose_connection { + my ($self, $target, @info) = @_; + + warn "compose_connection deprecated as of 0.08000" unless $warn++; + + my $base = 'DBIx::Class::ResultSetProxy'; + eval "require ${base};"; + $self->throw_exception + ("No arguments to load_classes and couldn't load ${base} ($@)") + if $@; + + if ($self eq $target) { + # Pathological case, largely caused by the docs on early C::M::DBIC::Plain + foreach my $moniker ($self->sources) { + my $source = $self->source($moniker); + my $class = $source->result_class; + $self->inject_base($class, $base); + $class->mk_classdata(resultset_instance => $source->resultset); + $class->mk_classdata(class_resolver => $self); + } + $self->connection(@info); + return $self; + } + + my $schema = $self->compose_namespace($target, $base); + { + no strict 'refs'; + *{"${target}::schema"} = sub { $schema }; + } + + $schema->connection(@info); + foreach my $moniker ($schema->sources) { + my $source = $schema->source($moniker); my $class = $source->result_class; - $self->inject_base($class, $base); + #warn "$moniker $class $source ".$source->storage; + $class->mk_classdata(result_source_instance => $source); $class->mk_classdata(resultset_instance => $source->resultset); - $class->mk_classdata(class_resolver => $self); + $class->mk_classdata(class_resolver => $schema); } - $self->connection(@info); - return $self; - } - - my $schema = $self->compose_namespace($target, $base); - { - no strict 'refs'; - *{"${target}::schema"} = sub { $schema }; + return $schema; } - - $schema->connection(@info); - foreach my $moniker ($schema->sources) { - my $source = $schema->source($moniker); - my $class = $source->result_class; - #warn "$moniker $class $source ".$source->storage; - $class->mk_classdata(result_source_instance => $source); - $class->mk_classdata(resultset_instance => $source->resultset); - $class->mk_classdata(class_resolver => $schema); - } - return $schema; } =head2 compose_namespace @@ -587,6 +627,26 @@ sub setup_connection_class { $target->connection(@info); } +=head2 storage_type + +=over 4 + +=item Arguments: $storage_type + +=item Return Value: $storage_type + +=back + +Set the storage class that will be instantiated when L is called. +If the classname starts with C<::>, the prefix C is +assumed by L. Defaults to C<::DBI>, +which is L. + +You want to use this to hardcoded subclasses of L +in cases where the appropriate subclass is not autodetected, such as when +dealing with MSSQL via L, in which case you'd set it to +C<::DBI::Sybase::MSSQL>. + =head2 connection =over 4 @@ -619,6 +679,7 @@ sub connection { my $storage = $storage_class->new($self); $storage->connect_info(\@info); $self->storage($storage); + $self->on_connect() if($self->can('on_connect')); return $self; } @@ -750,13 +811,22 @@ sub clone { =over 4 -=item Arguments: $moniker, \@data; +=item Arguments: $source_name, \@data; =back -Populates the source registered with the given moniker with the supplied data. -@data should be a list of listrefs -- the first containing column names, the -second matching values. +Pass this method a resultsource name, and an arrayref of +arrayrefs. The arrayrefs should contain a list of column names, +followed by one or many sets of matching data for the given columns. + +In void context, C in L is used +to insert the data, as this is a fast method. However, insert_bulk currently +assumes that your datasets all contain the same type of values, using scalar +references in a column in one row, and not in another will probably not work. + +Otherwise, each set of data is inserted into the database using +L, and a arrayref of the resulting row +objects is returned. i.e., @@ -773,13 +843,16 @@ sub populate { my ($self, $name, $data) = @_; my $rs = $self->resultset($name); my @names = @{shift(@$data)}; - my @created; - foreach my $item (@$data) { - my %create; - @create{@names} = @$item; - push(@created, $rs->create(\%create)); + if(defined wantarray) { + my @created; + foreach my $item (@$data) { + my %create; + @create{@names} = @$item; + push(@created, $rs->create(\%create)); + } + return @created; } - return @created; + $self->storage->insert_bulk($self->source($name)->from, \@names, $data); } =head2 exception_action @@ -862,16 +935,41 @@ sub deploy { =over 4 -=item Arguments: \@databases, $version, $directory, $sqlt_args +=item Arguments: \@databases, $version, $directory, $preversion, $sqlt_args =back Creates an SQL file based on the Schema, for each of the specified -database types, in the given directory. +database types, in the given directory. Given a previous version number, +this will also create a file containing the ALTER TABLE statements to +transform the previous schema into the current one. Note that these +statements may contain DROP TABLE or DROP COLUMN statements that can +potentially destroy data. + +The file names are created using the C method below, please +override this method in your schema if you would like a different file +name format. For the ALTER file, the same format is used, replacing +$version in the name with "$preversion-$version". + +If no arguments are passed, then the following default values are used: + +=over 4 + +=item databases - ['MySQL', 'SQLite', 'PostgreSQL'] + +=item version - $schema->VERSION + +=item directory - './' + +=item preversion - + +=back Note that this feature is currently EXPERIMENTAL and may not work correctly across all databases, or fully handle complex relationships. +WARNING: Please check all SQL files created, before applying them. + =cut sub create_ddl_dir { @@ -883,19 +981,30 @@ sub create_ddl_dir { =head2 ddl_filename (EXPERIMENTAL) - my $filename = $table->ddl_filename($type, $dir, $version) +=over 4 + +=item Arguments: $directory, $database-type, $version, $preversion + +=back + + my $filename = $table->ddl_filename($type, $dir, $version, $preversion) + +This method is called by C to compose a file name out of +the supplied directory, database type and version number. The default file +name format is: C<$dir$schema-$version-$type.sql>. -Creates a filename for a SQL file based on the table class name. Not -intended for direct end user use. +You may override this method in your schema if you wish to use a different +format. =cut sub ddl_filename { - my ($self, $type, $dir, $version) = @_; + my ($self, $type, $dir, $version, $pversion) = @_; my $filename = ref($self); $filename =~ s/::/-/; - $filename = "$dir$filename-$version-$type.sql"; + $filename = File::Spec->catfile($dir, "$filename-$version-$type.sql"); + $filename =~ s/$version/$pversion-$version/ if($pversion); return $filename; }