Skip to content

Commit

Permalink
Merge branch 'main' into akumar/autoscaler-min-free-storage
Browse files Browse the repository at this point in the history
  • Loading branch information
akumar1214 authored Nov 12, 2024
2 parents 8451f65 + 81c3701 commit 580d65f
Show file tree
Hide file tree
Showing 34 changed files with 433 additions and 125 deletions.
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

There are many ways to be an open source contributor, and we're here to help you on your way! You may:

* Propose ideas in our [discord](https://discord.com/invite/c79mzZnu)
* Propose ideas in our [discord](https://discord.gg/8m9FqJ7a7F)
* Raise an issue or feature request in our [issue tracker](https://github.com/block/elasticgraph/issues)
* Help another contributor with one of their questions, or a code review
* Suggest improvements to our Getting Started documentation by supplying a Pull Request
Expand Down Expand Up @@ -54,7 +54,7 @@ Anyone from the community is welcome (and encouraged!) to raise issues via

### Discussions

Design discussions and proposals take place in our [discord](https://discord.com/invite/c79mzZnu).
Design discussions and proposals take place in our [discord](https://discord.gg/8m9FqJ7a7F).

We advocate an asynchronous, written debate model - so write up your thoughts and invite the community to join in!

Expand Down
2 changes: 1 addition & 1 deletion GOVERNANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

Anyone may be a contributor to Block open source projects. Contribution may take the form of:

* Asking and answering questions on the [Discord](https://discord.com/invite/c79mzZnu) or [GitHub Issues](https://github.com/block/elasticgraph/issues).
* Asking and answering questions on the [Discord](https://discord.gg/8m9FqJ7a7F) or [GitHub Issues](https://github.com/block/elasticgraph/issues).
* Filing an issue
* Offering a feature or bug fix via a Pull Request
* Suggesting documentation improvements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
query OptionalMatchingFilter(
$optionalMatchQuery: MatchesQueryFilterInput = null
) {
artists(filter: {
bio: {
description: {
matchesQuery: $optionalMatchQuery
}
}
}) {
nodes {
name
bio {
description
}
}
}
}
8 changes: 8 additions & 0 deletions config/site/src/query-api/filtering/full-text-search.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,11 @@ are supported to control both aspects to make matching stricter:
{% highlight graphql %}
{{ site.data.music_queries.filtering.PhraseSearch }}
{% endhighlight %}

### Bypassing matchesPhrase and matchesQuery

In order to make a `matchesPhrase` or `matchesQuery` filter optional, you can supply `null` to the `MatchesQueryFilterInput` parameter, like this:

{% highlight graphql %}
{{ site.data.music_queries.filtering.OptionalMatchingFilter }}
{% endhighlight %}
2 changes: 1 addition & 1 deletion elasticgraph-apollo/elasticgraph-apollo.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, catego

spec.add_dependency "elasticgraph-graphql", eg_version
spec.add_dependency "elasticgraph-support", eg_version
spec.add_dependency "graphql", "~> 2.3.19"
spec.add_dependency "graphql", "~> 2.4.3"
spec.add_dependency "apollo-federation", "~> 3.8"

# Note: technically, this is not purely a development dependency, but since `eg-schema_def`
Expand Down
2 changes: 1 addition & 1 deletion elasticgraph-graphql/elasticgraph-graphql.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ ElasticGraphGemspecHelper.define_elasticgraph_gem(gemspec_file: __FILE__, catego

spec.add_dependency "elasticgraph-datastore_core", eg_version
spec.add_dependency "elasticgraph-schema_artifacts", eg_version
spec.add_dependency "graphql", "~> 2.3.19"
spec.add_dependency "graphql", "~> 2.4.3"

spec.add_development_dependency "elasticgraph-admin", eg_version
spec.add_development_dependency "elasticgraph-elasticsearch", eg_version
Expand Down
8 changes: 7 additions & 1 deletion elasticgraph-graphql/lib/elastic_graph/graphql.rb
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,13 @@ def datastore_query_builder
def graphql_gem_plugins
@graphql_gem_plugins ||= begin
require "graphql"
{::GraphQL::Dataloader => {}}
{
# We depend on this to avoid N+1 calls to the datastore.
::GraphQL::Dataloader => {},
# This is new in the graphql-ruby 2.4 release, and will be required in the future.
# We pass `preload: true` because the way we handle the schema depends on it being preloaded.
::GraphQL::Schema::Visibility => {preload: true}
}
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,7 @@ def merge_into(bool_node)
bool_node[occurrence].concat(clauses)
end

# For `any_of: []` we need a way to force the datastore to match no documents, but
# I haven't found any sort of literal `false` we can pass in the compound expression
# or even a literal `1 = 0` as is sometimes used in SQL. Instead, we use this for that
# case.
empty_array = [] # : ::Array[untyped]
ALWAYS_FALSE_FILTER = filter({ids: {values: empty_array}})
ALWAYS_FALSE_FILTER = filter({match_none: {}})
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def process_filter_hash(bool_node, filter_hash, field_path)
filter_hash.each do |field_or_op, expression|
case filter_node_interpreter.identify_node_type(field_or_op, expression)
when :empty
# This is an "empty" filter predicate and we can ignore it.
# This is an "empty" filter predicate and can be treated as `true`.
when :not
process_not_expression(bool_node, expression, field_path)
when :list_any_filter
Expand Down Expand Up @@ -103,13 +103,15 @@ def filters_on_sub_fields?(expression)
end

def process_not_expression(bool_node, expression, field_path)
return if expression.nil? || expression == {}

sub_filter = build_bool_hash do |inner_node|
process_filter_hash(inner_node, expression, field_path)
process_filter_hash(inner_node, expression || {}, field_path)
end

return unless sub_filter
unless sub_filter
# Since an empty expression is treated as `true`, convert to `false` when negating.
BooleanQuery::ALWAYS_FALSE_FILTER.merge_into(bool_node)
return
end

# Prevent any negated filters from being unnecessarily double-negated by
# converting them to a positive filter (i.e., !!A == A).
Expand Down Expand Up @@ -187,21 +189,32 @@ def process_any_satisfy_filter_expression_on_scalar_list(bool_node, filter, fiel
end
end

# We want to provide the following semantics for `any_of`:
#
# * `filter: {anyOf: []}` -> return no results
# * `filter: {anyOf: [{field: null}]}` -> return all results
# * `filter: {anyOf: [{field: null}, {field: ...}]}` -> return all results
def process_any_of_expression(bool_node, expressions, field_path)
return if expressions.nil? || expressions == {}

if expressions.empty?
# When our `expressions` array is empty, we want to match no documents. However, that's
# not the behavior the datastore will give us if we have an empty array in the query under
# `should`. To get the behavior we want, we need to pass the datastore some filter criteria
# that will evaluate to false for every document.
BooleanQuery::ALWAYS_FALSE_FILTER.merge_into(bool_node)
return
end

shoulds = expressions.filter_map do |expression|
build_bool_hash do |inner_bool_node|
process_filter_hash(inner_bool_node, expression, field_path)
end
end

# When our `shoulds` array is empty, the filtering semantics we want is to match no documents.
# However, that's not the behavior the datastore will give us if we have an empty array in the
# query under `should`. To get the behavior we want, we need to pass the datastore some filter
# criteria that will evaluate to false for every document.
bool_query = shoulds.empty? ? BooleanQuery::ALWAYS_FALSE_FILTER : BooleanQuery.should(*shoulds)
bool_query.merge_into(bool_node)
return if shoulds.size < expressions.size

BooleanQuery.should(*shoulds).merge_into(bool_node)
end

def process_all_of_expression(bool_node, expressions, field_path)
Expand Down Expand Up @@ -333,7 +346,7 @@ def process_list_count_expression(bool_node, expression, field_path)
def build_bool_hash(&block)
bool_node = Hash.new { |h, k| h[k] = [] }.tap(&block)

# To ignore "empty" filter predicates we need to return `nil` here.
# To treat "empty" filter predicates as `true` we need to return `nil` here.
return nil if bool_node.empty?

# According to https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-bool-query.html#bool-min-should-match,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def filter_value_set_for_filter_hash(filter_hash, target_field_path_parts, trave
# to a particular field.
def filter_value_set_for_filter_hash_entry(field_or_op, filter_value, target_field_path_parts, traversed_field_path_parts, negate:)
if filter_value.nil?
# Any filter with a `nil` value is effectively ignored by our filtering logic, so we need
# Any filter with a `nil` value is effectively treated as `true` by our filtering logic, so we need
# to return our `@all_values_set` to indicate this filter matches all documents.
@all_values_set
elsif field_or_op == @schema_names.not
Expand Down
33 changes: 15 additions & 18 deletions elasticgraph-graphql/lib/elastic_graph/graphql/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Schema
scalar_types.to_set.union(introspection_types)
)

attr_reader :element_names, :defined_types, :config, :graphql_schema, :runtime_metadata
attr_reader :element_names, :config, :graphql_schema, :runtime_metadata

def initialize(
graphql_schema_string:,
Expand All @@ -53,7 +53,6 @@ def initialize(
)
end

@types_by_name = Hash.new { |hash, key| hash[key] = lookup_type_by_name(key) }
@build_resolver = build_resolver

# Note: as part of loading the schema, the GraphQL gem may use the resolver (such
Expand All @@ -68,7 +67,7 @@ def initialize(

# Pre-load all defined types so that all field extras can get configured as part
# of loading the schema, before we execute the first query.
@defined_types = build_defined_types_array(@graphql_schema)
@types_by_name = build_types_by_name
end

def type_from(graphql_type)
Expand All @@ -80,7 +79,11 @@ def type_from(graphql_type)
# get type objects for wrapped types, but you need to get it from a field object of that
# type.
def type_named(type_name)
@types_by_name[type_name.to_s]
@types_by_name.fetch(type_name.to_s)
rescue KeyError => e
msg = "No type named #{type_name} could be found"
msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
raise Errors::NotFoundError, msg
end

def document_type_stored_in(index_definition_name)
Expand All @@ -106,6 +109,10 @@ def indexed_document_types
@indexed_document_types ||= defined_types.select(&:indexed_document?)
end

def defined_types
@defined_types ||= @types_by_name.except(*BUILT_IN_TYPE_NAMES).values
end

def to_s
"#<#{self.class.name} 0x#{__id__.to_s(16)} indexed_document_types=#{indexed_document_types.map(&:name).sort.to_s.delete(":")}>"
end
Expand All @@ -128,24 +135,14 @@ def resolver
def_delegators :resolver, :call, :resolve_type, :coerce_input, :coerce_result
end

def lookup_type_by_name(type_name)
type_from(@graphql_schema.types.fetch(type_name))
rescue KeyError => e
msg = "No type named #{type_name} could be found"
msg += "; Possible alternatives: [#{e.corrections.join(", ").delete('"')}]." if e.corrections.any?
raise Errors::NotFoundError, msg
end

def resolver
@resolver ||= @build_resolver.call(self)
end

def build_defined_types_array(graphql_schema)
graphql_schema
.types
.values
.reject { |t| BUILT_IN_TYPE_NAMES.include?(t.graphql_name) }
.map { |t| type_named(t.graphql_name) }
def build_types_by_name
graphql_schema.types.transform_values do |graphql_type|
@types_by_graphql_type[graphql_type]
end
end

def indexed_document_types_by_index_definition_name
Expand Down
3 changes: 3 additions & 0 deletions elasticgraph-graphql/sig/graphql_gem.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ module GraphQL
class Printer
def self.print_schema: (Schema, **untyped) -> ::String
end

class Visibility
end
end

module StaticValidation
Expand Down
Loading

0 comments on commit 580d65f

Please sign in to comment.