Skip to content

Commit

Permalink
feat: add in metadata key value searching to samples table
Browse files Browse the repository at this point in the history
  • Loading branch information
ericenns committed Oct 3, 2024
1 parent c21f739 commit 864fa3e
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 9 deletions.
3 changes: 3 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ gem 'pagy', '~> 9.0.5' # omit patch digit
# Ransack
gem 'ransack', '~> 4.2.1'

# Search Syntax
gem 'search_syntax'

# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
# gem "image_processing", "~> 1.2"

Expand Down
6 changes: 6 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,7 @@ GEM
ast (~> 2.4.1)
racc
pg (1.5.7)
polyglot (0.3.5)
prettier_print (1.2.1)
psych (5.1.2)
stringio
Expand Down Expand Up @@ -536,6 +537,8 @@ GEM
nokogiri (>= 1.13.10)
rexml
rubyzip (2.3.2)
search_syntax (0.1.3)
treetop (~> 1.6)
securerandom (0.3.1)
signet (0.19.0)
addressable (~> 2.8)
Expand Down Expand Up @@ -603,6 +606,8 @@ GEM
timecop (0.9.10)
timeout (0.4.1)
trailblazer-option (0.1.2)
treetop (1.6.12)
polyglot (~> 0.3)
turbo-rails (2.0.6)
actionpack (>= 6.0.0)
activejob (>= 6.0.0)
Expand Down Expand Up @@ -707,6 +712,7 @@ DEPENDENCIES
rubocop
rubocop-graphql
rubocop-rails
search_syntax
simplecov
solargraph
sprockets-rails
Expand Down
14 changes: 7 additions & 7 deletions app/controllers/groups/samples_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class SamplesController < Groups::ApplicationController
include Storable

before_action :group, :current_page
before_action :process_samples, only: %i[index search]
before_action :process_samples, only: %i[index search select]
include Sortable

def index
Expand All @@ -25,10 +25,7 @@ def select

respond_to do |format|
format.turbo_stream do
if params[:select].present?
@q = authorized_samples.ransack(search_params)
@selected_sample_ids = @q.result.select(:id).pluck(:id)
end
@selected_sample_ids = @q.result.select(:id).pluck(:id) if params[:select].present?
end
end
end
Expand Down Expand Up @@ -75,8 +72,11 @@ def process_samples
authorize! @group, to: :sample_listing?
@search_params = search_params
set_metadata_fields

@q = authorized_samples.ransack(@search_params)
query_parser = Irida::SearchSyntax::Ransack.new(text: :name_or_puid_cont,
# params: { project: 'project_namespace_puid' },
metadata_fields: @fields)
parsed_params = query_parser.parse(@search_params.fetch(:name_or_puid_cont, nil))
@q = authorized_samples.ransack(@search_params.except(:name_or_puid_cont).merge(parsed_params))
end

def search_params
Expand Down
4 changes: 3 additions & 1 deletion app/controllers/projects/samples_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,9 @@ def process_samples
@search_params = search_params

set_metadata_fields
@q = load_samples.ransack(@search_params)
query_parser = Irida::SearchSyntax::Ransack.new(text: :name_or_puid_cont, metadata_fields: @fields)
parsed_params = query_parser.parse(@search_params.fetch(:name_or_puid_cont, nil))
@q = load_samples.ransack(@search_params.except(:name_or_puid_cont).merge(parsed_params))
end

def search_params
Expand Down
1 change: 1 addition & 0 deletions app/models/sample.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def self.ransackable_attributes(_auth_object = nil)
end

def self.ransackable_associations(_auth_object = nil)
#%w[project]

Check warning on line 39 in app/models/sample.rb

View workflow job for this annotation

GitHub Actions / runner / rubocop

[rubocop] reported by reviewdog 🐶 Missing space after `#`. Raw Output: app/models/sample.rb:39:5: C: Layout/LeadingCommentSpace: Missing space after `#`.
%w[]
end

Expand Down
1 change: 1 addition & 0 deletions app/views/groups/samples/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<%= viral_icon(name: "magnifying_glass", classes: "h-5 w-5") %>
</div>
<%= f.search_field :name_or_puid_cont,
value: @search_params[:name_or_puid_cont],
"data-action": "filters#submit",
class:
"block w-full p-2.5 pl-10 text-sm text-slate-900 border border-slate-300 rounded-lg bg-slate-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-slate-700 dark:border-slate-600 dark:placeholder-slate-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500",
Expand Down
3 changes: 2 additions & 1 deletion app/views/projects/samples/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
},
class:
"flex items-center px-4 py-2 bg-slate-100 text-slate-600 dark:bg-slate-600 dark:text-slate-300
border-slate-100 dark:border-slate-600 pointer-events-none cursor-not-allowed",
border-slate-100 dark:border-slate-600 pointer-events-none cursor-not-allowed",
) %>
<% else %>
<% dropdown.with_item(
Expand Down Expand Up @@ -167,6 +167,7 @@
<%= viral_icon(name: "magnifying_glass", classes: "h-5 w-5") %>
</div>
<%= f.search_field :name_or_puid_cont,
value: @search_params[:name_or_puid_cont],
"data-action": "filters#submit",
class:
"block w-full p-2.5 pl-10 text-sm text-slate-900 border border-slate-300 rounded-lg bg-slate-50 focus:ring-primary-500 focus:border-primary-500 dark:bg-slate-700 dark:border-slate-600 dark:placeholder-slate-400 dark:text-white dark:focus:ring-primary-500 dark:focus:border-primary-500",
Expand Down
23 changes: 23 additions & 0 deletions lib/irida/search_syntax/ransack.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

require_relative 'ransack_transformer'

module Irida
module SearchSyntax
# IRIDA Next specific Ransack search syntax parser that supports metadata_fields
class Ransack
def initialize(text:, params: [], metadata_fields: [], sort: nil)
@transformer = RansackTransformer.new(text:, params:, metadata_fields:, sort:)
@parser = ::SearchSyntax::Parser.new
end

def parse_with_errors(text)
@transformer.transform_with_errors(@parser.parse(text || '').value)
end

def parse(text)
parse_with_errors(text)[0]
end
end
end
end
71 changes: 71 additions & 0 deletions lib/irida/search_syntax/ransack_transformer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
module Irida

Check warning on line 1 in lib/irida/search_syntax/ransack_transformer.rb

View workflow job for this annotation

GitHub Actions / runner / rubocop

[rubocop] reported by reviewdog 🐶 Missing frozen string literal comment. Raw Output: lib/irida/search_syntax/ransack_transformer.rb:1:1: C: Style/FrozenStringLiteralComment: Missing frozen string literal comment.
module SearchSyntax
# IRIDA Next specific RansackTransformer that supoorts metadata_fields
class RansackTransformer < ::SearchSyntax::RansackTransformer
def initialize(text:, params:, metadata_fields:, sort: nil)
super(text:, params:, sort:)
@metadata_fields = metadata_fields
end

def transform_with_errors(ast) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
errors = []
result = {}

if @allowed_params.length.positive? || @metadata_fields.length.positive?
ast = ast.filter do |node| # rubocop:disable Metrics/BlockLength
if node[:type] != :param
true
elsif node[:name] == @sort
result[:s] = transform_sort_param(node[:value])
false
elsif @allowed_params.include?(node[:name])
key = name_with_predicate(node)
if result.key?(key)
errors.push(::SearchSyntax::DuplicateParamError.new(
name: node[:name],
start: node[:start],
finish: node[:finish]
))
else
result[key] = node[:value]
end
false
elsif @metadata_fields.include?(node[:name])
key = 'metadata_jcont'
search_value = {}
search_value = JSON.parse(result[key]) if result.key?(key)
if search_value.key?(node[:name])
errors.push(::SearchSyntax::DuplicateParamError.new(
name: node[:name],
start: node[:start],
finish: node[:finish]
))
else
search_value[node[:name]] = node[:value]
result[key] = JSON.generate(search_value)
end
false
else
errors.push(::SearchSyntax::UnknownParamError.new(
name: node[:name],
start: node[:start],
finish: node[:finish],
did_you_mean: @spell_checker.correct(node[:name])
))
true
end
end
end

previous = -1
result[@text] = ast.map do |node|
separator = previous == node[:start] || previous == -1 ? '' : ' '
previous = node[:finish]
separator + node[:raw]
end.join

[result, errors]
end
end
end
end

0 comments on commit 864fa3e

Please sign in to comment.