make the stemma a property of the tradition
[scpubgit/stemmatology.git] / lib / Text / Tradition / Directory.pm
CommitLineData
8d9a1cd8 1package Text::Tradition::Directory;
2
3use strict;
4use warnings;
5use Moose;
6use KiokuDB::TypeMap;
7use KiokuDB::TypeMap::Entry::Naive;
8
9extends 'KiokuX::Model';
10
12523041 11=head1 NAME
12
13Text::Tradition::Directory - a KiokuDB interface for storing and retrieving traditions
14
15=head1 SYNOPSIS
16
17 use Text::Tradition::Directory;
18 my $d = Text::Tradition::Directory->new(
19 'dsn' => 'dbi:SQLite:mytraditions.db',
20 'extra_args' => { 'create' => 1 },
21 );
22
23 my $tradition = Text::Tradition->new( @args );
56cf65bd 24 my $stemma = $tradition->add_stemma( $dotfile );
12523041 25 $d->save_tradition( $tradition );
12523041 26
27 foreach my $id ( $d->traditions ) {
28 print $d->tradition( $id )->name;
12523041 29 }
30
31=head1 DESCRIPTION
32
33Text::Tradition::Directory is an interface for storing and retrieving text traditions and all their data, including an associated stemma hypothesis. It is an instantiation of a KiokuDB::Model, storing traditions and associated stemmas by UUID.
34
35=head1 METHODS
36
37=head2 new
38
56cf65bd 39Returns a Directory object.
12523041 40
41=head2 tradition_ids
42
43Returns the ID of all traditions in the database.
44
45=head2 tradition( $id )
46
47Returns the Text::Tradition object of the given ID.
48
56cf65bd 49=head2 save( $tradition )
12523041 50
56cf65bd 51Writes the given tradition to the database, returning its ID.
12523041 52
53=begin testing
54
56cf65bd 55use Test::Warn;
12523041 56use File::Temp;
57use Text::Tradition;
12523041 58use_ok 'Text::Tradition::Directory';
59
60my $fh = File::Temp->new();
61my $file = $fh->filename;
62$fh->close;
63my $dsn = "dbi:SQLite:dbname=$file";
64
65my $d = Text::Tradition::Directory->new( 'dsn' => $dsn,
56cf65bd 66 'extra_args' => { 'create' => 1 } );
12523041 67is( ref $d, 'Text::Tradition::Directory', "Got directory object" );
68
56cf65bd 69my $scope = $d->new_scope;
12523041 70my $t = Text::Tradition->new(
56cf65bd 71 'name' => 'inline',
72 'input' => 'Tabular',
73 'file' => 't/data/simple.txt',
74 );
75my $uuid = $d->save( $t );
12523041 76ok( $uuid, "Saved test tradition" );
77
56cf65bd 78my $s = $t->add_stemma( 't/data/simple.dot' );
79ok( $d->save( $t ), "Updated tradition with stemma" );
12523041 80is( $d->tradition( $uuid ), $t, "Correct tradition returned for id" );
56cf65bd 81is( $d->tradition( $uuid )->stemma, $s, "...and it has the correct stemma" );
82warning_like { $d->save( $s ) } qr/not a Text::Tradition/, "Correctly failed to save stemma directly";
12523041 83
12523041 84my $e = Text::Tradition::Directory->new( 'dsn' => $dsn );
56cf65bd 85$scope = $e->new_scope;
86is( scalar $e->tradition_ids, 1, "Directory index has our tradition" );
12523041 87my $te = $e->tradition( $uuid );
56cf65bd 88is( $te->name, $t->name, "Retrieved the tradition from a new directory" );
89my $sid = $e->object_to_id( $te->stemma );
90warning_like { $e->tradition( $sid ) } qr/not a Text::Tradition/, "Did not retrieve stemma via tradition call";
91warning_like { $e->delete( $sid ) } qr/Cannot directly delete non-Tradition object/, "Stemma object not deleted from DB";
92$e->delete( $uuid );
93ok( !$e->exists( $uuid ), "Object is deleted from DB" );
94is( scalar $e->tradition_ids, 0, "Object is deleted from index" );
95
12523041 96
97=end testing
98
99=cut
100
12523041 101has +typemap => (
8d9a1cd8 102 is => 'rw',
103 isa => 'KiokuDB::TypeMap',
104 default => sub {
105 KiokuDB::TypeMap->new(
106 isa_entries => {
8d9a1cd8 107 "Graph" => KiokuDB::TypeMap::Entry::Naive->new,
108 "Graph::AdjacencyMap" => KiokuDB::TypeMap::Entry::Naive->new,
109 }
110 );
111 },
112);
113
56cf65bd 114has tradition_index => (
115 traits => ['Hash'],
116 isa => 'HashRef[Str]',
117 handles => {
118 add_index => 'set',
119 del_index => 'delete',
120 name => 'get',
121 tradition_ids => 'keys',
122 },
123 default => sub { {} },
124 );
8d9a1cd8 125
56cf65bd 126# Populate the tradition index.
8d9a1cd8 127sub BUILD {
128 my $self = shift;
12523041 129 my $stream = $self->root_set;
12523041 130 until( $stream->is_done ) {
131 foreach my $obj ( $stream->items ) {
132 my $uuid = $self->object_to_id( $obj );
133 if( ref( $obj ) eq 'Text::Tradition' ) {
56cf65bd 134 $self->add_index( $uuid => $obj->name );
12523041 135 } else {
56cf65bd 136 warn "Found root object in DB that is not a Text::Tradition";
8d9a1cd8 137 }
138 }
12523041 139 }
56cf65bd 140 return $self;
8d9a1cd8 141}
12523041 142
56cf65bd 143# If a tradition is deleted, remove it from the index.
144around delete => sub {
145 my $orig = shift;
146 my $self = shift;
147 warn "Only the first object will be deleted" if @_ > 1;
148 my $arg = shift;
149 my $obj = ref( $arg ) ? $arg : $self->lookup( $arg );
150 my $id = ref( $arg ) ? $self->object_to_id( $arg ) : $arg;
151 unless( ref $obj eq 'Text::Tradition' ) {
152 warn "Cannot directly delete non-Tradition object $obj";
153 return;
154 }
155 $self->$orig( $arg );
156 $self->del_index( $id );
157};
158
159sub save {
160 my( $self, $obj ) = @_;
161 unless( ref( $obj ) eq 'Text::Tradition' ) {
162 warn "Object $obj is not a Text::Tradition";
163 return;
12523041 164 }
56cf65bd 165 my $uuid = $self->store( $obj );
166 $self->add_index( $uuid => $obj->name ) if $uuid;
12523041 167 return $uuid;
168}
169
56cf65bd 170
171sub tradition {
172 my( $self, $id ) = @_;
173 my $obj = $self->lookup( $id );
174 unless( ref( $obj ) eq 'Text::Tradition' ) {
175 warn "Retrieved object is a " . ref( $obj ) . ", not a Text::Tradition";
176 return;
12523041 177 }
56cf65bd 178 return $obj;
12523041 179}
8d9a1cd8 180
1811;
12523041 182
8d9a1cd8 183