Skip to content

Commit

Permalink
11878: Support searching for Date answer values
Browse files Browse the repository at this point in the history
  • Loading branch information
cooperka committed Aug 17, 2021
1 parent 8d12d6c commit b0da589
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 18 deletions.
2 changes: 2 additions & 0 deletions app/models/answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ class Answer < ResponseNode
.where("parents.type != 'AnswerSet' OR answers.new_rank = 0")
}

# Allow searching for various kinds of answer values (such as option ID, date, etc.)
# See answer_search_vector_updater.rb for details.
pg_search_scope :search_by_value,
against: :value,
using: {
Expand Down
4 changes: 4 additions & 0 deletions app/models/results/answer_search_vector_updater.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

module Results
# Updates the search vector on the Answers model and provides the trigger query to do the same.
#
# After modifying, make sure you run `rake db:generate_trigger_migration`
# (see https://github.com/jenseng/hair_trigger).
class AnswerSearchVectorUpdater
include Singleton

Expand All @@ -20,6 +23,7 @@ def trigger_expression
<<-SQL.squish
TO_TSVECTOR('simple', COALESCE(
new.value,
to_char(new.date_value, 'YYYY-MM-DD'),
(SELECT STRING_AGG(opt_name_translation.value, ' ')
FROM options, option_nodes, JSONB_EACH_TEXT(options.name_translations) opt_name_translation
WHERE
Expand Down
39 changes: 39 additions & 0 deletions db/migrate/20210805011611_create_trigger_answers_insert_update4.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

# This migration was auto-generated via `rake db:generate_trigger_migration'.
# While you can edit this file, any changes you make to the definitions here
# will be undone by the next auto-generated trigger migration.

class CreateTriggerAnswersInsertUpdate4 < ActiveRecord::Migration[6.1]
def up
drop_trigger("answers_before_insert_update_row_tr", "answers", generated: true)

create_trigger("answers_before_insert_update_row_tr", generated: true, compatibility: 1)
.on("answers")
.before(:insert, :update) do
"new.tsv := TO_TSVECTOR('simple', COALESCE( new.value, to_char(new.date_value, 'YYYY-MM-DD'), (SELECT STRING_AGG(opt_name_translation.value, ' ') FROM options, option_nodes, JSONB_EACH_TEXT(options.name_translations) opt_name_translation WHERE options.id = option_nodes.option_id AND (option_nodes.id = new.option_node_id OR option_nodes.id IN (SELECT option_node_id FROM choices WHERE answer_id = new.id))), '' ));"
end
end

def down
drop_trigger("answers_before_insert_update_row_tr", "answers", generated: true)

create_trigger("answers_before_insert_update_row_tr", generated: true, compatibility: 1)
.on("answers")
.before(:insert, :update) do
<<~SQL_ACTIONS
new.tsv := TO_TSVECTOR('simple', COALESCE(
new.value,
(SELECT STRING_AGG(opt_name_translation.value, ' ')
FROM options, option_nodes, JSONB_EACH_TEXT(options.name_translations) opt_name_translation
WHERE
options.id = option_nodes.option_id
AND (option_nodes.id = new.option_node_id
OR option_nodes.id IN (SELECT option_node_id FROM choices WHERE answer_id = new.id))),
''
))
;
SQL_ACTIONS
end
end
end
16 changes: 2 additions & 14 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2021_08_04_155804) do
ActiveRecord::Schema.define(version: 2021_08_05_011611) do

# These are extensions that must be enabled in order to support this database
enable_extension "pgcrypto"
Expand Down Expand Up @@ -677,19 +677,7 @@
create_trigger("answers_before_insert_update_row_tr", :generated => true, :compatibility => 1).
on("answers").
before(:insert, :update) do
<<-SQL_ACTIONS
new.tsv := TO_TSVECTOR('simple', COALESCE(
new.value,
(SELECT STRING_AGG(opt_name_translation.value, ' ')
FROM options, option_nodes, JSONB_EACH_TEXT(options.name_translations) opt_name_translation
WHERE
options.id = option_nodes.option_id
AND (option_nodes.id = new.option_node_id
OR option_nodes.id IN (SELECT option_node_id FROM choices WHERE answer_id = new.id))),
''
))
;
SQL_ACTIONS
"new.tsv := TO_TSVECTOR('simple', COALESCE( new.value, to_char(new.date_value, 'YYYY-MM-DD'), (SELECT STRING_AGG(opt_name_translation.value, ' ') FROM options, option_nodes, JSONB_EACH_TEXT(options.name_translations) opt_name_translation WHERE options.id = option_nodes.option_id AND (option_nodes.id = new.option_node_id OR option_nodes.id IN (SELECT option_node_id FROM choices WHERE answer_id = new.id))), '' ));"
end

end
29 changes: 25 additions & 4 deletions spec/searchers/responses_searcher_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@
let!(:q2) { create(:question, qtype_name: "text", add_to_form: form) }
let!(:q3) { create(:question, qtype_name: "long_text", code: "blue", add_to_form: form) }
let!(:q4) { create(:question, qtype_name: "long_text", code: "Green", add_to_form: form) }
let!(:q5) { create(:question, qtype_name: "select_one", code: "Pink", add_to_form: form) }
let!(:q6) do
let!(:q_select_one) { create(:question, qtype_name: "select_one", code: "Pink", add_to_form: form) }
let!(:q_select_multiple) do
create(:question, qtype_name: "select_multiple", code: "Brown",
option_names: %w[hammer wrench screwdriver], add_to_form: form)
end
Expand All @@ -232,10 +232,10 @@

before do
# Add option names a different languages
node = q5.option_set.c[0]
node = q_select_one.option_set.c[0]
node.update!(option_attribs: {id: node.option_id,
name_translations: {name_en: "Cat", name_fr: "chat"}})
node = q6.option_set.c[0]
node = q_select_multiple.option_set.c[0]
node.update!(option_attribs: {id: node.option_id,
name_translations: {name_en: "hammer", name_fr: "marteau"}})
end
Expand Down Expand Up @@ -293,6 +293,27 @@
end
end

describe "special non-text search" do
# TODO: All the other qtypes too.
let!(:q1) { create(:question, qtype_name: "date", code: "date", add_to_form: form) }
let!(:r1) do
create(:response, form: form, reviewed: false, answer_values:
[1, "2021-01-01"])
end
let!(:r2) do
create(:response, form: form, reviewed: true, answer_values:
[1, "2020-12-31"])
end
let!(:r3) do
create(:response, form: form, reviewed: true, answer_values:
[1, nil])
end

it "matches the correct objects" do
expect(search("{date}:2021-01-01")).to contain_exactly(r1)
end
end

describe "default text qualifier" do
let!(:q1) { create(:question, qtype_name: "long_text", add_to_form: form) }
let!(:q2) { create(:question, qtype_name: "text", add_to_form: form) }
Expand Down

0 comments on commit b0da589

Please sign in to comment.