diff options
-rw-r--r-- | lib/VNDB/DB/Misc.pm | 73 | ||||
-rw-r--r-- | lib/VNDB/DB/VN.pm | 55 | ||||
-rw-r--r-- | lib/VNDB/Handler/VNEdit.pm | 24 | ||||
-rw-r--r-- | util/updates/update_2.10.sql | 110 |
4 files changed, 160 insertions, 102 deletions
diff --git a/lib/VNDB/DB/Misc.pm b/lib/VNDB/DB/Misc.pm index a33ade8a..b1f79705 100644 --- a/lib/VNDB/DB/Misc.pm +++ b/lib/VNDB/DB/Misc.pm @@ -6,7 +6,7 @@ use warnings; use Exporter 'import'; our @EXPORT = qw| - dbStats dbItemEdit dbItemAdd dbRevisionGet dbItemMod dbRandomQuote + dbStats dbItemEdit dbRevisionGet dbItemMod dbRandomQuote |; @@ -20,67 +20,24 @@ sub dbStats { } -# Inserts a new revision and updates the item to point to this revision -# Arguments: type [vrp], item ID, %options->{ editsum uid + db[item]RevisionInsert } -# Returns: local revision, global revision +# Inserts a new revision into the database +# Arguments: type [vrp], revision id, %options->{ editsum uid + db[item]RevisionInsert } +# revision id = changes.id of the revision this edit is based on, undef to create a new DB item +# Returns: { iid, cid, rev } sub dbItemEdit { - my($self, $type, $iid, %o) = @_; - - my $table = {qw|v vn r releases p producers|}->{$type}; - - my $c = $self->dbRow(q| - INSERT INTO changes (type, requester, ip, comments, rev) - VALUES (?, ?, ?, ?, ( - SELECT c.rev+1 - FROM changes c - JOIN !s_rev ir ON ir.id = c.id - WHERE ir.!sid = ? - ORDER BY c.id DESC - LIMIT 1 - )) - RETURNING id, rev|, - $type, $o{uid}||$self->authInfo->{id}, $self->reqIP, $o{editsum}, - $table, $type, $iid - ); - - $self->dbVNRevisionInsert( $c->{id}, $iid, \%o) if $type eq 'v'; - $self->dbProducerRevisionInsert($c->{id}, $iid, \%o) if $type eq 'p'; - $self->dbReleaseRevisionInsert( $c->{id}, $iid, \%o) if $type eq 'r'; - - $self->dbExec(q|UPDATE !s SET latest = ? WHERE id = ?|, $table, $c->{id}, $iid); - return ($c->{rev}, $c->{id}); -} - - -# Comparable to dbItemEdit(), but creates a new item with a corresponding revision. -# Argumments: type [vrp] + same option hash as dbItemEdit() -# Returns: item id, global revision -sub dbItemAdd { - my($self, $type, %o) = @_; - - my $table = {qw|v vn r releases p producers|}->{$type}; - - my $cid = $self->dbRow(q| - INSERT INTO changes (type, requester, ip, comments) - VALUES (?, ?, ?, ?) - RETURNING id|, - $type, $o{uid}||$self->authInfo->{id}, $self->reqIP, $o{editsum} - )->{id}; - - my $iid = $self->dbRow(q| - INSERT INTO !s (latest) - VALUES (0) - RETURNING id|, - $table - )->{id}; + my($self, $type, $oid, %o) = @_; - $self->dbVNRevisionInsert( $cid, $iid, \%o) if $type eq 'v'; - $self->dbProducerRevisionInsert($cid, $iid, \%o) if $type eq 'p'; - $self->dbReleaseRevisionInsert( $cid, $iid, \%o) if $type eq 'r'; + die "Only VNs are supported at this moment!" if $type ne 'v'; + $self->dbExec('SELECT edit_!s_init(?)', + {qw|v vn r releases p producers|}->{$type}, $oid); + $self->dbExec('UPDATE edit_revision SET requester = ?, ip = ?, comments = ?', + $o{uid}||$self->authInfo->{id}, $self->reqIP, $o{editsum}); - $self->dbExec(q|UPDATE !s SET latest = ? WHERE id = ?|, $table, $cid, $iid); + $self->dbVNRevisionInsert( \%o) if $type eq 'v'; + #$self->dbProducerRevisionInsert(\%o) if $type eq 'p'; + #$self->dbReleaseRevisionInsert( \%o) if $type eq 'r'; - return ($iid, $cid); + return $self->dbRow('SELECT * FROM edit_vn_commit()'); } diff --git a/lib/VNDB/DB/VN.pm b/lib/VNDB/DB/VN.pm index 2c11d78e..b8cc0c42 100644 --- a/lib/VNDB/DB/VN.pm +++ b/lib/VNDB/DB/VN.pm @@ -171,37 +171,38 @@ sub dbVNGet { } -# inserts a visual novel revision, used from dbItemEdit() or dbItemAdd() -# Arguments: global revision, item id, { columns in producers_rev + anime + relations + screenshots } +# Updates the edit_* tables, used from dbItemEdit() +# Arguments: { columns in producers_rev + anime + relations + screenshots } # screenshots = [ [ scrid, nsfw, rid ], .. ] # relations = [ [ rel, vid ], .. ] # anime = [ aid, .. ] sub dbVNRevisionInsert { - my($self, $cid, $vid, $o) = @_; - - $o->{img_nsfw} = $o->{img_nsfw}?1:0; - $self->dbExec(q| - INSERT INTO vn_rev (id, vid, title, original, "desc", alias, image, img_nsfw, length, l_wp, l_encubed, l_renai, l_vnn) - VALUES (!l)|, - [ $cid, $vid, @$o{qw|title original desc alias image img_nsfw length l_wp l_encubed l_renai l_vnn|} ]); - - $self->dbExec(q| - INSERT INTO vn_screenshots (vid, scr, nsfw, rid) - VALUES (?, ?, ?, ?)|, - $cid, $_->[0], $_->[1]?1:0, $_->[2] - ) for (@{$o->{screenshots}}); - - $self->dbExec(q| - INSERT INTO vn_relations (vid1, vid2, relation) - VALUES (?, ?, ?)|, - $cid, $_->[1], $_->[0] - ) for (@{$o->{relations}}); - - $self->dbExec(q| - INSERT INTO vn_anime (vid, aid) - VALUES (?, ?)|, - $cid, $_ - ) for (@{$o->{anime}}); + my($self, $o) = @_; + + $o->{img_nsfw} = $o->{img_nsfw}?1:0 if exists $o->{img_nsfw}; + my %set = map exists($o->{$_}) ? (qq|"$_" = ?| => $o->{$_}) : (), + qw|title original desc alias image img_nsfw length l_wp l_encubed l_renai l_vnn|; + $self->dbExec('UPDATE edit_vn !H', \%set) if keys %set; + + if($o->{screenshots}) { + $self->dbExec('DELETE FROM edit_vn_screenshots'); + my $q = join ',', map '(?, ?, ?)', @{$o->{screenshots}}; + my @val = map +($_->[0], $_->[1]?1:0, $_->[2]), @{$o->{screenshots}}; + $self->dbExec("INSERT INTO edit_vn_screenshots (scr, nsfw, rid) VALUES $q", @val) if @val; + } + + if($o->{relations}) { + $self->dbExec('DELETE FROM edit_vn_relations'); + my $q = join ',', map '(?, ?)', @{$o->{relations}}; + my @val = map +($_->[1], $_->[0]), @{$o->{relations}}; + $self->dbExec("INSERT INTO edit_vn_relations (vid, relation) VALUES $q", @val) if @val; + } + + if($o->{anime}) { + $self->dbExec('DELETE FROM edit_vn_anime'); + my $q = join ',', map '(?)', @{$o->{anime}}; + $self->dbExec("INSERT INTO edit_vn_anime (aid) VALUES $q", @{$o->{anime}}) if @{$o->{anime}}; + } } diff --git a/lib/VNDB/Handler/VNEdit.pm b/lib/VNDB/Handler/VNEdit.pm index 21d92e8e..d5dfd878 100644 --- a/lib/VNDB/Handler/VNEdit.pm +++ b/lib/VNDB/Handler/VNEdit.pm @@ -69,8 +69,8 @@ sub edit { return $self->resRedirect("/v$vid", 'post') if $vid && !$self->reqUploadFileName('img') && !grep $frm->{$_} ne $b4{$_}, keys %b4; - # execute the edit/add - my %args = ( + # perform the edit/add + my $nrev = $self->dbItemEdit(v => $vid ? $v->{cid} : undef, (map { $_ => $frm->{$_} } qw|title original alias desc length l_wp l_encubed l_renai l_vnn editsum img_nsfw|), anime => [ keys %$anime ], relations => $relations, @@ -78,18 +78,14 @@ sub edit { screenshots => $screenshots, ); - my($nvid, $nrev) = ($vid, 1); - ($nrev) = $self->dbItemEdit(v => $vid, %args) if $vid; - ($nvid) = $self->dbItemAdd(v => %args) if !$vid; - # update reverse relations & relation graph if(!$vid && $#$relations >= 0 || $vid && $frm->{vnrelations} ne $b4{vnrelations}) { my %old = $vid ? (map { $_->{id} => $_->{relation} } @{$v->{relations}}) : (); my %new = map { $_->[1] => $_->[0] } @$relations; - _updreverse($self, \%old, \%new, $nvid, $nrev); + _updreverse($self, \%old, \%new, $nrev->{iid}, $nrev->{rev}); } - return $self->resRedirect("/v$nvid.$nrev", 'post'); + return $self->resRedirect("/v$nrev->{iid}.$nrev->{rev}", 'post'); } } @@ -240,8 +236,6 @@ sub _form { # %old,%new -> { vid2 => relation, .. } # from the perspective of vid # rev is of the related edit -# !IMPORTANT!: Don't forget to update this function when -# adding/removing fields to/from VN entries! sub _updreverse { my($self, $old, $new, $vid, $rev) = @_; my %upd; @@ -254,21 +248,17 @@ sub _updreverse { $upd{$_} = $self->{vn_relations}{$$new{$_}}[1]; } } - return if !keys %upd; # edit all related VNs for my $i (keys %upd) { - my $r = $self->dbVNGet(id => $i, what => 'extended relations anime screenshots')->[0]; + my $r = $self->dbVNGet(id => $i, what => 'relations')->[0]; my @newrel = map $_->{id} != $vid ? [ $_->{relation}, $_->{id} ] : (), @{$r->{relations}}; push @newrel, [ $upd{$i}, $vid ] if $upd{$i}; - $self->dbItemEdit(v => $i, + $self->dbItemEdit(v => $r->{cid}, relations => \@newrel, editsum => "Reverse relation update caused by revision v$vid.$rev", - uid => 1, # Multi - hardcoded - anime => [ map $_->{id}, @{$r->{anime}} ], - screenshots => [ map [ $_->{id}, $_->{nsfw}, $_->{rid} ], @{$r->{screenshots}} ], - ( map { $_ => $r->{$_} } qw| title original desc alias img_nsfw length l_wp l_encubed l_renai l_vnn image | ) + uid => 1, # Multi ); } } diff --git a/util/updates/update_2.10.sql b/util/updates/update_2.10.sql index 47a05ac5..d955a77b 100644 --- a/util/updates/update_2.10.sql +++ b/util/updates/update_2.10.sql @@ -190,3 +190,113 @@ UPDATE users SET GROUP BY requester ), 0); + + + +-- revision insertion abstraction +-- IMPORTANT: these functions will need to be updated on each change in the DB structure +-- of the relevant tables + +CREATE TYPE edit_rettype AS (iid integer, cid integer, rev integer); + +-- create temporary table for generic revision info +CREATE OR REPLACE FUNCTION edit_revtable(t dbentry_type, i integer) RETURNS void AS $$ +BEGIN + CREATE TEMPORARY TABLE edit_revision ( + type dbentry_type NOT NULL, + iid integer, + requester integer, + ip inet, + comments text + ); + INSERT INTO edit_revision (type, iid) VALUES (t, i); +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION edit_commit() RETURNS edit_rettype AS $$ +DECLARE + r edit_rettype; + t dbentry_type; + i integer; +BEGIN + SELECT type INTO t FROM edit_revision; + SELECT iid INTO i FROM edit_revision; + -- figure out revision number + IF i IS NULL THEN + r.rev := 1; + ELSE + SELECT c.rev+1 INTO r.rev FROM changes c + LEFT JOIN vn_rev vr ON c.id = vr.id + LEFT JOIN releases_rev rr ON c.id = rr.id + LEFT JOIN producers_rev pr ON c.id = pr.id + WHERE (t = 'v' AND vr.vid = i) + OR (t = 'r' AND rr.rid = i) + OR (t = 'p' AND pr.pid = i) + ORDER BY c.id DESC + LIMIT 1; + END IF; + -- insert change + INSERT INTO changes (type, requester, ip, comments, rev) + SELECT t, requester, ip, comments, r.rev + FROM edit_revision + RETURNING id INTO r.cid; + -- insert DB item + IF i IS NULL THEN + CASE t + WHEN 'v' THEN INSERT INTO vn (latest) VALUES (0) RETURNING id INTO r.iid; + WHEN 'r' THEN INSERT INTO releases (latest) VALUES (0) RETURNING id INTO r.iid; + WHEN 'p' THEN INSERT INTO producers (latest) VALUES (0) RETURNING id INTO r.iid; + END CASE; + ELSE + r.iid := i; + END IF; + RETURN r; +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION edit_vn_init(cid integer) RETURNS void AS $$ +BEGIN + -- create tables, based on existing tables (so that the column types are always synchronised) + CREATE TEMPORARY TABLE edit_vn (LIKE vn_rev INCLUDING DEFAULTS INCLUDING CONSTRAINTS); + ALTER TABLE edit_vn DROP COLUMN id; + ALTER TABLE edit_vn DROP COLUMN vid; + CREATE TEMPORARY TABLE edit_vn_anime (LIKE vn_anime INCLUDING DEFAULTS INCLUDING CONSTRAINTS); + ALTER TABLE edit_vn_anime DROP COLUMN vid; + CREATE TEMPORARY TABLE edit_vn_relations (LIKE vn_relations INCLUDING DEFAULTS INCLUDING CONSTRAINTS); + ALTER TABLE edit_vn_relations DROP COLUMN vid1; + ALTER TABLE edit_vn_relations RENAME COLUMN vid2 TO vid; + CREATE TEMPORARY TABLE edit_vn_screenshots (LIKE vn_screenshots INCLUDING DEFAULTS INCLUDING CONSTRAINTS); + ALTER TABLE edit_vn_screenshots DROP COLUMN vid; + -- new VN, load defaults + IF cid IS NULL THEN + PERFORM edit_revtable('v', NULL); + INSERT INTO edit_vn DEFAULT VALUES; + -- otherwise, load revision + ELSE + PERFORM edit_revtable('v', (SELECT vid FROM vn_rev WHERE id = cid)); + INSERT INTO edit_vn SELECT title, alias, img_nsfw, length, "desc", l_wp, l_vnn, image, l_encubed, l_renai, original FROM vn_rev WHERE id = cid; + INSERT INTO edit_vn_anime SELECT aid FROM vn_anime WHERE vid = cid; + INSERT INTO edit_vn_relations SELECT vid2, relation FROM vn_relations WHERE vid1 = cid; + INSERT INTO edit_vn_screenshots SELECT scr, nsfw, rid FROM vn_screenshots WHERE vid = cid; + END IF; +END; +$$ LANGUAGE plpgsql; + + +CREATE OR REPLACE FUNCTION edit_vn_commit() RETURNS edit_rettype AS $$ +DECLARE + r edit_rettype; +BEGIN + SELECT INTO r * FROM edit_commit(); + INSERT INTO vn_rev SELECT r.cid, r.iid, title, alias, img_nsfw, length, "desc", l_wp, l_vnn, image, l_encubed, l_renai, original FROM edit_vn; + INSERT INTO vn_anime SELECT r.cid, aid FROM edit_vn_anime; + INSERT INTO vn_relations SELECT r.cid, vid, relation FROM edit_vn_relations; + INSERT INTO vn_screenshots SELECT r.cid, scr, nsfw, rid FROM edit_vn_screenshots; + UPDATE vn SET latest = r.cid WHERE id = r.iid; + DROP TABLE edit_revision, edit_vn, edit_vn_anime, edit_vn_relations, edit_vn_screenshots; + RETURN r; +END; +$$ LANGUAGE plpgsql; + |