Module: Rails::GraphQL::Helpers::WithSchemaFields
- Included in:
- Schema, Source::Base
- Defined in:
- lib/rails/graphql/helpers/with_schema_fields.rb
Overview
Helper module that allows other objects to hold schema fields (query, mutation, and subscription fields). Works very similar to fields, but they are placed in different places regarding their type.
Defined Under Namespace
Modules: ClassMethods Classes: ScopedConfig
Constant Summary collapse
- TYPE_FIELD_CLASS =
{ query: 'OutputField', mutation: 'MutationField', subscription: 'SubscriptionField', }.freeze
Class Method Summary collapse
Instance Method Summary collapse
-
#[](type, name = nil) ⇒ Object
Allow hash access with the type or the type and the name.
-
#add_field(type, *args, **xargs, &block) ⇒ Object
Add a new field of the give
typeSee OutputField class. -
#add_proxy_field(type, field, *args, **xargs, &block) ⇒ Object
Add a new field to the list but use a proxy instead of a hard copy of a given
field. -
#change_field(type, object, **xargs, &block) ⇒ Object
(also: #overwrite_field)
Find a field and then change some flexible attributes of it.
-
#configure_field(type, object, &block) ⇒ Object
Run a configuration block for the given field of a given
type. -
#configure_fields(type, &block) ⇒ Object
Run a configuration block for the given
type. -
#disable_fields(type, *list) ⇒ Object
Disable a list of given
fieldsfrom a giventype. -
#enable_fields(type, *list) ⇒ Object
Enable a list of given
fieldsfrom a giventype. -
#enabled_fields_from(type) ⇒ Object
Return a lazy enumerator for enabled fields.
-
#field_names_for(type, enabled_only = true) ⇒ Object
Get the list of GraphQL names of all the fields defined.
-
#fields_for(type, initialize = nil) ⇒ Object
A little helper for getting the list of fields of a given type.
-
#fields_for?(type) ⇒ Boolean
Check if there are fields set fot he given type.
-
#find_by_gid(gid) ⇒ Object
Find a specific field using its id as
gql_name.type. -
#find_field(type, object) ⇒ Object
Find a specific field on the given
typelist. -
#find_field!(type, object) ⇒ Object
If the field is not found it will raise an exception.
-
#has_field?(type, object) ⇒ Boolean
Check if a field of the given
typeexists. -
#import_all(mod, **xargs) ⇒ Object
Same as above, but if the name of the module being imported already dictates the type, skip specifying it.
-
#import_all_into(type, mod, recursive: false, **xargs) ⇒ Object
Import a module containing several classes to be imported TODO: Maybe add deepness into the recursive value.
-
#import_into(type, source) ⇒ Object
Import a class of fields into the given section of schema fields.
-
#safe_add_field(*args, of_type: nil, **xargs, &block) ⇒ Object
Only add the field if it is not already defined.
-
#type_name_for(type) ⇒ Object
Return the object name for a given
typeof list of fields. -
#validate! ⇒ Object
Validate all the fields to make sure the definition is valid.
Class Method Details
.extended(other) ⇒ Object
68 69 70 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 68 def self.extended(other) other.extend(WithSchemaFields::ClassMethods) end |
Instance Method Details
#[](type, name = nil) ⇒ Object
Allow hash access with the type or the type and the name
82 83 84 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 82 def [](type, name = nil) name.nil? ? fields_for(type) : find_field(type, name) end |
#add_field(type, *args, **xargs, &block) ⇒ Object
Add a new field of the give type See OutputField class.
107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 107 def add_field(type, *args, **xargs, &block) klass = Field.const_get(TYPE_FIELD_CLASS[type], false) object = klass.new(*args, **xargs, owner: self, &block) raise DuplicatedError, (+" The \"\#{object.name}\" field is already defined on \#{type} fields and\n cannot be redefined.\n MSG\n\n fields_for(type, true)[object.name] = object\nrescue DefinitionError => e\n raise e.class, +\"\#{e.message}\\n Defined at: \#{caller(2)[0]}\"\nend\n").squish if has_field?(type, object.name) |
#add_proxy_field(type, field, *args, **xargs, &block) ⇒ Object
Add a new field to the list but use a proxy instead of a hard copy of a given field
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 123 def add_proxy_field(type, field, *args, **xargs, &block) field = field.field if field.is_a?(Module) && field <= Alternative::Query raise ArgumentError, (+" A \#{field.schema_type} field cannot be added as a \#{type} field.\n MSG\n\n klass = Field.const_get(TYPE_FIELD_CLASS[type], false)\n raise ArgumentError, (+<<~MSG).squish unless field.is_a?(klass)\n The \#{field.class.name} is not a valid field for \#{type} fields.\n MSG\n\n xargs[:owner] = self\n object = field.to_proxy(*args, **xargs, &block)\n raise DuplicatedError, (+<<~MSG).squish if has_field?(type, object.name)\n The \#{field.name.inspect} field is already defined on \#{type} fields\n and cannot be replaced.\n MSG\n\n fields_for(type, true)[object.name] = object\nend\n").squish if field.schema_type != type |
#change_field(type, object, **xargs, &block) ⇒ Object Also known as: overwrite_field
Find a field and then change some flexible attributes of it
145 146 147 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 145 def change_field(type, object, **xargs, &block) find_field!(type, object).apply_changes(**xargs, &block) end |
#configure_field(type, object, &block) ⇒ Object
Run a configuration block for the given field of a given type
152 153 154 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 152 def configure_field(type, object, &block) find_field!(type, object).configure(&block) end |
#configure_fields(type, &block) ⇒ Object
Run a configuration block for the given type
201 202 203 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 201 def configure_fields(type, &block) WithSchemaFields::ScopedConfig.new(self, type).instance_exec(&block) end |
#disable_fields(type, *list) ⇒ Object
Disable a list of given fields from a given type
157 158 159 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 157 def disable_fields(type, *list) list.flatten.map { |item| find_field(type, item)&.disable! } end |
#enable_fields(type, *list) ⇒ Object
Enable a list of given fields from a given type
162 163 164 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 162 def enable_fields(type, *list) list.flatten.map { |item| find_field(type, item)&.enable! } end |
#enabled_fields_from(type) ⇒ Object
Return a lazy enumerator for enabled fields
196 197 198 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 196 def enabled_fields_from(type) lazy_each_field_from(type)&.select(&:enabled?) end |
#field_names_for(type, enabled_only = true) ⇒ Object
Get the list of GraphQL names of all the fields defined
190 191 192 193 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 190 def field_names_for(type, enabled_only = true) source = (enabled_only ? enabled_fields_from(type) : lazy_each_field_from(type)) source&.map(&:gql_name)&.eager end |
#fields_for(type, initialize = nil) ⇒ Object
A little helper for getting the list of fields of a given type
73 74 75 76 77 78 79 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 73 def fields_for(type, initialize = nil) if instance_variable_defined?(ivar = :"@#{type}_fields") instance_variable_get(ivar) elsif initialize instance_variable_set(ivar, Concurrent::Map.new) end end |
#fields_for?(type) ⇒ Boolean
Check if there are fields set fot he given type
87 88 89 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 87 def fields_for?(type) public_send("#{type}_fields?") end |
#find_by_gid(gid) ⇒ Object
Find a specific field using its id as gql_name.type
270 271 272 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 270 def find_by_gid(gid) find_field!(gid.scope, gid.name) end |
#find_field(type, object) ⇒ Object
Find a specific field on the given type list. The object can be the gql_name, name, or an actual field.
176 177 178 179 180 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 176 def find_field(type, object) return unless fields_for?(type) object = object.name if object.is_a?(GraphQL::Field) fields_for(type)[object.is_a?(String) ? object.underscore.to_sym : object] end |
#find_field!(type, object) ⇒ Object
If the field is not found it will raise an exception
183 184 185 186 187 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 183 def find_field!(type, object) find_field(type, object) || raise(NotFoundError, (+" The \#{object.inspect} field on \#{type} is not defined yet.\n MSG\nend\n").squish) |
#has_field?(type, object) ⇒ Boolean
Check if a field of the given type exists. The object can be the gql_name, name, or an actual field.
168 169 170 171 172 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 168 def has_field?(type, object) return false unless fields_for?(type) object = object.name if object.is_a?(GraphQL::Field) fields_for(type).key?(object.is_a?(String) ? object.underscore.to_sym : object) end |
#import_all(mod, **xargs) ⇒ Object
Same as above, but if the name of the module being imported already dictates the type, skip specifying it
248 249 250 251 252 253 254 255 256 257 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 248 def import_all(mod, **xargs) type = mod.name.demodulize.underscore.singularize type = TYPE_FIELD_CLASS.each_key.find { |key| key.to_s == type } return import_all_into(type, mod, **xargs) unless type.nil? raise(::ArgumentError, (+" Unable to extract type from \#{mod.name}.\n Please use \"import_all_into(_type_, \#{mod.name}) instead.\"\n MSG\nend\n").squish) |
#import_all_into(type, mod, recursive: false, **xargs) ⇒ Object
Import a module containing several classes to be imported TODO: Maybe add deepness into the recursive value
237 238 239 240 241 242 243 244 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 237 def import_all_into(type, mod, recursive: false, **xargs) mod.constants.each do |const_name| object = mod.const_get(const_name, false) import_into(type, object, **xargs) if object.is_a?(Class) import_all_into(type, object, recursive: recursive, **xargs) if recursive && object.is_a?(Module) end end |
#import_into(type, source) ⇒ Object
Import a class of fields into the given section of schema fields
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 206 def import_into(type, source) # Import an alternative declaration of a field if source.is_a?(Module) && source <= Alternative::Query return add_proxy_field(type, source.field) end case source when Array # Import a list of fields source.each { |field| add_proxy_field(type, field) } when Hash, Concurrent::Map # Import a keyed list of fields source.each_value { |field| add_proxy_field(type, field) } when Helpers::WithFields # Import a set of fields source.fields.each_value { |field| add_proxy_field(type, field) } when Helpers::WithSchemaFields # Import other schema fields (type == :all ? TYPE_FIELD_CLASS.each_key : type.then).each do |import_type| source.fields_for(import_type)&.each_value do |field| add_proxy_field(import_type, field) end end else return if GraphQL.config.silence_import_warnings GraphQL.logger.warn(+"Unable to import #{source.inspect} into #{self.name}.") end end |
#safe_add_field(*args, of_type: nil, **xargs, &block) ⇒ Object
Only add the field if it is not already defined
98 99 100 101 102 103 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 98 def safe_add_field(*args, of_type: nil, **xargs, &block) method_name = of_type.nil? ? :add_field : "add_#{of_type}_field" public_send(method_name, *args, **xargs, &block) rescue DuplicatedError # Do not do anything if it is duplicated end |
#type_name_for(type) ⇒ Object
Return the object name for a given type of list of fields
92 93 94 95 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 92 def type_name_for(type) method_name = :"#{type}_type_name" public_send(method_name) if respond_to?(method_name) end |
#validate! ⇒ Object
Validate all the fields to make sure the definition is valid
260 261 262 263 264 265 266 267 |
# File 'lib/rails/graphql/helpers/with_schema_fields.rb', line 260 def validate!(*) super if defined? super TYPE_FIELD_CLASS.each_key do |type| next unless public_send("#{type}_fields?") fields_for(type).each_value(&:validate!) end end |