Skip to content

Instantly share code, notes, and snippets.

@rmosolgo
Last active November 12, 2019 15:55
Show Gist options
  • Select an option

  • Save rmosolgo/640d599bc1902812e46161b080f5cb05 to your computer and use it in GitHub Desktop.

Select an option

Save rmosolgo/640d599bc1902812e46161b080f5cb05 to your computer and use it in GitHub Desktop.
Calculating "complexity" in a duplication-agnostic way
inputs = [
# These inputs are "like" GraphQL queries because:
# - Some keys are scalars, others are nested hashes
# - Keys may be repeated
#
# Pretend they're like `{ field => complexity }` pairs.
[{ a: 1, b: 1 }],
[{ a: 1, b: 1 }, { b: 1 }],
[{ a: 1, b: 1, c: { d: 1 } }, { c: { d: 1, e: 1 } }]
]
# For each key in the hash:
# - if it's a scalar and we don't already have its complexity, "calculate" and store the complexity
# - if it's a hash, enter a new accumulator (or re-enter it) and continue analyzing the children
def analyze(hash, acc)
# Visit each field in the hash.
# IRL you would use `ast_field.alias` as the key here
hash.each do |key, value|
if value.is_a?(Hash)
# Continue traversing _into_ hashes, using the previous
# accumulator for this field if there's already one
next_acc = acc[key] ||= { }
analyze(value, next_acc)
else
# "calculate" the complexity for the scalar
acc[key] ||= value
end
end
# Recalculate the total because you might've added new values.
# If you're really tricky, maybe this could be accomplished without a total recalculation.
acc[:__total] = 0
acc.each do |k, v|
if v.is_a?(Hash)
acc[:__total] += v[:__total]
elsif k != :__total
acc[:__total] += v
end
end
# Return the analyzed complexities, by field name
acc
end
inputs.each do |input|
acc = {}
input.each do |h|
analyze(h, acc)
end
p acc
end
# {:a=>1, :b=>1, :__total=>2}
# {:a=>1, :b=>1, :__total=>2}
# {:a=>1, :b=>1, :c=>{:d=>1, :__total=>2, :e=>1}, :__total=>4}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment