From 54e517b2494b94508dbfb155f5d7f517e175fca9 Mon Sep 17 00:00:00 2001 From: Nenad Vujicic Date: Wed, 30 Oct 2024 14:48:21 +0100 Subject: [PATCH 1/2] Added NoteTag model and note_tags table Added NoteTag model class, note_tags DB table, associations between Note and NoteTag and private / foreign keys. --- app/models/note.rb | 2 ++ app/models/note_tag.rb | 20 +++++++++++ db/migrate/20241030122707_create_note_tags.rb | 13 +++++++ db/structure.sql | 35 +++++++++++++++++++ test/models/note_tag_test.rb | 7 ++++ 5 files changed, 77 insertions(+) create mode 100644 app/models/note_tag.rb create mode 100644 db/migrate/20241030122707_create_note_tags.rb create mode 100644 test/models/note_tag_test.rb diff --git a/app/models/note.rb b/app/models/note.rb index 6d8ca078fa..18a104c5cc 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -26,6 +26,8 @@ class Note < ApplicationRecord has_many :subscriptions, :class_name => "NoteSubscription" has_many :subscribers, :through => :subscriptions, :source => :user + has_many :note_tags + validates :id, :uniqueness => true, :presence => { :on => :update }, :numericality => { :on => :update, :only_integer => true } validates :latitude, :longitude, :numericality => { :only_integer => true } diff --git a/app/models/note_tag.rb b/app/models/note_tag.rb new file mode 100644 index 0000000000..36d3b2c552 --- /dev/null +++ b/app/models/note_tag.rb @@ -0,0 +1,20 @@ +# == Schema Information +# +# Table name: note_tags +# +# note_id :bigint(8) not null, primary key +# k :string default(""), not null, primary key +# v :string default(""), not null +# +# Foreign Keys +# +# note_tags_id_fkey (note_id => notes.id) +# + +class NoteTag < ApplicationRecord + belongs_to :note + + validates :note, :associated => true + validates :k, :v, :allow_blank => true, :length => { :maximum => 255 }, :characters => true + validates :k, :uniqueness => { :scope => :note_id } +end diff --git a/db/migrate/20241030122707_create_note_tags.rb b/db/migrate/20241030122707_create_note_tags.rb new file mode 100644 index 0000000000..a70e3a2008 --- /dev/null +++ b/db/migrate/20241030122707_create_note_tags.rb @@ -0,0 +1,13 @@ +class CreateNoteTags < ActiveRecord::Migration[7.2] + def change + # Create a table and primary key + create_table :note_tags, :primary_key => [:note_id, :k] do |t| + t.column "note_id", :bigint, :null => false + t.column "k", :string, :default => "", :null => false + t.column "v", :string, :default => "", :null => false + end + + # Add foreign key without validation + add_foreign_key :note_tags, :notes, :column => :note_id, :name => "note_tags_id_fkey", :validate => false + end +end diff --git a/db/structure.sql b/db/structure.sql index 9679e0b925..389f9af708 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -9,6 +9,13 @@ SET xmloption = content; SET client_min_messages = warning; SET row_security = off; +-- +-- Name: public; Type: SCHEMA; Schema: -; Owner: - +-- + +-- *not* creating schema, since initdb creates it + + -- -- Name: btree_gist; Type: EXTENSION; Schema: -; Owner: - -- @@ -1061,6 +1068,17 @@ CREATE TABLE public.note_subscriptions ( ); +-- +-- Name: note_tags; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.note_tags ( + note_id bigint NOT NULL, + k character varying DEFAULT ''::character varying NOT NULL, + v character varying DEFAULT ''::character varying NOT NULL +); + + -- -- Name: notes; Type: TABLE; Schema: public; Owner: - -- @@ -2028,6 +2046,14 @@ ALTER TABLE ONLY public.note_subscriptions ADD CONSTRAINT note_subscriptions_pkey PRIMARY KEY (user_id, note_id); +-- +-- Name: note_tags note_tags_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.note_tags + ADD CONSTRAINT note_tags_pkey PRIMARY KEY (note_id, k); + + -- -- Name: notes notes_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -3210,6 +3236,14 @@ ALTER TABLE ONLY public.note_comments ADD CONSTRAINT note_comments_note_id_fkey FOREIGN KEY (note_id) REFERENCES public.notes(id); +-- +-- Name: note_tags note_tags_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.note_tags + ADD CONSTRAINT note_tags_id_fkey FOREIGN KEY (note_id) REFERENCES public.notes(id) NOT VALID; + + -- -- Name: redactions redactions_user_id_fkey; Type: FK CONSTRAINT; Schema: public; Owner: - -- @@ -3397,6 +3431,7 @@ INSERT INTO "schema_migrations" (version) VALUES ('23'), ('22'), ('21'), +('20241030122707'), ('20241023004427'), ('20241022141247'), ('20240913171951'), diff --git a/test/models/note_tag_test.rb b/test/models/note_tag_test.rb new file mode 100644 index 0000000000..35a3087b86 --- /dev/null +++ b/test/models/note_tag_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class NoteTagTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From ea120b04271d7be36b07cf973246cc1b7e4a9cf8 Mon Sep 17 00:00:00 2001 From: Nenad Vujicic Date: Mon, 11 Nov 2024 12:38:15 +0100 Subject: [PATCH 2/2] Added note_tag factory and NoteTag model test-case Added registering new factory bot for note_tag and added new unit tests to NoteTagTest for checking if key length is valid, value length is valid, key length is invalid, value length is invalid, orphaned tag is invalid and note_tags are unique. --- test/factories/note_tags.rb | 8 ++++++ test/models/note_tag_test.rb | 48 +++++++++++++++++++++++++++++++++--- 2 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 test/factories/note_tags.rb diff --git a/test/factories/note_tags.rb b/test/factories/note_tags.rb new file mode 100644 index 0000000000..f7d90e002d --- /dev/null +++ b/test/factories/note_tags.rb @@ -0,0 +1,8 @@ +FactoryBot.define do + factory :note_tag do + sequence(:k) { |n| "Key #{n}" } + sequence(:v) { |n| "Value #{n}" } + + note + end +end diff --git a/test/models/note_tag_test.rb b/test/models/note_tag_test.rb index 35a3087b86..058d68eb87 100644 --- a/test/models/note_tag_test.rb +++ b/test/models/note_tag_test.rb @@ -1,7 +1,49 @@ require "test_helper" class NoteTagTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end + def test_length_key_valid + tag = create(:note_tag) + [0, 255].each do |i| + tag.k = "k" * i + assert_predicate tag, :valid? + end + end + + def test_length_value_valid + tag = create(:note_tag) + [0, 255].each do |i| + tag.v = "v" * i + assert_predicate tag, :valid? + end + end + + def test_length_key_invalid + tag = create(:note_tag) + tag.k = "k" * 256 + assert_not_predicate tag, :valid?, "Key should be too long" + assert_predicate tag.errors[:k], :any? + end + + def test_length_value_invalid + tag = create(:note_tag) + tag.v = "v" * 256 + assert_not_predicate tag, :valid?, "Value should be too long" + assert_predicate tag.errors[:v], :any? + end + + def test_orphaned_tag_invalid + tag = create(:note_tag) + tag.note = nil + assert_not_predicate tag, :valid?, "Orphaned tag should be invalid" + assert_predicate tag.errors[:note], :any? + end + + def test_uniqueness + existing = create(:note_tag) + tag = build(:note_tag, :note => existing.note, :k => existing.k, :v => existing.v) + assert_predicate tag, :new_record? + assert_not_predicate tag, :valid? + assert_raise(ActiveRecord::RecordInvalid) { tag.save! } + assert_predicate tag, :new_record? + end end