require_relative "test_helper" class SqlTest < Minitest::Test def test_operator store_names ["Honey"] assert_search "fresh honey", [] assert_search "fresh honey", ["Honey"], operator: "or" assert_search_relation ["Honey"], Product.search("fresh honey").operator(:or) end def test_operator_scoring store_names ["Big Red Circle", "Big Green Circle", "Small Orange Circle"] expected = ["Big Red Circle", "Big Green Circle", "Small Orange Circle"] assert_order "big red circle", expected, operator: "or" assert_search_relation expected, Product.search("big red circle").operator(:or) end def test_fields_operator store [ {name: "red", color: "red"}, {name: "blue", color: "blue"}, {name: "cyan", color: "blue green"}, {name: "magenta", color: "red blue"}, {name: "green", color: "green"} ] expected = ["red", "blue", "cyan", "magenta"] assert_search "red blue", expected, operator: "or", fields: ["color"] assert_search_relation expected, Product.search("red blue").operator(:or).fields(:color) end def test_fields store [ {name: "red", color: "light blue"}, {name: "blue", color: "red fish"} ] assert_search "blue", ["red"], fields: ["color"] assert_search_relation ["red"], Product.search("blue").fields(:color) assert_search_relation ["red", "blue"], Product.search("blue").fields(:name).fields(:color) end def test_non_existent_field store_names ["Milk"] assert_search "milk", [], fields: ["not_here"] end def test_fields_both_match # have same score due to dismax store [ {name: "Blue A", color: "red"}, {name: "Blue B", color: "light blue"} ] assert_first "blue", "Blue B", fields: [:name, :color] end def test_big_decimal store [ {name: "Product", latitude: 80.0} ] assert_search "product", ["Product"], where: {latitude: {gt: 79}} assert_search_relation ["Product"], Product.search("product").where(latitude: {gt: 79}) end # body_options def test_body_options_should_merge_into_body query = Product.search("*", body_options: {min_score: 1.0}, execute: false) assert_equal 1.0, query.body[:min_score] end # load def test_load_default store_names ["Product A"] assert_kind_of Product, Product.search("product").first end def test_load_false store_names ["Product A"] assert_kind_of Hash, Product.search("product", load: false).first assert_kind_of Hash, Product.search("product").load(false).first end def test_load_false_methods store_names ["Product A"] assert_equal "Product A", Product.search("product", load: false).first.name assert_equal "Product A", Product.search("product").load(false).first.name end def test_load_false_with_includes store_names ["Product A"] assert_kind_of Hash, Product.search("product", load: false, includes: [:store]).first assert_kind_of Hash, Product.search("product").load(false).includes(:store).first end def test_load_false_nested_object aisle = {"id" => 1, "name" => "Frozen"} store [{name: "Product A", aisle: aisle}] assert_equal aisle, Product.search("product", load: false).first.aisle.to_hash assert_equal aisle, Product.search("product").load(false).first.aisle.to_hash end # select def test_select store [{name: "Product A", store_id: 1}] result = Product.search("product", load: false, select: [:name, :store_id]).first assert_equal %w(id name store_id), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_equal 1, result.store_id end def test_select_array store [{name: "Product A", user_ids: [1, 2]}] result = Product.search("product", load: false, select: [:user_ids]).first assert_equal [1, 2], result.user_ids end def test_select_single_field store [{name: "Product A", store_id: 1}] result = Product.search("product", load: false, select: :name).first assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_nil result.store_id end def test_select_all store [{name: "Product A", user_ids: [1, 2]}] hit = Product.search("product", select: true).hits.first assert_equal hit["_source"]["name"], "Product A" assert_equal hit["_source"]["user_ids"], [1, 2] end def test_select_none store [{name: "Product A", user_ids: [1, 2]}] hit = Product.search("product", select: []).hits.first assert_nil hit["_source"] hit = Product.search("product", select: false).hits.first assert_nil hit["_source"] end def test_select_includes store [{name: "Product A", user_ids: [1, 2]}] result = Product.search("product", load: false, select: {includes: [:name]}).first assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_nil result.store_id end def test_select_excludes store [{name: "Product A", user_ids: [1, 2], store_id: 1}] result = Product.search("product", load: false, select: {excludes: [:name]}).first assert_nil result.name assert_equal [1, 2], result.user_ids assert_equal 1, result.store_id end def test_select_include_and_excludes # let's take this to the next level store [{name: "Product A", user_ids: [1, 2], store_id: 1}] result = Product.search("product", load: false, select: {includes: [:store_id], excludes: [:name]}).first assert_equal 1, result.store_id assert_nil result.name assert_nil result.user_ids end # select relation def test_select_relation store [{name: "Product A", store_id: 1}] result = Product.search("product").load(false).select(:name, :store_id).first assert_equal %w(id name store_id), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_equal 1, result.store_id end def test_select_multiple_relation store [{name: "Product A", store_id: 1}] # only last select applies - different from Active Record # since we have to allow for boolean, array, and hash values result = Product.search("product").load(false).select(:name).select(:store_id).first assert_equal %w(id store_id), result.keys.reject { |k| k.start_with?("_") }.sort assert_nil result.name assert_equal 1, result.store_id end def test_select_array_relation store [{name: "Product A", user_ids: [1, 2]}] result = Product.search("product").load(false).select(:user_ids).first assert_equal [1, 2], result.user_ids end def test_select_single_field_relation store [{name: "Product A", store_id: 1}] result = Product.search("product").load(false).select(:name).first assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_nil result.store_id end def test_select_all_relation store [{name: "Product A", user_ids: [1, 2]}] hit = Product.search("product").select(true).hits.first assert_equal hit["_source"]["name"], "Product A" assert_equal hit["_source"]["user_ids"], [1, 2] end def test_select_none_relation store [{name: "Product A", user_ids: [1, 2]}] hit = Product.search("product").select(false).hits.first assert_nil hit["_source"] end def test_select_includes_relation store [{name: "Product A", user_ids: [1, 2]}] result = Product.search("product").load(false).select(includes: [:name]).first assert_equal %w(id name), result.keys.reject { |k| k.start_with?("_") }.sort assert_equal "Product A", result.name assert_nil result.store_id end def test_select_excludes_relation store [{name: "Product A", user_ids: [1, 2], store_id: 1}] result = Product.search("product").load(false).select(excludes: [:name]).first assert_nil result.name assert_equal [1, 2], result.user_ids assert_equal 1, result.store_id end def test_select_include_and_excludes_relation # let's take this to the next level store [{name: "Product A", user_ids: [1, 2], store_id: 1}] result = Product.search("product").load(false).select(includes: [:store_id], excludes: [:name]).first assert_equal 1, result.store_id assert_nil result.name assert_nil result.user_ids end # nested def test_nested_search store [{name: "Product A", aisle: {"id" => 1, "name" => "Frozen"}}], Speaker assert_search "frozen", ["Product A"], {fields: ["aisle.name"]}, Speaker assert_equal ["Product A"], Speaker.search("frozen").fields("aisle.name").map(&:name) end # other tests def test_includes skip unless defined?(ActiveRecord) store_names ["Product A"] assert Product.search("product", includes: [:store]).first.association(:store).loaded? assert Product.search("product").includes(:store).first.association(:store).loaded? end def test_model_includes skip unless defined?(ActiveRecord) store_names ["Product A"] store_names ["Store A"], Store associations = {Product => [:store], Store => [:products]} result = Searchkick.search("*", models: [Product, Store], model_includes: associations) assert_equal 2, result.length result.group_by(&:class).each_pair do |klass, records| assert records.first.association(associations[klass].first).loaded? end result = Searchkick.search("*").models(Product, Store).model_includes(associations) assert_equal 2, result.length result.group_by(&:class).each_pair do |klass, records| assert records.first.association(associations[klass].first).loaded? end end def test_scope_results skip unless defined?(ActiveRecord) store_names ["Product A", "Product B"] assert_search "product", ["Product A"], scope_results: ->(r) { r.where(name: "Product A") } assert_equal ["Product A"], Product.search("product").load(->(r) { r.where(name: "Product A") }).map(&:name) end end