Refactor user_actions insert/update/delete statements with Mojo::Pg
This commit is contained in:
parent
ecedc6a4f2
commit
8ad05720a2
2 changed files with 235 additions and 253 deletions
486
lib/Travelynx.pm
486
lib/Travelynx.pm
|
@ -242,58 +242,6 @@ sub startup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$self->attr(
|
|
||||||
action_set_sched_time_query => sub {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
# TODO (re-)initialize all automatically added journeys with edited = 0
|
|
||||||
# and use it as a bit field to precisely indicate which fields have
|
|
||||||
# been edited. -> ".. set edited = edited | 1", "... | 2" etc.
|
|
||||||
# The action_id check is redundant, but better safe than sorry
|
|
||||||
return $self->app->dbh->prepare(
|
|
||||||
qq{
|
|
||||||
update user_actions
|
|
||||||
set sched_time = to_timestamp(?), edited = edited | 1
|
|
||||||
where id = ? and action_id = ?
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$self->attr(
|
|
||||||
action_set_real_time_query => sub {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
# The action_id check is redundant, but better safe than sorry
|
|
||||||
return $self->app->dbh->prepare(
|
|
||||||
qq{
|
|
||||||
update user_actions
|
|
||||||
set real_time = to_timestamp(?), edited = edited | 2
|
|
||||||
where id = ? and action_id = ?
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$self->attr(
|
|
||||||
action_query => sub {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
return $self->app->dbh->prepare(
|
|
||||||
qq{
|
|
||||||
insert into user_actions (
|
|
||||||
user_id, action_id, station_id, action_time, edited,
|
|
||||||
train_type, train_line, train_no, train_id,
|
|
||||||
sched_time, real_time,
|
|
||||||
route, messages
|
|
||||||
) values (
|
|
||||||
?, ?, ?, to_timestamp(?), ?,
|
|
||||||
?, ?, ?, ?,
|
|
||||||
to_timestamp(?), to_timestamp(?),
|
|
||||||
?, ?
|
|
||||||
)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
$self->attr(
|
$self->attr(
|
||||||
dbh => sub {
|
dbh => sub {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
@ -394,19 +342,6 @@ sub startup {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$self->attr(
|
|
||||||
drop_journey_query => sub {
|
|
||||||
my ($self) = @_;
|
|
||||||
|
|
||||||
return $self->app->dbh->prepare(
|
|
||||||
qq{
|
|
||||||
delete from user_actions
|
|
||||||
where user_id = ?
|
|
||||||
and (id = ? or id = ?)
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
$self->attr(
|
$self->attr(
|
||||||
get_userid_query => sub {
|
get_userid_query => sub {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
@ -640,60 +575,65 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}
|
||||||
return ( undef, undef, 'Unbekannter Zielbahnhof' );
|
return ( undef, undef, 'Unbekannter Zielbahnhof' );
|
||||||
}
|
}
|
||||||
|
|
||||||
say $dep_station->[0];
|
my $checkin_id;
|
||||||
say $dep_station->[1];
|
my $checkout_id;
|
||||||
say $arr_station->[0];
|
|
||||||
say $arr_station->[1];
|
|
||||||
|
|
||||||
my $success = $self->app->action_query->execute(
|
eval {
|
||||||
$uid,
|
$checkin_id = $self->pg->db->insert(
|
||||||
$self->app->action_type->{checkin},
|
'user_actions',
|
||||||
$self->get_station_id(
|
{
|
||||||
ds100 => $dep_station->[0],
|
user_id => $uid,
|
||||||
name => $dep_station->[1],
|
action_id => $self->app->action_type->{checkin},
|
||||||
),
|
station_id => $self->get_station_id(
|
||||||
DateTime->now( time_zone => 'Europe/Berlin' )->epoch,
|
ds100 => $dep_station->[0],
|
||||||
0x0f,
|
name => $dep_station->[1],
|
||||||
$opt{train_type},
|
),
|
||||||
$opt{train_line},
|
action_time =>
|
||||||
$opt{train_no},
|
DateTime->now( time_zone => 'Europe/Berlin' ),
|
||||||
undef,
|
edited => 0x0f,
|
||||||
$opt{sched_departure}->epoch,
|
train_type => $opt{train_type},
|
||||||
$opt{rt_departure} ? $opt{rt_departure}->epoch : undef,
|
train_line => $opt{train_line},
|
||||||
undef, undef
|
train_no => $opt{train_no},
|
||||||
);
|
sched_time => $opt{sched_departure},
|
||||||
if ( not $success ) {
|
real_time => $opt{rt_departure},
|
||||||
my $err = $self->app->action_query->errstr;
|
},
|
||||||
$self->app->log->error(
|
{ returning => 'id' }
|
||||||
"add_journey($uid, checkin): INSERT failed: $err");
|
)->hash->{id};
|
||||||
return ( undef, undef, 'INSERT failed: ' . $err );
|
};
|
||||||
}
|
|
||||||
my $checkin_id = $self->app->action_query->last_insert_id;
|
|
||||||
|
|
||||||
$success = $self->app->action_query->execute(
|
if ($@) {
|
||||||
$uid,
|
|
||||||
$self->app->action_type->{checkout},
|
|
||||||
$self->get_station_id(
|
|
||||||
ds100 => $arr_station->[0],
|
|
||||||
name => $arr_station->[1],
|
|
||||||
),
|
|
||||||
DateTime->now( time_zone => 'Europe/Berlin' )->epoch,
|
|
||||||
0x0f,
|
|
||||||
$opt{train_type},
|
|
||||||
$opt{train_line},
|
|
||||||
$opt{train_no},
|
|
||||||
undef,
|
|
||||||
$opt{sched_arrival}->epoch,
|
|
||||||
$opt{rt_arrival} ? $opt{rt_arrival}->epoch : undef,
|
|
||||||
undef, undef
|
|
||||||
);
|
|
||||||
if ( not $success ) {
|
|
||||||
my $err = $self->app->action_query->errstr;
|
|
||||||
$self->app->log->error(
|
$self->app->log->error(
|
||||||
"add_journey($uid, checkout): INSERT failed: $err");
|
"add_journey($uid, checkin): INSERT failed: $@");
|
||||||
return ( undef, undef, 'INSERT failed: ' . $err );
|
return ( undef, undef, 'INSERT failed: ' . $@ );
|
||||||
|
}
|
||||||
|
|
||||||
|
eval {
|
||||||
|
$checkout_id = $self->pg->db->insert(
|
||||||
|
'user_actions',
|
||||||
|
{
|
||||||
|
user_id => $uid,
|
||||||
|
action_id => $self->app->action_type->{checkout},
|
||||||
|
station_id => $self->get_station_id(
|
||||||
|
ds100 => $arr_station->[0],
|
||||||
|
name => $arr_station->[1],
|
||||||
|
),
|
||||||
|
action_time =>
|
||||||
|
DateTime->now( time_zone => 'Europe/Berlin' ),
|
||||||
|
edited => 0x0f,
|
||||||
|
train_type => $opt{train_type},
|
||||||
|
train_line => $opt{train_line},
|
||||||
|
train_no => $opt{train_no},
|
||||||
|
sched_time => $opt{sched_arrival},
|
||||||
|
real_time => $opt{rt_arrival},
|
||||||
|
},
|
||||||
|
{ returnning => 'id' }
|
||||||
|
)->hash->{id};
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$self->app->log->error(
|
||||||
|
"add_journey($uid, checkout): INSERT failed: $@");
|
||||||
|
return ( undef, undef, 'INSERT failed: ' . $@ );
|
||||||
}
|
}
|
||||||
my $checkout_id = $self->app->action_query->last_insert_id;
|
|
||||||
return ( $checkin_id, $checkout_id, undef );
|
return ( $checkin_id, $checkout_id, undef );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -730,40 +670,43 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}
|
||||||
$self->app->action_type->{cancelled_to} );
|
$self->app->action_type->{cancelled_to} );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $success = $self->app->action_query->execute(
|
eval {
|
||||||
$self->current_user->{id},
|
$self->pg->db->insert(
|
||||||
$action_id,
|
'user_actions',
|
||||||
$self->get_station_id(
|
{
|
||||||
ds100 => $status->{station_ds100},
|
user_id => $self->current_user->{id},
|
||||||
name => $status->{station_name}
|
action_id => $action_id,
|
||||||
),
|
station_id => $self->get_station_id(
|
||||||
DateTime->now( time_zone => 'Europe/Berlin' )->epoch,
|
ds100 => $status->{station_ds100},
|
||||||
0,
|
name => $status->{station_name}
|
||||||
$train->type,
|
),
|
||||||
$train->line_no,
|
action_time =>
|
||||||
$train->train_no,
|
DateTime->now( time_zone => 'Europe/Berlin' ),
|
||||||
$train->train_id,
|
edited => 0,
|
||||||
$train->sched_departure->epoch,
|
train_type => $train->type,
|
||||||
$train->departure->epoch,
|
train_line => $train->line_no,
|
||||||
join( '|', $train->route ),
|
train_no => $train->train_no,
|
||||||
join(
|
train_id => $train->train_id,
|
||||||
'|',
|
sched_time => $train->sched_departure,
|
||||||
map {
|
real_time => $train->departure,
|
||||||
( $_->[0] ? $_->[0]->epoch : q{} ) . ':'
|
route => join( '|', $train->route ),
|
||||||
. $_->[1]
|
messages => join(
|
||||||
} $train->messages
|
'|',
|
||||||
)
|
map {
|
||||||
);
|
( $_->[0] ? $_->[0]->epoch : q{} ) . ':'
|
||||||
if ( defined $success ) {
|
. $_->[1]
|
||||||
return ( $train, undef );
|
} $train->messages
|
||||||
}
|
)
|
||||||
else {
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
my $uid = $self->current_user->{id};
|
my $uid = $self->current_user->{id};
|
||||||
my $err = $self->app->action_query->errstr;
|
|
||||||
$self->app->log->error(
|
$self->app->log->error(
|
||||||
"Checkin($uid, $action_id): INSERT failed: $err");
|
"Checkin($uid, $action_id): INSERT failed: $@");
|
||||||
return ( undef, 'INSERT failed: ' . $err );
|
return ( undef, 'INSERT failed: ' . $@ );
|
||||||
}
|
}
|
||||||
|
return ( $train, undef );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -876,72 +819,73 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}
|
||||||
= first { $_->train_id eq $train_id } @{ $status->{results} };
|
= first { $_->train_id eq $train_id } @{ $status->{results} };
|
||||||
if ( not defined $train ) {
|
if ( not defined $train ) {
|
||||||
if ($force) {
|
if ($force) {
|
||||||
my $success = $self->app->action_query->execute(
|
eval {
|
||||||
$self->current_user->{id},
|
$self->pg->db->insert(
|
||||||
$action_id,
|
'user_actions',
|
||||||
$self->get_station_id(
|
{
|
||||||
ds100 => $status->{station_ds100},
|
user_id => $self->current_user->{id},
|
||||||
name => $status->{station_name}
|
action_id => $action_id,
|
||||||
),
|
station_id => $self->get_station_id(
|
||||||
$now->epoch,
|
ds100 => $status->{station_ds100},
|
||||||
0, undef, undef, undef, undef,
|
name => $status->{station_name}
|
||||||
undef, undef, undef, undef
|
),
|
||||||
);
|
action_time => $now,
|
||||||
if ( defined $success ) {
|
edited => 0
|
||||||
$self->invalidate_stats_cache;
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
my $uid = $self->current_user->{id};
|
|
||||||
my $err = $self->app->action_query->errstr;
|
|
||||||
$self->app->log->error(
|
|
||||||
"Force checkout($uid, $action_id): INSERT failed: $err"
|
|
||||||
);
|
);
|
||||||
return 'INSERT failed: ' . $err;
|
};
|
||||||
|
if ($@) {
|
||||||
|
my $uid = $self->current_user->{id};
|
||||||
|
$self->app->log->error(
|
||||||
|
"Force checkout($uid, $action_id): INSERT failed: $@"
|
||||||
|
);
|
||||||
|
return 'INSERT failed: ' . $@;
|
||||||
}
|
}
|
||||||
|
$self->invalidate_stats_cache;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return "Train ${train_id} not found";
|
return "Train ${train_id} not found";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
my $success = $self->app->action_query->execute(
|
eval {
|
||||||
$self->current_user->{id},
|
$self->pg->db->insert(
|
||||||
$action_id,
|
'user_actions',
|
||||||
$self->get_station_id(
|
{
|
||||||
ds100 => $status->{station_ds100},
|
user_id => $self->current_user->{id},
|
||||||
name => $status->{station_name}
|
action_id => $action_id,
|
||||||
),
|
station_id => $self->get_station_id(
|
||||||
$now->epoch,
|
ds100 => $status->{station_ds100},
|
||||||
0,
|
name => $status->{station_name}
|
||||||
$train->type,
|
),
|
||||||
$train->line_no,
|
action_time => $now,
|
||||||
$train->train_no,
|
edited => 0,
|
||||||
$train->train_id,
|
train_type => $train->type,
|
||||||
$train->sched_arrival
|
train_line => $train->line_no,
|
||||||
? $train->sched_arrival->epoch
|
train_no => $train->train_no,
|
||||||
: undef,
|
train_id => $train->train_id,
|
||||||
$train->arrival ? $train->arrival->epoch : undef,
|
sched_time => $train->sched_arrival,
|
||||||
join( '|', $train->route ),
|
real_time => $train->arrival,
|
||||||
join(
|
route => join( '|', $train->route ),
|
||||||
'|',
|
messages => join(
|
||||||
map {
|
'|',
|
||||||
( $_->[0] ? $_->[0]->epoch : q{} ) . ':'
|
map {
|
||||||
. $_->[1]
|
( $_->[0] ? $_->[0]->epoch : q{} ) . ':'
|
||||||
} $train->messages
|
. $_->[1]
|
||||||
)
|
} $train->messages
|
||||||
);
|
)
|
||||||
if ( defined $success ) {
|
}
|
||||||
$self->invalidate_stats_cache;
|
);
|
||||||
return;
|
};
|
||||||
}
|
if ($@) {
|
||||||
else {
|
|
||||||
my $uid = $self->current_user->{id};
|
my $uid = $self->current_user->{id};
|
||||||
my $err = $self->app->action_query->errstr;
|
|
||||||
$self->app->log->error(
|
$self->app->log->error(
|
||||||
"Checkout($uid, $action_id): INSERT failed: $err");
|
"Checkout($uid, $action_id): INSERT failed: $@");
|
||||||
return 'INSERT failed: ' . $err;
|
return 'INSERT failed: ' . $@;
|
||||||
}
|
}
|
||||||
|
$self->invalidate_stats_cache;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -949,45 +893,75 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}
|
||||||
$self->helper(
|
$self->helper(
|
||||||
'update_journey_part' => sub {
|
'update_journey_part' => sub {
|
||||||
my ( $self, $checkin_id, $checkout_id, $key, $value ) = @_;
|
my ( $self, $checkin_id, $checkout_id, $key, $value ) = @_;
|
||||||
my ( $query, $id, $action_type );
|
my $rows;
|
||||||
|
|
||||||
if ( $key eq 'sched_departure' ) {
|
eval {
|
||||||
$query = $self->app->action_set_sched_time_query;
|
my $db = $self->pg->db;
|
||||||
$id = $checkin_id;
|
if ( $key eq 'sched_departure' ) {
|
||||||
$action_type = $self->app->action_type->{checkin};
|
$rows = $db->update(
|
||||||
}
|
'user_actions',
|
||||||
elsif ( $key eq 'rt_departure' ) {
|
{
|
||||||
$query = $self->app->action_set_real_time_query;
|
sched_time => $value,
|
||||||
$id = $checkin_id;
|
},
|
||||||
$action_type = $self->app->action_type->{checkin};
|
{
|
||||||
}
|
id => $checkin_id,
|
||||||
elsif ( $key eq 'sched_arrival' ) {
|
action_id => $self->app->action_type->{checkin},
|
||||||
$query = $self->app->action_set_sched_time_query;
|
}
|
||||||
$id = $checkout_id;
|
)->rows;
|
||||||
$action_type = $self->app->action_type->{checkout};
|
|
||||||
}
|
|
||||||
elsif ( $key eq 'rt_arrival' ) {
|
|
||||||
$query = $self->app->action_set_real_time_query;
|
|
||||||
$id = $checkout_id;
|
|
||||||
$action_type = $self->app->action_type->{checkout};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->app->log->error(
|
|
||||||
"update_journey_part(id = $id): Invalid key $key");
|
|
||||||
return 'Internal Error';
|
|
||||||
}
|
|
||||||
|
|
||||||
my $success = $query->execute( $value, $id, $action_type );
|
|
||||||
if ($success) {
|
|
||||||
if ( $query->rows == 1 ) {
|
|
||||||
return undef;
|
|
||||||
}
|
}
|
||||||
return 'UPDATE failed: did not match any journey part';
|
elsif ( $key eq 'rt_departure' ) {
|
||||||
|
$rows = $db->update(
|
||||||
|
'user_actions',
|
||||||
|
{
|
||||||
|
real_time => $value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id => $checkin_id,
|
||||||
|
action_id => $self->app->action_type->{checkin},
|
||||||
|
}
|
||||||
|
)->rows;
|
||||||
|
}
|
||||||
|
elsif ( $key eq 'sched_arrival' ) {
|
||||||
|
$rows = $db->update(
|
||||||
|
'user_actions',
|
||||||
|
{
|
||||||
|
sched_time => $value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id => $checkout_id,
|
||||||
|
action_id => $self->app->action_type->{checkout},
|
||||||
|
}
|
||||||
|
)->rows;
|
||||||
|
}
|
||||||
|
elsif ( $key eq 'rt_arrival' ) {
|
||||||
|
$rows = $db->update(
|
||||||
|
'user_actions',
|
||||||
|
{
|
||||||
|
real_time => $value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id => $checkout_id,
|
||||||
|
action_id => $self->app->action_type->{checkout},
|
||||||
|
}
|
||||||
|
)->rows;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$self->app->log->error(
|
||||||
|
"update_journey_part($checkin_id, $checkout_id): Invalid key $key"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
$self->app->log->error(
|
||||||
|
"update_journey_part($checkin_id, $checkout_id): UPDATE failed: $@"
|
||||||
|
);
|
||||||
|
return 'UPDATE failed: ' . $@;
|
||||||
}
|
}
|
||||||
my $err = $query->errstr;
|
if ( $rows == 1 ) {
|
||||||
$self->app->log->error(
|
return undef;
|
||||||
"update_journey_part($id): UPDATE failed: $err");
|
}
|
||||||
return 'UPDATE failed: ' . $err;
|
return 'UPDATE failed: did not match any journey part';
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1221,22 +1195,30 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}
|
||||||
{
|
{
|
||||||
return 'Invalid journey data';
|
return 'Invalid journey data';
|
||||||
}
|
}
|
||||||
my $query = $self->app->drop_journey_query;
|
|
||||||
my $success = $query->execute( $uid, $checkin_id, $checkout_id );
|
my $rows;
|
||||||
if ($success) {
|
eval {
|
||||||
if ( $query->rows == 2 ) {
|
$rows = $self->pg->db->delete(
|
||||||
$self->invalidate_stats_cache( $journey->{checkout} );
|
'user_actions',
|
||||||
return undef;
|
{
|
||||||
}
|
user_id => $uid,
|
||||||
else {
|
id => [ $checkin_id, $checkout_id ]
|
||||||
return
|
}
|
||||||
sprintf( 'Deleted %d rows, expected 2', $query->rows );
|
)->rows;
|
||||||
}
|
};
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
$self->app->log->error(
|
||||||
|
"Delete($uid, $checkin_id, $checkout_id): DELETE failed: $@"
|
||||||
|
);
|
||||||
|
return 'DELETE failed: ' . $@;
|
||||||
}
|
}
|
||||||
my $err = $self->app->drop_journey_query->errstr;
|
|
||||||
$self->app->log->error(
|
if ( $rows == 2 ) {
|
||||||
"Delete($uid, $checkin_id, $checkout_id): DELETE failed: $err");
|
$self->invalidate_stats_cache( $journey->{checkout} );
|
||||||
return 'DELETE failed: ' . $err;
|
return undef;
|
||||||
|
}
|
||||||
|
return sprintf( 'Deleted %d rows, expected 2', $rows );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -470,7 +470,7 @@ sub edit_journey {
|
||||||
$error = $self->update_journey_part(
|
$error = $self->update_journey_part(
|
||||||
$journey->{ids}[0],
|
$journey->{ids}[0],
|
||||||
$journey->{ids}[1],
|
$journey->{ids}[1],
|
||||||
$key, $datetime->epoch
|
$key, $datetime
|
||||||
);
|
);
|
||||||
if ($error) {
|
if ($error) {
|
||||||
last;
|
last;
|
||||||
|
|
Loading…
Reference in a new issue