summaryrefslogtreecommitdiff
path: root/lib/Travelynx/Model/Stations.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Travelynx/Model/Stations.pm')
-rw-r--r--lib/Travelynx/Model/Stations.pm404
1 files changed, 361 insertions, 43 deletions
diff --git a/lib/Travelynx/Model/Stations.pm b/lib/Travelynx/Model/Stations.pm
index ac4019c..c6d9730 100644
--- a/lib/Travelynx/Model/Stations.pm
+++ b/lib/Travelynx/Model/Stations.pm
@@ -1,6 +1,7 @@
package Travelynx::Model::Stations;
# Copyright (C) 2022 Birte Kristina Friesel
+# Copyright (C) 2025 networkException <git@nwex.de>
#
# SPDX-License-Identifier: AGPL-3.0-or-later
@@ -14,56 +15,319 @@ sub new {
return bless( \%opt, $class );
}
+sub get_backend_id {
+ my ( $self, %opt ) = @_;
+
+ if ( $opt{iris} ) {
+
+ # special case
+ return 0;
+ }
+ if ( $opt{dbris} and $self->{backend_id}{dbris}{ $opt{dbris} } ) {
+ return $self->{backend_id}{dbris}{ $opt{dbris} };
+ }
+ if ( $opt{efa} and $self->{backend_id}{efa}{ $opt{efa} } ) {
+ return $self->{backend_id}{efa}{ $opt{efa} };
+ }
+ if ( $opt{hafas} and $self->{backend_id}{hafas}{ $opt{hafas} } ) {
+ return $self->{backend_id}{hafas}{ $opt{hafas} };
+ }
+ if ( $opt{motis} and $self->{backend_id}{motis}{ $opt{motis} } ) {
+ return $self->{backend_id}{motis}{ $opt{motis} };
+ }
+
+ my $db = $opt{db} // $self->{pg}->db;
+ my $backend_id = 0;
+
+ if ( $opt{dbris} ) {
+ $backend_id = $db->select(
+ 'backends',
+ ['id'],
+ {
+ dbris => 1,
+ name => $opt{dbris}
+ }
+ )->hash->{id};
+ $self->{backend_id}{dbris}{ $opt{dbris} } = $backend_id;
+ }
+ elsif ( $opt{efa} ) {
+ $backend_id = $db->select(
+ 'backends',
+ ['id'],
+ {
+ efa => 1,
+ name => $opt{efa}
+ }
+ )->hash->{id};
+ $self->{backend_id}{efa}{ $opt{efa} } = $backend_id;
+ }
+ elsif ( $opt{hafas} ) {
+ $backend_id = $db->select(
+ 'backends',
+ ['id'],
+ {
+ hafas => 1,
+ name => $opt{hafas}
+ }
+ )->hash->{id};
+ $self->{backend_id}{hafas}{ $opt{hafas} } = $backend_id;
+ }
+ elsif ( $opt{motis} ) {
+ $backend_id = $db->select(
+ 'backends',
+ ['id'],
+ {
+ motis => 1,
+ name => $opt{motis}
+ }
+ )->hash->{id};
+ $self->{backend_id}{motis}{ $opt{motis} } = $backend_id;
+ }
+
+ return $backend_id;
+}
+
+sub get_backend {
+ my ( $self, %opt ) = @_;
+
+ if ( $self->{backend_cache}{ $opt{backend_id} } ) {
+ return $self->{backend_cache}{ $opt{backend_id} };
+ }
+
+ my $db = $opt{db} // $self->{pg}->db;
+ my $ret = $db->select(
+ 'backends',
+ '*',
+ {
+ id => $opt{backend_id},
+ }
+ )->hash;
+
+ $self->{backend_cache}{ $opt{backend_id} } = $ret;
+
+ return $ret;
+}
+
+sub get_backends {
+ my ( $self, %opt ) = @_;
+
+ $opt{db} //= $self->{pg}->db;
+
+ my $res = $opt{db}->select( 'backends',
+ [ 'id', 'name', 'dbris', 'efa', 'hafas', 'iris', 'motis' ] );
+ my @ret;
+
+ while ( my $row = $res->hash ) {
+ push(
+ @ret,
+ {
+ id => $row->{id},
+ name => $row->{name},
+ dbris => $row->{dbris},
+ efa => $row->{efa},
+ hafas => $row->{hafas},
+ iris => $row->{iris},
+ motis => $row->{motis},
+ }
+ );
+ }
+
+ return @ret;
+}
+
+# Slow for MOTIS backends
sub add_or_update {
my ( $self, %opt ) = @_;
- my $stop = $opt{stop};
- my $loc = $stop->loc;
- my $source = 1;
- my $db = $opt{db} // $self->{pg}->db;
+ my $stop = $opt{stop};
+ $opt{db} //= $self->{pg}->db;
+
+ $opt{backend_id} //= $self->get_backend_id(%opt);
+
+ if ( $opt{dbris} ) {
+ if (
+ my $s = $self->get_by_eva(
+ $stop->eva,
+ db => $opt{db},
+ backend_id => $opt{backend_id}
+ )
+ )
+ {
+ $opt{db}->update(
+ 'stations',
+ {
+ name => $stop->name,
+ lat => $stop->lat,
+ lon => $stop->lon,
+ archived => 0
+ },
+ {
+ eva => $stop->eva,
+ source => $opt{backend_id}
+ }
+ );
+ return;
+ }
+ $opt{db}->insert(
+ 'stations',
+ {
+ eva => $stop->eva,
+ name => $stop->name,
+ lat => $stop->lat,
+ lon => $stop->lon,
+ source => $opt{backend_id},
+ archived => 0
+ }
+ );
+ return;
+ }
+
+ if ( $opt{efa} ) {
+ if (
+ my $s = $self->get_by_eva(
+ $stop->id_num,
+ db => $opt{db},
+ backend_id => $opt{backend_id}
+ )
+ )
+ {
+ $opt{db}->update(
+ 'stations',
+ {
+ name => $stop->full_name,
+ lat => $stop->latlon->[0],
+ lon => $stop->latlon->[1],
+ archived => 0
+ },
+ {
+ eva => $stop->id_num,
+ source => $opt{backend_id}
+ }
+ );
+ return;
+ }
+ if (not $stop->latlon) {
+ die('Backend Error: Stop "' . $stop->full_name . '" has no geo coordinates');
+ }
+ $opt{db}->insert(
+ 'stations',
+ {
+ eva => $stop->id_num,
+ name => $stop->full_name,
+ lat => $stop->latlon->[0],
+ lon => $stop->latlon->[1],
+ source => $opt{backend_id},
+ archived => 0
+ }
+ );
+ return;
+ }
+
+ if ( $opt{motis} ) {
+ if (
+ my $s = $self->get_by_external_id(
+ external_id => $stop->id,
+ db => $opt{db},
+ backend_id => $opt{backend_id}
+ )
+ )
+ {
+ $opt{db}->update(
+ 'stations',
+ {
+ name => $stop->name,
+ lat => $stop->lat,
+ lon => $stop->lon,
+ archived => 0
+ },
+ {
+ eva => $s->{eva},
+ source => $opt{backend_id}
+ }
+ );
- if ( my $s = $self->get_by_eva( $loc->eva, db => $db ) ) {
- if ( $source == 1 and $s->{source} == 0 and not $s->{archived} ) {
+ # MOTIS backends do not provide a numeric ID, so we set our ID here.
+ $stop->{eva} = $s->{eva};
return;
}
- $db->update(
+
+ my $s = $opt{db}->query(
+ qq {
+ with new_station as (
+ insert into stations_external_ids (backend_id, external_id)
+ values (?, ?)
+ returning eva, backend_id
+ )
+
+ insert into stations (eva, name, lat, lon, source, archived)
+ values ((select eva from new_station), ?, ?, ?, (select backend_id from new_station), ?)
+ returning *
+ },
+ (
+ $opt{backend_id}, $stop->id, $stop->name,
+ $stop->lat, $stop->lon, 0,
+ )
+ );
+
+ # MOTIS backends do not provide a numeric ID, so we set our ID here.
+ $stop->{eva} = $s->hash->{eva};
+ return;
+ }
+
+ my $loc = $stop->loc;
+ if (
+ my $s = $self->get_by_eva(
+ $loc->eva,
+ db => $opt{db},
+ backend_id => $opt{backend_id}
+ )
+ )
+ {
+ $opt{db}->update(
'stations',
{
name => $loc->name,
lat => $loc->lat,
lon => $loc->lon,
- source => $source,
archived => 0
},
- { eva => $loc->eva }
+ {
+ eva => $loc->eva,
+ source => $opt{backend_id}
+ }
);
return;
}
- $db->insert(
+ $opt{db}->insert(
'stations',
{
eva => $loc->eva,
name => $loc->name,
lat => $loc->lat,
lon => $loc->lon,
- source => $source,
+ source => $opt{backend_id},
archived => 0
}
);
+
+ return;
}
sub add_meta {
my ( $self, %opt ) = @_;
- my $db = $opt{db} // $self->{pg}->db;
my $eva = $opt{eva};
my @meta = @{ $opt{meta} };
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
+
for my $meta (@meta) {
if ( $meta != $eva ) {
- $db->insert(
+ $opt{db}->insert(
'related_stations',
{
- eva => $eva,
- meta => $meta
+ eva => $eva,
+ meta => $meta,
+ backend_id => $opt{backend_id},
},
{ on_conflict => undef }
);
@@ -74,7 +338,7 @@ sub add_meta {
sub get_db_iterator {
my ($self) = @_;
- return $self->{pg}->db->select( 'stations', '*' );
+ return $self->{pg}->db->select( 'stations_str', '*' );
}
sub get_meta {
@@ -82,7 +346,16 @@ sub get_meta {
my $db = $opt{db} // $self->{pg}->db;
my $eva = $opt{eva};
- my $res = $db->select( 'related_stations', ['meta'], { eva => $eva } );
+ $opt{backend_id} //= $self->get_backend_id( %opt, db => $db );
+
+ my $res = $db->select(
+ 'related_stations',
+ ['meta'],
+ {
+ eva => $eva,
+ backend_id => $opt{backend_id}
+ }
+ );
my @ret;
while ( my $row = $res->hash ) {
@@ -93,9 +366,12 @@ sub get_meta {
}
sub get_for_autocomplete {
- my ($self) = @_;
+ my ( $self, %opt ) = @_;
- my $res = $self->{pg}->db->select( 'stations', ['name'] );
+ $opt{backend_id} //= $self->get_backend_id(%opt);
+
+ my $res = $self->{pg}
+ ->db->select( 'stations', ['name'], { source => $opt{backend_id} } );
my %ret;
while ( my $row = $res->hash ) {
@@ -113,43 +389,74 @@ sub get_by_eva {
return;
}
- my $db = $opt{db} // $self->{pg}->db;
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
- return $db->select( 'stations', '*', { eva => $eva } )->hash;
+ return $opt{db}->select(
+ 'stations',
+ '*',
+ {
+ eva => $eva,
+ source => $opt{backend_id}
+ }
+ )->hash;
}
-# Fast
-sub get_by_evas {
- my ( $self, @evas ) = @_;
+# Slow
+sub get_by_external_id {
+ my ( $self, %opt ) = @_;
- my @ret
- = $self->{pg}->db->select( 'stations', '*', { eva => { '=', \@evas } } )
- ->hashes->each;
- return @ret;
+ if ( not $opt{external_id} ) {
+ return;
+ }
+
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
+
+ return $opt{db}->select(
+ 'stations_with_external_ids',
+ '*',
+ {
+ external_id => $opt{external_id},
+ source => $opt{backend_id},
+ }
+ )->hash;
}
-# Slow
-sub get_latlon_by_name {
+# Fast
+sub get_by_evas {
my ( $self, %opt ) = @_;
- my $db = $opt{db} // $self->{pg}->db;
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
- my %location;
- my $res = $db->select( 'stations', [ 'name', 'lat', 'lon' ] );
- while ( my $row = $res->hash ) {
- $location{ $row->{name} } = [ $row->{lat}, $row->{lon} ];
- }
- return \%location;
+ my @ret = $self->{pg}->db->select(
+ 'stations',
+ '*',
+ {
+ eva => { '=', $opt{evas} },
+ source => $opt{backend_id}
+ }
+ )->hashes->each;
+ return @ret;
}
# Slow
sub get_by_name {
my ( $self, $name, %opt ) = @_;
- my $db = $opt{db} // $self->{pg}->db;
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
- return $db->select( 'stations', '*', { name => $name }, { limit => 1 } )
- ->hash;
+ return $opt{db}->select(
+ 'stations',
+ '*',
+ {
+ name => $name,
+ source => $opt{backend_id}
+ },
+ { limit => 1 }
+ )->hash;
}
# Slow
@@ -166,16 +473,27 @@ sub get_by_names {
sub get_by_ds100 {
my ( $self, $ds100, %opt ) = @_;
- my $db = $opt{db} // $self->{pg}->db;
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
- return $db->select( 'stations', '*', { ds100 => $ds100 }, { limit => 1 } )
- ->hash;
+ return $opt{db}->select(
+ 'stations',
+ '*',
+ {
+ ds100 => $ds100,
+ source => $opt{backend_id}
+ },
+ { limit => 1 }
+ )->hash;
}
# Can be slow
sub search {
my ( $self, $identifier, %opt ) = @_;
+ $opt{db} //= $self->{pg}->db;
+ $opt{backend_id} //= $self->get_backend_id(%opt);
+
if ( $identifier =~ m{ ^ \d+ $ }x ) {
return $self->get_by_eva( $identifier, %opt )
// $self->get_by_ds100( $identifier, %opt )