elasticgraph-schema_definition 1.0.2 → 1.0.3.rc1
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/LICENSE.txt +1 -1
- data/lib/elastic_graph/schema_definition/api.rb +34 -2
- data/lib/elastic_graph/schema_definition/factory.rb +31 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/append_only_set.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/field_initializer_support.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/immutable_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_fields/min_or_max_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/derived_indexed_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/event_envelope.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field.rb +8 -2
- data/lib/elastic_graph/schema_definition/indexing/field_reference.rb +6 -4
- data/lib/elastic_graph/schema_definition/indexing/field_type/enum.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/object.rb +10 -4
- data/lib/elastic_graph/schema_definition/indexing/field_type/scalar.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/field_type/union.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/index.rb +39 -4
- data/lib/elastic_graph/schema_definition/indexing/json_schema_field_metadata.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/json_schema_with_metadata.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/list_counts_mapping.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/relationship_resolver.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/rollover_config.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/update_target_factory.rb +1 -1
- data/lib/elastic_graph/schema_definition/indexing/update_target_resolver.rb +1 -1
- data/lib/elastic_graph/schema_definition/json_schema_pruner.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/can_be_graphql_only.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_derived_graphql_type_customizations.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_directives.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_documentation.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_indices.rb +2 -2
- data/lib/elastic_graph/schema_definition/mixins/has_readable_to_s_and_inspect.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_subtypes.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/has_type_info.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/implements_interfaces.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/supports_default_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/supports_filtering_and_aggregation.rb +1 -1
- data/lib/elastic_graph/schema_definition/mixins/verifies_graphql_name.rb +1 -1
- data/lib/elastic_graph/schema_definition/rake_tasks.rb +6 -6
- data/lib/elastic_graph/schema_definition/results.rb +12 -1
- data/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +39 -29
- data/lib/elastic_graph/schema_definition/schema_elements/argument.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/built_in_types.rb +8 -1
- data/lib/elastic_graph/schema_definition/schema_elements/deprecated_element.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/directive.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enum_value_namer.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/enums_for_indexed_types.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/field.rb +6 -3
- data/lib/elastic_graph/schema_definition/schema_elements/field_path.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/field_source.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/graphql_sdl_enumerator.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/input_field.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/input_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/interface_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/list_counts_state.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/object_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/relationship.rb +3 -2
- data/lib/elastic_graph/schema_definition/schema_elements/scalar_type.rb +82 -4
- data/lib/elastic_graph/schema_definition/schema_elements/sort_order_enum_value.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/sub_aggregation_path.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_namer.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_reference.rb +1 -1
- data/lib/elastic_graph/schema_definition/schema_elements/type_with_subfields.rb +5 -3
- data/lib/elastic_graph/schema_definition/schema_elements/union_type.rb +1 -1
- data/lib/elastic_graph/schema_definition/scripting/file_system_repository.rb +1 -1
- data/lib/elastic_graph/schema_definition/scripting/script.rb +1 -1
- data/lib/elastic_graph/schema_definition/state.rb +7 -3
- data/lib/elastic_graph/schema_definition/test_support.rb +2 -3
- metadata +32 -26
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -45,28 +45,6 @@ module ElasticGraph
|
|
|
45
45
|
"they can perform code generation and event validation."
|
|
46
46
|
]
|
|
47
47
|
)
|
|
48
|
-
|
|
49
|
-
# Here we round-trip the SDL string through the GraphQL gem's formatting logic. This provides
|
|
50
|
-
# nice, consistent formatting (alphabetical order, consistent spacing, etc) and also prunes out
|
|
51
|
-
# any "orphaned" schema types (that is, types that are defined but never referenced).
|
|
52
|
-
# We also prepend a line break so there's a blank line between the comment block and the
|
|
53
|
-
# schema elements.
|
|
54
|
-
graphql_schema = ::GraphQL::Schema.from_definition(schema_definition_results.graphql_schema_string).to_definition.chomp
|
|
55
|
-
|
|
56
|
-
unversioned_artifacts = [
|
|
57
|
-
new_yaml_artifact(DATASTORE_CONFIG_FILE, schema_definition_results.datastore_config),
|
|
58
|
-
new_yaml_artifact(RUNTIME_METADATA_FILE, pruned_runtime_metadata(graphql_schema).to_dumpable_hash),
|
|
59
|
-
@json_schemas_artifact,
|
|
60
|
-
new_raw_artifact(GRAPHQL_SCHEMA_FILE, "\n" + graphql_schema)
|
|
61
|
-
]
|
|
62
|
-
|
|
63
|
-
versioned_artifacts = build_desired_versioned_json_schemas(@json_schemas_artifact.desired_contents).values.map do |versioned_schema|
|
|
64
|
-
new_versioned_json_schema_artifact(versioned_schema)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
@artifacts = (unversioned_artifacts + versioned_artifacts).sort_by(&:file_name)
|
|
68
|
-
notify_about_unused_type_name_overrides
|
|
69
|
-
notify_about_unused_enum_value_overrides
|
|
70
48
|
end
|
|
71
49
|
|
|
72
50
|
# Dumps all the schema artifacts to disk.
|
|
@@ -80,7 +58,7 @@ module ElasticGraph
|
|
|
80
58
|
setter_location_path = ::Pathname.new(setter_location.absolute_path.to_s).relative_path_from(::Dir.pwd)
|
|
81
59
|
|
|
82
60
|
abort "A change has been attempted to `json_schemas.yaml`, but the `json_schema_version` has not been correspondingly incremented. Please " \
|
|
83
|
-
"increase the schema's version, and then run the `schema_artifacts:dump` command again.\n\n" \
|
|
61
|
+
"increase the schema's version, and then run the `bundle exec rake schema_artifacts:dump` command again.\n\n" \
|
|
84
62
|
"To update the schema version to the expected version, change line #{setter_location.lineno} at `#{setter_location_path}` to:\n" \
|
|
85
63
|
" `schema.json_schema_version #{recommended_json_schema_version}`\n\n" \
|
|
86
64
|
"Alternately, pass `enforce_json_schema_version: false` to `ElasticGraph::SchemaDefinition::RakeTasks.new` to allow the JSON schemas " \
|
|
@@ -94,15 +72,15 @@ module ElasticGraph
|
|
|
94
72
|
end
|
|
95
73
|
|
|
96
74
|
::FileUtils.mkdir_p(@schema_artifacts_directory)
|
|
97
|
-
|
|
75
|
+
artifacts.each { |artifact| artifact.dump(@output) }
|
|
98
76
|
end
|
|
99
77
|
|
|
100
78
|
# Checks that all schema artifacts are up-to-date, raising an exception if not.
|
|
101
79
|
def check_artifacts
|
|
102
|
-
out_of_date_artifacts =
|
|
80
|
+
out_of_date_artifacts = artifacts.select(&:out_of_date?)
|
|
103
81
|
|
|
104
82
|
if out_of_date_artifacts.empty?
|
|
105
|
-
descriptions =
|
|
83
|
+
descriptions = artifacts.map.with_index(1) { |art, i| "#{i}. #{art.file_name}" }
|
|
106
84
|
@output.puts <<~EOS
|
|
107
85
|
Your schema artifacts are all up to date:
|
|
108
86
|
#{descriptions.join("\n")}
|
|
@@ -115,6 +93,38 @@ module ElasticGraph
|
|
|
115
93
|
|
|
116
94
|
private
|
|
117
95
|
|
|
96
|
+
def artifacts
|
|
97
|
+
@artifacts ||= artifacts_from_schema_def.sort_by(&:file_name).tap do
|
|
98
|
+
# This must be deferred until artifacts are generated, as we can't fully detect
|
|
99
|
+
# unused things until after we've used things to generate artifacts.
|
|
100
|
+
notify_about_unused_type_name_overrides
|
|
101
|
+
notify_about_unused_enum_value_overrides
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Defined to offer a convenient method to override in an extension in order to add a new schema artifact.
|
|
106
|
+
def artifacts_from_schema_def
|
|
107
|
+
# Here we round-trip the SDL string through the GraphQL gem's formatting logic. This provides
|
|
108
|
+
# nice, consistent formatting (alphabetical order, consistent spacing, etc) and also prunes out
|
|
109
|
+
# any "orphaned" schema types (that is, types that are defined but never referenced).
|
|
110
|
+
# We also prepend a line break so there's a blank line between the comment block and the
|
|
111
|
+
# schema elements.
|
|
112
|
+
graphql_schema = ::GraphQL::Schema.from_definition(schema_definition_results.graphql_schema_string).to_definition.chomp
|
|
113
|
+
|
|
114
|
+
unversioned_artifacts = [
|
|
115
|
+
new_yaml_artifact(DATASTORE_CONFIG_FILE, schema_definition_results.datastore_config),
|
|
116
|
+
new_yaml_artifact(RUNTIME_METADATA_FILE, pruned_runtime_metadata(graphql_schema).to_dumpable_hash),
|
|
117
|
+
@json_schemas_artifact,
|
|
118
|
+
new_raw_artifact(GRAPHQL_SCHEMA_FILE, "\n" + graphql_schema)
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
versioned_artifacts = build_desired_versioned_json_schemas(@json_schemas_artifact.desired_contents).values.map do |versioned_schema|
|
|
122
|
+
new_versioned_json_schema_artifact(versioned_schema)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
unversioned_artifacts + versioned_artifacts
|
|
126
|
+
end
|
|
127
|
+
|
|
118
128
|
def notify_about_unused_type_name_overrides
|
|
119
129
|
type_namer = @schema_definition_results.state.type_namer
|
|
120
130
|
return if (unused_overrides = type_namer.unused_name_overrides).empty?
|
|
@@ -338,7 +348,7 @@ module ElasticGraph
|
|
|
338
348
|
end
|
|
339
349
|
|
|
340
350
|
<<~EOS.strip
|
|
341
|
-
#{out_of_date_artifacts.size} schema artifact(s) are out of date. Run `rake schema_artifacts:dump` to update the following artifact(s):
|
|
351
|
+
#{out_of_date_artifacts.size} schema artifact(s) are out of date. Run `bundle exec rake schema_artifacts:dump` to update the following artifact(s):
|
|
342
352
|
|
|
343
353
|
#{descriptions.join("\n")}
|
|
344
354
|
|
|
@@ -471,7 +481,7 @@ module ElasticGraph
|
|
|
471
481
|
|
|
472
482
|
def comment_preamble
|
|
473
483
|
lines = [
|
|
474
|
-
"Generated by `rake schema_artifacts:dump`.",
|
|
484
|
+
"Generated by `bundle exec rake schema_artifacts:dump`.",
|
|
475
485
|
"DO NOT EDIT BY HAND. Any edits will be lost the next time the rake task is run."
|
|
476
486
|
]
|
|
477
487
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -719,6 +719,11 @@ module ElasticGraph
|
|
|
719
719
|
t.prepare_for_indexing_with "ElasticGraph::Indexer::IndexingPreparers::Integer",
|
|
720
720
|
defined_at: "elastic_graph/indexer/indexing_preparers/integer"
|
|
721
721
|
|
|
722
|
+
# The GraphQL gem automatically coerces Int values, so we can safely use MISSING_NUMERIC_PLACEHOLDER
|
|
723
|
+
# as the grouping missing value placeholder even though we don't override the default (no-op) ElasticGraph
|
|
724
|
+
# scalar coercion adapter.
|
|
725
|
+
t.grouping_missing_value_placeholder MISSING_NUMERIC_PLACEHOLDER
|
|
726
|
+
|
|
722
727
|
define_integral_aggregated_values_for(t)
|
|
723
728
|
end
|
|
724
729
|
|
|
@@ -789,6 +794,8 @@ module ElasticGraph
|
|
|
789
794
|
t.json_schema type: "string", format: "date-time"
|
|
790
795
|
t.coerce_with "ElasticGraph::GraphQL::ScalarCoercionAdapters::DateTime",
|
|
791
796
|
defined_at: "elastic_graph/graphql/scalar_coercion_adapters/date_time"
|
|
797
|
+
t.prepare_for_indexing_with "ElasticGraph::Indexer::IndexingPreparers::DateTime",
|
|
798
|
+
defined_at: "elastic_graph/indexer/indexing_preparers/date_time"
|
|
792
799
|
|
|
793
800
|
t.documentation <<~EOS
|
|
794
801
|
A timestamp, represented as an [ISO 8601 time string](https://en.wikipedia.org/wiki/ISO_8601).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -515,7 +515,9 @@ module ElasticGraph
|
|
|
515
515
|
# f.sourced_from "capitalOf", "currency"
|
|
516
516
|
# end
|
|
517
517
|
#
|
|
518
|
-
# t.index "cities"
|
|
518
|
+
# t.index "cities" do |i|
|
|
519
|
+
# i.has_had_multiple_sources!
|
|
520
|
+
# end
|
|
519
521
|
# end
|
|
520
522
|
# end
|
|
521
523
|
def sourced_from(relationship, field_path)
|
|
@@ -968,7 +970,8 @@ module ElasticGraph
|
|
|
968
970
|
json_schema_options: json_schema_options,
|
|
969
971
|
accuracy_confidence: accuracy_confidence,
|
|
970
972
|
source: source,
|
|
971
|
-
runtime_field_script: runtime_field_script
|
|
973
|
+
runtime_field_script: runtime_field_script,
|
|
974
|
+
doc_comment: doc_comment
|
|
972
975
|
)
|
|
973
976
|
end
|
|
974
977
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -112,8 +112,9 @@ module ElasticGraph
|
|
|
112
112
|
# f.sourced_from "launchPlan", "launchDate"
|
|
113
113
|
# end
|
|
114
114
|
#
|
|
115
|
-
# t.index "campaigns"do |i|
|
|
115
|
+
# t.index "campaigns" do |i|
|
|
116
116
|
# i.rollover :yearly, "createdAt"
|
|
117
|
+
# i.has_had_multiple_sources!
|
|
117
118
|
# end
|
|
118
119
|
# end
|
|
119
120
|
#
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -44,6 +44,7 @@ module ElasticGraph
|
|
|
44
44
|
class ScalarType < Struct.new(
|
|
45
45
|
:schema_def_state,
|
|
46
46
|
:type_ref,
|
|
47
|
+
:grouping_missing_value_placeholder_overridden,
|
|
47
48
|
:mapping_type,
|
|
48
49
|
:runtime_metadata,
|
|
49
50
|
:aggregated_values_customizations,
|
|
@@ -66,12 +67,13 @@ module ElasticGraph
|
|
|
66
67
|
|
|
67
68
|
# @private
|
|
68
69
|
def initialize(schema_def_state, name)
|
|
69
|
-
super(schema_def_state, schema_def_state.type_ref(name).to_final_form)
|
|
70
|
+
super(schema_def_state, schema_def_state.type_ref(name).to_final_form, false)
|
|
70
71
|
|
|
71
72
|
# Default the runtime metadata before yielding, so it can be overridden as needed.
|
|
72
73
|
self.runtime_metadata = SchemaArtifacts::RuntimeMetadata::ScalarType.new(
|
|
73
74
|
coercion_adapter_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_COERCION_ADAPTER_REF,
|
|
74
|
-
indexing_preparer_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_INDEXING_PREPARER_REF
|
|
75
|
+
indexing_preparer_ref: SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_INDEXING_PREPARER_REF,
|
|
76
|
+
grouping_missing_value_placeholder: nil
|
|
75
77
|
)
|
|
76
78
|
|
|
77
79
|
yield self
|
|
@@ -84,6 +86,10 @@ module ElasticGraph
|
|
|
84
86
|
if missing.any?
|
|
85
87
|
raise Errors::SchemaError, "Scalar types require `mapping` and `json_schema` to be configured, but `#{name}` lacks #{missing.join(" and ")}."
|
|
86
88
|
end
|
|
89
|
+
|
|
90
|
+
if (placeholder = inferred_grouping_missing_value_placeholder)
|
|
91
|
+
self.runtime_metadata = runtime_metadata.with(grouping_missing_value_placeholder: placeholder)
|
|
92
|
+
end
|
|
87
93
|
end
|
|
88
94
|
|
|
89
95
|
# @return [String] name of the scalar type
|
|
@@ -154,6 +160,31 @@ module ElasticGraph
|
|
|
154
160
|
}).tap(&:load_indexing_preparer) # verify the preparer is valid.
|
|
155
161
|
end
|
|
156
162
|
|
|
163
|
+
# Specifies a placeholder value to use for missing values when grouping by this scalar type.
|
|
164
|
+
# This optimization allows ElasticGraph to use a single terms aggregation instead of separate
|
|
165
|
+
# terms and missing aggregations, reducing the exponential explosion of subaggregations when
|
|
166
|
+
# grouping by multiple fields.
|
|
167
|
+
#
|
|
168
|
+
# @param placeholder [String, Numeric] the placeholder value to use for missing/null values
|
|
169
|
+
# @return [void]
|
|
170
|
+
#
|
|
171
|
+
# @example Define a grouping missing value placeholder
|
|
172
|
+
# ElasticGraph.define_schema do |schema|
|
|
173
|
+
# schema.scalar_type "BigInt" do |t|
|
|
174
|
+
# t.mapping type: "long"
|
|
175
|
+
# t.json_schema type: "integer", minimum: -(2**53) + 1, maximum: (2**53) - 1
|
|
176
|
+
# t.grouping_missing_value_placeholder "NaN"
|
|
177
|
+
# end
|
|
178
|
+
# end
|
|
179
|
+
def grouping_missing_value_placeholder(placeholder)
|
|
180
|
+
unless placeholder.nil? || placeholder.is_a?(String) || placeholder.is_a?(Numeric)
|
|
181
|
+
raise Errors::SchemaError, "grouping_missing_value_placeholder must be a String or Numeric value, but got #{placeholder.class}: #{placeholder.inspect}"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
self.grouping_missing_value_placeholder_overridden = true
|
|
185
|
+
self.runtime_metadata = runtime_metadata.with(grouping_missing_value_placeholder: placeholder)
|
|
186
|
+
end
|
|
187
|
+
|
|
157
188
|
# @return [String] the GraphQL SDL form of this scalar
|
|
158
189
|
def to_sdl
|
|
159
190
|
"#{formatted_documentation}scalar #{name} #{directives_sdl}"
|
|
@@ -310,9 +341,56 @@ module ElasticGraph
|
|
|
310
341
|
schema_def_state.factory.new_aggregated_values_type_for_index_leaf_type(name, &customization_block)
|
|
311
342
|
end
|
|
312
343
|
|
|
344
|
+
def inferred_grouping_missing_value_placeholder
|
|
345
|
+
return nil if grouping_missing_value_placeholder_overridden || mapping_type.nil?
|
|
346
|
+
|
|
347
|
+
if STRING_TYPES.include?(mapping_type)
|
|
348
|
+
MISSING_STRING_PLACEHOLDER
|
|
349
|
+
elsif FLOAT_TYPES.include?(mapping_type)
|
|
350
|
+
MISSING_NUMERIC_PLACEHOLDER
|
|
351
|
+
elsif mapping_type == "long"
|
|
352
|
+
# It is only safe to use NaN for a long when the long's range is safe to coerce to a float
|
|
353
|
+
# without loss of precision. This is because using NaN as the missing value will cause
|
|
354
|
+
# the datastore to coerce the other bucket keys to float.
|
|
355
|
+
# JSON schema min/max only constrains newly indexed values, not existing data that may fall outside the range before the constraints were added.
|
|
356
|
+
# This is an edge case where the long range may exceed safe float precision.
|
|
357
|
+
# In this case, users can set grouping_missing_value_placeholder to nil.
|
|
358
|
+
if (json_schema_options[:minimum] || LONG_STRING_MIN) >= JSON_SAFE_LONG_MIN &&
|
|
359
|
+
(json_schema_options[:maximum] || LONG_STRING_MAX) <= JSON_SAFE_LONG_MAX
|
|
360
|
+
inferred_numeric_placeholder_for_integer_type
|
|
361
|
+
end
|
|
362
|
+
elsif mapping_type == "unsigned_long"
|
|
363
|
+
# Similar to the checks above for long except we only need to check the max
|
|
364
|
+
# (since the min is zero even if not specified)
|
|
365
|
+
if (json_schema_options[:maximum] || LONG_STRING_MAX) <= JSON_SAFE_LONG_MAX
|
|
366
|
+
inferred_numeric_placeholder_for_integer_type
|
|
367
|
+
end
|
|
368
|
+
elsif INTEGER_TYPES.include?(mapping_type)
|
|
369
|
+
# All other integer types can safely be coerced to float without loss of precision
|
|
370
|
+
inferred_numeric_placeholder_for_integer_type
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
def inferred_numeric_placeholder_for_integer_type
|
|
375
|
+
# Using NaN as the missing value placeholder causes the datastore to coerce all bucket keys to float.
|
|
376
|
+
# If using the default coercion adapter (which is a no-op), the values won't be coerced back to integers,
|
|
377
|
+
# causing a type change in the returned values. Only use NaN if a custom coercion adapter is configured.
|
|
378
|
+
if runtime_metadata.coercion_adapter_ref == SchemaArtifacts::RuntimeMetadata::ScalarType::DEFAULT_COERCION_ADAPTER_REF
|
|
379
|
+
nil
|
|
380
|
+
else
|
|
381
|
+
MISSING_NUMERIC_PLACEHOLDER
|
|
382
|
+
end
|
|
383
|
+
end
|
|
384
|
+
|
|
313
385
|
# https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html
|
|
314
386
|
# https://www.elastic.co/guide/en/elasticsearch/reference/7.13/number.html#number
|
|
315
|
-
|
|
387
|
+
FLOAT_TYPES = %w[double float half_float scaled_float].to_set
|
|
388
|
+
INTEGER_TYPES = %w[long integer short byte unsigned_long].to_set
|
|
389
|
+
NUMERIC_TYPES = FLOAT_TYPES | INTEGER_TYPES
|
|
390
|
+
# https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/keyword
|
|
391
|
+
# https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/text-type-family
|
|
392
|
+
# https://docs.opensearch.org/latest/mappings/supported-field-types/index/#string-based-field-types
|
|
393
|
+
STRING_TYPES = %w[keyword constant_keyword wildcard text match_only_text pattern_text semantic_text].to_set
|
|
316
394
|
DATE_TYPES = %w[date date_nanos].to_set
|
|
317
395
|
# The Elasticsearch/OpenSearch docs do not exhaustively give a list of types on which range queries are efficient,
|
|
318
396
|
# but the docs are clear that it is efficient on numeric and date types, and is inefficient on string
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -146,7 +146,7 @@ module ElasticGraph
|
|
|
146
146
|
#
|
|
147
147
|
# @note Be careful about defining non-nullable fields. Changing a field’s type from non-nullable (e.g. `Int!`) to nullable (e.g.
|
|
148
148
|
# `Int`) is a breaking change for clients. Making a field non-nullable may also prevent you from applying permissioning to a field
|
|
149
|
-
# via an AuthZ layer (as such a layer would have no way to force a field value to `null`
|
|
149
|
+
# via an AuthZ layer (as such a layer would have no way to force a field value to `null` for a client denied field access).
|
|
150
150
|
# Therefore, we recommend limiting your use of `!` to only a few situations such as defining a type’s primary key (e.g.
|
|
151
151
|
# `t.field "id", "ID!"`) or defining a list field (e.g. `t.field "authors", "[String!]!"`) since empty lists already provide a
|
|
152
152
|
# "no data" representation. You can still configure the ElasticGraph indexer to require a non-null value for a field using
|
|
@@ -478,10 +478,12 @@ module ElasticGraph
|
|
|
478
478
|
# @private
|
|
479
479
|
def to_indexing_field_type
|
|
480
480
|
Indexing::FieldType::Object.new(
|
|
481
|
+
schema_def_state: schema_def_state,
|
|
481
482
|
type_name: name,
|
|
482
483
|
subfields: indexing_fields_by_name_in_index.values.map(&:to_indexing_field).compact,
|
|
483
484
|
mapping_options: mapping_options,
|
|
484
|
-
json_schema_options: json_schema_options
|
|
485
|
+
json_schema_options: json_schema_options,
|
|
486
|
+
doc_comment: doc_comment
|
|
485
487
|
)
|
|
486
488
|
end
|
|
487
489
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -52,7 +52,9 @@ module ElasticGraph
|
|
|
52
52
|
:type_refs_by_name,
|
|
53
53
|
:output,
|
|
54
54
|
:type_namer,
|
|
55
|
-
:enum_value_namer
|
|
55
|
+
:enum_value_namer,
|
|
56
|
+
:allow_omitted_json_schema_fields,
|
|
57
|
+
:allow_extra_json_schema_fields
|
|
56
58
|
)
|
|
57
59
|
include Mixins::HasReadableToSAndInspect.new
|
|
58
60
|
|
|
@@ -99,7 +101,9 @@ module ElasticGraph
|
|
|
99
101
|
name_overrides: type_name_overrides
|
|
100
102
|
),
|
|
101
103
|
enum_value_namer: SchemaElements::EnumValueNamer.new(enum_value_overrides_by_type),
|
|
102
|
-
output: output
|
|
104
|
+
output: output,
|
|
105
|
+
allow_omitted_json_schema_fields: false,
|
|
106
|
+
allow_extra_json_schema_fields: true
|
|
103
107
|
)
|
|
104
108
|
end
|
|
105
109
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright 2024 -
|
|
1
|
+
# Copyright 2024 - 2026 Block, Inc.
|
|
2
2
|
#
|
|
3
3
|
# Use of this source code is governed by an MIT-style
|
|
4
4
|
# license that can be found in the LICENSE file or at
|
|
@@ -85,7 +85,7 @@ module ElasticGraph
|
|
|
85
85
|
# Reloading the schema artifacts takes extra time that we don't usually want to spend (so it's opt-in)
|
|
86
86
|
# but it can be useful in some cases because there is a bit of extra pruning/validation that it applies.
|
|
87
87
|
tmp_dir = ::Dir.mktmpdir
|
|
88
|
-
artifacts_manager =
|
|
88
|
+
artifacts_manager = api.factory.new_schema_artifact_manager(
|
|
89
89
|
schema_definition_results: api.results,
|
|
90
90
|
schema_artifacts_directory: tmp_dir,
|
|
91
91
|
enforce_json_schema_version: false,
|
|
@@ -108,7 +108,6 @@ module ElasticGraph
|
|
|
108
108
|
type_def_keyword = '^(type|input|enum|union|interface|scalar|directive)\b'
|
|
109
109
|
# capture from the start of the type definition for `type` until the next type definition (or `\z` for end of string)
|
|
110
110
|
type_extraction_regex = /(#{DOC_COMMENTS}?#{type_def_keyword} #{type}\b.*?)(?:(?:#{DOC_COMMENTS}?#{type_def_keyword})|\z)/m
|
|
111
|
-
# type_defs = sdl.scan(type_extraction_regex).map(&:first)
|
|
112
111
|
type_defs = sdl.scan(type_extraction_regex).map { |match| [match].flatten.first }
|
|
113
112
|
|
|
114
113
|
if type_defs.size >= 2
|