Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ gem 'scenic' # manage DB views, materialized views
gem 'strong_migrations' # Use safe Migration patterns

gem 'rubocop'
gem 'rollups'

group :development, :test do
gem 'active_record_doctor'
Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ GEM
google-protobuf (4.31.0-x86_64-linux-gnu)
bigdecimal
rake (>= 13)
groupdate (6.7.0)
activesupport (>= 7.1)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
importmap-rails (1.2.3)
Expand Down Expand Up @@ -289,6 +291,9 @@ GEM
io-console (~> 0.5)
require_all (3.0.0)
rexml (3.4.1)
rollups (0.5.0)
activesupport (>= 7.1)
groupdate (>= 6.1)
rubocop (1.75.7)
json (~> 2.3)
language_server-protocol (~> 3.17.0.2)
Expand Down Expand Up @@ -384,6 +389,7 @@ DEPENDENCIES
rails-erd
rails-pg-extras
rails_best_practices
rollups
rubocop
scenic
sprockets-rails (~> 3.4)
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ PostgreSQL 16 or greater is required. Installation may be via Homebrew, although
### PostgresApp
- Once installed, from the Menu Bar app, choose "Open Postgres" then click the "+" icon to create a new PostgreSQL 16 server


## Ruby
Run `cat .ruby-version` from the Rideshare directory to find the needed version of Ruby.

Expand Down
5 changes: 4 additions & 1 deletion config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Application < Rails::Application
# set a timezone. Times are generally stored as
# timestamps without a time zone. This application
# would need to treat times based on the user's timezone.

config.time_zone = 'Central Time (US & Canada)'

# Enable Query Logging
Expand All @@ -63,6 +64,8 @@ class Application < Rails::Application
# Consider timestamps in the local time zone
# This is because the app used "timestamp without time zone" columns and times are
# stored in the local timezone (CST).
config.active_record.default_timezone = :local

# Needed for ankane/rollups
config.active_record.default_timezone = :utc
end
end
12 changes: 12 additions & 0 deletions db/migrate/20250606201409_create_rollups.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
class CreateRollups < ActiveRecord::Migration[7.2]
def change
create_table :rollups do |t|
t.string :name, null: false
t.string :interval, null: false
t.datetime :time, null: false
t.jsonb :dimensions, null: false, default: {}
t.float :value
end
add_index :rollups, [:name, :interval, :time, :dimensions], unique: true
end
end
61 changes: 61 additions & 0 deletions db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ DROP INDEX IF EXISTS rideshare.index_trips_on_driver_id;
DROP INDEX IF EXISTS rideshare.index_trip_requests_on_start_location_id;
DROP INDEX IF EXISTS rideshare.index_trip_requests_on_rider_id;
DROP INDEX IF EXISTS rideshare.index_trip_requests_on_end_location_id;
DROP INDEX IF EXISTS rideshare.index_rollups_on_name_and_interval_and_time_and_dimensions;
DROP INDEX IF EXISTS rideshare.index_locations_on_address;
DROP INDEX IF EXISTS rideshare.index_fast_search_results_on_driver_id;
ALTER TABLE IF EXISTS ONLY rideshare.vehicles DROP CONSTRAINT IF EXISTS vehicles_pkey;
Expand All @@ -36,6 +37,7 @@ ALTER TABLE IF EXISTS ONLY rideshare.trips DROP CONSTRAINT IF EXISTS trips_pkey;
ALTER TABLE IF EXISTS ONLY rideshare.trip_requests DROP CONSTRAINT IF EXISTS trip_requests_pkey;
ALTER TABLE IF EXISTS ONLY rideshare.trip_positions DROP CONSTRAINT IF EXISTS trip_positions_pkey;
ALTER TABLE IF EXISTS ONLY rideshare.schema_migrations DROP CONSTRAINT IF EXISTS schema_migrations_pkey;
ALTER TABLE IF EXISTS ONLY rideshare.rollups DROP CONSTRAINT IF EXISTS rollups_pkey;
ALTER TABLE IF EXISTS ONLY rideshare.vehicle_reservations DROP CONSTRAINT IF EXISTS non_overlapping_vehicle_registration;
ALTER TABLE IF EXISTS ONLY rideshare.locations DROP CONSTRAINT IF EXISTS locations_pkey;
ALTER TABLE IF EXISTS rideshare.trips DROP CONSTRAINT IF EXISTS chk_rails_4743ddc2d2;
Expand All @@ -46,6 +48,7 @@ ALTER TABLE IF EXISTS rideshare.users ALTER COLUMN id DROP DEFAULT;
ALTER TABLE IF EXISTS rideshare.trips ALTER COLUMN id DROP DEFAULT;
ALTER TABLE IF EXISTS rideshare.trip_requests ALTER COLUMN id DROP DEFAULT;
ALTER TABLE IF EXISTS rideshare.trip_positions ALTER COLUMN id DROP DEFAULT;
ALTER TABLE IF EXISTS rideshare.rollups ALTER COLUMN id DROP DEFAULT;
ALTER TABLE IF EXISTS rideshare.locations ALTER COLUMN id DROP DEFAULT;
DROP SEQUENCE IF EXISTS rideshare.vehicles_id_seq;
DROP TABLE IF EXISTS rideshare.vehicles;
Expand All @@ -59,6 +62,8 @@ DROP SEQUENCE IF EXISTS rideshare.trip_positions_id_seq;
DROP TABLE IF EXISTS rideshare.trip_positions;
DROP VIEW IF EXISTS rideshare.search_results;
DROP TABLE IF EXISTS rideshare.schema_migrations;
DROP SEQUENCE IF EXISTS rideshare.rollups_id_seq;
DROP TABLE IF EXISTS rideshare.rollups;
DROP SEQUENCE IF EXISTS rideshare.locations_id_seq;
DROP TABLE IF EXISTS rideshare.locations;
DROP MATERIALIZED VIEW IF EXISTS rideshare.fast_search_results;
Expand Down Expand Up @@ -291,6 +296,39 @@ CREATE SEQUENCE rideshare.locations_id_seq
ALTER SEQUENCE rideshare.locations_id_seq OWNED BY rideshare.locations.id;


--
-- Name: rollups; Type: TABLE; Schema: rideshare; Owner: -
--

CREATE TABLE rideshare.rollups (
id bigint NOT NULL,
name character varying NOT NULL,
"interval" character varying NOT NULL,
"time" timestamp(6) without time zone NOT NULL,
dimensions jsonb DEFAULT '{}'::jsonb NOT NULL,
value double precision
);


--
-- Name: rollups_id_seq; Type: SEQUENCE; Schema: rideshare; Owner: -
--

CREATE SEQUENCE rideshare.rollups_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;


--
-- Name: rollups_id_seq; Type: SEQUENCE OWNED BY; Schema: rideshare; Owner: -
--

ALTER SEQUENCE rideshare.rollups_id_seq OWNED BY rideshare.rollups.id;


--
-- Name: schema_migrations; Type: TABLE; Schema: rideshare; Owner: -
--
Expand Down Expand Up @@ -491,6 +529,13 @@ ALTER SEQUENCE rideshare.vehicles_id_seq OWNED BY rideshare.vehicles.id;
ALTER TABLE ONLY rideshare.locations ALTER COLUMN id SET DEFAULT nextval('rideshare.locations_id_seq'::regclass);


--
-- Name: rollups id; Type: DEFAULT; Schema: rideshare; Owner: -
--

ALTER TABLE ONLY rideshare.rollups ALTER COLUMN id SET DEFAULT nextval('rideshare.rollups_id_seq'::regclass);


--
-- Name: trip_positions id; Type: DEFAULT; Schema: rideshare; Owner: -
--
Expand Down Expand Up @@ -565,6 +610,14 @@ ALTER TABLE ONLY rideshare.vehicle_reservations
ADD CONSTRAINT non_overlapping_vehicle_registration EXCLUDE USING gist (int4range(vehicle_id, vehicle_id, '[]'::text) WITH =, tstzrange(starts_at, ends_at) WITH &&) WHERE ((NOT canceled));


--
-- Name: rollups rollups_pkey; Type: CONSTRAINT; Schema: rideshare; Owner: -
--

ALTER TABLE ONLY rideshare.rollups
ADD CONSTRAINT rollups_pkey PRIMARY KEY (id);


--
-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: rideshare; Owner: -
--
Expand Down Expand Up @@ -635,6 +688,13 @@ CREATE UNIQUE INDEX index_fast_search_results_on_driver_id ON rideshare.fast_sea
CREATE UNIQUE INDEX index_locations_on_address ON rideshare.locations USING btree (address);


--
-- Name: index_rollups_on_name_and_interval_and_time_and_dimensions; Type: INDEX; Schema: rideshare; Owner: -
--

CREATE UNIQUE INDEX index_rollups_on_name_and_interval_and_time_and_dimensions ON rideshare.rollups USING btree (name, "interval", "time", dimensions);


--
-- Name: index_trip_requests_on_end_location_id; Type: INDEX; Schema: rideshare; Owner: -
--
Expand Down Expand Up @@ -776,6 +836,7 @@ ALTER TABLE ONLY rideshare.trip_requests
SET search_path TO rideshare;

INSERT INTO "schema_migrations" (version) VALUES
('20250606201409'),
('20231220043547'),
('20231218215836'),
('20231213045957'),
Expand Down
24 changes: 24 additions & 0 deletions docs/rollups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Rollups
<https://github.com/ankane/rollup>

## Example
- Rollups for new drivers created on the platform

Populate drivers over the last week:
```sh
bin/rails data_generators:drivers
```

Create rollups:
```sh
rails runner 'Driver.rollup("New drivers")'

Driver.rollup("New drivers", range: 1.week.ago.all_week)
```

Check driver counts for a day:
```
Rollup.series("New drivers")

Rollup.where(time: Date.yesterday).series("New drivers").values.last.to_i
```
Binary file modified erd.pdf
Binary file not shown.
14 changes: 11 additions & 3 deletions lib/tasks/fake_data_generator.rake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'faker'

namespace :data_generators do
desc 'Generator Drivers'
desc 'Generate Drivers'
task drivers: :environment do |_t, _args|
TOTAL = 20_000
BATCH_SIZE = 10_000
Expand All @@ -14,12 +14,14 @@ namespace :data_generators do
first_name: first_name,
last_name: last_name,
email: "#{first_name}-#{last_name}-#{i}@email.com",
password_digest: SecureRandom.hex
password_digest: SecureRandom.hex,
created_at: random_day
)
end.map do |d|
d.attributes.symbolize_keys.slice(
:first_name, :last_name,
:email, :password, :type
:email, :password, :type,
:created_at
)
end

Expand All @@ -31,4 +33,10 @@ namespace :data_generators do
Driver.connection.execute('VACUUM (ANALYZE) users')
puts results
end

private

def random_day
(Date.today - rand(7))
end
end