Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DFC import: Find broader taxon if we don't have a specific one #13109

Merged
merged 4 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions engines/dfc_provider/app/services/dfc_product_type_factory.rb

This file was deleted.

31 changes: 31 additions & 0 deletions engines/dfc_provider/app/services/product_type_importer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

class ProductTypeImporter < DfcBuilder
# Try to find the taxon closest matching the given product type.
# If we don't find any matching taxon, we return a random one.
def self.taxon(product_type)
priority_list = [product_type, *list_broaders(product_type)].compact

# Optimistic querying.
# We could query all broader taxons in one but then we need to still sort
# them locally and use more memory. That would be a pessimistic query.
# Consider caching the result instead.
taxons = priority_list.lazy.map do |type|
Spree::Taxon.find_by(dfc_id: type.semanticId)
end.compact

taxons.first || Spree::Taxon.first
Comment on lines +13 to +17
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice to see different ways of doing things. I probably would have ended up with an each or reduce loop, but this is nice 👍

end

def self.list_broaders(type)
return [] if type.nil?

broaders = type.broaders.map do |id|
DataFoodConsortium::Connector::SKOSParser.concepts[id]
end

broaders + broaders.flat_map do |broader|
list_broaders(broader)
end
end
end
8 changes: 2 additions & 6 deletions engines/dfc_provider/app/services/supplied_product_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,11 @@ def self.apply(supplied_product, variant)
def self.product_type(variant)
taxon_dfc_id = variant.primary_taxon&.dfc_id

DfcProductTypeFactory.for(taxon_dfc_id)
DataFoodConsortium::Connector::SKOSParser.concepts[taxon_dfc_id]
end

def self.taxon(supplied_product)
dfc_id = supplied_product.productType&.semanticId

# Every product needs a primary taxon to be valid. So if we don't have
# one or can't find it we just take a random one.
Spree::Taxon.find_by(dfc_id:) || Spree::Taxon.first
ProductTypeImporter.taxon(supplied_product.productType)
end

private_class_method :product_type, :taxon
Expand Down

This file was deleted.

67 changes: 67 additions & 0 deletions engines/dfc_provider/spec/services/product_type_importer_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# frozen_string_literal: true

require_relative "../spec_helper"

RSpec.describe ProductTypeImporter do
let(:drink) {
DfcLoader.connector.PRODUCT_TYPES.DRINK
}
let(:soft_drink) {
DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK
}
let(:lemonade) {
DfcLoader.connector.PRODUCT_TYPES.DRINK.SOFT_DRINK.LEMONADE
}

describe ".taxon" do
it "finds a linked taxon" do
create(:taxon, dfc_id: soft_drink.semanticId)
lemonade_taxon = create(:taxon, dfc_id: lemonade.semanticId)
expect(described_class.taxon(lemonade)).to eq lemonade_taxon
end

it "falls back to a broader taxon" do
drink_taxon = create(:taxon, dfc_id: drink.semanticId)
expect(described_class.taxon(lemonade)).to eq drink_taxon
end

it "returns random taxon when none can be found" do
only_taxon = create(:taxon)
expect(described_class.taxon(lemonade)).to eq only_taxon
end

it "queries the database only until it found a taxon" do
soft_drink_taxon = create(:taxon, dfc_id: soft_drink.semanticId)

expect {
expect(described_class.taxon(lemonade)).to eq soft_drink_taxon
}.to query_database [
"Spree::Taxon Load", # query for lemonade, not found
"Spree::Taxon Load", # query for soft drink, found
# no query for drink
]
end
end

describe ".list_broaders" do
it "returns an empty array if no type is given" do
list = described_class.list_broaders(nil)
expect(list).to eq []
end

it "can return an empty list for top concepts" do
list = described_class.list_broaders(drink)
expect(list).to eq []
end

it "lists the broader concepts of a type" do
list = described_class.list_broaders(soft_drink)
expect(list).to eq [drink]
end

it "lists all the broader concepts to the top concepts" do
list = described_class.list_broaders(lemonade)
expect(list).to eq [soft_drink, drink]
end
end
end
Loading