From 476f3b8a281c75a09dbb8fa0954b696ca82610c7 Mon Sep 17 00:00:00 2001 From: Gaetan Craig-Riou Date: Fri, 15 Dec 2023 11:23:39 +1100 Subject: [PATCH] Fix DFC importer to support Product types --- .../connector/importer.rb | 26 +++++++++++++++---- .../connector/importer_spec.rb | 21 ++++++++++++--- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb b/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb index 4e7d2b289a..354fe7bf2a 100644 --- a/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb +++ b/engines/dfc_provider/lib/data_food_consortium/connector/importer.rb @@ -4,7 +4,7 @@ require_relative "skos_parser" module DataFoodConsortium module Connector - class Importer + class Importer # rubocop:disable Metrics/ClassLength TYPES = [ DataFoodConsortium::Connector::CatalogItem, DataFoodConsortium::Connector::Enterprise, @@ -106,7 +106,7 @@ module DataFoodConsortium if property.value.is_a?(Enumerable) property.value << value else - setter = guess_setter_name(statement.predicate) + setter = guess_setter_name(statement) subject.try(setter, value) if setter end end @@ -120,18 +120,26 @@ module DataFoodConsortium end def skos_concept(object) - return unless object.uri? - id = object.value.sub( "http://static.datafoodconsortium.org/data/measures.rdf#", "dfc-m:" ).sub( "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/measures.rdf#", "dfc-m:" + ).sub( + "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#", + "dfc-pt:" ) + SKOSParser.concepts[id] end - def guess_setter_name(predicate) + def guess_setter_name(statement) + predicate = statement.predicate + + # Ideally the product models would be consitent with the rule below and use "type" + # instead of "productType" but alast they are not so we need this exception + return "productType=" if predicate.fragment == "hasType" && product_type?(statement) + name = # Some predicates are named like `hasQuantity` # but the attribute name would be `quantity`. @@ -141,6 +149,14 @@ module DataFoodConsortium "#{name}=" end + + def product_type?(statement) + return true if statement.object.literal? && statement.object.value.match("dfc-pt") + + return true if statement.object.path.match("productTypes") + + false + end end end end diff --git a/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb b/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb index 7da3fdd88b..e292468818 100644 --- a/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb +++ b/engines/dfc_provider/spec/lib/data_food_consortium/connector/importer_spec.rb @@ -23,6 +23,7 @@ describe DataFoodConsortium::Connector::Importer do name: "Tomato", description: "Awesome tomato", totalTheoreticalStock: 3, + productType: non_local_vegetable, ) end let(:product_data) do @@ -36,7 +37,8 @@ describe DataFoodConsortium::Connector::Importer do "dfc-b:alcoholPercentage":0.0, "dfc-b:lifetime":"", "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 + "dfc-b:totalTheoreticalStock":3, + "dfc-b:hasType": "dfc-pt:non-local-vegetable" } JSON end @@ -55,7 +57,8 @@ describe DataFoodConsortium::Connector::Importer do "dfc-b:alcoholPercentage":0.0, "dfc-b:lifetime":"", "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 + "dfc-b:totalTheoreticalStock":3, + "dfc-b:hasType": "dfc-pt:non-local-vegetable" } JSON end @@ -74,7 +77,8 @@ describe DataFoodConsortium::Connector::Importer do "dfc-b:alcoholPercentage":0.0, "dfc-b:lifetime":"", "dfc-b:usageOrStorageCondition":"", - "dfc-b:totalTheoreticalStock":3 + "dfc-b:totalTheoreticalStock":3, + "dfc-b:hasType": "dfc-pt:non-local-vegetable" } JSON end @@ -96,6 +100,11 @@ describe DataFoodConsortium::Connector::Importer do end connector.MEASURES.PIECE end + let(:non_local_vegetable) do + connector.PRODUCT_TYPES.VEGETABLE.NON_LOCAL_VEGETABLE + end + + before { connector.loadProductTypes(read_file("productTypes")) } it "imports a single object with simple properties" do result = import(product) @@ -105,6 +114,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -116,6 +126,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -127,6 +138,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -138,6 +150,7 @@ describe DataFoodConsortium::Connector::Importer do expect(result.semanticId).to eq "https://example.net/tomato" expect(result.name).to eq "Tomato" expect(result.description).to eq "Awesome tomato" + expect(result.productType).to eq non_local_vegetable expect(result.totalTheoreticalStock).to eq 3 end @@ -154,6 +167,7 @@ describe DataFoodConsortium::Connector::Importer do expect(item.semanticId).to eq "https://example.net/tomatoItem" expect(tomato.name).to eq "Tomato" expect(tomato.description).to eq "Awesome tomato" + expect(tomato.productType).to eq non_local_vegetable expect(tomato.totalTheoreticalStock).to eq 3 end @@ -164,6 +178,7 @@ describe DataFoodConsortium::Connector::Importer do expect(tomato.name).to eq "Tomato" expect(tomato.quantity).to eq items + expect(tomato.productType).to eq non_local_vegetable expect(items.value).to eq 5 expect(items.unit).to eq piece end