Added prefixed IDs to repository rows (items) [SCI-5909] (#3441)

* Added prefixed IDs to repository rows (items) [SCI-5909]

* Fix prefixed id queries to work with joins, use subquery in repository search [SCI-5909]

* Fixed accessing repository_row parent code [SCI-5909]

* Better handling of repository_row code display [SCI-5909]

* Fix index warning for id prefixed models issue setting up project [SCI-5909]
This commit is contained in:
artoscinote 2021-07-19 14:23:36 +02:00 committed by GitHub
parent ef6c46a19c
commit 5f9c04844f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 91 additions and 24 deletions

View file

@ -9,7 +9,7 @@ module RepositoryDatatableHelper
'DT_RowId': record.id,
'DT_RowAttr': { 'data-state': row_style(record) },
'1': assigned_row(record),
'2': record.id,
'2': record.code,
'3': escape_input(record.name),
'4': I18n.l(record.created_at, format: :full),
'5': escape_input(record.created_by.full_name),
@ -52,7 +52,7 @@ module RepositoryDatatableHelper
row = {
'DT_RowId': record.id,
'DT_RowAttr': { 'data-state': row_style(record) },
'1': record.parent_id,
'1': record.code,
'2': escape_input(record.name),
'3': I18n.l(record.created_at, format: :full),
'4': escape_input(record.created_by.full_name),

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
module PrefixedIdModel
extend ActiveSupport::Concern
included do
begin
indexdef = "CREATE INDEX index_#{table_name}_on_#{name.underscore}_code"\
" ON public.#{table_name} USING gin ((('#{self::ID_PREFIX}'::text || id)) gin_trgm_ops)"
index_exists = ActiveRecord::Base.connection.execute(
"SELECT indexdef FROM pg_indexes WHERE tablename NOT LIKE 'pg%';"
).to_a.map(&:values).flatten.include?(indexdef)
# rubocop:disable Rails/Output
puts("\nWARNING missing index\n#{indexdef}\nfor prefixed id model #{name}!\n\n") unless index_exists
# rubocop:enable Rails/Output
rescue ActiveRecord::NoDatabaseError # only applicable when setting up project
end
self::PREFIXED_ID_SQL = "('#{self::ID_PREFIX}' || #{table_name}.id)"
def code
"#{self.class::ID_PREFIX}#{id}"
end
end
end

View file

@ -1,3 +1,5 @@
# frozen_string_literal: true
module SearchableModel
extend ActiveSupport::Concern
@ -43,8 +45,8 @@ module SearchableModel
(attrs.map.with_index do |a, i|
if %w(repository_rows.id repository_number_values.data).include?(a)
"((#{a})::text) #{like} :t#{i} OR "
elsif a == Experiment::EXPERIMENT_CODE_SQL
"#{Experiment::EXPERIMENT_CODE_SQL} #{like} :t#{i} OR "
elsif defined?(model::PREFIXED_ID_SQL) && a == model::PREFIXED_ID_SQL
"#{a} #{like} :t#{i} OR "
else
col = options[:at_search].to_s == 'true' ? "lower(#{a})": a
"(trim_html_tags(#{col})) #{like} :t#{i} OR "
@ -69,8 +71,8 @@ module SearchableModel
(attrs.map.with_index do |a, i|
if %w(repository_rows.id repository_number_values.data).include?(a)
"((#{a})::text) #{like} ANY (array[:t#{i}]) OR "
elsif a == Experiment::EXPERIMENT_CODE_SQL
"#{Experiment::EXPERIMENT_CODE_SQL} #{like} ANY (array[:t#{i}]) OR "
elsif defined?(model::PREFIXED_ID_SQL) && a == model::PREFIXED_ID_SQL
"#{a} #{like} ANY (array[:t#{i}]) OR "
else
"(trim_html_tags(#{a})) #{like} ANY (array[:t#{i}]) OR "
end
@ -90,8 +92,8 @@ module SearchableModel
(attrs.map.with_index do |a, i|
if %w(repository_rows.id repository_number_values.data).include?(a)
"((#{a})::text) #{like} :t#{i} OR "
elsif a == Experiment::EXPERIMENT_CODE_SQL
"#{Experiment::EXPERIMENT_CODE_SQL} #{like} :t#{i} OR "
elsif defined?(model::PREFIXED_ID_SQL) && a == model::PREFIXED_ID_SQL
"#{a} #{like} :t#{i} OR "
else
"(trim_html_tags(#{a})) #{like} :t#{i} OR "
end

View file

@ -1,9 +1,12 @@
# frozen_string_literal: true
class Experiment < ApplicationRecord
include ArchivableModel
include SearchableModel
include SearchableByNameModel
EXPERIMENT_CODE_SQL = "('EX' || id)".freeze
ID_PREFIX = 'EX'
include PrefixedIdModel
before_save -> { report_elements.destroy_all }, if: -> { !new_record? && project_id_changed? }
@ -73,7 +76,7 @@ class Experiment < ApplicationRecord
Experiment
.where('experiments.project_id IN (?)', projects_ids)
.where_attributes_like(
[:name, :description, EXPERIMENT_CODE_SQL], query, options
[:name, :description, PREFIXED_ID_SQL], query, options
)
return include_archived ? new_query : new_query.active
elsif include_archived
@ -81,7 +84,7 @@ class Experiment < ApplicationRecord
Experiment
.where(project: project_ids)
.where_attributes_like(
[:name, :description, EXPERIMENT_CODE_SQL], query, options
[:name, :description, PREFIXED_ID_SQL], query, options
)
else
new_query =
@ -89,7 +92,7 @@ class Experiment < ApplicationRecord
.active
.where(project: project_ids)
.where_attributes_like(
[:name, :description, EXPERIMENT_CODE_SQL], query, options
[:name, :description, PREFIXED_ID_SQL], query, options
)
end
@ -107,10 +110,6 @@ class Experiment < ApplicationRecord
where(project: Project.viewable_by_user(user, teams))
end
def code
"EX#{id}"
end
def archived_branch?
archived? || project.archived?
end

View file

@ -313,7 +313,7 @@ class MyModule < ApplicationRecord
rows = repository.assigned_rows(self).includes(:created_by).order(created_at: order)
rows.find_each do |row|
row_json = []
row_json << (row.repository.is_a?(RepositorySnapshot) ? row.parent_id : row.id)
row_json << row.code
row_json << (row.archived ? "#{row.name} [#{I18n.t('general.archived')}]" : row.name)
row_json << I18n.l(row.created_at, format: :full)
row_json << row.created_by.full_name

View file

@ -80,8 +80,14 @@ class Repository < RepositoryBase
matched_by_user = readable_rows.joins(:created_by).where_attributes_like('users.full_name', query, options)
prefixed_repository_row_ids = RepositoryRow.where(repository_id: repositories)
.where_attributes_like([RepositoryRow::PREFIXED_ID_SQL], query, options)
.select(:id)
repository_row_matches =
readable_rows.where_attributes_like(['repository_rows.name', 'repository_rows.id'], query, options)
readable_rows.where_attributes_like(['repository_rows.name'], query, options).or(
readable_rows.where('repository_rows.id' => prefixed_repository_row_ids)
)
repository_rows = readable_rows.where(id: repository_row_matches)
repository_rows = repository_rows.or(readable_rows.where(id: matched_by_user))

View file

@ -5,7 +5,11 @@ class RepositoryRow < ApplicationRecord
include SearchableByNameModel
include ArchivableModel
ID_PREFIX = 'IT'
include PrefixedIdModel
belongs_to :repository, class_name: 'RepositoryBase'
belongs_to :parent, class_name: 'RepositoryRow', optional: true
belongs_to :created_by, foreign_key: :created_by_id, class_name: 'User'
belongs_to :last_modified_by, foreign_key: :last_modified_by_id, class_name: 'User'
belongs_to :archived_by,
@ -33,6 +37,10 @@ class RepositoryRow < ApplicationRecord
scope :active, -> { where(archived: false) }
scope :archived, -> { where(archived: true) }
def code
"#{ID_PREFIX}#{parent_id || id}"
end
def self.viewable_by_user(user, teams)
where(repository: Repository.viewable_by_user(user, teams))
end

View file

@ -7,7 +7,7 @@ module Reports::Docx::RepositoryHelper
result = [repository_data[:headers]]
repository_data[:rows].each do |record|
row = []
row.push(record.repository.is_a?(RepositorySnapshot) ? record.parent_id : record.id)
row.push(record.code)
row.push(escape_input(record.archived ? "#{record.name} [#{I18n.t('general.archived')}]" : record.name))
row.push(I18n.l(record.created_at, format: :full))
row.push(escape_input(record.created_by.full_name))

View file

@ -78,8 +78,11 @@ class RepositoryDatatableService
if search_value.present?
matched_by_user = repository_rows.joins(:created_by).where_attributes_like('users.full_name', search_value)
repository_row_matches = repository_rows
.where_attributes_like(['repository_rows.name', 'repository_rows.id'], search_value)
repository_row_matches = repository_rows
.where_attributes_like(
['repository_rows.name', RepositoryRow::PREFIXED_ID_SQL],
search_value
)
results = repository_rows.where(id: repository_row_matches)
results = results.or(repository_rows.where(id: matched_by_user))

View file

@ -18,7 +18,7 @@
<p>
<span>
<%= t('repository_row.modal_info.ID') %>
<%= @repository_row.parent_id || @repository_row.id %>
<%= @repository_row.code %>
</span>
<br>
<span>

View file

@ -8,7 +8,7 @@
<p>
<span>
<%=t 'repository_row.modal_info.ID' %>
<%= repository_row.id %>
<%= repository_row.code %>
</span>
<br />
<span>

View file

@ -0,0 +1,14 @@
# frozen_string_literal: true
class AddRepositoryRowCodeIndex < ActiveRecord::Migration[6.1]
def up
ActiveRecord::Base.connection.execute(
"CREATE INDEX index_repository_rows_on_repository_row_code ON "\
"repository_rows using gin (('IT'::text || id) gin_trgm_ops);"
)
end
def down
remove_index :repository_rows, name: 'index_repository_rows_on_repository_row_code'
end
end

View file

@ -5196,6 +5196,13 @@ CREATE INDEX index_repository_rows_on_name ON public.repository_rows USING gin (
CREATE INDEX index_repository_rows_on_repository_id ON public.repository_rows USING btree (repository_id);
--
-- Name: index_repository_rows_on_repository_row_code; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX index_repository_rows_on_repository_row_code ON public.repository_rows USING gin ((('IT'::text || id)) public.gin_trgm_ops);
--
-- Name: index_repository_rows_on_restored_by_id; Type: INDEX; Schema: public; Owner: -
--
@ -7250,6 +7257,7 @@ INSERT INTO "schema_migrations" (version) VALUES
('20210407143303'),
('20210410100006'),
('20210506125657'),
('20210622101238');
('20210622101238'),
('20210715125349');