# frozen_string_literal: true require "spec_helper" require "active_support/core_ext/kernel/reporting" describe PgSearch::Features::TSearch do describe "#rank" do with_model :Model do table do |t| t.string :name t.text :content end end it "returns an expression using the ts_rank() function" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.rank.to_sql).to eq( %{(ts_rank((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 0))} ) end context "with a tsvector column and a custom normalization" do it "works?" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {tsvector_column: :my_tsvector, normalization: 2} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.rank.to_sql).to eq( %{(ts_rank((#{Model.quoted_table_name}."my_tsvector"), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 2))} ) end end end describe "#conditions" do with_model :Model do table do |t| t.string :name t.text :content end end it "returns an expression using the @@ infix operator" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.conditions.to_sql).to eq( %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))} ) end context "when options[:negation] is true" do it "returns a negated expression when a query is prepended with !" do query = "!query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {negation: true} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.conditions.to_sql).to eq( %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', '!' || ''' ' || 'query' || ' ''')))} ) end end context "when options[:negation] is false" do it "does not return a negated expression when a query is prepended with !" do query = "!query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {negation: false} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.conditions.to_sql).to eq( %{((to_tsvector('simple', coalesce((#{Model.quoted_table_name}."name")::text, '')) || to_tsvector('simple', coalesce((#{Model.quoted_table_name}."content")::text, ''))) @@ (to_tsquery('simple', ''' ' || '!query' || ' ''')))} ) end end context "when options[:tsvector_column] is a string" do it "uses the tsvector column" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {tsvector_column: "my_tsvector"} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.conditions.to_sql).to eq( %{((#{Model.quoted_table_name}."my_tsvector") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))} ) end end context "when options[:tsvector_column] is an array of strings" do it "uses the tsvector column" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = {tsvector_column: ["tsvector1", "tsvector2"]} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.conditions.to_sql).to eq( %{((#{Model.quoted_table_name}."tsvector1" || #{Model.quoted_table_name}."tsvector2") @@ (to_tsquery('simple', ''' ' || 'query' || ' ''')))} ) end end end describe "#highlight" do with_model :Model do table do |t| t.string :name t.text :content end end it "generates SQL to call ts_headline" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model) ] options = {} config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expect(feature.highlight.to_sql).to eq( "(ts_headline('simple', (coalesce((#{Model.quoted_table_name}.\"name\")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), ''))" ) end context "when options[:dictionary] is passed" do # standard:disable RSpec/ExampleLength it "uses the provided dictionary" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model), PgSearch::Configuration::Column.new(:content, nil, Model) ] options = { dictionary: "spanish", highlight: { StartSel: "", StopSel: "" } } config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expected_sql = %{(ts_headline('spanish', (coalesce((#{Model.quoted_table_name}."name")::text, '') || ' ' || coalesce((#{Model.quoted_table_name}."content")::text, '')), (to_tsquery('spanish', ''' ' || 'query' || ' ''')), 'StartSel = "", StopSel = ""'))} expect(feature.highlight.to_sql).to eq(expected_sql) end # standard:enable RSpec/ExampleLength end context "when options[:highlight] has options set" do # standard:disable RSpec/ExampleLength it "passes the options to ts_headline" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model) ] options = { highlight: { StartSel: '', StopSel: "", MaxWords: 123, MinWords: 456, ShortWord: 4, HighlightAll: true, MaxFragments: 3, FragmentDelimiter: "…" } } config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) expected_sql = %{(ts_headline('simple', (coalesce((#{Model.quoted_table_name}."name")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "", StopSel = "", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "…", HighlightAll = TRUE'))} expect(feature.highlight.to_sql).to eq(expected_sql) end # standard:enable RSpec/ExampleLength # standard:disable RSpec/ExampleLength it "passes deprecated options to ts_headline" do query = "query" columns = [ PgSearch::Configuration::Column.new(:name, nil, Model) ] options = { highlight: { start_sel: '', stop_sel: "", max_words: 123, min_words: 456, short_word: 4, highlight_all: false, max_fragments: 3, fragment_delimiter: "…" } } config = instance_double(PgSearch::Configuration, :config, ignore: []) normalizer = PgSearch::Normalizer.new(config) feature = described_class.new(query, options, columns, Model, normalizer) highlight_sql = silence_warnings { feature.highlight.to_sql } expected_sql = %{(ts_headline('simple', (coalesce((#{Model.quoted_table_name}."name")::text, '')), (to_tsquery('simple', ''' ' || 'query' || ' ''')), 'StartSel = "", StopSel = "", MaxFragments = 3, MaxWords = 123, MinWords = 456, ShortWord = 4, FragmentDelimiter = "…", HighlightAll = FALSE'))} expect(highlight_sql).to eq(expected_sql) end # standard:enable RSpec/ExampleLength end end end