TagIndex.pm 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. package Trog::SQLite::TagIndex;
  2. use strict;
  3. use warnings;
  4. no warnings 'experimental';
  5. use feature qw{signatures};
  6. use List::Util qw{uniq};
  7. use Trog::SQLite;
  8. =head1 Trog::SQLite::TagIndex
  9. An SQLite3 index of posts by tag and date.
  10. Used to speed up the flat-file data model.
  11. Also used to retrieve cached routes from posts.
  12. =head1 FUNCTIONS
  13. =cut
  14. sub posts_for_tags (@tags) {
  15. my $dbh = _dbh();
  16. my $clause = @tags ? "WHERE tag IN (".join(',' ,(map {'?'} @tags)).")" : '';
  17. my $rows = $dbh->selectall_arrayref("SELECT DISTINCT id FROM posts $clause ORDER BY created DESC",{ Slice => {} }, @tags);
  18. return () unless ref $rows eq 'ARRAY' && @$rows;
  19. return map { $_->{id} } @$rows;
  20. }
  21. sub routes {
  22. my $dbh = _dbh();
  23. my $rows = $dbh->selectall_arrayref("SELECT route, method, callback FROM all_routes",{ Slice => {} });
  24. return () unless ref $rows eq 'ARRAY' && @$rows;
  25. my %routes = map { $_->{route} => { method => $_->{method}, callback => $_->{callback} } } @$rows;
  26. return %routes;
  27. }
  28. sub add_post ($post,$data_obj) {
  29. my $dbh = _dbh();
  30. build_routes($data_obj,[$post]);
  31. return build_index($data_obj,[$post]);
  32. }
  33. sub remove_post ($post) {
  34. my $dbh = _dbh();
  35. $dbh->do("DELETE FROM routes WHERE route=?", undef, $post->{local_href});
  36. return $dbh->do("DELETE FROM posts_index WHERE post_id=?", undef, $post->{id});
  37. }
  38. sub build_index($data_obj,$posts=[]) {
  39. my $dbh = _dbh();
  40. $posts = $data_obj->read({ limit => 0, acls => ['admin'] }) unless @$posts;
  41. my @tags = uniq map { @{$_->{tags}} } @$posts;
  42. Trog::SQLite::bulk_insert($dbh,'tag', ['name'], 'IGNORE', @tags);
  43. my $t = $dbh->selectall_hashref("SELECT id,name FROM tag", 'name');
  44. foreach my $k (keys(%$t)) { $t->{$k} = $t->{$k}->{id} };
  45. Trog::SQLite::bulk_insert($dbh,'posts_index',[qw{post_id post_time tag_id}], 'IGNORE', map {
  46. my $subj = $_;
  47. map { ( $subj->{id}, $subj->{created}, $t->{$_} ) } @{$subj->{tags}}
  48. } @$posts );
  49. }
  50. # It is important we use get() instead of read() because of incomplete data.
  51. sub build_routes($data_obj,$posts=[]) {
  52. my $dbh = _dbh();
  53. @$posts = $data_obj->get( limit => 0, acls => ['admin'] ) unless @$posts;
  54. # Ensure the callbacks we need are installed
  55. Trog::SQLite::bulk_insert($dbh,'callbacks', [qw{callback}], 'IGNORE', (uniq map { $_->{callback} } @$posts) );
  56. my $m = $dbh->selectall_hashref("SELECT id, method FROM methods", 'method');
  57. foreach my $k (keys(%$m)) { $m->{$k} = $m->{$k}->{id} };
  58. my $c = $dbh->selectall_hashref("SELECT id, callback FROM callbacks", 'callback');
  59. foreach my $k (keys(%$c)) { $c->{$k} = $c->{$k}->{id} };
  60. @$posts = map {
  61. $_->{method_id} = $m->{$_->{method}};
  62. $_->{callback_id} = $c->{$_->{callback}};
  63. $_
  64. } @$posts;
  65. my @routes = map { ($_->{local_href}, $_->{method_id}, $_->{callback_id} ) } @$posts;
  66. Trog::SQLite::bulk_insert($dbh,'routes', [qw{route method_id callback_id}], 'IGNORE', @routes);
  67. }
  68. # Ensure the db schema is OK, and give us a handle
  69. sub _dbh {
  70. my $file = 'schema/flatfile.schema';
  71. my $dbname = "data/posts.db";
  72. return Trog::SQLite::dbh($file,$dbname);
  73. }
  74. 1;