diff --git a/Succession - Sheet1.csv b/Succession - Sheet1.csv index 3b1272c..5891745 100644 --- a/Succession - Sheet1.csv +++ b/Succession - Sheet1.csv @@ -1,19 +1,21 @@ -ID,Person,Born,Died,Parent,Order -1,Queen Elizabeth II,21/04/1926,,, -2,Prince Charles,14/11/1948,,1,1 -3,Princess Anne,15/08/1950,,1,4 -4,Prince Andrew,19/02/1960,,1,2 -5,Prince Edward,10/03/1964,,1,3 -6,Peter Phillips,15/11/1977,,3,1 -7,Zara Tindall,15/05/1981,,3,2 -8,Prince William,21/06/1982,,2,1 -9,Prince Henry,15/09/1984,,2,2 -10,Princess Beatrice,08/08/1988,,4,1 -11,Princess Eugenie,23/03/1990,,4,2 -12,Lady Louise WIndsor,08/11/2003,,5,2 -13,"James, Viscount Severn",17/12/2007,,5,1 -14,Savannah Phillips,29/12/2010,,6,1 -15,Isla Phillips,29/03/2012,,6,2 -16,Prince George,22/07/2013,,8,1 -17,Mia Tindall,17/01/2014,,3,1 -18,Princess Charlotte,02/05/2015,,8,2 \ No newline at end of file +Person,Born,Died,Parent,Order +King George VI,14/12/1895,6/2/1952,, +Queen Elizabeth II,21/04/1926,,King George VI,1 +Prince Charles,14/11/1948,,Queen Elizabeth II,1 +Princess Anne,15/08/1950,,Queen Elizabeth II,4 +Prince Andrew,19/02/1960,,Queen Elizabeth II,2 +Prince Edward,10/03/1964,,Queen Elizabeth II,3 +Peter Phillips,15/11/1977,,Princess Anne,1 +Zara Tindall,15/05/1981,,Princess Anne,2 +Prince William,21/06/1982,,Prince Charles,1 +Prince Henry,15/09/1984,,Prince Charles,2 +Princess Beatrice,08/08/1988,,Prince Andrew,1 +Princess Eugenie,23/03/1990,,Prince Andrew,2 +Lady Louise Windsor,08/11/2003,,Prince Edward,2 +"James, Viscount Severn",17/12/2007,,Prince Edward,1 +Savannah Phillips,29/12/2010,,Peter Phillips,1 +Isla Phillips,29/03/2012,,Peter Phillips,2 +Prince George,22/07/2013,,Prince William,1 +Mia Tindall,17/01/2014,,Zara Tindall,1 +Princess Charlotte,02/05/2015,,Prince William,2 +Princess Margaret,21/08/1930,9/2/2002,King George VI,2 diff --git a/get_succ b/get_succ new file mode 100755 index 0000000..c0019bc --- /dev/null +++ b/get_succ @@ -0,0 +1,30 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use 5.010; + +use Succession::Schema; +use DateTime; +use DateTime::Format::Strptime; + +my $date = shift; + +if (defined $date) { + $date = DateTime::Format::Strptime->new( + pattern => '%Y-%m-%d', + )->parse_datetime($date); +} else { + $date = DateTime->now; +} + +my $sch = Succession::Schema->get_schema; + +my ($sov) = $sch->resultset('Sovereign')->sovereign_on_date($date); + +say 'Sovereign on ', $date->strftime('%d %B %Y'), ': ', $sov->name; + +say 'Succession:'; + +my $i = 1; +say $i++, ': ', $_->name for $sov->succession_on_date($date); diff --git a/lib/Succession/Schema.pm b/lib/Succession/Schema.pm new file mode 100644 index 0000000..09a45b3 --- /dev/null +++ b/lib/Succession/Schema.pm @@ -0,0 +1,38 @@ +use utf8; +package Succession::Schema; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +use Moose; +use MooseX::MarkAsMethods autoclean => 1; +extends 'DBIx::Class::Schema'; + +__PACKAGE__->load_namespaces; + + +# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-12-04 17:40:32 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:cqEWNsPVtEZ+VfMbuLt1MQ + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration + +sub get_schema { + my @errors; + foreach (qw[SUCC_DB_HOST SUCC_DB_NAME SUCC_DB_USER SUCC_DB_PASS]) { + push @errors, $_ unless defined $ENV{$_}; + } + + if (@errors) { + die 'Please set the following environment variables: ', + join(', ', @errors), "\n"; + } + + return __PACKAGE__->connect( + "dbi:mysql:host=$ENV{SUCC_DB_HOST};database=$ENV{SUCC_DB_NAME}", + $ENV{SUCC_DB_USER}, $ENV{SUCC_DB_PASS}, + ); +} + +__PACKAGE__->meta->make_immutable(inline_constructor => 0); +1; diff --git a/lib/Succession/Schema/Result/Person.pm b/lib/Succession/Schema/Result/Person.pm new file mode 100644 index 0000000..6ec780a --- /dev/null +++ b/lib/Succession/Schema/Result/Person.pm @@ -0,0 +1,211 @@ +use utf8; +package Succession::Schema::Result::Person; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Succession::Schema::Result::Person + +=cut + +use strict; +use warnings; + +use Moose; +use MooseX::NonMoose; +use MooseX::MarkAsMethods autoclean => 1; +extends 'DBIx::Class::Core'; + +=head1 COMPONENTS LOADED + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->load_components("InflateColumn::DateTime"); + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("person"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 name + + data_type: 'varchar' + is_nullable: 0 + size: 50 + +=head2 born + + data_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 0 + +=head2 died + + data_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +=head2 parent + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 1 + +=head2 family_order + + data_type: 'integer' + is_nullable: 1 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "name", + { data_type => "varchar", is_nullable => 0, size => 50 }, + "born", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 0 }, + "died", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, + "parent", + { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, + "family_order", + { data_type => "integer", is_nullable => 1 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + +=head1 RELATIONS + +=head2 parent + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "parent", + "Succession::Schema::Result::Person", + { id => "parent" }, + { + is_deferrable => 1, + join_type => "LEFT", + on_delete => "RESTRICT", + on_update => "RESTRICT", + }, +); + +=head2 people + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "people", + "Succession::Schema::Result::Person", + { "foreign.parent" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + +=head2 sovereigns + +Type: has_many + +Related object: L + +=cut + +__PACKAGE__->has_many( + "sovereigns", + "Succession::Schema::Result::Sovereign", + { "foreign.person_id" => "self.id" }, + { cascade_copy => 0, cascade_delete => 0 }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-12-04 17:40:32 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:6h03yIJpwjWvQGw1B+Es6Q + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration + +sub succession_on_date { + my $self = shift; + my ($date) = @_; + + my @desc = map { + $_, $_->descendants_on_date($date) + } $self->descendants_on_date($date); + + push @desc, $self->younger_siblings_and_descendants_on_date($date); + + return @desc; +} + +sub younger_siblings_and_descendants_on_date { + my $self = shift; + my ($date) = @_; + + my $parent = $self->parent; + return unless $self->parent; + + my @younger_siblings = $parent->descendants_on_date($date) + -> search({ + family_order => { '>' => $self->family_order }, + }); + + my @people = map { + $_, $_->descendants_on_date($date) + } @younger_siblings; + + return @people; +} + +sub descendants_on_date { + my $self = shift; + my ($date) = @_; + + $date = $self->result_source->schema->storage-> + datetime_parser->format_datetime($date); + + return $self->people({ + born => { '<=' => $date }, + }, { + order_by => 'family_order', + }); +} + +__PACKAGE__->meta->make_immutable; +1; diff --git a/lib/Succession/Schema/Result/Sovereign.pm b/lib/Succession/Schema/Result/Sovereign.pm new file mode 100644 index 0000000..f4f1d33 --- /dev/null +++ b/lib/Succession/Schema/Result/Sovereign.pm @@ -0,0 +1,123 @@ +use utf8; +package Succession::Schema::Result::Sovereign; + +# Created by DBIx::Class::Schema::Loader +# DO NOT MODIFY THE FIRST PART OF THIS FILE + +=head1 NAME + +Succession::Schema::Result::Sovereign + +=cut + +use strict; +use warnings; + +use Moose; +use MooseX::NonMoose; +use MooseX::MarkAsMethods autoclean => 1; +extends 'DBIx::Class::Core'; + +=head1 COMPONENTS LOADED + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->load_components("InflateColumn::DateTime"); + +=head1 TABLE: C + +=cut + +__PACKAGE__->table("sovereign"); + +=head1 ACCESSORS + +=head2 id + + data_type: 'integer' + is_auto_increment: 1 + is_nullable: 0 + +=head2 start + + data_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 0 + +=head2 end + + data_type: 'date' + datetime_undef_if_invalid: 1 + is_nullable: 1 + +=head2 person_id + + data_type: 'integer' + is_foreign_key: 1 + is_nullable: 0 + +=cut + +__PACKAGE__->add_columns( + "id", + { data_type => "integer", is_auto_increment => 1, is_nullable => 0 }, + "start", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 0 }, + "end", + { data_type => "date", datetime_undef_if_invalid => 1, is_nullable => 1 }, + "person_id", + { data_type => "integer", is_foreign_key => 1, is_nullable => 0 }, +); + +=head1 PRIMARY KEY + +=over 4 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("id"); + +=head1 RELATIONS + +=head2 person + +Type: belongs_to + +Related object: L + +=cut + +__PACKAGE__->belongs_to( + "person", + "Succession::Schema::Result::Person", + { id => "person_id" }, + { is_deferrable => 1, on_delete => "RESTRICT", on_update => "RESTRICT" }, +); + + +# Created by DBIx::Class::Schema::Loader v0.07045 @ 2016-12-04 17:40:32 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:WN+m2I1O/MX5wUbD9leJdg + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration + +sub name { + return $_[0]->person->name; +} + +sub succession_on_date { + return $_[0]->person->succession_on_date($_[1]); +} + +__PACKAGE__->meta->make_immutable; +1; diff --git a/lib/Succession/Schema/ResultSet/Sovereign.pm b/lib/Succession/Schema/ResultSet/Sovereign.pm new file mode 100644 index 0000000..fe04d07 --- /dev/null +++ b/lib/Succession/Schema/ResultSet/Sovereign.pm @@ -0,0 +1,25 @@ +package Succession::Schema::ResultSet::Sovereign; + +use Moose; +use MooseX::NonMoose; + +extends 'DBIx::Class::ResultSet'; + +sub BUILDARGS { $_[2] } + +sub sovereign_on_date { + my $self = shift; + my ($date) = @_; + + $date = $self->result_source->schema->storage-> + datetime_parser->format_datetime($date); + + return $self->search({ + start => { '<=' => $date }, + end => [ { '>=' => $date }, undef ], + }); +} + +__PACKAGE__->meta->make_immutable; + +1; diff --git a/load b/load new file mode 100755 index 0000000..9ec86f0 --- /dev/null +++ b/load @@ -0,0 +1,42 @@ +#!/usr/bin/perl + +use strict; +use warnings; +use 5.010; + +use Text::ParseWords; +use DateTime::Format::Strptime; +use Succession::Schema; + +my $dt_p = DateTime::Format::Strptime->new( + pattern => '%d/%m/%Y', +); + +my $sch = Succession::Schema->get_schema; + +my $person_rs = $sch->resultset('Person'); + +<>; + +my @cols = qw[name born died parent family_order]; + +my %people; + +while (<>) { + chomp; + my %rec; + @rec{@cols} = map { length ? $_ : undef} parse_line(',', 0, $_); + + $rec{born} = $dt_p->parse_datetime($rec{born}); + $rec{died} = $dt_p->parse_datetime($rec{died}) if $rec{died}; + + if ($rec{parent}) { + if (exists $people{$rec{parent}}) { + $rec{parent} = $people{$rec{parent}}->id; + } else { + warn "Can't find parent for $rec{name} ($rec{parent})\n"; + next; + } + } + $people{$rec{name}} = $person_rs->create(\%rec); +} diff --git a/succession.conf b/succession.conf new file mode 100644 index 0000000..e6c32b5 --- /dev/null +++ b/succession.conf @@ -0,0 +1,13 @@ +schema_class Succession::Schema + + + dsn dbi:mysql:succession + user succession + pass 5ucc35510n + + + + dump_directory ./lib + components InflateColumn::DateTime + use_moose 1 + diff --git a/succession.sql b/succession.sql new file mode 100644 index 0000000..128ccbc --- /dev/null +++ b/succession.sql @@ -0,0 +1,21 @@ +drop table if exists person; + +create table person ( + id integer primary key auto_increment, + name varchar(50) not null, + born date not null, + died date, + parent integer null, + family_order integer, + foreign key (parent) references person(id) +); + +drop table if exists sovereign; + +create table sovereign ( + id integer primary key auto_increment, + start date not null, + end date, + person_id integer not null, + foreign key (person_id) references person(id) +);