From b6a5df17b3803bc87e1cbcc5204c33a12ff331ad Mon Sep 17 00:00:00 2001 From: Lee Richmond Date: Thu, 4 Apr 2019 11:31:06 -0400 Subject: [PATCH] Throw better error when polymorphic type not found If you are sideposting a polymorphic relationship, and pass a jsonapi type that is not registered, we would throw a confusing error. Now we throw an explicit error with information about what's happening. --- CHANGELOG.md | 5 +++++ lib/graphiti/errors.rb | 22 +++++++++++++++++++ .../sideload/polymorphic_belongs_to.rb | 9 ++++++++ lib/graphiti/util/relationship_payload.rb | 2 +- spec/filtering_spec.rb | 2 +- spec/persistence_spec.rb | 15 +++++++++++-- 6 files changed, 51 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c4459fb..628c6a3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ### master (unreleased) +Misc: + +- [#123](https://github.com/graphiti-api/graphiti/pull/123) Throw + better error when polymorphic type not found. + diff --git a/lib/graphiti/errors.rb b/lib/graphiti/errors.rb index 47e72c2c..5d91b330 100644 --- a/lib/graphiti/errors.rb +++ b/lib/graphiti/errors.rb @@ -561,6 +561,28 @@ def message end end + class PolymorphicSideloadTypeNotFound < Base + def initialize(sideload, name) + @sideload = sideload + @name = name + end + + def message + <<~MSG + #{@sideload.parent_resource}: Tried to find a Resource with type '#{@name.inspect}', but did not find one! + + This is because either a Resource with that type doesn't exist, or it's not registered on the sideload. The below example shows how to register a Resource with this sideload. Make sure one of the registered Resources has type '#{@name.inspect}' + + polymorphic_belongs_to #{@sideload.name.inspect} do + group_by(#{@sideload.grouper.field_name.inspect}) do + on(:foo) + on(:foo).belongs_to :foo, resource: FooResource # (long-hand example) + end + end + MSG + end + end + class PolymorphicSideloadChildNotFound < Base def initialize(sideload, name) @sideload = sideload diff --git a/lib/graphiti/sideload/polymorphic_belongs_to.rb b/lib/graphiti/sideload/polymorphic_belongs_to.rb index 8eb33961..1ce67bec 100644 --- a/lib/graphiti/sideload/polymorphic_belongs_to.rb +++ b/lib/graphiti/sideload/polymorphic_belongs_to.rb @@ -99,6 +99,15 @@ def child_for_type(type) end end + def child_for_type!(type) + if (child = child_for_type(type)) + child + else + err = ::Graphiti::Errors::PolymorphicSideloadTypeNotFound + raise err.new(self, type) + end + end + def resolve(parents, query, graph_parent) parents.group_by(&grouper.field_name).each_pair do |group_name, group| next if group_name.nil? || grouper.ignore?(group_name) diff --git a/lib/graphiti/util/relationship_payload.rb b/lib/graphiti/util/relationship_payload.rb index 15f75c10..7bfea921 100644 --- a/lib/graphiti/util/relationship_payload.rb +++ b/lib/graphiti/util/relationship_payload.rb @@ -47,7 +47,7 @@ def payload_for(sideload, relationship_payload) # For polymorphic *sideloads*, grab the correct child sideload if sideload.resource.type != type && sideload.type == :polymorphic_belongs_to - sideload = sideload.child_for_type(type) + sideload = sideload.child_for_type!(type) end # For polymorphic *resources*, grab the correct child resource diff --git a/spec/filtering_spec.rb b/spec/filtering_spec.rb index da772be6..8a6de634 100644 --- a/spec/filtering_spec.rb +++ b/spec/filtering_spec.rb @@ -390,7 +390,7 @@ def self.name params[:filter] = {enum_age: {eq: 2}} expect { records - }.to raise_error(Graphiti::Errors::InvalidFilterValue, /Allowlist: \[1, 3, 5]/) + }.to raise_error(Graphiti::Errors::InvalidFilterValue, /Allowlist: \[1, 3, 5\]/) end end diff --git a/spec/persistence_spec.rb b/spec/persistence_spec.rb index 92e771f2..8a5a2858 100644 --- a/spec/persistence_spec.rb +++ b/spec/persistence_spec.rb @@ -2439,6 +2439,7 @@ def self.name end describe "polymorphic_belongs_to" do + let(:jsonapi_type) { "visas" } let(:payload) do { data: { @@ -2446,7 +2447,7 @@ def self.name relationships: { credit_card: { data: { - type: "visas", + type: jsonapi_type, 'temp-id': "abc123", method: "create", }, @@ -2456,7 +2457,7 @@ def self.name included: [ { 'temp-id': "abc123", - type: "visas", + type: jsonapi_type, attributes: {number: 123456}, }, ], @@ -2505,6 +2506,16 @@ def self.name expect(data.credit_card.number).to eq(123456) expect(data.credit_card_type).to eq(:Visa) end + + context "when unknown jsonapi type" do + let(:jsonapi_type) { "foos" } + + it "raises helpful error" do + expect { + klass.build(payload).save + }.to raise_error(Graphiti::Errors::PolymorphicSideloadTypeNotFound) + end + end end context "when multiple levels" do