diff --git a/Rakefile b/Rakefile index 31c2d71ad..831dc68b3 100644 --- a/Rakefile +++ b/Rakefile @@ -46,7 +46,6 @@ end configure_local_rake_tasks = ->(tasks) do tasks.schema_element_name_form = :snake_case - tasks.enforce_json_schema_version = false tasks.index_document_sizes = true tasks.env_port_mapping = {test: test_port} tasks.output = schema_def_output diff --git a/config/schema.rb b/config/schema.rb index 4d2206af7..743c82add 100644 --- a/config/schema.rb +++ b/config/schema.rb @@ -8,6 +8,7 @@ ElasticGraph.define_schema do |schema| schema.json_schema_version 1 + schema.enforce_json_schema_version false end # Note: anytime you add a file to load here, you'll also have to update the list here: diff --git a/config/site/Rakefile b/config/site/Rakefile index 22fef6f0f..39e5e32a7 100644 --- a/config/site/Rakefile +++ b/config/site/Rakefile @@ -448,7 +448,6 @@ module ElasticGraph namespace schema_name do ::ElasticGraph::Local::RakeTasks.new(local_config_yaml: settings_file, path_to_schema: schema_file) do |tasks| tasks.opensearch_versions = [] - tasks.enforce_json_schema_version = false end task validate: ["schema_artifacts:dump"] do diff --git a/config/site/support/doctest_helper.rb b/config/site/support/doctest_helper.rb index 6f6d256d3..f322eb599 100644 --- a/config/site/support/doctest_helper.rb +++ b/config/site/support/doctest_helper.rb @@ -82,7 +82,6 @@ module ElasticGraph artifacts_manager = @api.factory.new_schema_artifact_manager( schema_definition_results: @api.results, schema_artifacts_directory: "#{@tmp_dir}/schema_artifacts", - enforce_json_schema_version: true, output: ::StringIO.new ) diff --git a/elasticgraph-admin/spec/integration/elastic_graph/admin/index_definition_configurator/for_index_template_spec.rb b/elasticgraph-admin/spec/integration/elastic_graph/admin/index_definition_configurator/for_index_template_spec.rb index 88fab0b68..2af2dd7cb 100644 --- a/elasticgraph-admin/spec/integration/elastic_graph/admin/index_definition_configurator/for_index_template_spec.rb +++ b/elasticgraph-admin/spec/integration/elastic_graph/admin/index_definition_configurator/for_index_template_spec.rb @@ -167,7 +167,6 @@ def fetch_artifact_configuration(schema_artifacts, index_def_name) factory.new_schema_artifact_manager( schema_definition_results: schema_def_results, schema_artifacts_directory: Dir.pwd, - enforce_json_schema_version: true, output: output_io ).dump_artifacts diff --git a/elasticgraph-apollo/README.md b/elasticgraph-apollo/README.md index 78b7a0835..e1535288a 100644 --- a/elasticgraph-apollo/README.md +++ b/elasticgraph-apollo/README.md @@ -69,9 +69,6 @@ index 2943335..26633c3 100644 path_to_schema: "#{project_root}/config/schema.rb" ) do |tasks| + tasks.schema_definition_extension_modules = [ElasticGraph::Apollo::SchemaDefinition::APIExtension] -+ - # Set this to true once you're beyond the prototyping stage. - tasks.enforce_json_schema_version = false ``` diff --git a/elasticgraph-apollo/apollo_tests_implementation/Rakefile b/elasticgraph-apollo/apollo_tests_implementation/Rakefile index 6c688c0db..befade088 100644 --- a/elasticgraph-apollo/apollo_tests_implementation/Rakefile +++ b/elasticgraph-apollo/apollo_tests_implementation/Rakefile @@ -17,6 +17,5 @@ ElasticGraph::SchemaDefinition::RakeTasks.new( index_document_sizes: false, path_to_schema: project_root / "config/products_schema.rb", schema_artifacts_directory: project_root / "config/schema/artifacts", - extension_modules: [ElasticGraph::Apollo::SchemaDefinition::APIExtension], - enforce_json_schema_version: false + extension_modules: [ElasticGraph::Apollo::SchemaDefinition::APIExtension] ) diff --git a/elasticgraph-apollo/apollo_tests_implementation/config/products_schema.rb b/elasticgraph-apollo/apollo_tests_implementation/config/products_schema.rb index 201e4057b..2530d7dc6 100644 --- a/elasticgraph-apollo/apollo_tests_implementation/config/products_schema.rb +++ b/elasticgraph-apollo/apollo_tests_implementation/config/products_schema.rb @@ -18,6 +18,7 @@ module ApolloTestImpl # https://github.com/apollographql/apollo-federation-subgraph-compatibility/blob/2.0.0/COMPATIBILITY.md#products-schema-to-be-implemented-by-library-maintainers ElasticGraph.define_schema do |schema| schema.json_schema_version 1 + schema.enforce_json_schema_version false schema.target_apollo_federation_version(federation_version) if federation_version unless federation_version == "2.0" diff --git a/elasticgraph-graphql/spec/acceptance/schema_evolution_spec.rb b/elasticgraph-graphql/spec/acceptance/schema_evolution_spec.rb index c055f4f5e..494152ebf 100644 --- a/elasticgraph-graphql/spec/acceptance/schema_evolution_spec.rb +++ b/elasticgraph-graphql/spec/acceptance/schema_evolution_spec.rb @@ -68,7 +68,6 @@ def dump_schema_artifacts(json_schema_version:, team_extras: "") index_document_sizes: true, path_to_schema: path_to_schema, schema_artifacts_directory: "config/schema/artifacts", - enforce_json_schema_version: true, output: output ) end diff --git a/elasticgraph-indexer/spec/acceptance/schema_evolution_spec.rb b/elasticgraph-indexer/spec/acceptance/schema_evolution_spec.rb index 286b58f5d..a7f241102 100644 --- a/elasticgraph-indexer/spec/acceptance/schema_evolution_spec.rb +++ b/elasticgraph-indexer/spec/acceptance/schema_evolution_spec.rb @@ -404,7 +404,6 @@ def dump_artifacts index_document_sizes: true, path_to_schema: path_to_schema, schema_artifacts_directory: "config/schema/artifacts", - enforce_json_schema_version: true, output: output ) end diff --git a/elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb b/elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb index 044465c40..a8b55e1b5 100644 --- a/elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb +++ b/elasticgraph-local/lib/elastic_graph/local/rake_tasks.rb @@ -213,33 +213,6 @@ class RakeTasks < ::Rake::TaskLib # @dynamic schema_definition_extension_modules, schema_definition_extension_modules= attr_accessor :schema_definition_extension_modules - # Whether or not to enforce the requirement that the JSON schema version is incremented every time - # dumping the JSON schemas results in a changed artifact. Defaults to `true`. - # - # @note Generally speaking, you will want this to be `true` for any ElasticGraph application that is in - # production as the versioning of JSON schemas is what supports safe schema evolution as it allows - # ElasticGraph to identify which version of the JSON schema the publishing system was operating on - # when it published an event. - # - # It can be useful to set it to `false` before your application is in production, as you do not want - # to be forced to bump the version after every single schema change while you are building an initial - # prototype. - # - # @return [Boolean] whether to require `json_schema_version` to be incremented on changes that impact `json_schemas.yaml` - # @see SchemaDefinition::API#json_schema_version - # - # @example Disable enforcement during initial prototyping - # ElasticGraph::Local::RakeTasks.new( - # local_config_yaml: "config/settings/local.yaml", - # path_to_schema: "config/schema.rb" - # ) do |tasks| - # # TODO: remove this once we're past the prototyping stage - # tasks.enforce_json_schema_version = false - # end - # - # @dynamic enforce_json_schema_version, enforce_json_schema_version= - attr_accessor :enforce_json_schema_version - # List of Elasticsearch versions you want to be able to boot. Rake tasks will be defined for each version to support booting and # halting Elasticsearch locally. If the configuration of `local_config_yaml` only configures `opensearch` as a cluster backend, # will default to an empty array. Otherwise, defaults to the versions of Elasticsearch that are exercised by the ElasticGraph test suite, as @@ -362,7 +335,6 @@ def initialize(local_config_yaml:, path_to_schema:) self.type_name_overrides = {} self.enum_value_overrides_by_type = {} self.schema_definition_extension_modules = [] - self.enforce_json_schema_version = true self.env_port_mapping = {} self.output = $stdout self.daemon_timeout = 300 @@ -394,7 +366,6 @@ def initialize(local_config_yaml:, path_to_schema:) type_name_overrides: type_name_overrides, enum_value_overrides_by_type: enum_value_overrides_by_type, extension_modules: schema_definition_extension_modules, - enforce_json_schema_version: enforce_json_schema_version, output: output ) diff --git a/elasticgraph-local/sig/elastic_graph/local/rake_tasks.rbs b/elasticgraph-local/sig/elastic_graph/local/rake_tasks.rbs index c984430a5..0d780ffc5 100644 --- a/elasticgraph-local/sig/elastic_graph/local/rake_tasks.rbs +++ b/elasticgraph-local/sig/elastic_graph/local/rake_tasks.rbs @@ -8,7 +8,6 @@ module ElasticGraph attr_accessor type_name_overrides: ::Hash[::Symbol, ::String] attr_accessor enum_value_overrides_by_type: ::Hash[::Symbol, ::Hash[::Symbol, ::String]] attr_accessor schema_definition_extension_modules: ::Array[::Module] - attr_accessor enforce_json_schema_version: bool attr_accessor elasticsearch_versions: ::Array[::String] attr_accessor opensearch_versions: ::Array[::String] attr_accessor env_port_mapping: ::Hash[::String, ::Integer] diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb index c254c47a1..814a13cb0 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/api.rb @@ -77,7 +77,7 @@ def initialize( @factory = @state.factory - extension_modules.each { |mod| extend(mod) } + extension_modules.uniq.each { |mod| extend(mod) } # These lines must come _after_ the extension modules are applied, so that the extension modules # have a chance to hook into the factory in order to customize built in types if desired. @@ -460,11 +460,11 @@ def results # # @note While this is an important part of how ElasticGraph is designed to support schema evolution, it can be annoying constantly # have to increment this while rapidly changing the schema during prototyping. You can disable the requirement to increment this - # on every JSON schema change by setting `enforce_json_schema_version` to `false` in your `Rakefile`. + # on every JSON schema change with {#enforce_json_schema_version}. # # @param version [Integer] current version number of the JSON schema artifact # @return [void] - # @see Local::RakeTasks#enforce_json_schema_version + # @see #enforce_json_schema_version # # @example Set the JSON schema version to 1 # ElasticGraph.define_schema do |schema| @@ -484,6 +484,25 @@ def json_schema_version(version) nil end + # Configures whether {SchemaArtifactManager} enforces that {#json_schema_version} gets bumped every time the JSON schemas artifact + # changes. This should generally remain enabled for production applications, but disabling it can be useful during early prototyping. + # + # @param value [Boolean] whether JSON schema version bumps should be enforced + # @return [void] + # + # @example Disable JSON schema version enforcement while prototyping + # ElasticGraph.define_schema do |schema| + # schema.enforce_json_schema_version false + # end + def enforce_json_schema_version(value) + unless value == true || value == false + raise Errors::SchemaError, "`enforce_json_schema_version` must be a boolean. Specified value: #{value.inspect}" + end + + @state.enforce_json_schema_version = value + nil + end + # Defines strictness of the JSON schema validation. By default, the JSON schema will require all fields to be provided by the # publisher (but they can be nullable) and will ignore extra fields that are not defined in the schema. Use this method to # configure this behavior. diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb index cd1bf8a8f..c0edddf7b 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/factory.rb @@ -59,6 +59,10 @@ module SchemaDefinition class Factory include Mixins::HasReadableToSAndInspect.new + # @dynamic state + # @return [State] schema definition state shared with the factory's API + attr_reader :state + def initialize(state) @state = state end @@ -297,14 +301,12 @@ def new_results def new_schema_artifact_manager( schema_definition_results:, schema_artifacts_directory:, - enforce_json_schema_version:, output:, max_diff_lines: 50 ) @@schema_artifact_manager_new.call( schema_definition_results:, schema_artifacts_directory:, - enforce_json_schema_version:, output:, max_diff_lines: ) diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb index 58fbe7517..8ab08390e 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/rake_tasks.rb @@ -41,12 +41,6 @@ class RakeTasks < ::Rake::TaskLib # specific enum types. For example, to rename the `DayOfWeek.MONDAY` enum to `DayOfWeek.MON`, pass `{DayOfWeek: {MONDAY: "MON"}}`. # @param extension_modules [Array] List of Ruby modules to extend onto the `SchemaDefinition::API` instance. Designed to # support ElasticGraph extension gems (such as `elasticgraph-apollo`). - # @param enforce_json_schema_version [Boolean] Whether or not to enforce the requirement that the JSON schema version is incremented - # every time dumping the JSON schemas results in a changed artifact. Generally speaking, you will want this to be `true` for any - # ElasticGraph application that is in production as the versioning of JSON schemas is what supports safe schema evolution as it - # allows ElasticGraph to identify which version of the JSON schema the publishing system was operating on when it published an - # event. It can be useful to set it to `false` before your application is in production, as you do not want to be forced to bump - # the version after every single schema change while you are building an initial prototype. # @param output [IO] used for printing task output # # @example Minimal setup with defaults @@ -117,7 +111,6 @@ def initialize( type_name_overrides: {}, enum_value_overrides_by_type: {}, extension_modules: [], - enforce_json_schema_version: true, output: $stdout ) @schema_element_names = SchemaArtifacts::RuntimeMetadata::SchemaElementNames.new( @@ -131,7 +124,6 @@ def initialize( @index_document_sizes = index_document_sizes @path_to_schema = path_to_schema @schema_artifacts_directory = schema_artifacts_directory - @enforce_json_schema_version = enforce_json_schema_version @extension_modules = extension_modules @output = output @@ -164,7 +156,6 @@ def schema_artifact_manager schema_def_api.factory.new_schema_artifact_manager( schema_definition_results: schema_def_api.results, schema_artifacts_directory: @schema_artifacts_directory.to_s, - enforce_json_schema_version: @enforce_json_schema_version, output: @output, max_diff_lines: max_diff_lines ) diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb index 56d288fae..d3e0a9a81 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/schema_artifact_manager.rb @@ -31,10 +31,9 @@ class SchemaArtifactManager # @dynamic schema_definition_results attr_reader :schema_definition_results - def initialize(schema_definition_results:, schema_artifacts_directory:, enforce_json_schema_version:, output:, max_diff_lines: 50) + def initialize(schema_definition_results:, schema_artifacts_directory:, output:, max_diff_lines: 50) @schema_definition_results = schema_definition_results @schema_artifacts_directory = schema_artifacts_directory - @enforce_json_schema_version = enforce_json_schema_version @output = output @max_diff_lines = max_diff_lines @@ -51,7 +50,7 @@ def initialize(schema_definition_results:, schema_artifacts_directory:, enforce_ # Dumps all the schema artifacts to disk. def dump_artifacts check_if_needs_json_schema_version_bump do |recommended_json_schema_version| - if @enforce_json_schema_version + if schema_definition_results.state.enforce_json_schema_version # @type var setter_location: ::Thread::Backtrace::Location # We use `_ =` because while `json_schema_version_setter_location` can be nil, # it'll never be nil if we get here and we want the type to be non-nilable. @@ -62,12 +61,12 @@ def dump_artifacts "increase the schema's version, and then run the `bundle exec rake schema_artifacts:dump` command again.\n\n" \ "To update the schema version to the expected version, change line #{setter_location.lineno} at `#{setter_location_path}` to:\n" \ " `schema.json_schema_version #{recommended_json_schema_version}`\n\n" \ - "Alternately, pass `enforce_json_schema_version: false` to `ElasticGraph::SchemaDefinition::RakeTasks.new` to allow the JSON schemas " \ - "file to change without requiring a version bump, but that is only recommended for non-production applications during initial schema prototyping." + "Alternately, call `schema.enforce_json_schema_version false` in your schema definition to allow the JSON schemas file " \ + "to change without requiring a version bump, but that is only recommended for non-production applications during initial schema prototyping." else @output.puts <<~EOS WARNING: the `json_schemas.yaml` artifact is being updated without the `json_schema_version` being correspondingly incremented. - This is not recommended for production applications, but is currently allowed because you have set `enforce_json_schema_version: false`. + This is not recommended for production applications, but is currently allowed because you have called `schema.enforce_json_schema_version false`. EOS end end diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb index ed1994f25..ccc4e76c5 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/state.rb @@ -43,6 +43,7 @@ class State < Struct.new( :deleted_fields_by_type_name_and_old_field_name, :json_schema_version, :json_schema_version_setter_location, + :enforce_json_schema_version, :graphql_extension_modules, :graphql_resolvers_by_name, :built_in_graphql_resolvers, @@ -93,6 +94,7 @@ def self.with( deleted_fields_by_type_name_and_old_field_name: ::Hash.new { |h, k| h[k] = {} }, json_schema_version_setter_location: nil, json_schema_version: nil, + enforce_json_schema_version: true, graphql_extension_modules: [], graphql_resolvers_by_name: {}, built_in_graphql_resolvers: ::Set.new, diff --git a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb index 7084db978..c4c10fb89 100644 --- a/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb +++ b/elasticgraph-schema_definition/lib/elastic_graph/schema_definition/test_support.rb @@ -7,6 +7,7 @@ # frozen_string_literal: true require "elastic_graph/errors" +require "elastic_graph/schema_artifacts/from_disk" require "elastic_graph/schema_artifacts/runtime_metadata/schema_element_names" require "elastic_graph/schema_definition/api" require "elastic_graph/schema_definition/schema_artifact_manager" @@ -76,7 +77,7 @@ def define_schema_with_schema_elements( # Set the json_schema_version to the provided value, if needed. if !json_schema_version.nil? && api.state.json_schema_version.nil? - api.json_schema_version json_schema_version + api.json_schema_version(json_schema_version) end # :nocov: -- the else branch and code past this aren't used by tests in elasticgraph-schema_definition. @@ -84,11 +85,11 @@ def define_schema_with_schema_elements( # Reloading the schema artifacts takes extra time that we don't usually want to spend (so it's opt-in) # but it can be useful in some cases because there is a bit of extra pruning/validation that it applies. + api.enforce_json_schema_version false tmp_dir = ::Dir.mktmpdir artifacts_manager = api.factory.new_schema_artifact_manager( schema_definition_results: api.results, schema_artifacts_directory: tmp_dir, - enforce_json_schema_version: false, output: ::StringIO.new ) diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/api.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/api.rbs index dbd1c818b..797db12cb 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/api.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/api.rbs @@ -78,6 +78,7 @@ module ElasticGraph @results: Results? def results: () -> Results def json_schema_version: (::Integer) -> void + def enforce_json_schema_version: (bool) -> void def register_graphql_extension: (::Module, defined_at: ::String, **untyped) -> void def register_graphql_resolver: (::Symbol, ::Class, defined_at: ::String, ?built_in: bool, **untyped) -> void def on_built_in_types: () { (SchemaElements::graphQLType) -> void } -> void diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/factory.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/factory.rbs index e40b2fa50..ab1bdea74 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/factory.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/factory.rbs @@ -2,6 +2,7 @@ module ElasticGraph module SchemaDefinition class Factory @state: State + attr_reader state: State def initialize: (State) -> void def self.prevent_non_factory_instantiation_of: (::Class) -> ::Method @@ -129,7 +130,6 @@ module ElasticGraph def new_schema_artifact_manager: ( schema_definition_results: Results, schema_artifacts_directory: ::String, - enforce_json_schema_version: bool, output: io, ?max_diff_lines: ::Integer ) -> SchemaArtifactManager diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/rake_tasks.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/rake_tasks.rbs index a6cde8232..61d7e76ea 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/rake_tasks.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/rake_tasks.rbs @@ -11,7 +11,6 @@ module ElasticGraph ?type_name_overrides: ::Hash[::Symbol, ::String], ?enum_value_overrides_by_type: ::Hash[::Symbol, ::Hash[::Symbol, ::String]], ?extension_modules: ::Array[::Module], - ?enforce_json_schema_version: bool, ?output: io ) -> void @@ -24,7 +23,6 @@ module ElasticGraph @index_document_sizes: bool @path_to_schema: ::String | ::Pathname @schema_artifacts_directory: ::String | ::Pathname - @enforce_json_schema_version: bool @extension_modules: ::Array[::Module] @output: io diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/schema_artifact_manager.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/schema_artifact_manager.rbs index b4b079de0..7c34a8824 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/schema_artifact_manager.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/schema_artifact_manager.rbs @@ -6,7 +6,6 @@ module ElasticGraph def initialize: ( schema_definition_results: Results, schema_artifacts_directory: ::String, - enforce_json_schema_version: bool, output: io, ?max_diff_lines: ::Integer ) -> void @@ -18,7 +17,6 @@ module ElasticGraph @schema_definition_results: Results @schema_artifacts_directory: ::String - @enforce_json_schema_version: bool @output: io @max_diff_lines: ::Integer @artifacts: ::Array[SchemaArtifact[untyped]]? diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/state.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/state.rbs index f80f19f24..bb9a73291 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/state.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/state.rbs @@ -20,6 +20,7 @@ module ElasticGraph attr_reader deleted_fields_by_type_name_and_old_field_name: ::Hash[::String, ::Hash[::String, SchemaElements::DeprecatedElement]] attr_accessor json_schema_version: ::Integer? attr_accessor json_schema_version_setter_location: ::Thread::Backtrace::Location? + attr_accessor enforce_json_schema_version: bool attr_reader graphql_extension_modules: ::Array[SchemaArtifacts::RuntimeMetadata::GraphQLExtension] attr_reader graphql_resolvers_by_name: ::Hash[::Symbol, SchemaArtifacts::RuntimeMetadata::GraphQLResolver] attr_reader built_in_graphql_resolvers: ::Set[::Symbol] @@ -56,6 +57,7 @@ module ElasticGraph deleted_fields_by_type_name_and_old_field_name: ::Hash[::String, ::Hash[::String, SchemaElements::DeprecatedElement]], json_schema_version: Integer?, json_schema_version_setter_location: ::Thread::Backtrace::Location?, + enforce_json_schema_version: bool, graphql_extension_modules: ::Array[SchemaArtifacts::RuntimeMetadata::GraphQLExtension], graphql_resolvers_by_name: ::Hash[::Symbol, SchemaArtifacts::RuntimeMetadata::GraphQLResolver], built_in_graphql_resolvers: ::Set[::Symbol], diff --git a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/test_support.rbs b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/test_support.rbs index 211039ae3..1b92524c5 100644 --- a/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/test_support.rbs +++ b/elasticgraph-schema_definition/sig/elastic_graph/schema_definition/test_support.rbs @@ -12,7 +12,7 @@ module ElasticGraph ?enum_value_overrides_by_type: ::Hash[::Symbol, ::Hash[::Symbol, ::String]], ?output: io?, ?reload_schema_artifacts: bool, - ) ?{ (API) -> void } -> _SchemaArtifacts + ) ?{ (API) -> void } -> (Results | SchemaArtifacts::FromDisk) def define_schema_with_schema_elements: ( SchemaArtifacts::RuntimeMetadata::SchemaElementNames, @@ -24,7 +24,7 @@ module ElasticGraph ?enum_value_overrides_by_type: ::Hash[::Symbol, ::Hash[::Symbol, ::String]], ?output: io?, ?reload_schema_artifacts: bool, - ) ?{ (API) -> void } -> _SchemaArtifacts + ) ?{ (API) -> void } -> (Results | SchemaArtifacts::FromDisk) DOC_COMMENTS: ::String diff --git a/elasticgraph-schema_definition/spec/integration/elastic_graph/schema_definition/rake_tasks_spec.rb b/elasticgraph-schema_definition/spec/integration/elastic_graph/schema_definition/rake_tasks_spec.rb index 709206b5d..54a235ec8 100644 --- a/elasticgraph-schema_definition/spec/integration/elastic_graph/schema_definition/rake_tasks_spec.rb +++ b/elasticgraph-schema_definition/spec/integration/elastic_graph/schema_definition/rake_tasks_spec.rb @@ -216,8 +216,10 @@ module SchemaDefinition "`schema.json_schema_version 4`" ).and matching(json_schema_version_setter_location_regex) + write_elastic_graph_schema_def_code(component_suffix: "3", json_schema_version: 3, component_extras: "t.renamed_from 'Component'", enforce_json_schema_version: false) + expect { - output = run_rake("schema_artifacts:dump", enforce_json_schema_version: false) + output = run_rake("schema_artifacts:dump") expect(output.lines).to include( a_string_including("Dumped", JSON_SCHEMAS_FILE), a_string_including("Dumped", versioned_json_schema_file(3)) @@ -492,10 +494,10 @@ module SchemaDefinition }) ) - # Here we add a different new field (`ordinal: Int!`), without bumping the version (and using `enforce_json_schema_version: false` - # to not have to bump the version)... - write_elastic_graph_schema_def_code(json_schema_version: 2, component_name_extras: "\nt.field 'ordinal', 'Int!'") - run_rake("schema_artifacts:dump", enforce_json_schema_version: false) + # Here we add a different new field (`ordinal: Int!`), without bumping the version, and disable + # enforcement so we do not have to bump the version. + write_elastic_graph_schema_def_code(json_schema_version: 2, component_name_extras: "\nt.field 'ordinal', 'Int!'", enforce_json_schema_version: false) + run_rake("schema_artifacts:dump") # It should not be added to the v1 schema... loaded_v1 = ::YAML.safe_load(read_artifact(versioned_json_schema_file(1))) @@ -859,7 +861,6 @@ module SchemaDefinition index_document_sizes: true, path_to_schema: "\#{project_root}/config/schema.rb", schema_artifacts_directory: "\#{project_root}/config/schema/artifacts", - enforce_json_schema_version: false ) EOS @@ -901,7 +902,7 @@ def expect_successful_run_of(*shell_commands) /line 7 at `(\S*\/?)schema\.rb`/ end - def write_elastic_graph_schema_def_code(json_schema_version:, component_suffix: "", extra_sdl: "", component_name_extras: "", component_extras: "", omit_component_name_field: false) + def write_elastic_graph_schema_def_code(json_schema_version:, enforce_json_schema_version: true, component_suffix: "", extra_sdl: "", component_name_extras: "", component_extras: "", omit_component_name_field: false) code = <<~EOS Thread.current[:eg_schema_load_count] = (Thread.current[:eg_schema_load_count] || 0) + 1 if Thread.current[:eg_schema_load_count] > 1 @@ -910,6 +911,7 @@ def write_elastic_graph_schema_def_code(json_schema_version:, component_suffix: ElasticGraph.define_schema do |schema| schema.json_schema_version #{json_schema_version} + #{"schema.enforce_json_schema_version false" unless enforce_json_schema_version} schema.enum_type "Size" do |t| t.values "SMALL", "MEDIUM", "LAGE" end @@ -966,6 +968,7 @@ def runtime_metadata_for_elastic_graph_schema_def_code(include_date_time_fields: ElasticGraph.define_schema do |schema| schema.json_schema_version 1 + schema.enforce_json_schema_version false schema.object_type "MyType" do |t| t.field "id", "ID!" @@ -976,7 +979,7 @@ def runtime_metadata_for_elastic_graph_schema_def_code(include_date_time_fields: end EOS - run_rake("schema_artifacts:dump", enforce_json_schema_version: false) + run_rake("schema_artifacts:dump") ::YAML.safe_load(read_artifact(RUNTIME_METADATA_FILE)) end @@ -1059,7 +1062,6 @@ def versioned_json_schema_file(version) def run_rake( *args, - enforce_json_schema_version: true, pretend_tty: false, path_to_schema: "schema.rb", include_extension_module: true, @@ -1086,7 +1088,6 @@ def as_active_instance index_document_sizes: true, path_to_schema: path_to_schema, schema_artifacts_directory: "config/schema/artifacts", - enforce_json_schema_version: enforce_json_schema_version, extension_modules: [extension_module].compact, derived_type_name_formats: derived_type_name_formats, type_name_overrides: type_name_overrides, diff --git a/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/graphql_schema/built_in_types_spec.rb b/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/graphql_schema/built_in_types_spec.rb index 2871e87ff..e25e95cee 100644 --- a/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/graphql_schema/built_in_types_spec.rb +++ b/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/graphql_schema/built_in_types_spec.rb @@ -1349,6 +1349,19 @@ def deprecated! expect(type_def_from(result, "DateTime")).to eq "scalar DateTime @deprecated" end + it "only applies each extension module once" do + applied_count = 0 + api_extension = Module.new do + define_singleton_method :extended do |_api| + applied_count += 1 + end + end + + define_schema(extension_modules: [api_extension, api_extension]) {} + + expect(applied_count).to eq 1 + end + describe "#on_built_in_types" do it "can tag built in types" do result = define_schema do |api| diff --git a/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/json_schema_spec.rb b/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/json_schema_spec.rb index c11a97ae2..90979c46b 100644 --- a/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/json_schema_spec.rb +++ b/elasticgraph-schema_definition/spec/unit/elastic_graph/schema_definition/json_schema_spec.rb @@ -2942,6 +2942,22 @@ def link_supertype_to_subtypes(interface_type, *subtype_names) expect(result[JSON_SCHEMA_VERSION_KEY]).to eq(1) end + it "allows json_schema_version enforcement to be disabled" do + result = define_schema(schema_element_name_form: "snake_case") do |s| + s.enforce_json_schema_version false + end + + expect(result.state.enforce_json_schema_version).to eq false + end + + it "fails if json_schema_version enforcement is set to a non-boolean value" do + expect { + define_schema(schema_element_name_form: "snake_case") do |s| + s.enforce_json_schema_version nil + end + }.to raise_error(Errors::SchemaError, a_string_including("must be a boolean", "nil")) + end + it "fails if json_schema_version is set to invalid values" do expect { define_schema(schema_element_name_form: "snake_case") do |s| diff --git a/elasticgraph-warehouse/README.md b/elasticgraph-warehouse/README.md index 847448001..1f05659f6 100644 --- a/elasticgraph-warehouse/README.md +++ b/elasticgraph-warehouse/README.md @@ -58,9 +58,6 @@ index 2943335..26633c3 100644 path_to_schema: "#{project_root}/config/schema.rb" ) do |tasks| + tasks.schema_definition_extension_modules = [ElasticGraph::Warehouse::SchemaDefinition::APIExtension] -+ - # Set this to true once you're beyond the prototyping stage. - tasks.enforce_json_schema_version = false ``` diff --git a/elasticgraph-warehouse/spec/integration/elastic_graph/warehouse/schema_definition/rake_tasks_spec.rb b/elasticgraph-warehouse/spec/integration/elastic_graph/warehouse/schema_definition/rake_tasks_spec.rb index 2a6e74225..da74eb579 100644 --- a/elasticgraph-warehouse/spec/integration/elastic_graph/warehouse/schema_definition/rake_tasks_spec.rb +++ b/elasticgraph-warehouse/spec/integration/elastic_graph/warehouse/schema_definition/rake_tasks_spec.rb @@ -85,7 +85,7 @@ module SchemaDefinition original_content = read_warehouse_artifact expect(original_content).not_to include("added_field") - write_warehouse_schema(table_defs: <<~EOS) + write_warehouse_schema(enforce_json_schema_version: false, table_defs: <<~EOS) s.object_type "Product" do |t| t.field "id", "ID" t.field "added_field", "String" @@ -94,7 +94,7 @@ module SchemaDefinition EOS expect { - run_rake_with_warehouse("schema_artifacts:dump", enforce_json_schema_version: false) + run_rake_with_warehouse("schema_artifacts:dump") }.to change { read_warehouse_artifact } .from(original_content) .to(a_string_including("added_field")) @@ -157,10 +157,11 @@ module SchemaDefinition end end - def write_warehouse_schema(table_defs:) + def write_warehouse_schema(table_defs:, enforce_json_schema_version: true) ::File.write("schema.rb", <<~EOS) ElasticGraph.define_schema do |s| s.json_schema_version 1 + #{"s.enforce_json_schema_version false" unless enforce_json_schema_version} # Add a dummy indexed type to ensure the Query type has at least one field. # This prevents GraphQL-Ruby warnings about empty Query types in tests. @@ -177,14 +178,13 @@ def write_warehouse_schema(table_defs:) EOS end - def run_rake_with_warehouse(*args, enforce_json_schema_version: true) + def run_rake_with_warehouse(*args) run_rake(*args) do |output| ElasticGraph::SchemaDefinition::RakeTasks.new( schema_element_name_form: :snake_case, index_document_sizes: false, path_to_schema: "schema.rb", schema_artifacts_directory: "config/schema/artifacts", - enforce_json_schema_version: enforce_json_schema_version, extension_modules: [Warehouse::SchemaDefinition::APIExtension], output: output ) diff --git a/elasticgraph/lib/elastic_graph/project_template/Rakefile.tt b/elasticgraph/lib/elastic_graph/project_template/Rakefile.tt index 9ca5c55f7..7507ebfbe 100644 --- a/elasticgraph/lib/elastic_graph/project_template/Rakefile.tt +++ b/elasticgraph/lib/elastic_graph/project_template/Rakefile.tt @@ -12,9 +12,6 @@ ElasticGraph::Local::RakeTasks.new( local_config_yaml: settings_file, path_to_schema: "#{project_root}/config/schema.rb" ) do |tasks| - # Set this to true once you're beyond the prototyping stage. - tasks.enforce_json_schema_version = false - # Determines casing of field names. Can be either `:camelCase` or `:snake_case`. tasks.schema_element_name_form = :camelCase diff --git a/elasticgraph/lib/elastic_graph/project_template/config/schema.rb.tt b/elasticgraph/lib/elastic_graph/project_template/config/schema.rb.tt index fb70616d4..69792447b 100644 --- a/elasticgraph/lib/elastic_graph/project_template/config/schema.rb.tt +++ b/elasticgraph/lib/elastic_graph/project_template/config/schema.rb.tt @@ -2,6 +2,9 @@ ElasticGraph.define_schema do |schema| # ElasticGraph will tell you when you need to bump this. schema.json_schema_version 1 + # Set this to true once you're beyond the prototyping stage. + schema.enforce_json_schema_version false + # This registers the elasticgraph-query_registry extension, which can be used to reject queries that # clients have not registered (and to reject queries that differ from what a client has registered). # In addition, every registered query is validated against the schema in the CI build, giving you