rails-graphql 0.2.1 → 1.0.0.beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/console.rb +18 -0
- data/ext/extconf.h +3 -0
- data/ext/extconf.rb +1 -54
- data/ext/gql_parser.c +646 -0
- data/ext/shared.c +482 -0
- data/ext/shared.h +177 -0
- data/lib/gql_parser.so +0 -0
- data/lib/rails/graphql/adapters/mysql_adapter.rb +59 -0
- data/lib/rails/graphql/adapters/pg_adapter.rb +25 -22
- data/lib/rails/graphql/adapters/sqlite_adapter.rb +17 -14
- data/lib/rails/graphql/alternative/field_set.rb +36 -0
- data/lib/rails/graphql/alternative/mutation.rb +17 -0
- data/lib/rails/graphql/alternative/query.rb +93 -0
- data/lib/rails/graphql/alternative/subscription.rb +17 -0
- data/lib/rails/graphql/alternative.rb +20 -0
- data/lib/rails/graphql/argument.rb +21 -24
- data/lib/rails/graphql/callback.rb +24 -9
- data/lib/rails/graphql/collectors/hash_collector.rb +14 -6
- data/lib/rails/graphql/collectors/idented_collector.rb +10 -7
- data/lib/rails/graphql/collectors/json_collector.rb +22 -17
- data/lib/rails/graphql/collectors.rb +4 -4
- data/lib/rails/graphql/config.rb +130 -15
- data/lib/rails/graphql/directive/cached_directive.rb +33 -0
- data/lib/rails/graphql/directive/deprecated_directive.rb +10 -10
- data/lib/rails/graphql/directive/include_directive.rb +5 -4
- data/lib/rails/graphql/directive/skip_directive.rb +5 -4
- data/lib/rails/graphql/directive.rb +118 -63
- data/lib/rails/graphql/errors.rb +33 -4
- data/lib/rails/graphql/event.rb +16 -5
- data/lib/rails/graphql/field/authorized_field.rb +19 -3
- data/lib/rails/graphql/field/input_field.rb +11 -10
- data/lib/rails/graphql/field/mutation_field.rb +42 -7
- data/lib/rails/graphql/field/output_field.rb +102 -13
- data/lib/rails/graphql/field/proxied_field.rb +31 -22
- data/lib/rails/graphql/field/resolved_field.rb +26 -24
- data/lib/rails/graphql/field/scoped_config.rb +10 -4
- data/lib/rails/graphql/field/subscription_field.rb +140 -0
- data/lib/rails/graphql/field/typed_field.rb +43 -22
- data/lib/rails/graphql/field.rb +70 -56
- data/lib/rails/graphql/global_id.rb +85 -0
- data/lib/rails/graphql/helpers/attribute_delegator.rb +5 -5
- data/lib/rails/graphql/helpers/inherited_collection/array.rb +50 -0
- data/lib/rails/graphql/helpers/inherited_collection/base.rb +43 -0
- data/lib/rails/graphql/helpers/inherited_collection/hash.rb +87 -0
- data/lib/rails/graphql/helpers/inherited_collection.rb +25 -76
- data/lib/rails/graphql/helpers/instantiable.rb +15 -0
- data/lib/rails/graphql/helpers/leaf_from_ar.rb +7 -7
- data/lib/rails/graphql/helpers/registerable.rb +44 -62
- data/lib/rails/graphql/helpers/unregisterable.rb +16 -0
- data/lib/rails/graphql/helpers/with_arguments.rb +31 -27
- data/lib/rails/graphql/helpers/with_assignment.rb +6 -6
- data/lib/rails/graphql/helpers/with_callbacks.rb +25 -8
- data/lib/rails/graphql/helpers/with_description.rb +71 -0
- data/lib/rails/graphql/helpers/with_directives.rb +54 -30
- data/lib/rails/graphql/helpers/with_events.rb +21 -23
- data/lib/rails/graphql/helpers/with_fields.rb +76 -22
- data/lib/rails/graphql/helpers/with_global_id.rb +22 -0
- data/lib/rails/graphql/helpers/with_name.rb +43 -0
- data/lib/rails/graphql/helpers/with_namespace.rb +7 -4
- data/lib/rails/graphql/helpers/with_owner.rb +8 -7
- data/lib/rails/graphql/helpers/with_schema_fields.rb +137 -55
- data/lib/rails/graphql/helpers/with_validator.rb +9 -9
- data/lib/rails/graphql/helpers.rb +10 -3
- data/lib/rails/graphql/introspection.rb +43 -36
- data/lib/rails/graphql/railtie.rb +88 -33
- data/lib/rails/graphql/railties/base_generator.rb +3 -9
- data/lib/rails/graphql/railties/channel.rb +157 -0
- data/lib/rails/graphql/railties/controller.rb +62 -17
- data/lib/rails/graphql/railties/controller_runtime.rb +5 -5
- data/lib/rails/graphql/railties/log_subscriber.rb +81 -14
- data/lib/rails/graphql/request/arguments.rb +24 -49
- data/lib/rails/graphql/request/backtrace.rb +191 -0
- data/lib/rails/graphql/request/component/field.rb +86 -65
- data/lib/rails/graphql/request/component/fragment.rb +72 -24
- data/lib/rails/graphql/request/component/operation/subscription.rb +164 -4
- data/lib/rails/graphql/request/component/operation.rb +63 -31
- data/lib/rails/graphql/request/component/spread.rb +68 -25
- data/lib/rails/graphql/request/component/typename.rb +27 -12
- data/lib/rails/graphql/request/component.rb +75 -36
- data/lib/rails/graphql/request/context.rb +18 -8
- data/lib/rails/graphql/request/errors.rb +16 -6
- data/lib/rails/graphql/request/event.rb +19 -8
- data/lib/rails/graphql/request/helpers/directives.rb +68 -27
- data/lib/rails/graphql/request/helpers/selection_set.rb +51 -25
- data/lib/rails/graphql/request/helpers/value_writers.rb +18 -16
- data/lib/rails/graphql/request/prepared_data.rb +98 -0
- data/lib/rails/graphql/request/steps/authorizable.rb +24 -14
- data/lib/rails/graphql/request/steps/organizable.rb +110 -48
- data/lib/rails/graphql/request/steps/{prepareable.rb → preparable.rb} +20 -7
- data/lib/rails/graphql/request/steps/{resolveable.rb → resolvable.rb} +15 -6
- data/lib/rails/graphql/request/strategy/cached_strategy.rb +64 -0
- data/lib/rails/graphql/request/strategy/dynamic_instance.rb +6 -6
- data/lib/rails/graphql/request/strategy/multi_query_strategy.rb +6 -13
- data/lib/rails/graphql/request/strategy/sequenced_strategy.rb +9 -9
- data/lib/rails/graphql/request/strategy.rb +131 -75
- data/lib/rails/graphql/request/subscription.rb +80 -0
- data/lib/rails/graphql/request.rb +305 -86
- data/lib/rails/graphql/schema.rb +240 -48
- data/lib/rails/graphql/shortcuts.rb +22 -3
- data/lib/rails/graphql/source/active_record/builders.rb +49 -35
- data/lib/rails/graphql/source/active_record_source.rb +70 -54
- data/lib/rails/graphql/source/base.rb +111 -0
- data/lib/rails/graphql/source/builder.rb +128 -0
- data/lib/rails/graphql/source/scoped_arguments.rb +31 -19
- data/lib/rails/graphql/source.rb +89 -213
- data/lib/rails/graphql/subscription/provider/action_cable.rb +112 -0
- data/lib/rails/graphql/subscription/provider/base.rb +191 -0
- data/lib/rails/graphql/subscription/provider.rb +18 -0
- data/lib/rails/graphql/subscription/store/base.rb +145 -0
- data/lib/rails/graphql/subscription/store/memory.rb +127 -0
- data/lib/rails/graphql/subscription/store.rb +19 -0
- data/lib/rails/graphql/subscription.rb +17 -0
- data/lib/rails/graphql/to_gql.rb +29 -32
- data/lib/rails/graphql/type/enum/directive_location_enum.rb +11 -11
- data/lib/rails/graphql/type/enum/type_kind_enum.rb +3 -3
- data/lib/rails/graphql/type/enum.rb +34 -48
- data/lib/rails/graphql/type/input.rb +74 -23
- data/lib/rails/graphql/type/interface.rb +16 -26
- data/lib/rails/graphql/type/object/directive_object.rb +4 -4
- data/lib/rails/graphql/type/object/enum_value_object.rb +3 -3
- data/lib/rails/graphql/type/object/field_object.rb +24 -6
- data/lib/rails/graphql/type/object/input_value_object.rb +3 -3
- data/lib/rails/graphql/type/object/schema_object.rb +5 -8
- data/lib/rails/graphql/type/object/type_object.rb +29 -19
- data/lib/rails/graphql/type/object.rb +26 -23
- data/lib/rails/graphql/type/scalar/any_scalar.rb +30 -0
- data/lib/rails/graphql/type/scalar/bigint_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar/binary_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/boolean_scalar.rb +8 -8
- data/lib/rails/graphql/type/scalar/date_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/date_time_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/decimal_scalar.rb +3 -3
- data/lib/rails/graphql/type/scalar/float_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar/id_scalar.rb +6 -5
- data/lib/rails/graphql/type/scalar/int_scalar.rb +6 -5
- data/lib/rails/graphql/type/scalar/json_scalar.rb +39 -0
- data/lib/rails/graphql/type/scalar/string_scalar.rb +18 -4
- data/lib/rails/graphql/type/scalar/time_scalar.rb +5 -5
- data/lib/rails/graphql/type/scalar.rb +25 -22
- data/lib/rails/graphql/type/union.rb +14 -16
- data/lib/rails/graphql/type.rb +34 -25
- data/lib/rails/graphql/type_map.rb +256 -164
- data/lib/rails/graphql/uri.rb +166 -0
- data/lib/rails/graphql/version.rb +15 -3
- data/lib/rails/graphql.rake +3 -0
- data/lib/rails/graphql.rb +85 -52
- data/lib/rails-graphql.rb +1 -1
- data/test/assets/en.yml +29 -0
- data/test/assets/introspection-mem.txt +1 -1
- data/test/assets/mem.gql +18 -45
- data/test/assets/mysql.gql +392 -0
- data/test/assets/sqlite.gql +21 -12
- data/test/assets/translate.gql +335 -0
- data/test/config.rb +18 -8
- data/test/graphql/schema_test.rb +12 -19
- data/test/graphql/source_test.rb +8 -75
- data/test/graphql/type/enum_test.rb +207 -203
- data/test/graphql/type/input_test.rb +14 -9
- data/test/graphql/type/interface_test.rb +4 -4
- data/test/graphql/type/scalar/any_scalar_test.rb +38 -0
- data/test/graphql/type/scalar/boolean_scalar_test.rb +6 -3
- data/test/graphql/type/scalar/json_scalar_test.rb +23 -0
- data/test/graphql/type_map_test.rb +51 -66
- data/test/graphql/type_test.rb +0 -19
- data/test/graphql_test.rb +1 -1
- data/test/integration/{authorization/authorization_test.rb → authorization_test.rb} +40 -14
- data/test/integration/config.rb +36 -3
- data/test/integration/customization_test.rb +39 -0
- data/test/integration/global_id_test.rb +99 -0
- data/test/integration/memory/star_wars_introspection_test.rb +24 -16
- data/test/integration/memory/star_wars_query_test.rb +54 -3
- data/test/integration/memory/star_wars_validation_test.rb +1 -1
- data/test/integration/mysql/star_wars_introspection_test.rb +25 -0
- data/test/integration/persisted_query_test.rb +87 -0
- data/test/integration/resolver_precedence_test.rb +154 -0
- data/test/integration/schemas/memory.rb +22 -7
- data/test/integration/schemas/mysql.rb +62 -0
- data/test/integration/schemas/sqlite.rb +21 -12
- data/test/integration/sqlite/star_wars_global_id_test.rb +83 -0
- data/test/integration/sqlite/star_wars_introspection_test.rb +10 -0
- data/test/integration/sqlite/star_wars_query_test.rb +14 -1
- data/test/integration/translate_test.rb +61 -0
- data/test/test_ext.rb +16 -13
- metadata +108 -157
- data/ext/depend +0 -3
- data/ext/graphqlparser/Ast.cpp +0 -346
- data/ext/graphqlparser/Ast.h +0 -1214
- data/ext/graphqlparser/AstNode.h +0 -36
- data/ext/graphqlparser/AstVisitor.h +0 -137
- data/ext/graphqlparser/GraphQLParser.cpp +0 -76
- data/ext/graphqlparser/GraphQLParser.h +0 -55
- data/ext/graphqlparser/JsonVisitor.cpp +0 -161
- data/ext/graphqlparser/JsonVisitor.cpp.inc +0 -456
- data/ext/graphqlparser/JsonVisitor.h +0 -121
- data/ext/graphqlparser/JsonVisitor.h.inc +0 -110
- data/ext/graphqlparser/VERSION +0 -1
- data/ext/graphqlparser/c/GraphQLAst.cpp +0 -324
- data/ext/graphqlparser/c/GraphQLAst.h +0 -180
- data/ext/graphqlparser/c/GraphQLAstForEachConcreteType.h +0 -44
- data/ext/graphqlparser/c/GraphQLAstNode.cpp +0 -25
- data/ext/graphqlparser/c/GraphQLAstNode.h +0 -33
- data/ext/graphqlparser/c/GraphQLAstToJSON.cpp +0 -21
- data/ext/graphqlparser/c/GraphQLAstToJSON.h +0 -24
- data/ext/graphqlparser/c/GraphQLAstVisitor.cpp +0 -55
- data/ext/graphqlparser/c/GraphQLAstVisitor.h +0 -53
- data/ext/graphqlparser/c/GraphQLParser.cpp +0 -35
- data/ext/graphqlparser/c/GraphQLParser.h +0 -54
- data/ext/graphqlparser/dump_json_ast.cpp +0 -48
- data/ext/graphqlparser/lexer.lpp +0 -324
- data/ext/graphqlparser/parser.ypp +0 -693
- data/ext/graphqlparser/parsergen/lexer.cpp +0 -2633
- data/ext/graphqlparser/parsergen/lexer.h +0 -528
- data/ext/graphqlparser/parsergen/location.hh +0 -189
- data/ext/graphqlparser/parsergen/parser.tab.cpp +0 -3300
- data/ext/graphqlparser/parsergen/parser.tab.hpp +0 -646
- data/ext/graphqlparser/parsergen/position.hh +0 -179
- data/ext/graphqlparser/parsergen/stack.hh +0 -156
- data/ext/graphqlparser/syntaxdefs.h +0 -19
- data/ext/libgraphqlparser/AstNode.h +0 -36
- data/ext/libgraphqlparser/CMakeLists.txt +0 -148
- data/ext/libgraphqlparser/CONTRIBUTING.md +0 -23
- data/ext/libgraphqlparser/GraphQLParser.cpp +0 -76
- data/ext/libgraphqlparser/GraphQLParser.h +0 -55
- data/ext/libgraphqlparser/JsonVisitor.cpp +0 -161
- data/ext/libgraphqlparser/JsonVisitor.h +0 -121
- data/ext/libgraphqlparser/LICENSE +0 -22
- data/ext/libgraphqlparser/README.clang-tidy +0 -7
- data/ext/libgraphqlparser/README.md +0 -84
- data/ext/libgraphqlparser/ast/ast.ast +0 -203
- data/ext/libgraphqlparser/ast/ast.py +0 -61
- data/ext/libgraphqlparser/ast/c.py +0 -100
- data/ext/libgraphqlparser/ast/c.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_impl.py +0 -61
- data/ext/libgraphqlparser/ast/c_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/c_visitor_impl.py +0 -39
- data/ext/libgraphqlparser/ast/c_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/casing.py +0 -26
- data/ext/libgraphqlparser/ast/casing.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx.py +0 -197
- data/ext/libgraphqlparser/ast/cxx.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_impl.py +0 -61
- data/ext/libgraphqlparser/ast/cxx_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.py +0 -42
- data/ext/libgraphqlparser/ast/cxx_json_visitor_header.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.py +0 -80
- data/ext/libgraphqlparser/ast/cxx_json_visitor_impl.pyc +0 -0
- data/ext/libgraphqlparser/ast/cxx_visitor.py +0 -64
- data/ext/libgraphqlparser/ast/cxx_visitor.pyc +0 -0
- data/ext/libgraphqlparser/ast/js.py +0 -65
- data/ext/libgraphqlparser/ast/license.py +0 -10
- data/ext/libgraphqlparser/ast/license.pyc +0 -0
- data/ext/libgraphqlparser/c/GraphQLAstNode.cpp +0 -25
- data/ext/libgraphqlparser/c/GraphQLAstNode.h +0 -33
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.cpp +0 -21
- data/ext/libgraphqlparser/c/GraphQLAstToJSON.h +0 -24
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.cpp +0 -55
- data/ext/libgraphqlparser/c/GraphQLAstVisitor.h +0 -53
- data/ext/libgraphqlparser/c/GraphQLParser.cpp +0 -35
- data/ext/libgraphqlparser/c/GraphQLParser.h +0 -54
- data/ext/libgraphqlparser/clang-tidy-all.sh +0 -3
- data/ext/libgraphqlparser/cmake/version.cmake +0 -16
- data/ext/libgraphqlparser/dump_json_ast.cpp +0 -48
- data/ext/libgraphqlparser/go/README.md +0 -20
- data/ext/libgraphqlparser/go/callbacks.go +0 -18
- data/ext/libgraphqlparser/go/gotest.go +0 -64
- data/ext/libgraphqlparser/lexer.lpp +0 -324
- data/ext/libgraphqlparser/libgraphqlparser.pc.in +0 -11
- data/ext/libgraphqlparser/parser.ypp +0 -693
- data/ext/libgraphqlparser/parsergen/lexer.cpp +0 -2633
- data/ext/libgraphqlparser/parsergen/lexer.h +0 -528
- data/ext/libgraphqlparser/parsergen/location.hh +0 -189
- data/ext/libgraphqlparser/parsergen/parser.tab.cpp +0 -3300
- data/ext/libgraphqlparser/parsergen/parser.tab.hpp +0 -646
- data/ext/libgraphqlparser/parsergen/position.hh +0 -179
- data/ext/libgraphqlparser/parsergen/stack.hh +0 -156
- data/ext/libgraphqlparser/python/CMakeLists.txt +0 -14
- data/ext/libgraphqlparser/python/README.md +0 -5
- data/ext/libgraphqlparser/python/example.py +0 -31
- data/ext/libgraphqlparser/syntaxdefs.h +0 -19
- data/ext/libgraphqlparser/test/BuildCAPI.c +0 -5
- data/ext/libgraphqlparser/test/CMakeLists.txt +0 -25
- data/ext/libgraphqlparser/test/JsonVisitorTests.cpp +0 -28
- data/ext/libgraphqlparser/test/ParserTests.cpp +0 -352
- data/ext/libgraphqlparser/test/kitchen-sink.graphql +0 -59
- data/ext/libgraphqlparser/test/kitchen-sink.json +0 -1
- data/ext/libgraphqlparser/test/schema-kitchen-sink.graphql +0 -78
- data/ext/libgraphqlparser/test/schema-kitchen-sink.json +0 -1
- data/ext/libgraphqlparser/test/valgrind.supp +0 -33
- data/ext/version.cpp +0 -21
- data/lib/graphqlparser.so +0 -0
- data/lib/rails/graphql/native/functions.rb +0 -38
- data/lib/rails/graphql/native/location.rb +0 -41
- data/lib/rails/graphql/native/pointers.rb +0 -23
- data/lib/rails/graphql/native/visitor.rb +0 -349
- data/lib/rails/graphql/native.rb +0 -56
- data/test/integration/schemas/authorization.rb +0 -12
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
5
|
# = GraphQL Source Active Record
|
6
6
|
#
|
7
7
|
# This source allows the translation of active record objects into a new
|
@@ -10,20 +10,23 @@ module Rails # :nodoc:
|
|
10
10
|
# 2. 1 Input
|
11
11
|
# 3. 2 Query fields (ingular and plural)
|
12
12
|
# 4. 3 Mutation fields (create, update, destroy)
|
13
|
-
class Source::ActiveRecordSource < Source
|
13
|
+
class Source::ActiveRecordSource < Source::Base
|
14
14
|
include Source::ScopedArguments
|
15
15
|
|
16
16
|
require_relative 'active_record/builders'
|
17
17
|
extend Builders
|
18
18
|
|
19
19
|
validate_assignment('ActiveRecord::Base') do |value|
|
20
|
-
"The \"#{value.name}\" is not a valid Active Record model"
|
20
|
+
+"The \"#{value.name}\" is not a valid Active Record model"
|
21
21
|
end
|
22
22
|
|
23
|
+
# Mark if the objects created from this source will build fields for
|
24
|
+
# associations associated to the object
|
25
|
+
class_attribute :with_associations, instance_accessor: false, default: true
|
26
|
+
|
23
27
|
# The name of the class (or the class itself) to be used as superclass for
|
24
28
|
# the generate GraphQL interface type of this source
|
25
|
-
class_attribute :interface_class,
|
26
|
-
alias interface interface_class
|
29
|
+
class_attribute :interface_class, instance_accessor: false
|
27
30
|
|
28
31
|
%i[object interface input].each do |type|
|
29
32
|
settings = { abstract: true, with_owner: true }
|
@@ -31,23 +34,22 @@ module Rails # :nodoc:
|
|
31
34
|
end
|
32
35
|
|
33
36
|
self.abstract = true
|
37
|
+
self.hook_names = hook_names.to_a.insert(1, :enums).to_set
|
34
38
|
|
35
|
-
delegate :primary_key, :singular, :plural, :model, to: :class
|
39
|
+
delegate :primary_key, :singular, :plural, :model, :id_columns, to: :class
|
36
40
|
|
37
|
-
|
41
|
+
skip_from(:input, :created_at, :updated_at)
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
build_enum_types
|
42
|
-
end
|
43
|
+
step(:start) { GraphQL.enable_ar_adapter(adapter_name) }
|
44
|
+
step(:enums) { build_enum_types }
|
43
45
|
|
44
|
-
|
46
|
+
step(:object) do
|
45
47
|
build_attribute_fields(self)
|
46
48
|
build_reflection_fields(self)
|
47
49
|
end
|
48
50
|
|
49
|
-
|
50
|
-
extra =
|
51
|
+
step(:input) do
|
52
|
+
extra = GraphQL.enumerate(primary_key).entries.product([{ null: true }]).to_h
|
51
53
|
build_attribute_fields(self, **extra)
|
52
54
|
build_reflection_inputs(self)
|
53
55
|
|
@@ -61,47 +63,39 @@ module Rails # :nodoc:
|
|
61
63
|
end
|
62
64
|
end
|
63
65
|
|
64
|
-
|
66
|
+
step(:query) do
|
67
|
+
build_object
|
68
|
+
|
65
69
|
safe_field(plural, object, full: true) do
|
66
|
-
before_resolve
|
70
|
+
before_resolve(:load_records)
|
67
71
|
end
|
68
72
|
|
69
73
|
safe_field(singular, object, null: false) do
|
70
|
-
|
71
|
-
before_resolve
|
74
|
+
build_primary_key_arguments(self)
|
75
|
+
before_resolve(:load_record)
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
75
|
-
|
79
|
+
step(:mutation) do
|
80
|
+
build_object
|
81
|
+
build_input
|
82
|
+
|
76
83
|
safe_field("create_#{singular}", object, null: false) do
|
77
|
-
argument
|
78
|
-
perform
|
84
|
+
argument(singular, input, null: false)
|
85
|
+
perform(:create_record)
|
79
86
|
end
|
80
87
|
|
81
88
|
safe_field("update_#{singular}", object, null: false) do
|
82
|
-
|
83
|
-
argument
|
84
|
-
before_resolve
|
85
|
-
perform
|
89
|
+
build_primary_key_arguments(self)
|
90
|
+
argument(singular, input, null: false)
|
91
|
+
before_resolve(:load_record)
|
92
|
+
perform(:update_record)
|
86
93
|
end
|
87
94
|
|
88
95
|
safe_field("delete_#{singular}", :boolean, null: false) do
|
89
|
-
|
90
|
-
before_resolve
|
91
|
-
perform
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
on :finish do
|
96
|
-
attach_fields!
|
97
|
-
attach_scoped_arguments_to(query_fields.values)
|
98
|
-
attach_scoped_arguments_to(mutation_fields.values)
|
99
|
-
|
100
|
-
next if model.base_class == model
|
101
|
-
|
102
|
-
# TODO: Allow nested inheritance for setting up implementation
|
103
|
-
type_map_after_register(model.base_class) do |type|
|
104
|
-
object.implements(type) if type.interface?
|
96
|
+
build_primary_key_arguments(self)
|
97
|
+
before_resolve(:load_record)
|
98
|
+
perform(:destroy_record)
|
105
99
|
end
|
106
100
|
end
|
107
101
|
|
@@ -110,10 +104,11 @@ module Rails # :nodoc:
|
|
110
104
|
delegate :singular, :plural, :param_key, to: :model_name
|
111
105
|
delegate :adapter_name, to: 'model.connection'
|
112
106
|
|
107
|
+
alias interface interface_class
|
113
108
|
alias model assigned_class
|
114
109
|
alias model= assigned_to=
|
115
110
|
|
116
|
-
# Set the
|
111
|
+
# Set the assignment to a model with a similar name as the source
|
117
112
|
def assigned_to
|
118
113
|
@assigned_to ||= name.delete_prefix('GraphQL::')[0..-7]
|
119
114
|
end
|
@@ -125,26 +120,38 @@ module Rails # :nodoc:
|
|
125
120
|
end
|
126
121
|
|
127
122
|
# Just a little override to ensure that both model and table are ready
|
128
|
-
def build!
|
123
|
+
def build!(*)
|
129
124
|
super if model&.table_exists?
|
130
125
|
end
|
131
126
|
|
127
|
+
# Hook into the unregister to clean enums
|
128
|
+
def unregister!
|
129
|
+
super
|
130
|
+
@enums = nil
|
131
|
+
end
|
132
|
+
|
132
133
|
protected
|
133
134
|
|
134
135
|
# Check if a given +attr_name+ is associated with a presence validator
|
135
|
-
# but ignores when there is
|
136
|
+
# (that does not include +if+ nor +unless+), but ignores when there is
|
137
|
+
# a default value
|
136
138
|
def attr_required?(attr_name)
|
137
139
|
return true if attr_name.eql?(primary_key)
|
138
140
|
return false if model.columns_hash[attr_name]&.default.present?
|
139
141
|
return false unless model._validators.key?(attr_name.to_sym)
|
140
|
-
|
142
|
+
|
143
|
+
model._validators[attr_name.to_sym].any? do |validator|
|
144
|
+
validator.is_a?(presence_validator) &&
|
145
|
+
!(validator.options[:if] ||
|
146
|
+
validator.options[:unless])
|
147
|
+
end
|
141
148
|
rescue ::ActiveRecord::StatementInvalid
|
142
149
|
false
|
143
150
|
end
|
144
151
|
|
145
152
|
private
|
146
153
|
|
147
|
-
def presence_validator
|
154
|
+
def presence_validator
|
148
155
|
::ActiveRecord::Validations::PresenceValidator
|
149
156
|
end
|
150
157
|
end
|
@@ -155,8 +162,9 @@ module Rails # :nodoc:
|
|
155
162
|
end
|
156
163
|
|
157
164
|
# Prepare to load a single record from the underlying table
|
158
|
-
def load_record(scope = model.default_scoped)
|
159
|
-
|
165
|
+
def load_record(scope = model.default_scoped, find_by: nil)
|
166
|
+
find_by ||= { primary_key => event.argument(primary_key) }
|
167
|
+
inject_scopes(scope, :relation).find_by(find_by)
|
160
168
|
end
|
161
169
|
|
162
170
|
# Get the chain result and preload the records with thre resulting scope
|
@@ -212,23 +220,31 @@ module Rails # :nodoc:
|
|
212
220
|
|
213
221
|
# Preload the records for a given +association+ using the current value.
|
214
222
|
# It can be further specified with a given +scope+
|
223
|
+
# TODO: On Rails 7 we can use the Preloader::Branch class
|
215
224
|
def preload(association, scope = nil)
|
216
225
|
reflection = model._reflect_on_association(association)
|
217
226
|
records = current_value.is_a?(preloader_association) \
|
218
227
|
? current_value.preloaded_records \
|
219
228
|
: Array.wrap(current_value.itself).compact
|
220
229
|
|
221
|
-
|
230
|
+
klass = preload_class(reflection)
|
231
|
+
args = [reflection.klass, records, reflection, scope]
|
232
|
+
args << nil if klass.instance_method(:initialize).arity == 6 # Rails 7
|
233
|
+
klass.new(*args, true).run
|
222
234
|
end
|
223
235
|
|
224
|
-
# Get the cached instance of active record
|
225
|
-
def
|
226
|
-
|
236
|
+
# Get the cached instance of active record preloader
|
237
|
+
def preload_class(reflection)
|
238
|
+
if reflection.options[:through]
|
239
|
+
::ActiveRecord::Associations::Preloader::ThroughAssociation
|
240
|
+
else
|
241
|
+
::ActiveRecord::Associations::Preloader::Association
|
242
|
+
end
|
227
243
|
end
|
228
244
|
|
229
245
|
private
|
230
246
|
|
231
|
-
def preloader_association
|
247
|
+
def preloader_association
|
232
248
|
ActiveRecord::Associations::Preloader::Association
|
233
249
|
end
|
234
250
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Source
|
6
|
+
class Base < GraphQL::Source
|
7
|
+
extend Helpers::WithSchemaFields
|
8
|
+
extend Helpers::WithAssignment
|
9
|
+
extend Helpers::Unregisterable
|
10
|
+
|
11
|
+
self.abstract = true
|
12
|
+
|
13
|
+
# The name of the class (or the class itself) to be used as superclass
|
14
|
+
# for the generate GraphQL object type of this source
|
15
|
+
class_attribute :object_class, instance_accessor: false,
|
16
|
+
default: '::Rails::GraphQL::Type::Object'
|
17
|
+
|
18
|
+
# The name of the class (or the class itself) to be used as superclass
|
19
|
+
# for the generate GraphQL input type of this source
|
20
|
+
class_attribute :input_class, instance_accessor: false,
|
21
|
+
default: '::Rails::GraphQL::Type::Input'
|
22
|
+
|
23
|
+
# Allow defining a name for the object without going to many troubles
|
24
|
+
# like overriding methods
|
25
|
+
class_attribute :object_name, instance_accessor: false
|
26
|
+
|
27
|
+
# Allow defining a name for the input without going to many troubles
|
28
|
+
# like overriding methods
|
29
|
+
class_attribute :input_name, instance_accessor: false
|
30
|
+
|
31
|
+
class << self
|
32
|
+
|
33
|
+
# Unregister all objects that this source was providing
|
34
|
+
def unregister!
|
35
|
+
GraphQL.type_map.unregister(*created_types) if defined?(@created_types)
|
36
|
+
@object = @input = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return the GraphQL object type associated with the source. It will
|
40
|
+
# create one if it's not defined yet. The created class will be added
|
41
|
+
# to the +::GraphQL+ namespace with the addition of any namespace of
|
42
|
+
# the current class
|
43
|
+
def object
|
44
|
+
@object ||= create_type(superclass: object_class, gql_name: object_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
# Return the GraphQL input type associated with the source. It will
|
48
|
+
# create one if it's not defined yet. The created class will be added
|
49
|
+
# to the +::GraphQL+ namespace with the addition of any namespace of
|
50
|
+
# the current class
|
51
|
+
def input
|
52
|
+
@input ||= create_type(superclass: input_class, gql_name: input_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
# A helper method to create an enum type
|
58
|
+
def create_enum(enum_name, values, **xargs, &block)
|
59
|
+
enumerator = values.each_pair if values.respond_to?(:each_pair)
|
60
|
+
enumerator ||= values.each.with_index
|
61
|
+
|
62
|
+
xargs = xargs.reverse_merge(once: true)
|
63
|
+
create_type(:enum, as: enum_name.classify, **xargs) do
|
64
|
+
indexed! if enumerator.first.last.is_a?(Numeric)
|
65
|
+
enumerator.sort_by(&:last).map(&:first).each(&method(:add))
|
66
|
+
instance_exec(&block) if block.present?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Helper method to create a class based on the given +type+ and
|
71
|
+
# allows several other settings to be executed on it
|
72
|
+
def create_type(type = nil, **xargs, &block)
|
73
|
+
name = "#{gql_module.name}::#{xargs.delete(:as) || base_name}"
|
74
|
+
superclass = xargs.delete(:superclass)
|
75
|
+
with_owner = xargs.delete(:with_owner)
|
76
|
+
|
77
|
+
if superclass.nil?
|
78
|
+
superclass = type.to_s.classify
|
79
|
+
elsif superclass.is_a?(String)
|
80
|
+
superclass = superclass.constantize
|
81
|
+
end
|
82
|
+
|
83
|
+
source = self
|
84
|
+
gql_name = xargs.delete(:gql_name)
|
85
|
+
Schema.send(:create_type, name, superclass, **xargs) do
|
86
|
+
include Helpers::WithOwner if with_owner
|
87
|
+
set_namespaces(*source.namespaces)
|
88
|
+
|
89
|
+
instance_variable_set(:@gql_name, gql_name) unless gql_name.nil?
|
90
|
+
|
91
|
+
self.owner = source if respond_to?(:owner=)
|
92
|
+
self.assigned_to = source.safe_assigned_class \
|
93
|
+
if source.assigned? && is_a?(Helpers::WithAssignment)
|
94
|
+
|
95
|
+
instance_exec(&block) if block.present?
|
96
|
+
end.tap { |klass| created_types << klass }
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
# Keep track of all the types created byt this source
|
102
|
+
def created_types
|
103
|
+
@created_types ||= []
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
|
+
class Source
|
6
|
+
module Builder
|
7
|
+
|
8
|
+
# Check if the object was already built
|
9
|
+
def built?(part = nil)
|
10
|
+
defined?(@built) && @built.present? &&
|
11
|
+
(part.nil? || @built.include?(part.to_sym))
|
12
|
+
end
|
13
|
+
|
14
|
+
# Build all from all descendant sources
|
15
|
+
def build_all_sources
|
16
|
+
descendants.each(&:build_all)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Trigger a safe build of everything
|
20
|
+
def build_all
|
21
|
+
build_all! unless abstract?
|
22
|
+
end
|
23
|
+
|
24
|
+
# Allows building anything that is in hooks
|
25
|
+
def respond_to_missing?(method_name, *)
|
26
|
+
return super unless method_name.to_s.start_with?('build_') &&
|
27
|
+
hook_names.include?(method_name.to_s[6..-1].to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Allow fast creation of values
|
31
|
+
def method_missing(method_name, *args, **xargs, &block)
|
32
|
+
return super unless method_name.to_s.start_with?('build_')
|
33
|
+
|
34
|
+
type = method_name.to_s[6..-1]
|
35
|
+
type = type.singularize unless hook_names.include?(type.to_sym)
|
36
|
+
type = type.to_sym
|
37
|
+
|
38
|
+
import_skips_for(type, xargs)
|
39
|
+
|
40
|
+
build!(type, *args, **xargs, &block) unless built?(type)
|
41
|
+
end
|
42
|
+
|
43
|
+
protected
|
44
|
+
|
45
|
+
# Store the list of built steps
|
46
|
+
def built
|
47
|
+
@built ||= Set.new
|
48
|
+
end
|
49
|
+
|
50
|
+
# Make sure to mark the hook name as built
|
51
|
+
def run_hooks(hook_name, *)
|
52
|
+
super
|
53
|
+
ensure
|
54
|
+
built << hook_name
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Import all options-based settings for skipping field
|
60
|
+
def import_skips_for(type, options)
|
61
|
+
return if type == :all
|
62
|
+
|
63
|
+
if !(values = options.delete(:except)).nil?
|
64
|
+
segmented_skip_fields[type] += GraphQL.enumerate(values).map do |value|
|
65
|
+
value.to_s.underscore
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
if !(values = options.delete(:only)).nil?
|
70
|
+
segmented_only_fields[type] += GraphQL.enumerate(values).map do |value|
|
71
|
+
value.to_s.underscore
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Build all the hooks if it's not built
|
77
|
+
def build_all!
|
78
|
+
catch(:done) do
|
79
|
+
hook_names.to_enum.drop(1).each do |hook|
|
80
|
+
send("build_#{hook}")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check if the build process can happen
|
86
|
+
def ensure_build!(type)
|
87
|
+
raise DefinitionError, (+<<~MSG).squish if hook_names.exclude?(type)
|
88
|
+
#{self.name} doesn't know how build #{type}, hook not proper defined.
|
89
|
+
MSG
|
90
|
+
|
91
|
+
raise DefinitionError, (+<<~MSG).squish if abstract
|
92
|
+
Abstract source #{name} cannot be built.
|
93
|
+
MSG
|
94
|
+
|
95
|
+
raise DefinitionError, (+<<~MSG).squish if built?(type)
|
96
|
+
The #{type} part is already built.
|
97
|
+
MSG
|
98
|
+
end
|
99
|
+
|
100
|
+
# Build all the objects associated with this source
|
101
|
+
def build!(type)
|
102
|
+
ensure_build!(type)
|
103
|
+
|
104
|
+
catch(:skip) { run_hooks(:start) } unless built?(:start)
|
105
|
+
catch(:skip) { run_hooks(type, hook_scope_for(type)) }
|
106
|
+
|
107
|
+
built << type.to_sym
|
108
|
+
end
|
109
|
+
|
110
|
+
# Get the correct +self_object+ for the hook instance
|
111
|
+
def hook_scope_for(type)
|
112
|
+
type = type.to_sym
|
113
|
+
object =
|
114
|
+
if Helpers::WithSchemaFields::TYPE_FIELD_CLASS.key?(type)
|
115
|
+
Helpers::WithSchemaFields::ScopedConfig.new(self, type)
|
116
|
+
else
|
117
|
+
Helpers::AttributeDelegator.new(self, type)
|
118
|
+
end
|
119
|
+
|
120
|
+
Source::ScopedConfig.new(self, object, type)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
@@ -1,13 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
module Rails
|
4
|
-
module GraphQL
|
3
|
+
module Rails
|
4
|
+
module GraphQL
|
5
5
|
# This is a helper class that allows sources to have scoped-based arguments,
|
6
6
|
# meaning that when an argument is present, it triggers the underlying block
|
7
7
|
# on the fields where the argument was attached to
|
8
|
-
#
|
9
|
-
# TODO: Easy the usage of scoped arguments with AR, to map model scopes as
|
10
|
-
# arguments using the abilities here provided
|
11
8
|
module Source::ScopedArguments
|
12
9
|
def self.included(other)
|
13
10
|
other.extend(ClassMethods)
|
@@ -15,26 +12,37 @@ module Rails # :nodoc:
|
|
15
12
|
|
16
13
|
# Extended argument class to be the instance of the scoped
|
17
14
|
class Argument < GraphQL::Argument
|
18
|
-
|
19
|
-
|
20
|
-
def initialize(*args, on: nil, **xargs, &block)
|
15
|
+
def initialize(*args, block:, on: nil, **xargs)
|
21
16
|
super(*args, **xargs)
|
22
17
|
|
23
18
|
@block = block
|
24
|
-
@fields =
|
19
|
+
@fields = GraphQL.enumerate(on)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Apply the argument block to the given object, using or not the value
|
23
|
+
def apply_to(object, value)
|
24
|
+
callable = @block.is_a?(Symbol) ? object.method(@block) : @block
|
25
|
+
raise ::ArgumentError, (+<<~MSG) unless callable.respond_to?(:call)
|
26
|
+
Unable to call "#{@block.inspect}" on #{object.class}.
|
27
|
+
MSG
|
28
|
+
|
29
|
+
args = (callable.arity == 1 || callable.arity == -1) ? [value] : nil
|
30
|
+
|
31
|
+
return callable.call(*args) if callable.is_a?(Method)
|
32
|
+
object.instance_exec(*args, &callable)
|
25
33
|
end
|
26
34
|
|
27
35
|
# Check if the argument should be attached to the given +field+
|
28
36
|
def attach_to?(field)
|
29
|
-
return true if fields.nil?
|
37
|
+
return true if @fields.nil?
|
30
38
|
|
31
|
-
fields.any? do |item|
|
39
|
+
@fields.any? do |item|
|
32
40
|
(item.is_a?(Symbol) && field.name.eql?(item)) || field.gql_name.eql?(item)
|
33
41
|
end
|
34
42
|
end
|
35
43
|
end
|
36
44
|
|
37
|
-
module ClassMethods
|
45
|
+
module ClassMethods
|
38
46
|
# Return the list of scoped params defined
|
39
47
|
def scoped_arguments
|
40
48
|
defined?(@scoped_arguments) ? @scoped_arguments : {}
|
@@ -45,11 +53,11 @@ module Rails # :nodoc:
|
|
45
53
|
# Add a new scoped param to the list
|
46
54
|
def scoped_argument(param, type = :string, proc_method = nil, **settings, &block)
|
47
55
|
block = proc_method if proc_method.present? && block.nil?
|
48
|
-
argument = Argument.new(param, type, **settings, owner: self,
|
56
|
+
argument = Argument.new(param, type, **settings, owner: self, block: block)
|
49
57
|
(@scoped_arguments ||= {})[argument.name] = argument
|
50
58
|
end
|
51
59
|
|
52
|
-
alias scoped_arg
|
60
|
+
alias scoped_arg scoped_argument
|
53
61
|
|
54
62
|
# Helper method to attach the scoped arguments to a given +field+
|
55
63
|
def attach_scoped_arguments_to(*fields, safe: true)
|
@@ -69,14 +77,18 @@ module Rails # :nodoc:
|
|
69
77
|
# Find all the executable arguments attached to the running field and
|
70
78
|
# call them with the given object
|
71
79
|
def inject_scopes(object, assigned_to = nil)
|
72
|
-
return object if event.field.nil? || (
|
80
|
+
return object if event.field.nil? || (field_args = event.field.all_arguments).blank?
|
73
81
|
|
82
|
+
args_source = event.send(:args_source)
|
74
83
|
event.data[assigned_to] ||= object unless assigned_to.nil?
|
75
|
-
|
76
|
-
|
77
|
-
|
84
|
+
field_args.each_value.inject(object) do |result, argument|
|
85
|
+
arg_value = args_source.key?(argument.name) \
|
86
|
+
? args_source[argument.name] \
|
87
|
+
: argument.default
|
88
|
+
|
89
|
+
next result if arg_value.nil? || !argument.is_a?(Argument)
|
78
90
|
|
79
|
-
value =
|
91
|
+
value = argument.apply_to(result, arg_value)
|
80
92
|
value = value.nil? ? result : value
|
81
93
|
|
82
94
|
assigned_to.nil? ? value : event.data[assigned_to] = value
|