118 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			Ruby
		
	
	
	
| # frozen_string_literal: true
 | |
| 
 | |
| module Gitlab
 | |
|   module ImportExport
 | |
|     # Generates a hash that conforms with http://apidock.com/rails/Hash/to_json
 | |
|     # and its peculiar options.
 | |
|     class JsonHashBuilder
 | |
|       def self.build(model_objects, attributes_finder)
 | |
|         new(model_objects, attributes_finder).build
 | |
|       end
 | |
| 
 | |
|       def initialize(model_objects, attributes_finder)
 | |
|         @model_objects = model_objects
 | |
|         @attributes_finder = attributes_finder
 | |
|       end
 | |
| 
 | |
|       def build
 | |
|         process_model_objects(@model_objects)
 | |
|       end
 | |
| 
 | |
|       private
 | |
| 
 | |
|       # Called when the model is actually a hash containing other relations (more models)
 | |
|       # Returns the config in the right format for calling +to_json+
 | |
|       #
 | |
|       # +model_object_hash+ - A model relationship such as:
 | |
|       #   {:merge_requests=>[:merge_request_diff, :notes]}
 | |
|       def process_model_objects(model_object_hash)
 | |
|         json_config_hash = {}
 | |
|         current_key = model_object_hash.first.first
 | |
| 
 | |
|         model_object_hash.values.flatten.each do |model_object|
 | |
|           @attributes_finder.parse(current_key) { |hash| json_config_hash[current_key] ||= hash }
 | |
|           handle_model_object(current_key, model_object, json_config_hash)
 | |
|         end
 | |
| 
 | |
|         json_config_hash
 | |
|       end
 | |
| 
 | |
|       # Creates or adds to an existing hash an individual model or list
 | |
|       #
 | |
|       # +current_key+ main model that will be a key in the hash
 | |
|       # +model_object+ model or list of models to include in the hash
 | |
|       # +json_config_hash+ the original hash containing the root model
 | |
|       def handle_model_object(current_key, model_object, json_config_hash)
 | |
|         model_or_sub_model = model_object.is_a?(Hash) ? process_model_objects(model_object) : model_object
 | |
| 
 | |
|         if json_config_hash[current_key]
 | |
|           add_model_value(current_key, model_or_sub_model, json_config_hash)
 | |
|         else
 | |
|           create_model_value(current_key, model_or_sub_model, json_config_hash)
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       # Constructs a new hash that will hold the configuration for that particular object
 | |
|       # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+
 | |
|       #
 | |
|       # +current_key+ main model that will be a key in the hash
 | |
|       # +value+ existing model to be included in the hash
 | |
|       # +json_config_hash+ the original hash containing the root model
 | |
|       def create_model_value(current_key, value, json_config_hash)
 | |
|         json_config_hash[current_key] = parse_hash(value) || { include: value }
 | |
|       end
 | |
| 
 | |
|       # Calls attributes finder to parse the hash and add any attributes to it
 | |
|       #
 | |
|       # +value+ existing model to be included in the hash
 | |
|       # +parsed_hash+ the original hash
 | |
|       def parse_hash(value)
 | |
|         return if already_contains_methods?(value)
 | |
| 
 | |
|         @attributes_finder.parse(value) do |hash|
 | |
|           { include: hash_or_merge(value, hash) }
 | |
|         end
 | |
|       end
 | |
| 
 | |
|       def already_contains_methods?(value)
 | |
|         value.is_a?(Hash) && value.values.detect { |val| val[:methods]}
 | |
|       end
 | |
| 
 | |
|       # Adds new model configuration to an existing hash with key +current_key+
 | |
|       # It may include exceptions or other attribute detail configuration, parsed by +@attributes_finder+
 | |
|       #
 | |
|       # +current_key+ main model that will be a key in the hash
 | |
|       # +value+ existing model to be included in the hash
 | |
|       # +json_config_hash+ the original hash containing the root model
 | |
|       def add_model_value(current_key, value, json_config_hash)
 | |
|         @attributes_finder.parse(value) do |hash|
 | |
|           value = { value => hash } unless value.is_a?(Hash)
 | |
|         end
 | |
| 
 | |
|         add_to_array(current_key, json_config_hash, value)
 | |
|       end
 | |
| 
 | |
|       # Adds new model configuration to an existing hash with key +current_key+
 | |
|       # it creates a new array if it was previously a single value
 | |
|       #
 | |
|       # +current_key+ main model that will be a key in the hash
 | |
|       # +value+ existing model to be included in the hash
 | |
|       # +json_config_hash+ the original hash containing the root model
 | |
|       def add_to_array(current_key, json_config_hash, value)
 | |
|         old_values = json_config_hash[current_key][:include]
 | |
| 
 | |
|         json_config_hash[current_key][:include] = ([old_values] + [value]).compact.flatten
 | |
|       end
 | |
| 
 | |
|       # Construct a new hash or merge with an existing one a model configuration
 | |
|       # This is to fulfil +to_json+ requirements.
 | |
|       #
 | |
|       # +hash+ hash containing configuration generated mainly from +@attributes_finder+
 | |
|       # +value+ existing model to be included in the hash
 | |
|       def hash_or_merge(value, hash)
 | |
|         value.is_a?(Hash) ? value.merge(hash) : { value => hash }
 | |
|       end
 | |
|     end
 | |
|   end
 | |
| end
 |