Skip to content

Commit

Permalink
add generator
Browse files Browse the repository at this point in the history
  • Loading branch information
sallyhall committed Dec 16, 2024
1 parent ef1f6d8 commit 4e1134d
Showing 1 changed file with 162 additions and 0 deletions.
162 changes: 162 additions & 0 deletions lib/michel/generators/michel_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
class MichelGenerator < Rails::Generators::Base
def add_scenic_gem
puts "Adding scenic gem to Gemfile"
gem "scenic"
`bundle install`
end

def create_index_in_migration
puts "Generating bookings index migration"
generate "migration", "add_index_to_bookings"
Dir.glob("db/migrate/*add_index_to_bookings.rb").each do |file|
insert_into_file file, after: "def change" do
<<~RUBY
\nreversible do |direction|
direction.up do
execute <<-SQL
CREATE EXTENSION btree_gist;
CREATE INDEX on bookings using gist (resource_id, tsrange(start_time, start_time + interval '1 minute' * duration, '()'));
SQL
end
direction.down do
execute <<-SQL
DROP INDEX bookings_resource_id_tsrange_idx;
DROP EXTENSION IF EXISTS btree_gist;
SQL
end
end
RUBY
end
end
end

def create_scenic_model
puts "Creating scenic model available_time_slots"
generate "scenic:model", "available_time_slots", "--materialized"
end

def create_sql_file
puts "Creating materialized view SQL at db/views/available_time_slots_v01.sql"
insert_into_file "db/views/available_time_slots_v01.sql" do
<<~SQL
WITH RECURSIVE time_slots AS (
-- Generate a series of dates for the next year, starting from tomorrow
SELECT
p.id AS availability_id,
p.resource_id,
-- what is DATE_TRUNC?
-- DATE_TRUNC('week', CURRENT_DATE) returns the first day of the week
(DATE_TRUNC('week', CURRENT_DATE) + (p.weekday - 1 || ' days')::interval) AS start_date,
CURRENT_DATE + INTERVAL '6 months' AS end_date,
p.start_time,
p.end_time,
p.timezone
FROM
availabilities p
UNION ALL
-- Recursively generate dates for all instances of the given weekday
SELECT
ts.availability_id,
ts.resource_id,
ts.start_date + INTERVAL '1 week' AS start_date, -- Explicitly alias the column
ts.end_date,
ts.start_time,
ts.end_time,
ts.timezone
FROM
time_slots ts
WHERE
ts.start_date + INTERVAL '1 week' <= ts.end_date
),
-- Generate time slots for each day, every 15 minutes
slot_intervals AS (
SELECT
ts.availability_id,
ts.resource_id,
ts.start_date,
-- Create proper timestamps for start and end times with timezone handling
(make_timestamptz(
date_part('year', ts.start_date)::integer,
date_part('month', ts.start_date)::integer,
date_part('day', ts.start_date)::integer,
split_part(ts.start_time, ':', 1)::int,
split_part(ts.start_time, ':', 2)::int,
0,
ts.timezone
)) AT TIME ZONE 'UTC' AS slot_start_time,
(make_timestamptz(
date_part('year', ts.start_date)::integer,
date_part('month', ts.start_date)::integer,
date_part('day', ts.start_date)::integer,
split_part(ts.end_time, ':', 1)::int,
split_part(ts.end_time, ':', 2)::int,
0,
ts.timezone
)) AT TIME ZONE 'UTC' AS slot_end_time
FROM
time_slots ts
),
time_slots_every_15_min AS (
SELECT
si.availability_id,
si.resource_id,
si.start_date,
-- Generate the series for time slots every 15 minutes
generate_series(
GREATEST(si.slot_start_time, CURRENT_DATE + INTERVAL '1 day'),
-- Ensure it starts from tomorrow
si.slot_end_time - INTERVAL '30 minutes',
INTERVAL '15 minutes'
) AS slot_start_time
FROM
slot_intervals si
)
SELECT
concat(availability_id, slot_start_time) AS id,
availability_id,
resource_id,
slot_start_time as start_time,
slot_start_time + INTERVAL '30 minutes' AS end_time
FROM
time_slots_every_15_min
EXCEPT
SELECT
concat(availability_id, slot_start_time) AS id,
time_slots_every_15_min.availability_id,
time_slots_every_15_min.resource_id,
time_slots_every_15_min.slot_start_time as start_time,
time_slots_every_15_min.slot_start_time + INTERVAL '30 minutes' AS end_time
FROM time_slots_every_15_min
CROSS JOIN bookings
WHERE tsrange(bookings.start_time, bookings.start_time + interval '1 minute' * bookings.duration, '()')
&& tsrange(time_slots_every_15_min.slot_start_time, time_slots_every_15_min.slot_start_time + INTERVAL '30 minutes', '()')
AND bookings.resource_id = time_slots_every_15_min.resource_id
SQL
end
end

def add_associations_to_models
insert_into_file "app/models/availability.rb", after: "class Availability < ApplicationRecord" do
<<~RUBY
\nhas_many :available_time_slots
RUBY
end

insert_into_file "app/models/available_time_slot.rb", after: "class AvailableTimeSlot < ApplicationRecord" do
<<~RUBY
\nbelongs_to :availability
\nbelongs_to :resource
RUBY
end

insert_into_file "app/models/resource.rb", after: "class Resource < ApplicationRecord" do
<<~RUBY
\nhas_many :available_time_slots
RUBY
end
end
end

0 comments on commit 4e1134d

Please sign in to comment.