From 8ad9b396088a6f96a1df3250ba10e3490cf5948a Mon Sep 17 00:00:00 2001 From: Nathan Smith Date: Sun, 27 Aug 2023 12:01:51 -0700 Subject: [PATCH] wip --- app/models/relationship.rb | 23 ++-- ...0230827154404_track_relationship_status.rb | 2 +- db/structure.sql | 2 +- sorbet/rbi/dsl/relationship.rbi | 119 ++++++++++++++++++ 4 files changed, 137 insertions(+), 9 deletions(-) diff --git a/app/models/relationship.rb b/app/models/relationship.rb index 61ff2273..3c505a27 100644 --- a/app/models/relationship.rb +++ b/app/models/relationship.rb @@ -8,14 +8,23 @@ class Relationship < ApplicationRecord belongs_to :section has_one :review, dependent: :restrict_with_exception + enum stored_status: { + planned: "planned", + subscribed: "subscribed", + enrolled: "enrolled", + } + class Status < T::Enum enums do - Planned = new - Subscribed = new - Enrolled = new + # A relationship can be in one of the following states: + Planned = new("planned") # A user has put this section into their class plan for a quarter + Subscribed = new("subscribed") # The section is in a class plan and the user wants enrollment notifications for the section + Enrolled = new("enrolled") # The section has been enrolled in. No need to send further notifications. + + Completed = new("completed") # Where enrolled sections go after the quarter ends. The user has taken the course! + Reviewed = new("reviewed") # The user has taken the section and reviewed it. - Completed = new - Reviewed = new + # How does Status differ from stored_status above? We track the first three states (planned, subscribed, enrolled) in the database on this relationship model. The other two states (completed, reviewed) are derived based off other information (term calendar and if a review was written, respectively). end end @@ -25,8 +34,8 @@ def status Status::Reviewed elsif completed? Status::Completed - # else - # current_status + else + Status.deserialize(stored_status) end end diff --git a/db/migrate/20230827154404_track_relationship_status.rb b/db/migrate/20230827154404_track_relationship_status.rb index d4c93aea..3324482b 100644 --- a/db/migrate/20230827154404_track_relationship_status.rb +++ b/db/migrate/20230827154404_track_relationship_status.rb @@ -19,7 +19,7 @@ def change change_table(:relationships, bulk: true) do |t| # Will make this non-null in a future migration - t.column(:status, :relationship_status) + t.column(:stored_status, :relationship_status) end end end diff --git a/db/structure.sql b/db/structure.sql index 6e5f229e..730c61bc 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -982,7 +982,7 @@ CREATE TABLE public.relationships ( created_at timestamp(6) without time zone NOT NULL, updated_at timestamp(6) without time zone NOT NULL, notify boolean DEFAULT false NOT NULL, - status public.relationship_status + stored_status public.relationship_status ); diff --git a/sorbet/rbi/dsl/relationship.rbi b/sorbet/rbi/dsl/relationship.rbi index cd121626..70f6de1f 100644 --- a/sorbet/rbi/dsl/relationship.rbi +++ b/sorbet/rbi/dsl/relationship.rbi @@ -7,6 +7,7 @@ class Relationship include GeneratedAssociationMethods include GeneratedAttributeMethods + include EnumMethodsModule extend CommonRelationMethods extend GeneratedRelationMethods @@ -15,6 +16,11 @@ class Relationship sig { returns(NilClass) } def to_ary; end + class << self + sig { returns(T::Hash[T.any(String, Symbol), String]) } + def stored_statuses; end + end + module CommonRelationMethods sig { params(block: T.nilable(T.proc.params(record: ::Relationship).returns(T.untyped))).returns(T::Boolean) } def any?(&block); end @@ -263,6 +269,26 @@ class Relationship def third_to_last!; end end + module EnumMethodsModule + sig { void } + def enrolled!; end + + sig { returns(T::Boolean) } + def enrolled?; end + + sig { void } + def planned!; end + + sig { returns(T::Boolean) } + def planned?; end + + sig { void } + def subscribed!; end + + sig { returns(T::Boolean) } + def subscribed?; end + end + module GeneratedAssociationMethods sig { params(args: T.untyped, blk: T.untyped).returns(::Review) } def build_review(*args, &blk); end @@ -338,6 +364,9 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def eager_load(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def enrolled(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def except(*args, &blk); end @@ -423,6 +452,15 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def none(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def not_enrolled(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def not_planned(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def not_subscribed(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def offset(*args, &blk); end @@ -438,6 +476,9 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def order(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def planned(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def preload(*args, &blk); end @@ -468,6 +509,9 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def structurally_compatible?(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } + def subscribed(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateAssociationRelation) } def uniq!(*args, &blk); end @@ -647,6 +691,9 @@ class Relationship sig { void } def restore_section_id!; end + sig { void } + def restore_stored_status!; end + sig { void } def restore_updated_at!; end @@ -677,6 +724,12 @@ class Relationship sig { returns(T::Boolean) } def saved_change_to_section_id?; end + sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) } + def saved_change_to_stored_status; end + + sig { returns(T::Boolean) } + def saved_change_to_stored_status?; end + sig { returns(T.nilable([T.nilable(::ActiveSupport::TimeWithZone), T.nilable(::ActiveSupport::TimeWithZone)])) } def saved_change_to_updated_at; end @@ -734,6 +787,51 @@ class Relationship sig { void } def section_id_will_change!; end + sig { returns(T.nilable(::String)) } + def stored_status; end + + sig { params(value: T.nilable(T.any(::String, ::Symbol))).returns(T.nilable(T.any(::String, ::Symbol))) } + def stored_status=(value); end + + sig { returns(T::Boolean) } + def stored_status?; end + + sig { returns(T.nilable(::String)) } + def stored_status_before_last_save; end + + sig { returns(T.untyped) } + def stored_status_before_type_cast; end + + sig { returns(T::Boolean) } + def stored_status_came_from_user?; end + + sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) } + def stored_status_change; end + + sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) } + def stored_status_change_to_be_saved; end + + sig { returns(T::Boolean) } + def stored_status_changed?; end + + sig { returns(T.nilable(::String)) } + def stored_status_in_database; end + + sig { returns(T.nilable([T.nilable(::String), T.nilable(::String)])) } + def stored_status_previous_change; end + + sig { returns(T::Boolean) } + def stored_status_previously_changed?; end + + sig { returns(T.nilable(::String)) } + def stored_status_previously_was; end + + sig { returns(T.nilable(::String)) } + def stored_status_was; end + + sig { void } + def stored_status_will_change!; end + sig { returns(T.nilable(::ActiveSupport::TimeWithZone)) } def updated_at; end @@ -836,6 +934,9 @@ class Relationship sig { returns(T::Boolean) } def will_save_change_to_section_id?; end + sig { returns(T::Boolean) } + def will_save_change_to_stored_status?; end + sig { returns(T::Boolean) } def will_save_change_to_updated_at?; end @@ -862,6 +963,9 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def eager_load(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def enrolled(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def except(*args, &blk); end @@ -913,6 +1017,15 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def none(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def not_enrolled(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def not_planned(*args, &blk); end + + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def not_subscribed(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def offset(*args, &blk); end @@ -931,6 +1044,9 @@ class Relationship sig { params(num: T.nilable(Integer)).returns(ActiveRecord::Relation) } def page(num = nil); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def planned(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def preload(*args, &blk); end @@ -961,6 +1077,9 @@ class Relationship sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def structurally_compatible?(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } + def subscribed(*args, &blk); end + sig { params(args: T.untyped, blk: T.untyped).returns(PrivateRelation) } def uniq!(*args, &blk); end