Class: ElasticGraph::SchemaDefinition::SchemaElements::ScalarType

Inherits:
Struct
  • Object
show all
Includes:
Mixins::CanBeGraphQLOnly, Mixins::HasDerivedGraphQLTypeCustomizations, Mixins::HasDirectives, Mixins::HasDocumentation, Mixins::HasTypeInfo, Mixins::VerifiesGraphQLName
Defined in:
elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb

Overview

Defines a GraphQL scalar type. ElasticGraph itself uses this to define a few common scalar types (e.g. Date and DateTime), but it is also available to you to use to define your own custom scalar types.

Examples:

Define a scalar type

ElasticGraph.define_schema do |schema|
  schema.scalar_type "URL" do |t|
    t.mapping type: "keyword"
    t.json_schema type: "string", format: "uri"
  end
end

Constant Summary

Constants included from Mixins::HasTypeInfo

Mixins::HasTypeInfo::CUSTOMIZABLE_DATASTORE_PARAMS

Instance Attribute Summary collapse

Attributes included from Mixins::HasDocumentation

#doc_comment

Instance Method Summary collapse

Methods included from Mixins::HasTypeInfo

#json_schema, #json_schema_options, #mapping_options

Methods included from Mixins::HasDerivedGraphQLTypeCustomizations

#customize_derived_type_fields, #customize_derived_types

Methods included from Mixins::HasDirectives

#directive, #directives, #directives_sdl

Methods included from Mixins::HasDocumentation

#append_to_documentation, #derived_documentation, #documentation, #formatted_documentation

Methods included from Mixins::CanBeGraphQLOnly

#graphql_only, #graphql_only?

Methods included from Mixins::VerifiesGraphQLName

verify_name!

Instance Attribute Details

#grouping_missing_value_placeholder_overriddenObject

Returns the value of attribute grouping_missing_value_placeholder_overridden

Returns:

  • (Object)

    the current value of grouping_missing_value_placeholder_overridden



44
45
46
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 44

def grouping_missing_value_placeholder_overridden
  @grouping_missing_value_placeholder_overridden
end

#schema_def_stateState (readonly)

Returns schema definition state.

Returns:

  • (State)

    schema definition state



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 44

class ScalarType < Struct.new(
  :schema_def_state,
  :type_ref,
  :grouping_missing_value_placeholder_overridden,
  :mapping_type,
  :runtime_metadata,
  :aggregated_values_customizations,
  :filter_input_customizations
)
  # `Struct.new` provides the following methods:
  # @dynamic type_ref, runtime_metadata
  prepend Mixins::VerifiesGraphQLName
  include Mixins::CanBeGraphQLOnly
  include Mixins::HasDocumentation
  include Mixins::HasDirectives
  include Mixins::HasDerivedGraphQLTypeCustomizations
  include Mixins::HasReadableToSAndInspect.new { |t| t.name }

  # `HasTypeInfo` provides the following methods:
  # @dynamic mapping_options, json_schema_options
  include Mixins::HasTypeInfo

  # @dynamic graphql_only?

  # @private
  def initialize(schema_def_state, name)
    super(schema_def_state, schema_def_state.type_ref(name).to_final_form, false)

    # Default the runtime metadata before yielding, so it can be overridden as needed.
    self. = SchemaArtifacts::RuntimeMetadata::ScalarType.new(
      coercion_adapter_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_COERCION_ADAPTER_REF,
      indexing_preparer_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_INDEXING_PREPARER_REF,
      grouping_missing_value_placeholder: nil
    )

    yield self

    missing = [
      ("`mapping`" if mapping_options.empty?),
      ("`json_schema`" if json_schema_options.empty?)
    ].compact

    if missing.any?
      raise Errors::SchemaError, "Scalar types require `mapping` and `json_schema` to be configured, but `#{name}` lacks #{missing.join(" and ")}."
    end

    if (placeholder = inferred_grouping_missing_value_placeholder)
      self. = .with(grouping_missing_value_placeholder: placeholder)
    end
  end

  # @return [String] name of the scalar type
  def name
    type_ref.name
  end

  # (see Mixins::HasTypeInfo#mapping)
  def mapping(**options)
    self.mapping_type = options.fetch(:type) do
      raise Errors::SchemaError, "Must specify a mapping `type:` on custom scalars but was missing on the `#{name}` type."
    end

    super
  end

  # Specifies the scalar coercion adapter that should be used for this scalar type. The scalar coercion adapter is responsible
  # for validating and coercing scalar input values, and converting scalar return values to a form suitable for JSON serialization.
  #
  # @note For examples of scalar coercion adapters, see `ElasticGraph::GraphQL::ScalarCoercionAdapters`.
  # @note If the `defined_at` require path requires any directories be put on the Ruby `$LOAD_PATH`, you are responsible for doing
  #   that before booting {ElasticGraph::GraphQL}.
  #
  # @param adapter_name [String] fully qualified Ruby class name of the adapter
  # @param defined_at [String] the `require` path of the adapter
  # @return [void]
  #
  # @example Register a coercion adapter
  #   ElasticGraph.define_schema do |schema|
  #     schema.scalar_type "PhoneNumber" do |t|
  #       t.mapping type: "keyword"
  #       t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
  #       t.coerce_with "CoercionAdapters::PhoneNumber", defined_at: "./coercion_adapters/phone_number"
  #     end
  #   end
  def coerce_with(adapter_name, defined_at:)
    self. = .with(coercion_adapter_ref: {
      "name" => adapter_name,
      "require_path" => defined_at
    }).tap(&:load_coercion_adapter) # verify the adapter is valid.
  end

  # Specifies an indexing preparer that should be used for this scalar type. The indexing preparer is responsible for preparing
  # scalar values before indexing them, performing any desired formatting or normalization.
  #
  # @note For examples of scalar coercion adapters, see `ElasticGraph::Indexer::IndexingPreparers`.
  # @note If the `defined_at` require path requires any directories be put on the Ruby `$LOAD_PATH`, you are responsible for doing
  #   that before booting {ElasticGraph::GraphQL}.
  #
  # @param preparer_name [String] fully qualified Ruby class name of the indexing preparer
  # @param defined_at [String] the `require` path of the preparer
  # @return [void]
  #
  # @example Register an indexing preparer
  #   ElasticGraph.define_schema do |schema|
  #     schema.scalar_type "PhoneNumber" do |t|
  #       t.mapping type: "keyword"
  #       t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
  #
  #       t.prepare_for_indexing_with "IndexingPreparers::PhoneNumber",
  #         defined_at: "./indexing_preparers/phone_number"
  #     end
  #   end
  def prepare_for_indexing_with(preparer_name, defined_at:)
    self. = .with(indexing_preparer_ref: {
      "name" => preparer_name,
      "require_path" => defined_at
    }).tap(&:load_indexing_preparer) # verify the preparer is valid.
  end

  # Specifies a placeholder value to use for missing values when grouping by this scalar type.
  # This optimization allows ElasticGraph to use a single terms aggregation instead of separate
  # terms and missing aggregations, reducing the exponential explosion of subaggregations when
  # grouping by multiple fields.
  #
  # @param placeholder [String, Numeric] the placeholder value to use for missing/null values
  # @return [void]
  #
  # @example Define a grouping missing value placeholder
  #   ElasticGraph.define_schema do |schema|
  #     schema.scalar_type "BigInt" do |t|
  #       t.mapping type: "long"
  #       t.json_schema type: "integer", minimum: -(2**53) + 1, maximum: (2**53) - 1
  #       t.grouping_missing_value_placeholder "NaN"
  #     end
  #   end
  def grouping_missing_value_placeholder(placeholder)
    unless placeholder.nil? || placeholder.is_a?(String) || placeholder.is_a?(Numeric)
      raise Errors::SchemaError, "grouping_missing_value_placeholder must be a String or Numeric value, but got #{placeholder.class}: #{placeholder.inspect}"
    end

    self.grouping_missing_value_placeholder_overridden = true
    self. = .with(grouping_missing_value_placeholder: placeholder)
  end

  # @return [String] the GraphQL SDL form of this scalar
  def to_sdl
    "#{formatted_documentation}scalar #{name} #{directives_sdl}"
  end

  # Registers a block which will be used to customize the derived `*AggregatedValues` object type.
  #
  # @private
  def customize_aggregated_values_type(&block)
    self.aggregated_values_customizations = block
  end

  # Registers a block which will be used to customize the derived `*FilterInput` object type.
  #
  # @private
  def customize_filter_input_type(&block)
    self.filter_input_customizations = block
  end

  # @private
  def aggregated_values_type
    if aggregated_values_customizations
      type_ref.as_aggregated_values
    else
      schema_def_state.type_ref("NonNumeric").as_aggregated_values
    end
  end

  # @private
  def to_indexing_field_type
    Indexing::FieldType::Scalar.new(scalar_type: self)
  end

  # @private
  def derived_graphql_types
    return [] if graphql_only?

    pagination_types =
      if schema_def_state.paginated_collection_element_types.include?(name)
        schema_def_state.factory.build_relay_pagination_types(name, include_total_edge_count: true)
      else
        [] # : ::Array[ObjectType]
      end

    (to_input_filters + pagination_types).tap do |derived_types|
      if (aggregated_values_type = to_aggregated_values_type)
        derived_types << aggregated_values_type
      end
    end
  end

  # @private
  def indexed?
    false
  end

  private

  EQUAL_TO_ANY_OF_DOC = <<~EOS
    Matches records where the field value is equal to any of the provided values.
    This works just like an IN operator in SQL.

    When `null` is passed, matches all documents. When an empty list is passed,
    this part of the filter matches no documents. When `null` is passed in the
    list, this part of the filter matches records where the field value is `null`.
  EOS

  GT_DOC = <<~EOS
    Matches records where the field value is greater than (>) the provided value.

    When `null` is passed, matches all documents.
  EOS

  GTE_DOC = <<~EOS
    Matches records where the field value is greater than or equal to (>=) the provided value.

    When `null` is passed, matches all documents.
  EOS

  LT_DOC = <<~EOS
    Matches records where the field value is less than (<) the provided value.

    When `null` is passed, matches all documents.
  EOS

  LTE_DOC = <<~EOS
    Matches records where the field value is less than or equal to (<=) the provided value.

    When `null` is passed, matches all documents.
  EOS

  def to_input_filters
    # Note: all fields on inputs should be nullable, to support parameterized queries where
    # the parameters are allowed to be set to `null`. We also now support nulls within lists.

    # For floats, we may want to remove the `equal_to_any_of` operator at some point.
    # In many languages. checking exact equality with floats is problematic.
    # For example, in IRB:
    #
    # 2.7.1 :003 > 0.3 == (0.1 + 0.2)
    # => false
    #
    # However, it's not yet clear if that issue will come up with GraphQL, because
    # float values are serialized on the wire as JSON, using an exact decimal
    # string representation. So for now we are keeping `equal_to_any_of`.
    schema_def_state.factory.build_standard_filter_input_types_for_index_leaf_type(name) do |t|
      # Normally, we use a nullable type for `equal_to_any_of`, to allow a filter expression like this:
      #
      # filter: {optional_field: {equal_to_any_of: [null]}}
      #
      # That filter expression matches documents where `optional_field == null`. However,
      # we cannot support this:
      #
      # filter: {tags: {any_satisfy: {equal_to_any_of: [null]}}}
      #
      # We can't support that because we implement filtering on `null` using an `exists` query:
      # https://www.elastic.co/guide/en/elasticsearch/reference/8.10/query-dsl-exists-query.html
      #
      # ...but that works based on the field existing (or not), and does not let us filter on the
      # presence or absence of `null` within a list.
      #
      # So, here we make the field non-null if we're in an `any_satisfy` context (as indicated by
      # the type ending with `ListElementFilterInput`).
      equal_to_any_of_type = t.type_ref.list_element_filter_input? ? "[#{name}!]" : "[#{name}]"

      t.field schema_def_state.schema_elements.equal_to_any_of, equal_to_any_of_type do |f|
        f.documentation EQUAL_TO_ANY_OF_DOC
      end

      if mapping_type_efficiently_comparable?
        t.field schema_def_state.schema_elements.gt, name do |f|
          f.documentation GT_DOC
        end

        t.field schema_def_state.schema_elements.gte, name do |f|
          f.documentation GTE_DOC
        end

        t.field schema_def_state.schema_elements.lt, name do |f|
          f.documentation LT_DOC
        end

        t.field schema_def_state.schema_elements.lte, name do |f|
          f.documentation LTE_DOC
        end
      end

      filter_input_customizations&.call(t)
    end
  end

  def to_aggregated_values_type
    return nil unless (customization_block = aggregated_values_customizations)
    schema_def_state.factory.new_aggregated_values_type_for_index_leaf_type(name, &customization_block)
  end

  def inferred_grouping_missing_value_placeholder
    return nil if grouping_missing_value_placeholder_overridden || mapping_type.nil?

    if STRING_TYPES.include?(mapping_type)
      MISSING_STRING_PLACEHOLDER
    elsif FLOAT_TYPES.include?(mapping_type)
      MISSING_NUMERIC_PLACEHOLDER
    elsif mapping_type == "long"
      # It is only safe to use NaN for a long when the long's range is safe to coerce to a float
      # without loss of precision. This is because using NaN as the missing value will cause
      # the datastore to coerce the other bucket keys to float.
      # JSON schema min/max only constrains newly indexed values, not existing data that may fall outside the range before the constraints were added.
      # This is an edge case where the long range may exceed safe float precision.
      # In this case, users can set grouping_missing_value_placeholder to nil.
      if (json_schema_options[:minimum] || LONG_STRING_MIN) >= JSON_SAFE_LONG_MIN &&
          (json_schema_options[:maximum] || LONG_STRING_MAX) <= JSON_SAFE_LONG_MAX
        inferred_numeric_placeholder_for_integer_type
      end
    elsif mapping_type == "unsigned_long"
      # Similar to the checks above for long except we only need to check the max
      # (since the min is zero even if not specified)
      if (json_schema_options[:maximum] || LONG_STRING_MAX) <= JSON_SAFE_LONG_MAX
        inferred_numeric_placeholder_for_integer_type
      end
    elsif INTEGER_TYPES.include?(mapping_type)
      # All other integer types can safely be coerced to float without loss of precision
      inferred_numeric_placeholder_for_integer_type
    end
  end

  def inferred_numeric_placeholder_for_integer_type
    # Using NaN as the missing value placeholder causes the datastore to coerce all bucket keys to float.
    # If using the default coercion adapter (which is a no-op), the values won't be coerced back to integers,
    # causing a type change in the returned values. Only use NaN if a custom coercion adapter is configured.
    if .coercion_adapter_ref == SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_COERCION_ADAPTER_REF
      nil
    else
      MISSING_NUMERIC_PLACEHOLDER
    end
  end

  # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
  # https://www.elastic.co/guide/en/elasticsearch/reference/7.13/number.html#number
  FLOAT_TYPES = %w[double float half_float scaled_float].to_set
  INTEGER_TYPES = %w[long integer short byte unsigned_long].to_set
  NUMERIC_TYPES = FLOAT_TYPES | INTEGER_TYPES
  # https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/keyword
  # https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/text-type-family
  # https://docs.opensearch.org/latest/mappings/supported-field-types/index/#string-based-field-types
  STRING_TYPES = %w[keyword constant_keyword wildcard text match_only_text pattern_text semantic_text].to_set
  DATE_TYPES = %w[date date_nanos].to_set
  # The Elasticsearch/OpenSearch docs do not exhaustively give a list of types on which range queries are efficient,
  # but the docs are clear that it is efficient on numeric and date types, and is inefficient on string
  # types: https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html
  COMPARABLE_TYPES = NUMERIC_TYPES | DATE_TYPES

  def mapping_type_efficiently_comparable?
    COMPARABLE_TYPES.include?(mapping_type)
  end
end

Instance Method Details

#coerce_with(adapter_name, defined_at:) ⇒ void

Note:

For examples of scalar coercion adapters, see ElasticGraph::GraphQL::ScalarCoercionAdapters.

Note:

If the defined_at require path requires any directories be put on the Ruby $LOAD_PATH, you are responsible for doing that before booting GraphQL.

This method returns an undefined value.

Specifies the scalar coercion adapter that should be used for this scalar type. The scalar coercion adapter is responsible for validating and coercing scalar input values, and converting scalar return values to a form suitable for JSON serialization.

Examples:

Register a coercion adapter

ElasticGraph.define_schema do |schema|
  schema.scalar_type "PhoneNumber" do |t|
    t.mapping type: "keyword"
    t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"
    t.coerce_with "CoercionAdapters::PhoneNumber", defined_at: "./coercion_adapters/phone_number"
  end
end

Parameters:

  • adapter_name (String)

    fully qualified Ruby class name of the adapter

  • defined_at (String)

    the require path of the adapter



128
129
130
131
132
133
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 128

def coerce_with(adapter_name, defined_at:)
  self. = .with(coercion_adapter_ref: {
    "name" => adapter_name,
    "require_path" => defined_at
  }).tap(&:load_coercion_adapter) # verify the adapter is valid.
end

#grouping_missing_value_placeholder(placeholder) ⇒ void

This method returns an undefined value.

Specifies a placeholder value to use for missing values when grouping by this scalar type. This optimization allows ElasticGraph to use a single terms aggregation instead of separate terms and missing aggregations, reducing the exponential explosion of subaggregations when grouping by multiple fields.

Examples:

Define a grouping missing value placeholder

ElasticGraph.define_schema do |schema|
  schema.scalar_type "BigInt" do |t|
    t.mapping type: "long"
    t.json_schema type: "integer", minimum: -(2**53) + 1, maximum: (2**53) - 1
    t.grouping_missing_value_placeholder "NaN"
  end
end

Parameters:

  • placeholder (String, Numeric)

    the placeholder value to use for missing/null values



179
180
181
182
183
184
185
186
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 179

def grouping_missing_value_placeholder(placeholder)
  unless placeholder.nil? || placeholder.is_a?(String) || placeholder.is_a?(Numeric)
    raise Errors::SchemaError, "grouping_missing_value_placeholder must be a String or Numeric value, but got #{placeholder.class}: #{placeholder.inspect}"
  end

  self.grouping_missing_value_placeholder_overridden = true
  self. = .with(grouping_missing_value_placeholder: placeholder)
end

#mapping(**options) ⇒ void

This method returns an undefined value.

Defines the Elasticsearch/OpenSearch field mapping type and mapping parameters for a field or type. The options passed here will be included in the generated datastore_config.yaml artifact that ElasticGraph uses to configure Elasticsearch/OpenSearch.

Can be called multiple times; each time, the options will be merged into the existing options.

This is required on a ElasticGraph::SchemaDefinition::SchemaElements::ScalarType; without it, ElasticGraph would have no way to know how the datatype should be indexed in the datastore.

On a Field, this can be used to customize how a field is indexed. For example, String fields are normally indexed as keywords; to instead index a String field for full text search, you’d need to configure mapping type: "text".

On a ObjectType, this can be used to use a specific Elasticsearch/OpenSearch data type for something that is modeled as an object in GraphQL. For example, we use it for the GeoLocation type so they get indexed in Elasticsearch using the geo_point type.

Examples:

Define the mapping of a custom scalar type

ElasticGraph.define_schema do |schema|
  schema.scalar_type "URL" do |t|
    t.mapping type: "keyword"
    t.json_schema type: "string", format: "uri"
  end
end

Customize the mapping of a field

ElasticGraph.define_schema do |schema|
  schema.object_type "Card" do |t|
    t.field "id", "ID!"

    t.field "cardholderName", "String" do |f|
      # index this field for full text search
      f.mapping type: "text"
    end

    t.field "expYear", "Int" do |f|
      # Use a smaller numeric type to save space in the datastore
      f.mapping type: "short"
      f.json_schema minimum: 2000, maximum: 2099
    end

    t.field "expMonth", "Int" do |f|
      # Use a smaller numeric type to save space in the datastore
      f.mapping type: "byte"
      f.json_schema minimum: 1, maximum: 12
    end

    t.index "cards"
  end
end

Parameters:



101
102
103
104
105
106
107
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 101

def mapping(**options)
  self.mapping_type = options.fetch(:type) do
    raise Errors::SchemaError, "Must specify a mapping `type:` on custom scalars but was missing on the `#{name}` type."
  end

  super
end

#nameString

Returns name of the scalar type.

Returns:

  • (String)

    name of the scalar type



96
97
98
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 96

def name
  type_ref.name
end

#prepare_for_indexing_with(preparer_name, defined_at:) ⇒ void

Note:

For examples of scalar coercion adapters, see ElasticGraph::Indexer::IndexingPreparers.

Note:

If the defined_at require path requires any directories be put on the Ruby $LOAD_PATH, you are responsible for doing that before booting GraphQL.

This method returns an undefined value.

Specifies an indexing preparer that should be used for this scalar type. The indexing preparer is responsible for preparing scalar values before indexing them, performing any desired formatting or normalization.

Examples:

Register an indexing preparer

ElasticGraph.define_schema do |schema|
  schema.scalar_type "PhoneNumber" do |t|
    t.mapping type: "keyword"
    t.json_schema type: "string", pattern: "^\\+[1-9][0-9]{1,14}$"

    t.prepare_for_indexing_with "IndexingPreparers::PhoneNumber",
      defined_at: "./indexing_preparers/phone_number"
  end
end

Parameters:

  • preparer_name (String)

    fully qualified Ruby class name of the indexing preparer

  • defined_at (String)

    the require path of the preparer



156
157
158
159
160
161
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 156

def prepare_for_indexing_with(preparer_name, defined_at:)
  self. = .with(indexing_preparer_ref: {
    "name" => preparer_name,
    "require_path" => defined_at
  }).tap(&:load_indexing_preparer) # verify the preparer is valid.
end

#to_sdlString

Returns the GraphQL SDL form of this scalar.

Returns:

  • (String)

    the GraphQL SDL form of this scalar



189
190
191
# File 'elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb', line 189

def to_sdl
  "#{formatted_documentation}scalar #{name} #{directives_sdl}"
end