Toby Inkster avatar Toby Inkster committed bd1d52f Draft

initial blog index work

Comments (0)

Files changed (5)

bin/demiblog4-reindex-blog

+use Demiblog4;
+use Demiblog4::BlogIndexer;
+
+my $app     = Demiblog4::->new;
+my $model   = RDF::Trine::Model::->new( $app->store );
+my $indexer = Demiblog4::BlogIndexer::->new(verbose => !!1);
+
+$indexer->index($model);

lib/Demiblog4/BlogIndexer.pm

+package Demiblog4::BlogIndexer;
+
+use Demiblog4::Sugar
+	-types => -all;
+
+use RDF::Trine;
+use RDF::NS::Trine;
+use DateTime::Format::W3CDTF;
+use constant NS   => RDF::NS::Trine::->new('20120521');
+use constant PRED => RDF::Trine::Node::Resource::->new('http://ontologi.es/demiblog#timestamp');
+use constant W3C  => DateTime::Format::W3CDTF::->new;
+
+has verbose => (
+	is         => read_only,
+	isa        => Bool,
+	default    => false,
+);
+
+has graph_uri => (
+	is         => read_only,
+	isa        => TrineNode | Undef,
+	coerce     => true,
+	lazy_build => true,
+);
+
+sub _build_graph_uri { PRED };
+
+method index ($model)
+{
+	my $verbose   = $self->verbose;
+	my $graph_uri = $self->graph_uri;
+	
+	my $iter = $model->get_statements(undef, NS->rdf_type, NS->rss_item);
+	while (my $st = $iter->next)
+	{
+		my $item = $st->subject;
+		next if $model->count_statements($item, PRED, undef);
+		
+		my ($dt) =
+			grep { defined $_ }
+			map  { eval { W3C->parse_datetime($_->literal_value) } }
+			grep { $_->is_literal }
+			$model->objects_for_predicate_list(
+				$item => (
+					NS->dcterms_issued,
+					NS->dcterms_created,
+					NS->dcterms_date,
+					NS->dc11_date,
+				),
+			);
+		$dt //= DateTime::->now;
+		
+		$dt->set_time_zone('UTC');
+		
+		say "WEBLOG INDEX: $item  -->  ", $dt->strftime('%FT%T%z')
+			if $verbose;
+		
+		$model->add_statement(
+			RDF::Trine::Statement::Quad::->new(
+				$item,
+				PRED,
+				RDF::Trine::Node::Literal::->new($dt),
+				($graph_uri ? $graph_uri : ()),
+			),
+		);
+	}
+}
+

lib/Demiblog4/Context.pm

 
 has data_subject => (
 	is          => read_write,
-	isa         => UriStr,
+	isa         => UriStr | ArrayRef,
 	required    => false,
 );
 

lib/Demiblog4/Resource/BlogIndex.pm

 	-types => -all,
 	-base  => 'Magpie::Resource';
 
+use constant LIMIT => 10;
+
+use Data::Dumper;
+use DateTime;
+use RDF::Query;
+use RDF::Trine;
+
+method _parse_date_from_uri ($uri)
+{
+	my @parts = split '/', $uri;
+	my $offset = 0;
+	if (@parts and $parts[-1] =~ /^p(\d+)/)
+	{
+		$offset = $1 - 1;
+		pop @parts;
+	}
+	my (undef, $y, $m, $d) = @parts;
+	
+	my ($start, $end);
+	my $now = DateTime::->now;
+
+	if ($y)
+	{
+		$start = DateTime::->new(
+			year      => $y,
+			month     => $m || 1,
+			day       => $d || 1,
+			hour      => 0,
+			minute    => 0,
+			second    => 0,
+			time_zone => 'UTC',
+		);
+		
+		if ($d)
+			{ $end = $start->clone->add(days => 1) }
+		elsif ($m)
+			{ $end = $start->clone->add(months => 1) }
+		elsif ($y)
+			{ $end = $start->clone->add(years => 1) }		
+	}
+
+	$start ||= DateTime::->from_epoch(epoch => 0);
+
+	$end ||= $now;
+	$end = $now if $end > $now;
+	
+	return ($start => $end, $offset);
+}
+
+method _item_list ($ctxt, $start, $end, $offset)
+{
+	$offset *= (my $lim = LIMIT);
+	
+	my $query = RDF::Query::->new(<<MESSAGE);
+SELECT ?item ?date
+WHERE {
+	GRAPH ?g {
+		?item <http://ontologi.es/demiblog#timestamp> ?date .
+	}
+	FILTER( ?date > "$start" && ?date < "$end" )
+}
+ORDER BY DESC( STR(?date) )
+LIMIT $lim
+OFFSET $offset
+MESSAGE
+
+	my $result = $query->execute(
+		RDF::Trine::Model::->new( $ctxt->store ),
+	);
+	return map { $_->{item}->uri } $result->get_all;
+}
+
+method _gather_model ($ctxt, @items)
+{
+	my $source = RDF::Trine::Model::->new( $ctxt->store );
+	my $result = RDF::Trine::Model::->new;
+	
+	foreach my $i (@items)
+	{
+		my $iter = $source->get_statements(
+			RDF::Trine::Node::Resource::->new($i),
+			(undef) x 3,
+		);
+		$result->add_iterator($iter);
+	}
+	
+	return $result;
+}
+
+handle GET
+{
+	my ($start, $end, $offset) =
+		$self->_parse_date_from_uri($self->request->path_info);
+
+	my @items = $self->_item_list($ctxt, $start, $end, $offset);
+	my $model = $self->_gather_model($ctxt, @items);
+
+	$ctxt->data($model);
+	$ctxt->data_subject(\@items);
+	$ctxt->data_type("Graph");
+	OK;
+}
+

lib/Demiblog4/Transformer/Graph.pm

 	my $title    =
 		$entitler->title(RDF::Trine::Node::Resource::->new($ctxt->data_subject))
 		// $ctxt->data_subject;
+	
+	my $style = 'Demiblog4::General';
+	$style = 'Demiblog4::SingleResource'
+		if !ref $ctxt->data_subject;
+	$style = 'Demiblog4::BlogIndex'
+		if ref $ctxt->data_subject eq 'ARRAY';
+	
 	my $ser = RDF::RDFa::Generator::->new(
-		style     => 'Demiblog4::SingleResource',
+		style     => $style,
 		subject   => $ctxt->data_subject,
 		entitler  => $entitler,
 		title     => $title,
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.