From 81b1715e2e220e35ed024896d9721b8d0dff165c Mon Sep 17 00:00:00 2001 From: Darin Date: Sat, 9 Sep 2017 11:29:58 -0700 Subject: [PATCH 1/7] Changes file --- Build.PL | 55 +++++++------------------------------------------------ Changes | 6 ++++++ 2 files changed, 13 insertions(+), 48 deletions(-) create mode 100644 Changes diff --git a/Build.PL b/Build.PL index 4322aba..16855c4 100644 --- a/Build.PL +++ b/Build.PL @@ -1,53 +1,12 @@ +# ========================================================================= +# THIS FILE IS AUTOMATICALLY GENERATED BY MINILLA. +# DO NOT EDIT DIRECTLY. +# ========================================================================= -# This file was automatically generated by Dist::Zilla::Plugin::ModuleBuild v6.009. +use 5.008_001; use strict; -use warnings; -use Module::Build 0.28; +use Module::Build::Tiny 0.035; +Build_PL(); -my %module_build_args = ( - "build_requires" => { - "Module::Build" => "0.28" - }, - "configure_requires" => { - "Module::Build" => "0.28" - }, - "dist_abstract" => "A Perl port of the reference implementation of L.", - "dist_author" => [ - "Artur Khabibullin - rtkh\@cpan.org" - ], - "dist_name" => "GraphQL", - "dist_version" => "0.01", - "license" => "perl", - "module_name" => "GraphQL", - "recursive_test_files" => 1, - "requires" => { - "Data::Dumper" => "2.131", - "JSON" => "2.90", - "List::Util" => "1.26", - "perl" => "5.010000" - }, - "test_requires" => { - "Test::Deep" => "1.127", - "Test::More" => "1.302085" - } -); - - -my %fallback_build_requires = ( - "Module::Build" => "0.28", - "Test::Deep" => "1.127", - "Test::More" => "1.302085" -); - - -unless ( eval { Module::Build->VERSION(0.4004) } ) { - delete $module_build_args{test_requires}; - $module_build_args{build_requires} = \%fallback_build_requires; -} - -my $build = Module::Build->new(%module_build_args); - - -$build->create_build_script; diff --git a/Changes b/Changes new file mode 100644 index 0000000..c34f9e9 --- /dev/null +++ b/Changes @@ -0,0 +1,6 @@ +Revision history for Perl extension graphql-perl + +{{$NEXT}} + + - original version + From 1b01c0bdaf4d97f7d03c054665f764053e490628 Mon Sep 17 00:00:00 2001 From: Darin Date: Sat, 9 Sep 2017 12:53:13 -0700 Subject: [PATCH 2/7] replicating https://github.com/khrt/graphql-perl --- .gitignore | 2 ++ minil.toml | 5 +++++ 2 files changed, 7 insertions(+) create mode 100644 minil.toml diff --git a/.gitignore b/.gitignore index a3ed95d..5ca1a3f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,5 @@ nytprof.out *.bs /_eumm/ .DS_Store +/local/ +cpanfile.snapshot diff --git a/minil.toml b/minil.toml new file mode 100644 index 0000000..86162c5 --- /dev/null +++ b/minil.toml @@ -0,0 +1,5 @@ +name = "GraphQL" + +# badges = ["travis"] +module_maker="ModuleBuildTiny" + From 6eb7d5b6988ab49bd660147a96c9dbcbed9e4bfb Mon Sep 17 00:00:00 2001 From: Darin Date: Mon, 11 Sep 2017 16:24:59 -0700 Subject: [PATCH 3/7] Checking in changes prior to tagging of version 0.02. Changelog diff is: --- lib/GraphQL.pm | 2 +- lib/GraphQL/Execute.pm | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/GraphQL.pm b/lib/GraphQL.pm index 722960a..4246c6c 100644 --- a/lib/GraphQL.pm +++ b/lib/GraphQL.pm @@ -67,7 +67,7 @@ use GraphQL::Language::Source; use GraphQL::Type qw/:all/; use GraphQL::Validator qw/validate/; -our $VERSION = 0.01; +our $VERSION = 0.02; sub graphql { my ($schema, $request, $root_value, $context, $variable_values, $operation_name) = @_; diff --git a/lib/GraphQL/Execute.pm b/lib/GraphQL/Execute.pm index cdbd7d5..dc2026c 100644 --- a/lib/GraphQL/Execute.pm +++ b/lib/GraphQL/Execute.pm @@ -599,7 +599,10 @@ sub complete_value { ); # if (!$completed) { # null - if (!defined($completed)) { # null +# DRL - change made to support NonNull error propagation +# DRL if (!defined($completed)) { # null + if (!defined($completed) || $completed == NULLISH) { # null + # if ($completed && ref($completed) && $completed == NULLISH) { die GraphQLError( "Cannot return null for non-nullable field $info->{parent_type}{name}.$info->{field_name}.", @@ -612,7 +615,8 @@ sub complete_value { # If result value is null-ish (null, undefined, or NaN) then return null. unless ($result) { - warn 'NULLISH'; +# DRL quieting warning for intended state +# DRL warn 'NULLISH'; return NULLISH; # null } From 9b11117c4dd6cb74186c0477885b22efb5f10077 Mon Sep 17 00:00:00 2001 From: Darin Date: Tue, 12 Sep 2017 17:24:36 -0700 Subject: [PATCH 4/7] new test_helper shim to address the randomly failing tests due to uncertain key order when encoding --- lib/GraphQL/Util.pm | 2 +- .../Validator/Rule/FieldsOnCorrectType.pm | 2 +- t/graphql/execute-resolve.t | 9 +-- t/graphql/execute-variables.t | 16 +++-- t/graphql/type.t | 4 +- t/graphql/type/introspection.t | 28 ++++++-- .../validator/rules/fields_on_correct_type.t | 2 +- t/lib/test_helper.pm | 71 +++++++++++++++++++ 8 files changed, 115 insertions(+), 19 deletions(-) create mode 100644 t/lib/test_helper.pm diff --git a/lib/GraphQL/Util.pm b/lib/GraphQL/Util.pm index eb96ea4..25dfc95 100644 --- a/lib/GraphQL/Util.pm +++ b/lib/GraphQL/Util.pm @@ -291,7 +291,7 @@ sub stringify { return ref($value) && $value == NULLISH ? 'null' - : ref($value) ? encode_json($value) + : ref($value) ? JSON->new->canonical(1)->encode($value) : qq'"$value"'; } diff --git a/lib/GraphQL/Validator/Rule/FieldsOnCorrectType.pm b/lib/GraphQL/Validator/Rule/FieldsOnCorrectType.pm index f4abf1c..9acc870 100644 --- a/lib/GraphQL/Validator/Rule/FieldsOnCorrectType.pm +++ b/lib/GraphQL/Validator/Rule/FieldsOnCorrectType.pm @@ -19,7 +19,7 @@ sub undefined_field_message { my $message = qq`Cannot query field "$field_name" on type "${ stringify_type($type) }".`; if ($suggested_type_names && @$suggested_type_names) { - my $suggestions = quoted_or_list($suggested_type_names); + my $suggestions = quoted_or_list([sort @$suggested_type_names]); $message .= " Did you mean to use an inline fragment on $suggestions?"; } elsif ($suggested_field_names && @$suggested_field_names) { diff --git a/t/graphql/execute-resolve.t b/t/graphql/execute-resolve.t index fb51f15..cd1451e 100644 --- a/t/graphql/execute-resolve.t +++ b/t/graphql/execute-resolve.t @@ -4,11 +4,12 @@ use warnings; use Test::More; use Test::Deep; -use JSON qw/encode_json/; -use GraphQL qw/graphql :types/; +use GraphQL qw/:types/; use GraphQL::Language::Parser qw/parse/; -use GraphQL::Execute qw/execute/; + +use lib "t/lib"; +use test_helper qw/graphql execute encode_json/; sub testSchema { my $testField = shift; @@ -103,7 +104,7 @@ subtest 'uses provided resolve function' => sub { }; is_deeply graphql($schema, '{ test(aInt: -123, aStr: "String!") }', 'Source!'), { - data => { test => '["Source!",{"aStr":"String!","aInt":-123}]' } + data => { test => '["Source!",{"aInt":-123,"aStr":"String!"}]' } }; }; diff --git a/t/graphql/execute-variables.t b/t/graphql/execute-variables.t index 5659367..d15a6fa 100644 --- a/t/graphql/execute-variables.t +++ b/t/graphql/execute-variables.t @@ -5,14 +5,15 @@ use warnings; use DDP; use Test::More; use Test::Deep; -use JSON qw/encode_json/; -use GraphQL qw/graphql :types/; +use GraphQL qw/:types/; use GraphQL::Nullish qw/NULLISH/; use GraphQL::Language::Parser qw/parse/; -use GraphQL::Execute qw/execute/; use GraphQL::Util qw/stringify/; +use lib "t/lib"; +use test_helper qw/graphql execute encode_json/; + my $TestComplexScalar = GraphQLScalarType( name => 'ComplexScalar', serialize => sub { @@ -362,10 +363,13 @@ EOQ # NOTE: Flunky because of unordered hashes cmp_deeply $e, noclass(superhashof({ locations => [{ line => 2, column => 19 }], - message => qq'Variable "\$input" got invalid value ${ \encode_json($params->{input}) }.' - . qq'\nIn field "nb": Expected "String!", found null.' - . qq'\nIn field "na": In field "c": Expected "String!", found null.' })); + + my $err_msgs = [sort split("\n", $e->{message})]; + is_deeply $err_msgs, [qq'In field "na": In field "c": Expected "String!", found null.', + qq'In field "nb": Expected "String!", found null.', + qq'Variable "\$input" got invalid value ${ \encode_json($params->{input}) }.']; + }; subtest 'errors on addition of unknown input field' => sub { diff --git a/t/graphql/type.t b/t/graphql/type.t index 0a6d855..8b5f14b 100644 --- a/t/graphql/type.t +++ b/t/graphql/type.t @@ -177,7 +177,7 @@ subtest 'defines an enum type with a value of `null` and `undefined`' => sub { }, ); - is_deeply $EnumTypeWithNullishValue->get_values, [ + is_deeply [sort {$a->{name} cmp $b->{name}} @{$EnumTypeWithNullishValue->get_values}], [sort {$a->{name} cmp $b->{name}} ( { name => 'NULL', description => undef, @@ -192,7 +192,7 @@ subtest 'defines an enum type with a value of `null` and `undefined`' => sub { deprecation_reason => undef, value => 'UNDEFINED', # XXX WAS value: undefined }, - ]; + )]; }; subtest 'defines an object type with deprecated field' => sub { diff --git a/t/graphql/type/introspection.t b/t/graphql/type/introspection.t index 62f8b04..b43e40b 100644 --- a/t/graphql/type/introspection.t +++ b/t/graphql/type/introspection.t @@ -1061,7 +1061,12 @@ subtest 'identifies deprecated fields'=> sub { } EOQ - is_deeply graphql($schema, $request), { + my $result; + $result = graphql($schema, $request); + foreach my $key (qw/fields/){ + $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; + } + is_deeply $result, { data => { __type => { name => 'TestType', @@ -1114,7 +1119,12 @@ subtest 'respects the includeDeprecated parameter for fields'=> sub { } EOQ - is_deeply graphql($schema, $request), { + my $result; + $result = graphql($schema, $request); + foreach my $key (qw/trueFields falseFields omittedFields/){ + $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; + } + is_deeply $result, { data => { __type => { name => 'TestType', @@ -1166,7 +1176,12 @@ subtest 'identifies deprecated enum values'=> sub { } EOQ - is_deeply graphql($schema, $request), { + my $result; + $result = graphql($schema, $request); + foreach my $key (qw/enum_values/){ + $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; + } + is_deeply $result, { data => { __type => { name => 'TestEnum', @@ -1229,7 +1244,12 @@ subtest 'respects the includeDeprecated parameter for enum values'=> sub { } EOQ - is_deeply graphql($schema, $request), { + my $result; + $result = graphql($schema, $request); + foreach my $key (qw/trueValues falseValues omittedValues/){ + $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; + } + is_deeply $result, { data => { __type => { name => 'TestEnum', diff --git a/t/graphql/validator/rules/fields_on_correct_type.t b/t/graphql/validator/rules/fields_on_correct_type.t index 5f3d10f..00016ba 100644 --- a/t/graphql/validator/rules/fields_on_correct_type.t +++ b/t/graphql/validator/rules/fields_on_correct_type.t @@ -195,7 +195,7 @@ subtest 'Defined on implementors queried on union' => sub { name }', #TODO: NOTE: ORIG [undefined_field( 'name', 'CatOrDog', ['Being', 'Pet', 'Canine', 'Dog', 'Cat'], [], 3, 9)] - [undefined_field( 'name', 'CatOrDog', ['Pet', 'Being', 'Canine', 'Dog', 'Cat'], [], 3, 9)] + [undefined_field( 'name', 'CatOrDog', [sort ('Pet', 'Being', 'Canine', 'Dog', 'Cat')], [], 3, 9)] ); }; diff --git a/t/lib/test_helper.pm b/t/lib/test_helper.pm new file mode 100644 index 0000000..49bc717 --- /dev/null +++ b/t/lib/test_helper.pm @@ -0,0 +1,71 @@ +package test_helper; + +# this project's tests randomly fail comparisons due to the uncertain ordering of hash keys. +# test_helper is a shim between the existing tests and GraphQL-Perl as well as JSON to address this issue. +# +# the test_helper package wraps 'graphql' and the lower level 'execute' methods +# so that the response keys can be sorted prior to comparision testing. +# +# similarly 'encode_json' is provide so that JSON will sort before encoding. +# +# place the following in tests that need sorting support. +# +# use lib "t/lib"; +# use test_helper qw/graphql execute encode_json/; + +use strict; +use warnings; + +use Exporter qw/import/; + +use JSON qw//; +use GraphQL; +use GraphQL::Execute; + +our @ISA = qw(Exporter); +our @EXPORT_OK = ( + qw/ + graphql + execute + encode_json + / +); + +# enable sorted keys in JSON testing +my $json = JSON->new->canonical(1); + +sub encode_json { + $json->encode(shift); +} + +sub graphql { + return sort_response( GraphQL::graphql(@_) ); +} + +sub execute { + return sort_response( GraphQL::Execute::execute(@_) ); +} + +sub sort_response { + my $resp = shift; + + if ( 'HASH' eq ref $resp + && defined $resp->{data} + && 'HASH' eq ref $resp->{data} ) + { + foreach my $key ( keys %{ $resp->{data} } ) { + + # if data looks like json then lets try to parse and re-encode it sorted + if ( $resp->{data}->{$key} + && $resp->{data}->{$key} =~ m/^\{[^}]+\}/ ) + { + $resp->{data}->{$key} + = $json->encode( $json->decode( $resp->{data}->{$key} ) ); + } + } + } + + return $resp; +} + +1; From be3fcf1a3f959a8084371bd08431683ce08533d6 Mon Sep 17 00:00:00 2001 From: Darin Date: Tue, 12 Sep 2017 17:49:25 -0700 Subject: [PATCH 5/7] Revert "Checking in changes prior to tagging of version 0.02." This reverts commit 6eb7d5b6988ab49bd660147a96c9dbcbed9e4bfb. --- lib/GraphQL.pm | 2 +- lib/GraphQL/Execute.pm | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/GraphQL.pm b/lib/GraphQL.pm index 4246c6c..722960a 100644 --- a/lib/GraphQL.pm +++ b/lib/GraphQL.pm @@ -67,7 +67,7 @@ use GraphQL::Language::Source; use GraphQL::Type qw/:all/; use GraphQL::Validator qw/validate/; -our $VERSION = 0.02; +our $VERSION = 0.01; sub graphql { my ($schema, $request, $root_value, $context, $variable_values, $operation_name) = @_; diff --git a/lib/GraphQL/Execute.pm b/lib/GraphQL/Execute.pm index dc2026c..cdbd7d5 100644 --- a/lib/GraphQL/Execute.pm +++ b/lib/GraphQL/Execute.pm @@ -599,10 +599,7 @@ sub complete_value { ); # if (!$completed) { # null -# DRL - change made to support NonNull error propagation -# DRL if (!defined($completed)) { # null - if (!defined($completed) || $completed == NULLISH) { # null - + if (!defined($completed)) { # null # if ($completed && ref($completed) && $completed == NULLISH) { die GraphQLError( "Cannot return null for non-nullable field $info->{parent_type}{name}.$info->{field_name}.", @@ -615,8 +612,7 @@ sub complete_value { # If result value is null-ish (null, undefined, or NaN) then return null. unless ($result) { -# DRL quieting warning for intended state -# DRL warn 'NULLISH'; + warn 'NULLISH'; return NULLISH; # null } From 98f4ca396ebaf5378877576787ed90239a023ea0 Mon Sep 17 00:00:00 2001 From: Darin Date: Tue, 12 Sep 2017 17:57:10 -0700 Subject: [PATCH 6/7] revert Build.PL to original --- Build.PL | 55 ++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/Build.PL b/Build.PL index 16855c4..4322aba 100644 --- a/Build.PL +++ b/Build.PL @@ -1,12 +1,53 @@ -# ========================================================================= -# THIS FILE IS AUTOMATICALLY GENERATED BY MINILLA. -# DO NOT EDIT DIRECTLY. -# ========================================================================= -use 5.008_001; +# This file was automatically generated by Dist::Zilla::Plugin::ModuleBuild v6.009. use strict; +use warnings; -use Module::Build::Tiny 0.035; +use Module::Build 0.28; -Build_PL(); +my %module_build_args = ( + "build_requires" => { + "Module::Build" => "0.28" + }, + "configure_requires" => { + "Module::Build" => "0.28" + }, + "dist_abstract" => "A Perl port of the reference implementation of L.", + "dist_author" => [ + "Artur Khabibullin - rtkh\@cpan.org" + ], + "dist_name" => "GraphQL", + "dist_version" => "0.01", + "license" => "perl", + "module_name" => "GraphQL", + "recursive_test_files" => 1, + "requires" => { + "Data::Dumper" => "2.131", + "JSON" => "2.90", + "List::Util" => "1.26", + "perl" => "5.010000" + }, + "test_requires" => { + "Test::Deep" => "1.127", + "Test::More" => "1.302085" + } +); + + +my %fallback_build_requires = ( + "Module::Build" => "0.28", + "Test::Deep" => "1.127", + "Test::More" => "1.302085" +); + + +unless ( eval { Module::Build->VERSION(0.4004) } ) { + delete $module_build_args{test_requires}; + $module_build_args{build_requires} = \%fallback_build_requires; +} + +my $build = Module::Build->new(%module_build_args); + + +$build->create_build_script; From 2ac7a6e8ae8afdef2ef1129d161624809c55028e Mon Sep 17 00:00:00 2001 From: Darin Date: Tue, 12 Sep 2017 18:19:59 -0700 Subject: [PATCH 7/7] refactored key sorting on tests --- t/graphql/type/introspection.t | 38 +++++++++++++--------------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/t/graphql/type/introspection.t b/t/graphql/type/introspection.t index b43e40b..0126004 100644 --- a/t/graphql/type/introspection.t +++ b/t/graphql/type/introspection.t @@ -1061,12 +1061,7 @@ subtest 'identifies deprecated fields'=> sub { } EOQ - my $result; - $result = graphql($schema, $request); - foreach my $key (qw/fields/){ - $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; - } - is_deeply $result, { + is_deeply sort_keys( graphql( $schema, $request ), [qw/fields/] ), { data => { __type => { name => 'TestType', @@ -1119,12 +1114,7 @@ subtest 'respects the includeDeprecated parameter for fields'=> sub { } EOQ - my $result; - $result = graphql($schema, $request); - foreach my $key (qw/trueFields falseFields omittedFields/){ - $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; - } - is_deeply $result, { + is_deeply sort_keys( graphql( $schema, $request ), [qw/trueFields falseFields omittedFields/] ), { data => { __type => { name => 'TestType', @@ -1176,12 +1166,7 @@ subtest 'identifies deprecated enum values'=> sub { } EOQ - my $result; - $result = graphql($schema, $request); - foreach my $key (qw/enum_values/){ - $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; - } - is_deeply $result, { + is_deeply sort_keys( graphql( $schema, $request ), [qw/enum_values/] ), { data => { __type => { name => 'TestEnum', @@ -1244,12 +1229,7 @@ subtest 'respects the includeDeprecated parameter for enum values'=> sub { } EOQ - my $result; - $result = graphql($schema, $request); - foreach my $key (qw/trueValues falseValues omittedValues/){ - $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; - } - is_deeply $result, { + is_deeply sort_keys( graphql( $schema, $request ), [qw/trueValues falseValues omittedValues/] ), { data => { __type => { name => 'TestEnum', @@ -1420,3 +1400,13 @@ EOQ }; done_testing; + +sub sort_keys { + my($result, $keys) = @_; + + foreach my $key (@$keys){ + $result->{data}->{__type}->{$key} = [sort {$b->{name} cmp $a->{name}} @{$result->{data}->{__type}->{$key}}]; + } + + return $result; +} \ No newline at end of file