gtfs-realtime 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 05148a6c6a4925c9072942c4ab6a57c1d8ddda4b
4
- data.tar.gz: 072e0487c28f7f7ff2483bdeac72f006dc507f8a
3
+ metadata.gz: c4fb01e9aa3b3d57def85c0ebdbda36acbc4c9ab
4
+ data.tar.gz: d3bbf13907cd3b09a0e55cada1aa16dae4ec09c9
5
5
  SHA512:
6
- metadata.gz: c2bd4c6f34c66db13ddc5eb56f27aa7238c1dc68208ce8a7ba027fb542b1b907539ebef06fccc7b042450361a2ae15e486f64183e4eca6caabf900711ca7b7e2
7
- data.tar.gz: 29ec92ae65ecbef01d633610eea3594669a32510985089f8e7675f9b82acdf37dd7b2953f3e11cfe9683eed5bf1b944df55f0ca0247e1171fb707b6ca64e80a0
6
+ metadata.gz: bfc85354de0492acac1c60bf85a1d9085b170f502f57b3f32364b06eaa8fca59237bfee4f51b00e8ea8cac52a6d49ccce18ac90f1724aa1cbad80e106276934c
7
+ data.tar.gz: ff2b51ad9471a0f11ca788363f8968446504625b6f5a0538302dbe362d37e7954705014c5f8373d4c366f9dbb683d14a68418bc03f9fd2755a308e9d95288003
data/README.md CHANGED
@@ -30,14 +30,16 @@ GTFS::Realtime.configure do |config|
30
30
  config.trip_updates_feed = "http://realtime.ripta.com:81/api/tripupdates"
31
31
  config.vehicle_positions_feed = "http://realtime.ripta.com:81/api/vehiclepositions"
32
32
  config.service_alerts_feed = "http://realtime.ripta.com:81/api/servicealerts"
33
- config.database_path = "sqlite://database.db" # leave unset to use an in-memory database
33
+ config.database_url = "sqlite3:////Users/rofreg/database.db"
34
+ # leave database_url unset to use your existing ActiveRecord DB, or
35
+ # set it to `nil` to use an in-memory SQLite database
34
36
  end
35
37
 
36
38
  # After calling 'configure', the gem loads all relevant GTFS info into a database.
37
39
  # This may take some time (up to a minute) depending on the size of the input data.
38
40
  # By default, gtfs-realtime uses an in-memory database, which requires reloading all
39
41
  # data from scratch on each launch. If you'd like to use a persistent database instead,
40
- # set 'config.database_path' above, and include a scheme/protocol path for the DB type
42
+ # set 'config.database_url' above, and include a scheme/protocol path for the DB type
41
43
  # that you would like to use. gtfs-realtime will generate the relevant tables.
42
44
 
43
45
  @nearby = GTFS::Realtime::Stop.nearby(41.834521, -71.396906)
@@ -3,6 +3,7 @@
3
3
  require "bundler/setup"
4
4
  require "gtfs/realtime"
5
5
  require "sqlite3"
6
+ require "uri"
6
7
 
7
8
  # Load the RIPTA feed as an example, with a sqlite3 database
8
9
  GTFS::Realtime.configure do |config|
@@ -10,7 +11,7 @@ GTFS::Realtime.configure do |config|
10
11
  config.trip_updates_feed = "http://realtime.ripta.com:81/api/tripupdates"
11
12
  config.vehicle_positions_feed = "http://realtime.ripta.com:81/api/vehiclepositions"
12
13
  config.service_alerts_feed = "http://realtime.ripta.com:81/api/servicealerts"
13
- config.database_path = "sqlite://database.db"
14
+ config.database_url = "sqlite3:///#{URI.escape(File.expand_path("../../database.db", __FILE__))}"
14
15
  end
15
16
 
16
17
  def reload!
@@ -29,5 +29,6 @@ Gem::Specification.new do |spec|
29
29
 
30
30
  spec.add_dependency "gtfs-realtime-bindings"
31
31
  spec.add_dependency "gtfs"
32
- spec.add_dependency "sequel"
32
+ spec.add_dependency "activerecord"
33
+ spec.add_dependency "bulk_insert"
33
34
  end
@@ -1,8 +1,22 @@
1
1
  require "google/transit/gtfs-realtime.pb"
2
2
  require "gtfs"
3
- require "sequel"
3
+ require "active_record"
4
+ require "bulk_insert"
5
+ require "gtfs/gtfs_gem_patch"
4
6
 
5
7
  require "gtfs/realtime/configuration"
8
+ require "gtfs/realtime/model"
9
+ require "gtfs/realtime/calendar_date"
10
+ require "gtfs/realtime/route"
11
+ require "gtfs/realtime/service_alert"
12
+ require "gtfs/realtime/shape"
13
+ require "gtfs/realtime/stop"
14
+ require "gtfs/realtime/stop_time"
15
+ require "gtfs/realtime/stop_time_update"
16
+ require "gtfs/realtime/trip"
17
+ require "gtfs/realtime/trip_update"
18
+ require "gtfs/realtime/vehicle_position"
19
+ require "gtfs/realtime/version"
6
20
 
7
21
  module GTFS
8
22
  class Realtime
@@ -17,9 +31,174 @@ module GTFS
17
31
  def configure
18
32
  yield(configuration)
19
33
 
34
+ run_migrations
20
35
  load_static_feed!
21
36
  refresh_realtime_feed!
22
37
  end
38
+
39
+ def load_static_feed!(force: false)
40
+ return if !force && GTFS::Realtime::Route.count > 0
41
+
42
+ static_data = GTFS::Source.build(@configuration.static_feed)
43
+ return unless static_data
44
+
45
+ GTFS::Realtime::Model.transaction do
46
+ GTFS::Realtime::CalendarDate.delete_all
47
+ GTFS::Realtime::CalendarDate.bulk_insert(values:
48
+ static_data.calendar_dates.collect do |calendar_date|
49
+ {
50
+ service_id: calendar_date.service_id.strip,
51
+ date: Date.strptime(calendar_date.date, "%Y%m%d"),
52
+ exception_type: calendar_date.exception_type
53
+ }
54
+ end
55
+ )
56
+
57
+ GTFS::Realtime::Route.delete_all
58
+ GTFS::Realtime::Route.bulk_insert(:id, :short_name, :long_name, :url, values:
59
+ static_data.routes.collect do |route|
60
+ {
61
+ id: route.id.strip,
62
+ short_name: route.short_name,
63
+ long_name: route.long_name,
64
+ url: route.url
65
+ }
66
+ end
67
+ )
68
+
69
+ GTFS::Realtime::Shape.delete_all
70
+ GTFS::Realtime::Shape.bulk_insert(:id, :sequence, :latitude, :longitude, values:
71
+ static_data.shapes.collect do |shape|
72
+ {
73
+ id: shape.id.strip,
74
+ sequence: shape.pt_sequence,
75
+ latitude: shape.pt_lat.to_f,
76
+ longitude: shape.pt_lon.to_f
77
+ }
78
+ end
79
+ )
80
+
81
+ GTFS::Realtime::Stop.delete_all
82
+ GTFS::Realtime::Stop.bulk_insert(:id, :name, :latitude, :longitude, values:
83
+ static_data.stops.collect do |stop|
84
+ {
85
+ id: stop.id.strip,
86
+ name: stop.name.strip,
87
+ latitude: stop.lat.to_f,
88
+ longitude: stop.lon.to_f
89
+ }
90
+ end
91
+ )
92
+
93
+ GTFS::Realtime::StopTime.delete_all
94
+ GTFS::Realtime::StopTime.bulk_insert(values:
95
+ static_data.stop_times.collect do |stop_time|
96
+ {
97
+ stop_id: stop_time.stop_id.strip,
98
+ trip_id: stop_time.trip_id.strip,
99
+ arrival_time: stop_time.arrival_time,
100
+ departure_time: stop_time.departure_time,
101
+ stop_sequence: stop_time.stop_sequence.to_i
102
+ }
103
+ end
104
+ )
105
+
106
+ GTFS::Realtime::Trip.delete_all
107
+ GTFS::Realtime::Trip.bulk_insert(:id, :headsign, :route_id, :service_id, :shape_id, :direction_id, values:
108
+ static_data.trips.collect do |trip|
109
+ {
110
+ id: trip.id.strip,
111
+ headsign: trip.headsign.strip,
112
+ route_id: trip.route_id.strip,
113
+ service_id: trip.service_id.strip,
114
+ shape_id: trip.shape_id.strip,
115
+ direction_id: trip.direction_id
116
+ }
117
+ end
118
+ )
119
+ end
120
+ end
121
+
122
+ def refresh_realtime_feed!
123
+ trip_updates = get_entities(@configuration.trip_updates_feed)
124
+ vehicle_positions = get_entities(@configuration.vehicle_positions_feed)
125
+ service_alerts = get_entities(@configuration.service_alerts_feed)
126
+
127
+ GTFS::Realtime::Model.transaction do
128
+ GTFS::Realtime::TripUpdate.delete_all
129
+ GTFS::Realtime::TripUpdate.bulk_insert(:id, :trip_id, :route_id, values:
130
+ trip_updates.collect do |trip_update|
131
+ {
132
+ id: trip_update.id.strip,
133
+ trip_id: trip_update.trip_update.trip.trip_id.strip,
134
+ route_id: trip_update.trip_update.trip.route_id.strip
135
+ }
136
+ end
137
+ )
138
+
139
+ GTFS::Realtime::StopTimeUpdate.delete_all
140
+ GTFS::Realtime::StopTimeUpdate.bulk_insert(values:
141
+ trip_updates.collect do |trip_update|
142
+ trip_update.trip_update.stop_time_update.collect do |stop_time_update|
143
+ {
144
+ trip_update_id: trip_update.id.strip,
145
+ stop_id: stop_time_update.stop_id.strip,
146
+ arrival_delay: stop_time_update.arrival ? stop_time_update.arrival.delay : nil,
147
+ arrival_time: stop_time_update.arrival ? Time.at(stop_time_update.arrival.time) : nil,
148
+ departure_delay: stop_time_update.departure ? stop_time_update.departure.delay : nil,
149
+ departure_time: stop_time_update.departure ? Time.at(stop_time_update.departure.time) : nil,
150
+ }
151
+ end
152
+ end.flatten
153
+ )
154
+
155
+ GTFS::Realtime::VehiclePosition.delete_all
156
+ GTFS::Realtime::VehiclePosition.bulk_insert(values:
157
+ vehicle_positions.collect do |vehicle|
158
+ {
159
+ trip_id: vehicle.vehicle.trip.trip_id.strip,
160
+ stop_id: vehicle.vehicle.stop_id.strip,
161
+ latitude: vehicle.vehicle.position.latitude.to_f,
162
+ longitude: vehicle.vehicle.position.longitude.to_f,
163
+ bearing: vehicle.vehicle.position.bearing.to_f,
164
+ timestamp: Time.at(vehicle.vehicle.timestamp)
165
+ }
166
+ end
167
+ )
168
+
169
+ GTFS::Realtime::ServiceAlert.delete_all
170
+ GTFS::Realtime::ServiceAlert.bulk_insert(values:
171
+ service_alerts.collect do |service_alert|
172
+ {
173
+ stop_id: service_alert.alert.informed_entity.first.stop_id.strip,
174
+ header_text: service_alert.alert.header_text.translation.first.text,
175
+ description_text: service_alert.alert.description_text.translation.first.text,
176
+ start_time: Time.at(service_alert.alert.active_period.first.start),
177
+ end_time: Time.at(service_alert.alert.active_period.first.end)
178
+ }
179
+ end
180
+ )
181
+ end
182
+ end
183
+
184
+ private
185
+
186
+ def get_entities(path)
187
+ return [] if path.nil?
188
+
189
+ if File.exists?(path)
190
+ data = File.open(path, 'r'){|f| f.read}
191
+ else
192
+ data = Net::HTTP.get(URI.parse(path))
193
+ end
194
+ feed = Transit_realtime::FeedMessage.decode(data)
195
+ feed.entity # array of entities
196
+ end
197
+
198
+ def run_migrations
199
+ ActiveRecord::Migration.verbose = false
200
+ ActiveRecord::Migrator.migrate(File.expand_path("../realtime/migrations", __FILE__))
201
+ end
23
202
  end
24
203
  end
25
204
  end
@@ -4,7 +4,7 @@ module GTFS
4
4
  ADDED = 1
5
5
  REMOVED = 2
6
6
 
7
- many_to_one :trip, primary_key: :service_id, key: :service_id
7
+ belongs_to :trip, primary_key: :service_id, foreign_key: :service_id
8
8
  end
9
9
  end
10
10
  end
@@ -1,17 +1,16 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class Configuration
4
- attr_accessor :static_feed, :trip_updates_feed, :vehicle_positions_feed, :service_alerts_feed, :database_path
4
+ attr_accessor :static_feed, :trip_updates_feed, :vehicle_positions_feed, :service_alerts_feed, :database_url
5
5
 
6
- def database_path=(new_path)
7
- @database_path = new_path
6
+ def database_url=(new_path)
7
+ @database_url = new_path
8
8
 
9
- # now that we know the DB path, we can initialize the database
10
- require 'gtfs/realtime/database'
11
- GTFS::Realtime::Database.path = database_path
12
-
13
- # now that we have a database, initialize all the other models
14
- require 'gtfs/realtime/bootstrap'
9
+ if @database_url
10
+ ActiveRecord::Base.establish_connection(@database_url)
11
+ else
12
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
13
+ end
15
14
  end
16
15
  end
17
16
  end
@@ -0,0 +1,81 @@
1
+ class CreateGtfsTables < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :gtfs_realtime_calendar_dates, id: false do |t|
4
+ t.string :service_id, index: true
5
+ t.date :date
6
+ t.integer :exception_type
7
+ end
8
+
9
+ create_table :gtfs_realtime_routes do |t|
10
+ t.string :short_name
11
+ t.string :long_name
12
+ t.string :url
13
+ end
14
+ change_column :gtfs_realtime_routes, :id, :string
15
+
16
+ create_table :gtfs_realtime_shapes, id: false do |t|
17
+ t.string :id # NOT unique
18
+ t.integer :sequence
19
+ t.float :latitude
20
+ t.float :longitude
21
+
22
+ t.index [:id, :sequence]
23
+ end
24
+
25
+ create_table :gtfs_realtime_stops do |t|
26
+ t.string :name
27
+ t.float :latitude
28
+ t.float :longitude
29
+ end
30
+ change_column :gtfs_realtime_stops, :id, :string
31
+
32
+ create_table :gtfs_realtime_stop_times, id: false do |t|
33
+ t.string :trip_id, index: true
34
+ t.string :stop_id, index: true
35
+ t.string :arrival_time
36
+ t.string :departure_time
37
+ t.integer :stop_sequence
38
+ end
39
+
40
+ create_table :gtfs_realtime_trips do |t|
41
+ t.string :headsign
42
+ t.string :route_id, index: true
43
+ t.string :service_id
44
+ t.string :shape_id
45
+ t.integer :direction_id
46
+ end
47
+ change_column :gtfs_realtime_trips, :id, :string
48
+
49
+ create_table :gtfs_realtime_trip_updates do |t|
50
+ t.string :trip_id
51
+ t.string :route_id
52
+ end
53
+ change_column :gtfs_realtime_trip_updates, :id, :string
54
+
55
+ create_table :gtfs_realtime_stop_time_updates, id: false do |t|
56
+ t.string :trip_update_id, index: true
57
+ t.string :stop_id, index: true
58
+ t.integer :arrival_delay
59
+ t.timestamp :arrival_time
60
+ t.integer :departure_delay
61
+ t.timestamp :departure_time
62
+ end
63
+
64
+ create_table :gtfs_realtime_vehicle_positions, id: false do |t|
65
+ t.string :trip_id, index: true
66
+ t.string :stop_id, index: true
67
+ t.float :latitude
68
+ t.float :longitude
69
+ t.float :bearing
70
+ t.timestamp :timestamp
71
+ end
72
+
73
+ create_table :gtfs_realtime_service_alerts, id: false do |t|
74
+ t.string :stop_id, index: true
75
+ t.string :header_text
76
+ t.text :description_text
77
+ t.timestamp :start_time
78
+ t.timestamp :end_time
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,8 @@
1
+ module GTFS
2
+ class Realtime
3
+ class Model < ActiveRecord::Base
4
+ self.abstract_class = true
5
+ self.table_name_prefix = "gtfs_realtime_"
6
+ end
7
+ end
8
+ end
@@ -1,7 +1,7 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class ServiceAlert < GTFS::Realtime::Model
4
- many_to_one :stop
4
+ belongs_to :stop
5
5
  end
6
6
  end
7
7
  end
@@ -1,14 +1,7 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class Shape < GTFS::Realtime::Model
4
- dataset_module do
5
- def ordered_by_sequence
6
- order(:sequence)
7
- end
8
- end
9
-
10
- # order results by sequence by default
11
- set_dataset(self.ordered_by_sequence)
4
+ scope :ordered, -> { order(sequence: :ASC) }
12
5
  end
13
6
  end
14
7
  end
@@ -5,24 +5,16 @@ module GTFS
5
5
  class Stop < GTFS::Realtime::Model
6
6
  include GTFS::Realtime::Nearby
7
7
 
8
- one_to_many :service_alerts
9
- one_to_many :stop_times
10
- one_to_many :stop_time_updates
11
- many_to_many :trip_updates, join_table: :gtfs_realtime_stop_time_updates
12
- many_to_many :trips, join_table: :gtfs_realtime_stop_times
13
- many_through_many :routes, through: [
14
- [:stop_times, :stop_id, :trip_id],
15
- [:trips, :id, :route_id]
16
- ]
17
- many_through_many :active_routes, class: GTFS::Realtime::Route, through: [
18
- [:stop_time_updates, :stop_id, :trip_update_id],
19
- [:trip_updates, :id, :route_id]
20
- ]
8
+ has_many :service_alerts
9
+ has_many :stop_times
10
+ has_many :stop_time_updates
11
+ has_many :trips, through: :stop_times
12
+ has_many :trip_updates, through: :stop_times
13
+ has_many :routes, through: :trips
14
+ has_many :active_routes, through: :trip_updates, source: :route
21
15
 
22
16
  def stop_times_schedule_for(date)
23
- # TODO: .all.first is a weird syntax to do eager loading correctly. Maybe there's a better way?
24
- self_with_eager_loads = GTFS::Realtime::Stop.where(id: id).eager(stop_times: {trip: [:calendar_dates, :route, :shapes]}).all.first
25
- self_with_eager_loads.stop_times.select{|st| st.trip.active?(Date.today)}.sort_by{|st| st.departure_time}
17
+ stop_times.includes(trip: [:calendar_dates, :route, :shapes]).select{|st| st.trip.active?(date)}.sort_by{|st| st.departure_time}
26
18
  end
27
19
 
28
20
  def stop_times_for_today
@@ -1,8 +1,9 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class StopTime < GTFS::Realtime::Model
4
- many_to_one :trip
5
- many_to_one :stop
4
+ belongs_to :trip
5
+ belongs_to :trip_update, primary_key: :trip_id, foreign_key: :trip_id
6
+ belongs_to :stop
6
7
 
7
8
  attr_accessor :actual_arrival_time, :actual_arrival_delay, :actual_departure_time, :actual_departure_delay
8
9
 
@@ -38,7 +39,6 @@ module GTFS
38
39
  private
39
40
 
40
41
  def self.parse_time(time, date = Date.today)
41
- # TODO: handle case where date != Date.today
42
42
  day_adjustment = 0
43
43
  hour = time[0...2].to_i
44
44
 
@@ -48,7 +48,7 @@ module GTFS
48
48
  time[0...2] = (hour % 24).to_s.rjust(2, '0')
49
49
  end
50
50
 
51
- Time.parse(time) + day_adjustment * 60 * 60 * 24
51
+ Time.parse("#{date} #{time}").in_time_zone(Time.zone) + day_adjustment * 60 * 60 * 24
52
52
  end
53
53
  end
54
54
  end
@@ -1,10 +1,18 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class StopTimeUpdate < GTFS::Realtime::Model
4
- one_through_one :route, join_table: :gtfs_realtime_trip_updates, left_key: :id, left_primary_key: :trip_update_id, right_key: :route_id
5
- many_to_one :stop
6
- one_through_one :trip, join_table: :gtfs_realtime_trip_updates, left_key: :id, left_primary_key: :trip_update_id, right_key: :trip_id
7
- many_to_one :trip_update
4
+ belongs_to :stop
5
+ belongs_to :trip_update
6
+ has_one :trip, through: :trip_update
7
+ has_one :route, through: :trip_update
8
+
9
+ def arrival_time
10
+ super ? super.in_time_zone(Time.zone) : nil
11
+ end
12
+
13
+ def departure_time
14
+ super ? super.in_time_zone(Time.zone) : nil
15
+ end
8
16
  end
9
17
  end
10
18
  end
@@ -1,14 +1,14 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class Trip < GTFS::Realtime::Model
4
- many_to_one :route
5
- many_to_many :stops, join_table: :gtfs_realtime_stop_times
6
- one_to_many :calendar_dates, primary_key: :service_id, key: :service_id
7
- one_to_many :shapes, primary_key: :shape_id, key: :id
4
+ belongs_to :route
5
+ has_many :stop_times
6
+ has_many :stops, through: :stop_times
7
+ has_many :calendar_dates, primary_key: :service_id, foreign_key: :service_id
8
+ has_many :shapes, primary_key: :shape_id, foreign_key: :id
8
9
 
9
10
  def active?(date)
10
- # can't use .where chaining b/c Sequel is weird
11
- calendar_dates.find{|cd| cd.exception_type == GTFS::Realtime::CalendarDate::ADDED && cd.date == date}
11
+ calendar_dates.where(exception_type: GTFS::Realtime::CalendarDate::ADDED, date: date).any?
12
12
  end
13
13
  end
14
14
  end
@@ -1,8 +1,8 @@
1
1
  module GTFS
2
2
  class Realtime
3
3
  class TripUpdate < GTFS::Realtime::Model
4
- many_to_one :trip
5
- many_to_one :route
4
+ belongs_to :trip
5
+ belongs_to :route
6
6
  end
7
7
  end
8
8
  end
@@ -5,8 +5,8 @@ module GTFS
5
5
  class VehiclePosition < GTFS::Realtime::Model
6
6
  include GTFS::Realtime::Nearby
7
7
 
8
- many_to_one :stop
9
- many_to_one :trip
8
+ belongs_to :stop
9
+ belongs_to :trip
10
10
  end
11
11
  end
12
12
  end
@@ -1,5 +1,5 @@
1
1
  module GTFS
2
2
  class Realtime
3
- VERSION = "0.3.0"
3
+ VERSION = "0.4.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gtfs-realtime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Laughlin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-11-26 00:00:00.000000000 Z
11
+ date: 2016-12-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -109,7 +109,21 @@ dependencies:
109
109
  - !ruby/object:Gem::Version
110
110
  version: '0'
111
111
  - !ruby/object:Gem::Dependency
112
- name: sequel
112
+ name: activerecord
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: bulk_insert
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
129
  - - ">="
@@ -143,10 +157,10 @@ files:
143
157
  - gtfs-realtime.gemspec
144
158
  - lib/gtfs/gtfs_gem_patch.rb
145
159
  - lib/gtfs/realtime.rb
146
- - lib/gtfs/realtime/bootstrap.rb
147
160
  - lib/gtfs/realtime/calendar_date.rb
148
161
  - lib/gtfs/realtime/configuration.rb
149
- - lib/gtfs/realtime/database.rb
162
+ - lib/gtfs/realtime/migrations/001_create_gtfs_tables.rb
163
+ - lib/gtfs/realtime/model.rb
150
164
  - lib/gtfs/realtime/nearby.rb
151
165
  - lib/gtfs/realtime/route.rb
152
166
  - lib/gtfs/realtime/service_alert.rb
@@ -1,178 +0,0 @@
1
- require "gtfs/gtfs_gem_patch"
2
- require "gtfs/realtime/calendar_date"
3
- require "gtfs/realtime/route"
4
- require "gtfs/realtime/service_alert"
5
- require "gtfs/realtime/shape"
6
- require "gtfs/realtime/stop"
7
- require "gtfs/realtime/stop_time"
8
- require "gtfs/realtime/stop_time_update"
9
- require "gtfs/realtime/trip"
10
- require "gtfs/realtime/trip_update"
11
- require "gtfs/realtime/vehicle_position"
12
- require "gtfs/realtime/version"
13
-
14
- module GTFS
15
- class Realtime
16
- # This is a singleton object, so everything will be on the class level
17
- class << self
18
- def load_static_feed!(force: false)
19
- return if !force && GTFS::Realtime::Route.count > 0
20
-
21
- static_data = GTFS::Source.build(@configuration.static_feed)
22
- return unless static_data
23
-
24
- GTFS::Realtime::Model.db.transaction do
25
- GTFS::Realtime::CalendarDate.dataset.delete
26
- GTFS::Realtime::CalendarDate.multi_insert(
27
- static_data.calendar_dates.collect do |calendar_date|
28
- {
29
- service_id: calendar_date.service_id.strip,
30
- date: Date.strptime(calendar_date.date, "%Y%m%d"),
31
- exception_type: calendar_date.exception_type
32
- }
33
- end
34
- )
35
-
36
- GTFS::Realtime::Route.dataset.delete
37
- GTFS::Realtime::Route.multi_insert(
38
- static_data.routes.collect do |route|
39
- {
40
- id: route.id.strip,
41
- short_name: route.short_name,
42
- long_name: route.long_name,
43
- url: route.url
44
- }
45
- end
46
- )
47
-
48
- GTFS::Realtime::Shape.dataset.delete
49
- GTFS::Realtime::Shape.multi_insert(
50
- static_data.shapes.collect do |shape|
51
- {
52
- id: shape.id.strip,
53
- sequence: shape.pt_sequence,
54
- latitude: shape.pt_lat.to_f,
55
- longitude: shape.pt_lon.to_f
56
- }
57
- end
58
- )
59
-
60
- GTFS::Realtime::Stop.dataset.delete
61
- GTFS::Realtime::Stop.multi_insert(
62
- static_data.stops.collect do |stop|
63
- {
64
- id: stop.id.strip,
65
- name: stop.name.strip,
66
- latitude: stop.lat.to_f,
67
- longitude: stop.lon.to_f
68
- }
69
- end
70
- )
71
-
72
- GTFS::Realtime::StopTime.dataset.delete
73
- GTFS::Realtime::StopTime.multi_insert(
74
- static_data.stop_times.collect do |stop_time|
75
- {
76
- stop_id: stop_time.stop_id.strip,
77
- trip_id: stop_time.trip_id.strip,
78
- arrival_time: stop_time.arrival_time,
79
- departure_time: stop_time.departure_time,
80
- stop_sequence: stop_time.stop_sequence.to_i
81
- }
82
- end
83
- )
84
-
85
- GTFS::Realtime::Trip.dataset.delete
86
- GTFS::Realtime::Trip.multi_insert(
87
- static_data.trips.collect do |trip|
88
- {
89
- id: trip.id.strip,
90
- headsign: trip.headsign.strip,
91
- route_id: trip.route_id.strip,
92
- service_id: trip.service_id.strip,
93
- shape_id: trip.shape_id.strip,
94
- direction_id: trip.direction_id
95
- }
96
- end
97
- )
98
- end
99
- end
100
-
101
- def refresh_realtime_feed!
102
- trip_updates = get_entities(@configuration.trip_updates_feed)
103
- vehicle_positions = get_entities(@configuration.vehicle_positions_feed)
104
- service_alerts = get_entities(@configuration.service_alerts_feed)
105
-
106
- GTFS::Realtime::Model.db.transaction do
107
- GTFS::Realtime::TripUpdate.dataset.delete
108
- GTFS::Realtime::TripUpdate.multi_insert(
109
- trip_updates.collect do |trip_update|
110
- {
111
- id: trip_update.id.strip,
112
- trip_id: trip_update.trip_update.trip.trip_id.strip,
113
- route_id: trip_update.trip_update.trip.route_id.strip
114
- }
115
- end
116
- )
117
-
118
- GTFS::Realtime::StopTimeUpdate.dataset.delete
119
- GTFS::Realtime::StopTimeUpdate.multi_insert(
120
- trip_updates.collect do |trip_update|
121
- trip_update.trip_update.stop_time_update.collect do |stop_time_update|
122
- {
123
- trip_update_id: trip_update.id.strip,
124
- stop_id: stop_time_update.stop_id.strip,
125
- arrival_delay: stop_time_update.arrival ? stop_time_update.arrival.delay : nil,
126
- arrival_time: stop_time_update.arrival ? Time.at(stop_time_update.arrival.time) : nil,
127
- departure_delay: stop_time_update.departure ? stop_time_update.departure.delay : nil,
128
- departure_time: stop_time_update.departure ? Time.at(stop_time_update.departure.time) : nil,
129
- }
130
- end
131
- end.flatten
132
- )
133
-
134
- GTFS::Realtime::VehiclePosition.dataset.delete
135
- GTFS::Realtime::VehiclePosition.multi_insert(
136
- vehicle_positions.collect do |vehicle|
137
- {
138
- trip_id: vehicle.vehicle.trip.trip_id.strip,
139
- stop_id: vehicle.vehicle.stop_id.strip,
140
- latitude: vehicle.vehicle.position.latitude.to_f,
141
- longitude: vehicle.vehicle.position.longitude.to_f,
142
- bearing: vehicle.vehicle.position.bearing.to_f,
143
- timestamp: Time.at(vehicle.vehicle.timestamp)
144
- }
145
- end
146
- )
147
-
148
- GTFS::Realtime::ServiceAlert.dataset.delete
149
- GTFS::Realtime::ServiceAlert.multi_insert(
150
- service_alerts.collect do |service_alert|
151
- {
152
- stop_id: service_alert.alert.informed_entity.first.stop_id.strip,
153
- header_text: service_alert.alert.header_text.translation.first.text,
154
- description_text: service_alert.alert.description_text.translation.first.text,
155
- start_time: Time.at(service_alert.alert.active_period.first.start),
156
- end_time: Time.at(service_alert.alert.active_period.first.end)
157
- }
158
- end
159
- )
160
- end
161
- end
162
-
163
- private
164
-
165
- def get_entities(path)
166
- return [] if path.nil?
167
-
168
- if File.exists?(path)
169
- data = File.open(path, 'r'){|f| f.read}
170
- else
171
- data = Net::HTTP.get(URI.parse(path))
172
- end
173
- feed = Transit_realtime::FeedMessage.decode(data)
174
- feed.entity # array of entities
175
- end
176
- end
177
- end
178
- end
@@ -1,140 +0,0 @@
1
- module GTFS
2
- class Realtime
3
- class Database
4
- class << self
5
- attr_writer :database_path
6
-
7
- def path=(new_path)
8
- @path = new_path
9
-
10
- # This script sets up an in-memory DB so that it can be used by this gem.
11
- # It also extends Sequel::Model so that Sequel may be used independently by
12
- # the parent project if desired.
13
- db = Sequel.connect(new_path || "sqlite://")
14
-
15
- # Set up all database tables
16
- db.create_table? :gtfs_realtime_calendar_dates do
17
- String :service_id
18
- Date :date
19
- Integer :exception_type
20
-
21
- index :service_id
22
- end
23
-
24
- db.create_table? :gtfs_realtime_routes do
25
- String :id, primary_key: true
26
- String :short_name
27
- String :long_name
28
- String :url
29
-
30
- index :id
31
- end
32
-
33
- db.create_table? :gtfs_realtime_shapes do
34
- String :id
35
- Integer :sequence
36
- Float :latitude
37
- Float :longitude
38
-
39
- index :id
40
- end
41
-
42
- db.create_table? :gtfs_realtime_stops do
43
- String :id, primary_key: true
44
- String :name
45
- Float :latitude
46
- Float :longitude
47
-
48
- index :id
49
- end
50
-
51
- db.create_table? :gtfs_realtime_stop_times do
52
- String :trip_id
53
- String :stop_id
54
- String :arrival_time
55
- String :departure_time
56
- Integer :stop_sequence
57
-
58
- index :trip_id
59
- index :stop_id
60
- end
61
-
62
- db.create_table? :gtfs_realtime_trips do
63
- String :id, primary_key: true
64
- String :headsign
65
- String :route_id
66
- String :service_id
67
- String :shape_id
68
- Integer :direction_id
69
-
70
- index :id
71
- index :route_id
72
- end
73
-
74
- db.create_table? :gtfs_realtime_trip_updates do
75
- String :id, primary_key: true
76
- String :trip_id
77
- String :route_id
78
-
79
- index :id
80
- end
81
-
82
- db.create_table? :gtfs_realtime_stop_time_updates do
83
- String :trip_update_id
84
- String :stop_id
85
- Integer :arrival_delay
86
- Time :arrival_time
87
- Integer :departure_delay
88
- Time :departure_time
89
-
90
- index :trip_update_id
91
- index :stop_id
92
- end
93
-
94
- db.create_table? :gtfs_realtime_vehicle_positions do
95
- String :trip_id
96
- String :stop_id
97
- Float :latitude
98
- Float :longitude
99
- Float :bearing
100
- Time :timestamp
101
-
102
- index :trip_id
103
- index :stop_id
104
- end
105
-
106
- db.create_table? :gtfs_realtime_service_alerts do
107
- String :stop_id
108
- String :header_text
109
- Text :description_text
110
- Time :start_time
111
- Time :end_time
112
-
113
- index :stop_id
114
- end
115
-
116
- # Set up all gtfs-realtime models to use this database
117
- model_classes.each do |model_class|
118
- model_class.db = db
119
- end
120
- end
121
-
122
- def model_classes
123
- ObjectSpace.each_object(::Class).select{|klass| klass <= GTFS::Realtime::Model}
124
- end
125
- end
126
- end
127
- end
128
- end
129
-
130
- # If we have not defined our model parent class yet, initialize it.
131
- if !defined?(GTFS::Realtime::Model)
132
- GTFS::Realtime::Model = Class.new(Sequel::Model)
133
- GTFS::Realtime::Model.plugin :many_through_many
134
-
135
- class GTFS::Realtime::Model
136
- def self.implicit_table_name
137
- "gtfs_realtime_#{super}".to_sym
138
- end
139
- end
140
- end