$schema->storage->txn_do(sub {
$schema->storage->with_deferred_fk_checks(sub {
- use SQL::Translator;
- my $sqlt = SQL::Translator->new(
- parser => 'SQL::Translator::Parser::DBIx::Class',
- parser_args => {
- dbic_schema => $schema,
- },
- );
- $sqlt->translate;
- my $sqlt_schema = $sqlt->schema;
- my %table_order = map +($_->name => $_->order - 1), $sqlt_schema->get_tables;
- {
- # testing stuff
- my @testing_sorted_sn = sort $schema->sources;
- my %sources_deps = map { $_ => {} } @testing_sorted_sn;
- for my $testing_source ( @testing_sorted_sn ) {
- ::Dwarn "Source: " . $testing_source;
- my @testing_relationships = $schema->source( $testing_source )->relationships;
- ::Dwarn "Relationships: " . join (', ', @testing_relationships);
- if ( scalar @testing_relationships ) {
- for my $testing_rel ( @testing_relationships ) {
- my $rel_info = $schema->source( $testing_source )->relationship_info( $testing_rel );
- ::Dwarn $rel_info;
-
- if (
- exists( $rel_info->{ attrs }->{ 'is_foreign_key_constraint' } )
- && $rel_info->{ attrs }->{ 'is_foreign_key_constraint' }
- && ! $rel_info->{ attrs }->{ 'is_deferrable' }
- && ! ( $rel_info->{attrs}{accessor} eq 'multi' )
- ) {
- my $dep = $schema->source( $testing_source )->related_source( $testing_rel )->source_name;
- $sources_deps{ $testing_source }->{ $dep } = $sources_deps{ $dep };
- }
- }
- # set to 0 if there are no deps
- $sources_deps{ $testing_source } = 0 unless scalar keys $sources_deps{ $testing_source };
- }
- ::Dwarn "";
- ::Dwarn "";
- }
- ::Dwarn \%sources_deps;
-
- for my $source ( keys %sources_deps ) {
- my $tally = 0;
- if ( ref( $sources_deps{ $source } ) eq "HASH" ) {
- for my $dep ( keys %{ $sources_deps{ $source } } ) {
- my $val = $sources_deps{ $source }->{ $dep };
- if ( ( ref( $val ) eq 'SCALAR' ) && ( $tally == $val ) ) {
- $tally++;
- } else {
- $tally = 99;
- }
- }
- }
- $sources_deps{ $source } = $tally;
- }
- ::Dwarn \%sources_deps;
-
-
-# my @test_names = keys %sources_deps;
-
-# my @test_sorted = sort {
-# ( $sources_deps{ $a }->{ $b } || 0 )
-# cmp
-# ( $sources_deps{ $b }->{ $a } || 0 )
-# } @test_names;
-
-# ::Dwarn \@test_names;
-# ::Dwarn \@test_sorted;
-
-# ::Dwarn \%sources_deps;
-
-# my @test_sources = @test_sorted;
-# my @test_output;
-
-
-
-# while ( @test_sources ) {
-# my $source = shift @test_sources;
-# ::Dwarn "checking: $source";
-# my $deps = keys $sources_deps{ $source };
-# if ( $deps ) {
-# push @test_sources, $source;
-# ::Dwarn "pushing: $source";
-# } else {
-# for ( keys %sources_deps ) {
-# delete $sources_deps{ $_ }->{ $source };
-# ::Dwarn "deleting: $source from $_";
-# }
-# push @test_output, $source;
-# ::Dwarn "Adding $source to output";
-# }
-# }
-
-# ::Dwarn \@test_output;
-
- }
- my @sorted_source_names;
- for my $source ( $schema->sources ) {
- next unless $source; # somehow theres an undef one
- my $table = $schema->source( $source )->name;
- $sorted_source_names[ $table_order{ $table } ] = $source;
- }
- ::Dwarn "Sorted Source Names\n";
- ::Dwarn \@sorted_source_names;
+ my @sorted_source_names = $self->_get_sorted_sources( $schema );
foreach my $source (@sorted_source_names) {
$self->msg("- adding " . $source);
my $rs = $schema->resultset($source);
return 1;
}
+# the overall logic is modified from SQL::Translator::Parser::DBIx::Class->parse
+sub _get_sorted_sources {
+ my ( $self, $dbicschema ) = @_;
+
+
+ my %table_monikers = map { $_ => 1 } $dbicschema->sources;
+
+ my %tables;
+ foreach my $moniker (sort keys %table_monikers) {
+ my $source = $dbicschema->source($moniker);
+
+ my $table_name = $source->name;
+ my @primary = $source->primary_columns;
+ my @rels = $source->relationships();
+
+ my %created_FK_rels;
+ foreach my $rel (sort @rels) {
+ my $rel_info = $source->relationship_info($rel);
+
+ # Ignore any rel cond that isn't a straight hash
+ next unless ref $rel_info->{cond} eq 'HASH';
+
+ my @keys = map {$rel_info->{cond}->{$_} =~ /^\w+\.(\w+)$/} keys(%{$rel_info->{cond}});
+
+ # determine if this relationship is a self.fk => foreign.pk (i.e. belongs_to)
+ my $fk_constraint;
+ if ( exists $rel_info->{attrs}{is_foreign_key_constraint} ) {
+ $fk_constraint = $rel_info->{attrs}{is_foreign_key_constraint};
+ } elsif ( $rel_info->{attrs}{accessor}
+ && $rel_info->{attrs}{accessor} eq 'multi' ) {
+ $fk_constraint = 0;
+ } else {
+ $fk_constraint = not $source->_compare_relationship_keys(\@keys, \@primary);
+ }
+
+ # Dont add a relation if its not constraining
+ next unless $fk_constraint;
+
+ my $rel_table = $source->related_source($rel)->source_name;
+ # Make sure we don't create the same relation twice
+ my $key_test = join("\x00", sort @keys);
+ next if $created_FK_rels{$rel_table}->{$key_test};
+
+ if (scalar(@keys)) {
+ $created_FK_rels{$rel_table}->{$key_test} = 1;
+
+ # calculate dependencies: do not consider deferrable constraints and
+ # self-references for dependency calculations
+ if (! $rel_info->{attrs}{is_deferrable} and $rel_table ne $table_name) {
+ $tables{$moniker}{$rel_table}++;
+ }
+ }
+ }
+ $tables{$moniker} = {} unless exists $tables{$moniker};
+ }
+
+ # resolve entire dep tree
+ my $dependencies = {
+ map { $_ => _resolve_deps ($_, \%tables) } (keys %tables)
+ };
+
+ # return the sorted result
+ return sort {
+ keys %{$dependencies->{$a} || {} } <=> keys %{ $dependencies->{$b} || {} }
+ ||
+ $a cmp $b
+ } (keys %tables);
+}
+
+sub _resolve_deps {
+ my ( $question, $answers, $seen ) = @_;
+ my $ret = {};
+ $seen ||= {};
+
+ my %seen = map { $_ => $seen->{$_} + 1 } ( keys %$seen );
+ $seen{$question} = 1;
+
+ for my $dep (keys %{ $answers->{$question} }) {
+ return {} if $seen->{$dep};
+ my $subdeps = _resolve_deps( $dep, $answers, \%seen );
+ ::Dwarn $subdeps if $dep eq 'downloads';
+ $ret->{$_} += $subdeps->{$_} for ( keys %$subdeps );
+ ++$ret->{$dep};
+ }
+ return $ret;
+}
+
sub do_post_ddl {
my ($self, $params) = @_;