summaryrefslogtreecommitdiff
path: root/lib/AniDB/Datastore.pm
blob: 41602e64a61d22be8bca1680dad53b78fa24c972 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
package AniDB::Datastore; 
use 5.024;
use experimental 'signatures';
use Moo;
use Path::Tiny;
use Try::Tiny;
use JSON::MaybeXS qw(encode_json decode_json);
use namespace::clean;
 
has database => ( is => 'ro'required => 1 );
has dbh => ( is => 'ro'lazy => 1 );
 
sub _build_dbh($self) {
    require DBI;
    return DBI->connect(
        'dbi:SQLite:dbname='.$self->database,
        '''',
        {
            AutoCommit => 1,
            RaiseError => 1,
            PrintError => 0,
        },
    );
}
 
sub BUILD($self) {
    try {
        $self->dbh->selectall_arrayref('SELECT * FROM path_info LIMIT 1');
    } catch {
        if (/\bno such table\b/) {
            my @sql = do { local $/ = ";\n\n"; <DATA> };
            $self->dbh->do($_for @sql;
        }
        else {
            die $_;
        }
    };
}
 
sub has_changed($self,$path,$stat) {
    my $path_info = $self->path_info_for($path);
    # if we don't know about the file, it's definitely changed! 
    return 1 unless $path_info;
 
    return (
        $path_info->{size} == $stat->size
            && $path_info->{mtime} == $stat->mtime
        );
}
 
sub rename($self,$path,$new_path) {
    $self->dbh->do(
        q{UPDATE path_info SET name=? WHERE name=?},
        $path->stringify,$new_path->stringify,
    );
}
 
sub full_info_for($self,$path) {
    my $path_info = $self->path_info_for($path);
    my $episode_info = $self->episode_info_for(
        $path_info,
    );
    my $anime_info = $self->anime_info_for(
        $episode_info,
    );
    return {
        path => $path_info,
        episode => $episode_info,
        anime => $anime_info,
    };
}
 
sub path_info_for($self,$path) {
    my $ret = $self->dbh->selectall_arrayref(
        qr{SELECT * FROM path_info WHERE name=?},
        Slice => {} },
        $path->stringify,
    );
    return $ret->[0];
}
 
sub update_path_info($self,$path,$path_info) {
    my @binds = (@{$path_info}{qw(size mtime hash)}, $path->stringify);
    return $self->dbh->do(
        qr{UPDATE path_info SET size=?, mtime=?, hash=? WHERE name=?},
        {},
        @binds,
    or $self->dbh->do(
        qr{INSERT INTO path_info(size,mtime,hash,name) VALUES (?,?,?,?)},
        {},
        @binds,
    );
}
 
sub episode_info_for($self,$args) {
    my $ret = $self->dbh->selectall_arrayref(
        qr{SELECT json FROM episode_info WHERE hash=? AND size=?},
        { },
        @{$args}{qw(hash size)},
    );
    return unless $ret && $ret->[0];
    return decode_json($ret->[0][0]);
}
 
sub update_episode_info($self,$path_info$episode_info) {
    my $json = encode_json($episode_info);
    my @binds = ($json, @{$path_info}{qw(size hash)});
    return $self->dbh->do(
        qr{UPDATE episode_info SET json=? WHERE size=? AND hash=?},
        {},
        @binds,
    or $self->dbh->do(
        qr{INSERT INTO episode_info(json,size,hash) VALUES (?,?,?)},
        {},
        @binds,
    );
}
 
sub anime_info_for($self,$args) {
    my $ret = $self->dbh->selectall_arrayref(
        qr{SELECT json FROM anime_info WHERE aid=?},
        { },
        @{$args}{qw(aid)},
    );
    return unless $ret && $ret->[0];
    return decode_json($ret->[0][0]);
}
 
sub update_anime_info($self,$episode_info$anime_info) {
    my $json = encode_json($anime_info);
    my @binds = ($json$episode_info->{eid});
    return $self->dbh->do(
        qr{UPDATE anime_info SET json=? WHERE eid=?},
        {},
        @binds,
    or $self->dbh->do(
        qr{INSERT INTO anime_info(json,eid) VALUES (?,?)},
        {},
        @binds,
    );
}
 
1;
 
__DATA__
CREATE TABLE path_info (
    name TEXT PRIMARY KEY,
    mtime INT NOT NULL,
    size INT NOT NULL,
    hash TEXT NOT NULL
);
 
CREATE TABLE episode_info (
    size INT NOT NULL,
    hash TEXT NOT NULL,
    json TEST NOT NULL,
    PRIMARY KEY (size,hash)
);
 
CREATE TABLE anime_info (
    eid INT PRIMARY KEY,
    json TEST NOT NULL
);