fix(graphql): detect custom champs in fragment definitions

This commit is contained in:
Paul Chavard 2022-04-11 22:35:51 +02:00
parent ac6010da06
commit b6bb9552e6
2 changed files with 63 additions and 10 deletions

View file

@ -1,13 +1,14 @@
class API::V2::Context < GraphQL::Query::Context
def has_fragment?(name)
if self["has_fragment_#{name}"]
true
else
visitor = HasFragment.new(self.query.selected_operation, name)
# This method is used to check if a given fragment is used in the given query.
# We need that in order to maintain backward compatibility for Types de Champ
# that we extended in later iterations of our schema.
def has_fragment?(fragment_name)
self[:has_fragment] ||= Hash.new do |hash, fragment_name|
visitor = HasFragment.new(query.document, fragment_name)
visitor.visit
self["has_fragment_#{name}"] = visitor.found
self["has_fragment_#{name}"]
hash[fragment_name] = visitor.found
end
self[:has_fragment][fragment_name]
end
def internal_use?
@ -36,17 +37,28 @@ class API::V2::Context < GraphQL::Query::Context
self[:authorized][demarche.id]
end
# This is a query AST visitor that we use to check
# if a fragment with a given name is used in the given document.
# We check for both inline and standalone fragments.
class HasFragment < GraphQL::Language::Visitor
def initialize(document, name)
def initialize(document, fragment_name)
super(document)
@name = name.to_s
@fragment_name = fragment_name.to_s
@found = false
end
attr_reader :found
def on_inline_fragment(node, parent)
if node.type.name == @name
if node.type.name == @fragment_name
@found = true
end
super
end
def on_fragment_definition(node, parent)
if node.type.name == @fragment_name
@found = true
end

View file

@ -26,6 +26,16 @@ RSpec.describe Types::DossierType, type: :graphql do
end
end
describe 'dossier with champs' do
let(:procedure) { create(:procedure, :published, :with_commune, :with_address) }
let(:dossier) { create(:dossier, :accepte, :with_populated_champs, procedure: procedure) }
let(:query) { DOSSIER_WITH_CHAMPS_QUERY }
let(:variables) { { number: dossier.id } }
it { expect(data[:dossier][:champs][0][:__typename]).to eq "CommuneChamp" }
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
end
DOSSIER_QUERY = <<-GRAPHQL
query($number: Int!) {
dossier(number: $number) {
@ -48,4 +58,35 @@ RSpec.describe Types::DossierType, type: :graphql do
}
}
GRAPHQL
DOSSIER_WITH_CHAMPS_QUERY = <<-GRAPHQL
query($number: Int!) {
dossier(number: $number) {
id
number
champs {
id
label
__typename
...CommuneChampFragment
... on AddressChamp {
address {
...AddressFragment
}
}
}
}
}
fragment CommuneChampFragment on CommuneChamp {
commune {
...CommuneFragment
}
}
fragment CommuneFragment on Commune {
code
}
fragment AddressFragment on Address {
cityName
}
GRAPHQL
end