Commit c26690dc authored by Mikolaj Wawrzyniak's avatar Mikolaj Wawrzyniak

Include constraints on joined relations

To make Product Intelligence metrics name suggestion more
descriptive, constraint applicable to joined relations should
be expressed as adjective prompt before joined relations names
parent 3731b3ef
...@@ -6,6 +6,7 @@ module Gitlab ...@@ -6,6 +6,7 @@ module Gitlab
module NamesSuggestions module NamesSuggestions
class Generator < ::Gitlab::UsageData class Generator < ::Gitlab::UsageData
FREE_TEXT_METRIC_NAME = "<please fill metric name>" FREE_TEXT_METRIC_NAME = "<please fill metric name>"
CONSTRAINTS_PROMPT_TEMPLATE = "<adjective describing: '%{constraints}'>"
class << self class << self
def generate(key_path) def generate(key_path)
...@@ -76,15 +77,20 @@ module Gitlab ...@@ -76,15 +77,20 @@ module Gitlab
# count_environment_id_from_clusters_with_deployments # count_environment_id_from_clusters_with_deployments
actual_source = parse_source(relation, arel_column) actual_source = parse_source(relation, arel_column)
if constraints.include?(actual_source) append_constraints_prompt(actual_source, [constraints], parts)
parts << "<adjective describing: '#{constraints}'>"
end
parts << actual_source parts << actual_source
parts += process_joined_relations(actual_source, arel, relation) parts += process_joined_relations(actual_source, arel, relation, constraints)
parts.compact.join('_') parts.compact.join('_')
end end
def append_constraints_prompt(target, constraints, parts)
applicable_constraints = constraints.select { |constraint| constraint.include?(target) }
return unless applicable_constraints.any?
parts << CONSTRAINTS_PROMPT_TEMPLATE % { constraints: applicable_constraints.join(' AND ') }
end
def parse_constraints(relation:, arel:) def parse_constraints(relation:, arel:)
connection = relation.connection connection = relation.connection
::Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::Constraints ::Gitlab::Usage::Metrics::NamesSuggestions::RelationParsers::Constraints
...@@ -94,7 +100,7 @@ module Gitlab ...@@ -94,7 +100,7 @@ module Gitlab
end end
# TODO: joins with `USING` keyword # TODO: joins with `USING` keyword
def process_joined_relations(actual_source, arel, relation) def process_joined_relations(actual_source, arel, relation, where_constraints)
joins = parse_joins(connection: relation.connection, arel: arel) joins = parse_joins(connection: relation.connection, arel: arel)
return [] unless joins.any? return [] unless joins.any?
...@@ -109,7 +115,7 @@ module Gitlab ...@@ -109,7 +115,7 @@ module Gitlab
build_relations_tree(joins + [{ source: relation.table_name }], actual_source, source_key: :target, target_key: :source) build_relations_tree(joins + [{ source: relation.table_name }], actual_source, source_key: :target, target_key: :source)
end end
collect_join_parts(relations[actual_source]) collect_join_parts(relations: relations[actual_source], joins: joins, wheres: where_constraints)
end end
def parse_joins(connection:, arel:) def parse_joins(connection:, arel:)
...@@ -128,7 +134,11 @@ module Gitlab ...@@ -128,7 +134,11 @@ module Gitlab
join_cond_regex = /(#{source_regex}\s+=\s+#{target_regex})|(#{target_regex}\s+=\s+#{source_regex})/i join_cond_regex = /(#{source_regex}\s+=\s+#{target_regex})|(#{target_regex}\s+=\s+#{source_regex})/i
matched = join_cond_regex.match(join[:constraints]) matched = join_cond_regex.match(join[:constraints])
join[:target] = matched[:target] if matched if matched
join[:target] = matched[:target]
join[:constraints].gsub!(/#{join_cond_regex}(\s+(and|or))*/i, '')
end
join join
end end
end end
...@@ -147,13 +157,15 @@ module Gitlab ...@@ -147,13 +157,15 @@ module Gitlab
tree tree
end end
def collect_join_parts(joined_relations, parts = [], conjunctions = %w[with having including].cycle) def collect_join_parts(relations:, joins:, wheres:, parts: [], conjunctions: %w[with having including].cycle)
conjunction = conjunctions.next conjunction = conjunctions.next
joined_relations.each do |subtree| relations.each do |subtree|
subtree.each do |parent, children| subtree.each do |parent, children|
parts << "<#{conjunction}>" parts << "<#{conjunction}>"
join_constraints = joins.find { |join| join[:source] == parent }&.dig(:constraints)
append_constraints_prompt(parent, [wheres, join_constraints].compact, parts)
parts << parent parts << parent
collect_join_parts(children, parts, conjunctions) collect_join_parts(relations: children, joins: joins, wheres: wheres, parts: parts, conjunctions: conjunctions)
end end
end end
parts parts
......
...@@ -44,7 +44,10 @@ RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::Generator do ...@@ -44,7 +44,10 @@ RSpec.describe Gitlab::Usage::Metrics::NamesSuggestions::Generator do
# ::Deployment.arel_table[:environment_id] # ::Deployment.arel_table[:environment_id]
# ) # )
let(:key_path) { 'counts.ingress_modsecurity_logging' } let(:key_path) { 'counts.ingress_modsecurity_logging' }
let(:name_suggestion) { /count_distinct_environment_id_from_<adjective describing\: '\(clusters_applications_ingress\.modsecurity_enabled = TRUE AND clusters_applications_ingress\.modsecurity_mode = \d+ AND clusters.enabled = TRUE AND deployments.status = \d+\)'>_deployments_<with>_clusters_<having>_clusters_applications_ingress/ } let(:name_suggestion) do
constrains = /'\(clusters_applications_ingress\.modsecurity_enabled = TRUE AND clusters_applications_ingress\.modsecurity_mode = \d+ AND clusters.enabled = TRUE AND deployments.status = \d+\)'/
/count_distinct_environment_id_from_<adjective describing\: #{constrains}>_deployments_<with>_<adjective describing\: #{constrains}>_clusters_<having>_<adjective describing\: #{constrains}>_clusters_applications_ingress/
end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment