Skip to content

Commit

Permalink
Added version to notes table and table old_notes
Browse files Browse the repository at this point in the history
Added migration script for adding version column to existing table notes (will become current_notes) and adding new table old_notes (will become notes) which looks like notes but with note_id instead of id and timestamp instead of updated_at, created_at and closed_at.
  • Loading branch information
nenad-vujicic committed Jan 10, 2025
1 parent a6c6f26 commit ba1a558
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 1 deletion.
1 change: 1 addition & 0 deletions app/models/note.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
# created_at :datetime not null
# status :enum not null
# closed_at :datetime
# version :bigint(8) default(1), not null
#
# Indexes
#
Expand Down
99 changes: 99 additions & 0 deletions app/models/old_note.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# == Schema Information
#
# Table name: old_notes
#
# note_id :bigint(8) not null
# latitude :integer not null
# longitude :integer not null
# tile :bigint(8) not null
# timestamp :datetime not null
# status :enum not null
# version :bigint(8) default(1), not null
#
# Indexes
#
# index_old_notes_on_tile (tile)
# index_old_notes_on_timestamp (timestamp)
#

class OldNote < ApplicationRecord
include GeoRecord

has_many :comments, -> { left_joins(:author).where(:visible => true, :users => { :status => [nil, "active", "confirmed"] }).order(:created_at) }, :class_name => "NoteComment", :foreign_key => :note_id
has_many :all_comments, -> { left_joins(:author).order(:created_at) }, :class_name => "NoteComment", :foreign_key => :note_id, :inverse_of => :note
has_many :subscriptions, :class_name => "NoteSubscription"
has_many :subscribers, :through => :subscriptions, :source => :user

validates :id, :uniqueness => true, :presence => { :on => :update },
:numericality => { :on => :update, :only_integer => true }
validates :latitude, :longitude, :numericality => { :only_integer => true }
validates :closed_at, :presence => true, :if => proc { :status == "closed" }
validates :status, :inclusion => %w[open closed hidden]

validate :validate_position

scope :visible, -> { where.not(:status => "hidden") }
scope :invisible, -> { where(:status => "hidden") }

after_initialize :set_defaults

DEFAULT_FRESHLY_CLOSED_LIMIT = 7.days

# Sanity check the latitude and longitude and add an error if it's broken
def validate_position
errors.add(:base, "Note is not in the world") unless in_world?
end

# Close a note
def close
self.status = "closed"
self.closed_at = Time.now.utc
save
end

# Reopen a note
def reopen
self.status = "open"
self.closed_at = nil
save
end

# Check if a note is visible
def visible?
status != "hidden"
end

# Check if a note is closed
def closed?
!closed_at.nil?
end

def freshly_closed?
return false unless closed?

Time.now.utc < freshly_closed_until
end

def freshly_closed_until
return nil unless closed?

closed_at + DEFAULT_FRESHLY_CLOSED_LIMIT
end

# Return the author object, derived from the first comment
def author
comments.first.author
end

# Return the author IP address, derived from the first comment
def author_ip
comments.first.author_ip
end

private

# Fill in default values for new notes
def set_defaults
self.status = "open" unless attribute_present?(:status)
end
end
19 changes: 19 additions & 0 deletions db/migrate/20250109133505_add_notes_versions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

class AddNotesVersions < ActiveRecord::Migration[7.2]
def change
add_column :notes, :version, :bigint, :null => false, :default => 1

create_table :old_notes, :id => false, :primary_key => [:note_id, :version] do |t|
t.bigint :note_id, :null => false
t.integer :latitude, :null => false
t.integer :longitude, :null => false
t.bigint :tile, :null => false
t.datetime :timestamp, :null => false
t.column :status, "note_status_enum", :null => false
t.bigint :version, :null => false, :default => 1
end

add_index :old_notes, :tile
add_index :old_notes, :timestamp
end
end
29 changes: 29 additions & 0 deletions db/migrate/20250110113134_backfill_notes_versions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
class BackfillNotesVersions < ActiveRecord::Migration[7.2]
class Note < ApplicationRecord; end
class NoteComment < ApplicationRecord; end

def change
Note.in_batches(of: 1000) do |notes|
note_ids = notes.pluck(:id)
groups_of_comments = NoteComment.where(note_id: note_ids).order(:created_at).group_by(&:note_id)

values = notes.flat_map do |note|
version = 1
comments = groups_of_comments[note.id]
comments.map do |comment|
if %w[opened reopened closed hidden].include?(comment.event)
new_status = %w[opened reopened].include?(comment.event) ? "open" : comment.event
"(#{note.id}, #{note.latitude}, #{note.longitude}, #{note.tile}, '#{comment.created_at}', '#{new_status}'::note_status_enum, #{version})".tap { version += 1 }
else
nil
end
end.compact
end.join(", ")

unless values.empty?
sql = "INSERT INTO old_notes (note_id, latitude, longitude, tile, timestamp, status, version) VALUES #{values}"
ActiveRecord::Base.connection.execute(sql)
end
end
end
end
34 changes: 33 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1073,7 +1073,8 @@ CREATE TABLE public.notes (
updated_at timestamp without time zone NOT NULL,
created_at timestamp without time zone NOT NULL,
status public.note_status_enum NOT NULL,
closed_at timestamp without time zone
closed_at timestamp without time zone,
version bigint DEFAULT 1 NOT NULL
);


Expand Down Expand Up @@ -1239,6 +1240,21 @@ CREATE SEQUENCE public.oauth_openid_requests_id_seq
ALTER SEQUENCE public.oauth_openid_requests_id_seq OWNED BY public.oauth_openid_requests.id;


--
-- Name: old_notes; Type: TABLE; Schema: public; Owner: -
--

CREATE TABLE public.old_notes (
note_id bigint NOT NULL,
latitude integer NOT NULL,
longitude integer NOT NULL,
tile bigint NOT NULL,
"timestamp" timestamp(6) without time zone NOT NULL,
status public.note_status_enum NOT NULL,
version bigint DEFAULT 1 NOT NULL
);


--
-- Name: redactions; Type: TABLE; Schema: public; Owner: -
--
Expand Down Expand Up @@ -2593,6 +2609,20 @@ CREATE UNIQUE INDEX index_oauth_applications_on_uid ON public.oauth_applications
CREATE INDEX index_oauth_openid_requests_on_access_grant_id ON public.oauth_openid_requests USING btree (access_grant_id);


--
-- Name: index_old_notes_on_tile; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_old_notes_on_tile ON public.old_notes USING btree (tile);


--
-- Name: index_old_notes_on_timestamp; Type: INDEX; Schema: public; Owner: -
--

CREATE INDEX index_old_notes_on_timestamp ON public.old_notes USING btree ("timestamp");


--
-- Name: index_reports_on_issue_id; Type: INDEX; Schema: public; Owner: -
--
Expand Down Expand Up @@ -3397,6 +3427,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('23'),
('22'),
('21'),
('20250110113134'),
('20250109133505'),
('20241023004427'),
('20241022141247'),
('20240913171951'),
Expand Down

0 comments on commit ba1a558

Please sign in to comment.