App-DrivePlayer

 view release on metacpan or  search on metacpan

lib/App/DrivePlayer/DB.pm  view on Meta::CPAN

}

sub all_scan_folders {
    my ($self) = @_;
    return map { _row_to_hash($_) }
        $self->_rs('ScanFolder')->search({}, { order_by => 'name' })->all;
}

sub delete_scan_folder {
    my ($self, $drive_id) = @_;
    # cascade_delete on the has_many relationship removes child folders+tracks
    my $row = $self->_rs('ScanFolder')->find({ drive_id => $drive_id });
    $row->delete if $row;
}

# ---------- folders ----------

sub upsert_folder {
    my ($self, %f) = @_;
    my $row = $self->_rs('Folder')->update_or_create(
        {

lib/App/DrivePlayer/DB.pm  view on Meta::CPAN

            album  => undef,
            album  => '',
            year   => undef,
        ],
    })->update_all({ metadata_fetched => 0 });
}

sub clear_scan_folder_tracks {
    my ($self, $scan_folder_id) = @_;
    # Collect folder IDs, then bulk-delete tracks and folders.
    # (Relies on foreign_keys=ON cascade for correctness; explicit here for speed.)
    my @folder_ids = $self->_rs('Folder')
        ->search({ scan_folder_id => $scan_folder_id })
        ->get_column('id')->all;

    if (@folder_ids) {
        $self->_rs('Track')->search({ folder_id => \@folder_ids })->delete;
    }
    $self->_rs('Folder')->search({ scan_folder_id => $scan_folder_id })->delete;
}

lib/App/DrivePlayer/DB.pm  view on Meta::CPAN


=head1 SYNOPSIS

  use App::DrivePlayer::DB;

  my $db = App::DrivePlayer::DB->new(path => '/path/to/music.db');

  # Scan-folder management
  my $sf = $db->upsert_scan_folder($drive_id, 'My Music');
  my @sfs = $db->all_scan_folders;
  $db->delete_scan_folder($drive_id);   # cascades to folders + tracks

  # Track queries
  my @tracks = $db->all_tracks;
  my @tracks = $db->search_tracks('zeppelin');
  my @tracks = $db->tracks_by_artist('Queen');
  my @tracks = $db->tracks_by_album('Led Zeppelin IV');
  my $track  = $db->get_track_by_drive_id($drive_id);
  my $track  = $db->get_track($id);

  my @artists = $db->all_artists;

lib/App/DrivePlayer/DB.pm  view on Meta::CPAN

=head2 all_scan_folders

  my @hashrefs = $db->all_scan_folders;

Returns all scan folders ordered alphabetically by name.

=head2 delete_scan_folder

  $db->delete_scan_folder($drive_id);

Deletes the scan folder and, via cascaded foreign-key constraints, all of
its child folders and tracks.

=head2 upsert_folder

  my $hashref = $db->upsert_folder(%fields);

Insert or update a subfolder record.  Required keys: C<drive_id>, C<name>,
C<path>, C<scan_folder_id>.  Optional: C<parent_drive_id>.

=head2 get_folder_by_drive_id

lib/App/DrivePlayer/Schema/Result/Folder.pm  view on Meta::CPAN

__PACKAGE__->add_unique_constraint( unique_drive_id => ['drive_id'] );

__PACKAGE__->belongs_to(
    scan_folder => 'App::DrivePlayer::Schema::Result::ScanFolder',
    'scan_folder_id',
);

__PACKAGE__->has_many(
    tracks => 'App::DrivePlayer::Schema::Result::Track',
    'folder_id',
    { cascade_delete => 1 },
);

sub sqlt_deploy_hook {
    my ($self, $sqlt_table) = @_;
    $sqlt_table->add_index( name => 'idx_folders_scan_folder', fields => ['scan_folder_id'] );
}

1;

__END__

=head1 NAME

App::DrivePlayer::Schema::Result::Folder - DBIx::Class result for the folders table

=head1 DESCRIPTION

Represents a Drive folder (root or subfolder) encountered during a scan.
Belongs to a L<App::DrivePlayer::Schema::Result::ScanFolder> and has many
L<App::DrivePlayer::Schema::Result::Track> children (cascade-deleted with the
folder).

Columns: C<id>, C<drive_id>, C<name>, C<parent_drive_id>, C<path>,
C<scan_folder_id>.

=cut

lib/App/DrivePlayer/Schema/Result/ScanFolder.pm  view on Meta::CPAN

        is_nullable => 0,
    },
);

__PACKAGE__->set_primary_key('id');
__PACKAGE__->add_unique_constraint( unique_drive_id => ['drive_id'] );

__PACKAGE__->has_many(
    folders => 'App::DrivePlayer::Schema::Result::Folder',
    'scan_folder_id',
    { cascade_delete => 1 },
);

1;

__END__

=head1 NAME

App::DrivePlayer::Schema::Result::ScanFolder - DBIx::Class result for the scan_folders table

=head1 DESCRIPTION

Represents a top-level Google Drive folder that the user has configured for
scanning.  Has many L<App::DrivePlayer::Schema::Result::Folder> children
(cascade-deleted when the scan folder is removed).

Columns: C<id>, C<drive_id>, C<name>.

=cut

t/unit/Test/DrivePlayer/DB.pm  view on Meta::CPAN


    $self->db->upsert_scan_folder('id_z', 'Zzz Folder');
    $self->db->upsert_scan_folder('id_a', 'Aaa Folder');
    $self->db->upsert_scan_folder('id_m', 'Mmm Folder');

    my @folders = $self->db->all_scan_folders;
    is scalar @folders, 3, 'all_scan_folders returns all rows';
    is $folders[0]{name}, 'Aaa Folder', 'scan_folders ordered by name';
}

sub delete_scan_folder_cascade : Tests(3) {
    my ($self) = @_;

    my $sf  = $self->db->upsert_scan_folder(FAKE_FOLDER_ID, FAKE_FOLDER_NAME);
    my $fld = $self->db->upsert_folder(sample_folder(scan_folder_id => $sf->{id}));
    $self->db->upsert_track(sample_track(folder_id => $fld->{id}));

    is $self->db->track_count, 1, 'track exists before delete';
    $self->db->delete_scan_folder(FAKE_FOLDER_ID);
    is $self->db->schema->resultset('ScanFolder')->count, 0, 'scan_folder deleted';
    is $self->db->track_count, 0, 'tracks cascade-deleted';
}

# ---- folders ----

sub upsert_folder_create : Tests(5) {
    my ($self) = @_;

    my $sf  = $self->db->upsert_scan_folder(FAKE_FOLDER_ID, FAKE_FOLDER_NAME);
    my $fld = $self->db->upsert_folder(sample_folder(scan_folder_id => $sf->{id}));



( run in 0.940 second using v1.01-cache-2.11-cpan-e93a5daba3e )