Merge pull request #8398 from artoscinote/ma_SCI_11768

Add cell value filtering to inventory items API [SCI-11768]
This commit is contained in:
Martin Artnik 2025-04-08 11:48:55 +02:00 committed by GitHub
commit 59a25a5b46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 71 additions and 10 deletions

View file

@ -19,9 +19,18 @@ module Api
.active
.preload(repository_cells: :repository_column)
.preload(repository_cells: { value: @inventory.cell_preload_includes })
.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
.order(:id)
if params.dig(:filter, :inventory_column)
items = items.filtered_by_column_value(
@inventory.repository_columns.find(params[:filter][:inventory_column][:id]),
params[:filter][:inventory_column][:value]
)
end
items =
items.page(params.dig(:page, :number))
.per(params.dig(:page, :size))
.order(:id)
render jsonapi: items, each_serializer: InventoryItemSerializer, include: include_params
end

View file

@ -121,6 +121,35 @@ class RepositoryRow < ApplicationRecord
left_outer_joins_active_reminders(repository, user).where.not(repository_cells_with_active_reminders: { id: nil })
}
scope :filtered_by_column_value, lambda { |repository_column, filter_params|
value_class_name = repository_column.data_type
value_class = value_class_name.constantize
value_type = value_class_name.underscore
repository_rows =
repository_column.repository_rows
.joins(
"INNER JOIN repository_cells AS #{value_type}_cells " \
"ON repository_rows.id = #{value_type}_cells.repository_row_id " \
"AND #{value_type}_cells.repository_column_id = '#{repository_column.id}' "
).joins(
"INNER JOIN #{value_type.pluralize} AS values " \
"ON values.id = #{value_type}_cells.value_id"
)
repository_rows = value_class.add_filter_condition(
repository_rows,
'values',
RepositoryTableFilterElement.new(
operator: filter_params[:operator],
repository_column: repository_column,
parameters: filter_params
)
)
where(id: repository_rows.select(:id))
}
def code
"#{ID_PREFIX}#{parent_id || id}"
end
@ -134,7 +163,6 @@ class RepositoryRow < ApplicationRecord
query = nil,
current_team = nil,
options = {})
teams = options[:teams] || current_team || user.teams.select(:id)
searchable_row_fields = [RepositoryRow::PREFIXED_ID_SQL, 'repository_rows.name', 'users.full_name']

View file

@ -17,7 +17,7 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
create(:repository, name: Faker::Name.unique.name,
created_by: @another_user, team: @team2)
text_column = create(:repository_column, name: Faker::Name.unique.name,
@text_column = create(:repository_column, name: Faker::Name.unique.name,
repository: @valid_inventory, data_type: :RepositoryTextValue)
list_column = create(:repository_column, name: Faker::Name.unique.name,
repository: @valid_inventory, data_type: :RepositoryListValue)
@ -27,13 +27,15 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
repository: @valid_inventory, data_type: :RepositoryAssetValue)
asset = create(:asset)
create_list(:repository_row, 100, repository: @valid_inventory)
@repository_rows = create_list(:repository_row, 100, repository: @valid_inventory)
@valid_inventory.repository_rows.each do |row|
@searchable_repository_row = @repository_rows.last
@valid_inventory.repository_rows.each_with_index do |row, i|
create(:repository_text_value,
data: Faker::Name.name,
data: row.id == @searchable_repository_row.id ? 'SEARCH TEXT VALUE' : Faker::Name.name,
repository_cell_attributes:
{ repository_row: row, repository_column: text_column })
{ repository_row: row, repository_column: @text_column })
create(:repository_list_value, repository_list_item: list_item,
repository_cell_attributes:
{ repository_row: row, repository_column: list_column })
@ -57,7 +59,7 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
included: [
{ type: 'inventory_cells',
attributes: {
column_id: text_column.id,
column_id: @text_column.id,
value: Faker::Name.unique.name
} }
] }
@ -129,6 +131,28 @@ RSpec.describe 'Api::V1::InventoryItemsController', type: :request do
expect(hash_body).not_to include('included')
end
it 'When provided a column filter, finds correct item' do
hash_body = nil
get api_v1_team_inventory_items_path(
team_id: @team1.id,
inventory_id: @team1.repositories.first.id
), params: {
filter: {
inventory_column: {
id: @text_column.id,
value: {
operator: 'contains',
text: 'SEARCH TEXT VALUE'
}
}
}
}, headers: @valid_headers
expect { hash_body = json }.not_to raise_exception
expect(hash_body[:data].length).to eq(1)
expect(hash_body[:data].first[:id].to_i).to eq(@searchable_repository_row.id)
end
it 'When invalid request, user in not member of the team' do
hash_body = nil
get api_v1_team_inventory_items_path(