Refactor checklist column data structure

This commit is contained in:
aignatov-bio 2019-12-18 14:10:41 +01:00
parent 2da7eeaedd
commit dc91893d7e
11 changed files with 128 additions and 105 deletions

View file

@ -0,0 +1,8 @@
# frozen_string_literal: true
class RepositoryCellValuesChecklistItem < ApplicationRecord
belongs_to :repository_checklist_item
belongs_to :repository_checklist_value
validates :repository_checklist_item, :repository_checklist_value, presence: true
end

View file

@ -11,4 +11,6 @@ class RepositoryChecklistItem < ApplicationRecord
inverse_of: :created_repository_checklist_types
belongs_to :last_modified_by, foreign_key: 'last_modified_by_id', class_name: 'User',
inverse_of: :modified_repository_checklist_types
has_many :repository_cell_values_checklist_items, dependent: :destroy
has_many :repository_checklist_values, through: :repository_cell_values_checklist_items
end

View file

@ -6,9 +6,12 @@ class RepositoryChecklistValue < ApplicationRecord
belongs_to :last_modified_by, foreign_key: 'last_modified_by_id', class_name: 'User',
inverse_of: :modified_repository_checklist_values
has_one :repository_cell, as: :value, dependent: :destroy, inverse_of: :value
has_many :repository_cell_values_checklist_items, dependent: :destroy
has_many :repository_checklist_items, through: :repository_cell_values_checklist_items
accepts_nested_attributes_for :repository_cell
SORTABLE_COLUMN_NAME = 'repository_checklistitems'
SORTABLE_COLUMN_NAME = 'repository_checklist_items.data'
SORTABLE_VALUE_INCLUDE = { repository_checklist_value: :repository_checklist_items }.freeze
def formatted
@ -16,24 +19,30 @@ class RepositoryChecklistValue < ApplicationRecord
end
def data
repository_cell.repository_column.repository_checklist_items
.where(id: repository_checklist_items).select(:id, :data)
.map { |i| { value: i.id, label: i.data } }
repository_checklist_items.order(created_at: :asc).map { |i| { value: i.id, label: i.data } }
end
def data_changed?(new_data)
JSON.parse(new_data) != repository_checklist_items
JSON.parse(new_data) != repository_checklist_items.pluck(:id)
end
def update_data!(new_data, user)
self.repository_checklist_items = JSON.parse(new_data)
repository_cell_values_checklist_items.destroy_all
repository_cell.repository_column
.repository_checklist_items.where(id: JSON.parse(new_data)).find_each do |item|
repository_cell_values_checklist_items.create(repository_checklist_item: item)
end
self.last_modified_by = user
save!
end
def self.new_with_payload(payload, attributes)
value = new(attributes)
value.repository_checklist_items = JSON.parse(payload)
value = create(attributes)
value.repository_cell
.repository_column
.repository_checklist_items.where(id: JSON.parse(payload)).find_each do |item|
value.repository_cell_values_checklist_items.create(repository_checklist_item: item)
end
value
end
end

View file

@ -1,5 +1,6 @@
class RepositoryDatatableService
# frozen_string_literal: true
class RepositoryDatatableService
attr_reader :repository_rows, :assigned_rows, :mappings
def initialize(repository, params, user, my_module = nil)
@ -100,6 +101,7 @@ class RepositoryDatatableService
if sortable_columns[column_id - 1] == 'assigned'
return records if @my_module && @params[:assigned] == 'assigned'
if @my_module
# Depending on the sort, order nulls first or
# nulls last on repository_cells association
@ -119,14 +121,14 @@ class RepositoryDatatableService
end
elsif sortable_columns[column_id - 1] == 'repository_cell.value'
id = @mappings.key(column_id.to_s)
sorting_column = RepositoryColumn.find_by_id(id)
sorting_column = RepositoryColumn.find_by(id: id)
return records unless sorting_column
sorting_data_type = sorting_column.data_type.constantize
cells = RepositoryCell.joins(sorting_data_type::SORTABLE_VALUE_INCLUDE)
.where('repository_cells.repository_column_id': sorting_column.id)
.select("repository_cells.repository_row_id,
.select("DISTINCT ON (repository_cells.repository_row_id) repository_row_id,
#{sorting_data_type::SORTABLE_COLUMN_NAME} AS value")
records.joins("LEFT OUTER JOIN (#{cells.to_sql}) AS values ON values.repository_row_id = repository_rows.id")

View file

@ -63,11 +63,13 @@ class Extends
# are only supported
REPOSITORY_EXTRA_SEARCH_ATTR = ['repository_text_values.data',
'repository_list_items.data',
'repository_checklist_items.data',
'active_storage_blobs.filename']
# Array of includes used in search query for repository rows
REPOSITORY_SEARCH_INCLUDES = [:repository_text_value,
repository_list_value: :repository_list_item,
repository_checklist_value: :repository_checklist_items,
repository_asset_value: { asset: { file_attachment: :blob } }]
# List of implemented core API versions

View file

@ -5,7 +5,6 @@ class CreateRepositoryChecklistValues < ActiveRecord::Migration[6.0]
create_table :repository_checklist_values do |t|
t.references :created_by, index: true, foreign_key: { to_table: :users }, null: true
t.references :last_modified_by, index: true, foreign_key: { to_table: :users }, null: true
t.jsonb :repository_checklist_items,
t.timestamps
end

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
class CreateRepositoryCellValuesChecklistItems < ActiveRecord::Migration[6.0]
def change
create_table :repository_cell_values_checklist_items do |t|
t.references :repository_checklist_item, null: false, foreign_key: true,
index: { name: :repository_cell_values_checklist_item_id }
t.references :repository_checklist_value, null: false, foreign_key: true,
index: { name: :repository_cell_values_checklist_value_id }
t.timestamps
end
end
end

View file

@ -1142,6 +1142,38 @@ CREATE SEQUENCE public.repository_asset_values_id_seq
ALTER SEQUENCE public.repository_asset_values_id_seq OWNED BY public.repository_asset_values.id;
--
-- Name: repository_cell_values_checklist_items; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public.repository_cell_values_checklist_items (
id bigint NOT NULL,
repository_checklist_item_id bigint NOT NULL,
repository_checklist_value_id bigint NOT NULL,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL
);
--
-- Name: repository_cell_values_checklist_items_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public.repository_cell_values_checklist_items_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: repository_cell_values_checklist_items_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public.repository_cell_values_checklist_items_id_seq OWNED BY public.repository_cell_values_checklist_items.id;
--
-- Name: repository_cells; Type: TABLE; Schema: public; Owner: -
--
@ -1220,9 +1252,7 @@ CREATE TABLE public.repository_checklist_values (
created_by_id bigint,
last_modified_by_id bigint,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
repository_checklist_items jsonb,
"#<ActiveRecord::ConnectionAdapters::PostgreSQL::TableDefinition" jsonb
updated_at timestamp(6) without time zone NOT NULL
);
@ -2966,6 +2996,13 @@ ALTER TABLE ONLY public.repositories ALTER COLUMN id SET DEFAULT nextval('public
ALTER TABLE ONLY public.repository_asset_values ALTER COLUMN id SET DEFAULT nextval('public.repository_asset_values_id_seq'::regclass);
--
-- Name: repository_cell_values_checklist_items id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.repository_cell_values_checklist_items ALTER COLUMN id SET DEFAULT nextval('public.repository_cell_values_checklist_items_id_seq'::regclass);
--
-- Name: repository_cells id; Type: DEFAULT; Schema: public; Owner: -
--
@ -3534,6 +3571,14 @@ ALTER TABLE ONLY public.repository_asset_values
ADD CONSTRAINT repository_asset_values_pkey PRIMARY KEY (id);
--
-- Name: repository_cell_values_checklist_items repository_cell_values_checklist_items_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.repository_cell_values_checklist_items
ADD CONSTRAINT repository_cell_values_checklist_items_pkey PRIMARY KEY (id);
--
-- Name: repository_cells repository_cells_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@ -5669,6 +5714,20 @@ CREATE INDEX index_wopi_actions_on_extension_and_action ON public.wopi_actions U
CREATE INDEX index_zip_exports_on_user_id ON public.zip_exports USING btree (user_id);
--
-- Name: repository_cell_values_checklist_item_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX repository_cell_values_checklist_item_id ON public.repository_cell_values_checklist_items USING btree (repository_checklist_item_id);
--
-- Name: repository_cell_values_checklist_value_id; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX repository_cell_values_checklist_value_id ON public.repository_cell_values_checklist_items USING btree (repository_checklist_value_id);
--
-- Name: repository_status_items fk_rails_00642f1707; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -6861,6 +6920,14 @@ ALTER TABLE ONLY public.oauth_access_tokens
ADD CONSTRAINT fk_rails_ee63f25419 FOREIGN KEY (resource_owner_id) REFERENCES public.users(id);
--
-- Name: repository_cell_values_checklist_items fk_rails_efd3251ebf; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.repository_cell_values_checklist_items
ADD CONSTRAINT fk_rails_efd3251ebf FOREIGN KEY (repository_checklist_value_id) REFERENCES public.repository_checklist_values(id);
--
-- Name: repository_date_time_range_values fk_rails_efe428fafe; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -6885,6 +6952,14 @@ ALTER TABLE ONLY public.report_elements
ADD CONSTRAINT fk_rails_f36eac136b FOREIGN KEY (experiment_id) REFERENCES public.experiments(id);
--
-- Name: repository_cell_values_checklist_items fk_rails_f5260bda13; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public.repository_cell_values_checklist_items
ADD CONSTRAINT fk_rails_f5260bda13 FOREIGN KEY (repository_checklist_item_id) REFERENCES public.repository_checklist_items(id);
--
-- Name: user_projects fk_rails_f58e9073ce; Type: FK CONSTRAINT; Schema: public; Owner: -
--
@ -7120,7 +7195,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20191205133447'),
('20191205133522'),
('20191206105058'),
('20191210103004');
('20191210103004'),
('20191217132401');

View file

@ -1,86 +0,0 @@
require 'rails_helper'
describe RepositoryListItemsController, type: :controller do
login_user
render_views
let(:user) { subject.current_user }
let!(:team) { create :team, created_by: user }
let!(:user_team) { create :user_team, team: team, user: user }
let!(:repository) { create :repository, team: team, created_by: user }
let!(:repository_column_one) do
create :repository_column, repository: repository,
created_by: user,
name: 'List Value',
data_type: 'RepositoryListValue'
end
let!(:repository_list_item_one) do
create :repository_list_item, data: 'item one',
repository: repository,
repository_column: repository_column_one
end
let!(:repository_list_item_two) do
create :repository_list_item, data: 'item two',
repository: repository,
repository_column: repository_column_one
end
let!(:user_two) { create :user, email: 'new@user.com' }
let!(:team_two) { create :team, created_by: user }
let!(:user_team_two) { create :user_team, team: team_two, user: user_two }
let!(:repository_two) do
create :repository, team: team_two, created_by: user_two
end
let!(:user_two_repository_column_two) do
create :repository_column, repository: repository_two,
created_by: user_two,
name: 'List Value',
data_type: 'RepositoryListValue'
end
let!(:user_two_repository_list_item_one) do
create :repository_list_item,
data: 'item one of user two',
repository: repository_two,
repository_column: user_two_repository_column_two,
created_by: user_two,
last_modified_by: user_two
end
let!(:user_two_repository_list_item_two) do
create :repository_list_item,
data: 'item two of user two',
repository: repository_two,
repository_column: user_two_repository_column_two,
created_by: user_two,
last_modified_by: user_two
end
describe '#search' do
let(:params) { { q: '', column_id: repository_column_one.id } }
it 'returns all column\'s list items' do
get :search, format: :json, params: params
expect(response).to have_http_status(:ok)
body = JSON.parse(response.body)
expect(body['list_items'].count).to eq 2
end
it 'returns queried item' do
params[:q] = 'item one'
get :search, format: :json, params: params
expect(response).to have_http_status(:success)
body = JSON.parse(response.body)
expect(body['list_items'].count).to eq 1
expect(body['list_items'].first['data']).to eq 'item one'
end
it 'returns a 404 error if column does not exist' do
params[:column_id] = 999999
get :search, format: :json, params: params
expect(response).to have_http_status(:not_found)
end
it 'returns a 403 error user does not have permissions' do
params[:column_id] = user_two_repository_column_two.id
get :search, format: :json, params: params
expect(response).to have_http_status(:forbidden)
end
end
end

View file

@ -16,7 +16,6 @@ RSpec.describe RepositoryChecklistValue, type: :model do
describe 'Database table' do
it { should have_db_column :created_by_id }
it { should have_db_column :last_modified_by_id }
it { should have_db_column :repository_checklist_items }
end
describe 'Relations' do

View file

@ -39,7 +39,7 @@ describe RepositoryRows::CreateRepositoryRowService do
let(:params) do
{
repository_cells: Hash[column.id, ''],
repository_row: { name: 'name' }
repository_row: { name: '' }
}
end