class ModelApi::OpenApiExtensions::Utils
Public Class Methods
add_sort_params(params, model_class, addl_sort_attrs, opts)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 89 def add_sort_params(params, model_class, addl_sort_attrs, opts) attr_prefix = opts[:attr_prefix] if (sort_metadata = ModelApi::Utils.filtered_ext_attrs(model_class, :sort, opts)).present? if attr_prefix.present? params[:sort_by] = sort_metadata.keys.sort.map { |k| :"#{attr_prefix}#{k}" } else addl_sort_attrs = (sort_metadata.keys + addl_sort_attrs).compact.sort params[:sort_by] = { type: :string, description: "Sortable fields: #{addl_sort_attrs.join(', ')} " \ '(optionally append " asc" or " desc" on field(s) to indicate sort order)' } end end params end
attr_types_from_columns(model_class)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 248 def attr_types_from_columns(model_class) Hash[model_class.columns.map { |col| [col.name.to_sym, col.type] }] end
class_model_assoc_property(property_hash, controller_class, attr_metadata, opts)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 230 def class_model_assoc_property(property_hash, controller_class, attr_metadata, opts) assoc = opts[:association] return property_hash unless assoc.present? assoc_class = assoc.class_name.constantize assoc_opts = ModelApi::Utils.assoc_opts(assoc, attr_metadata, opts) assoc_opts = assoc_opts.reject do |k, _v| [:result, :collection_result].include?(k) end assoc_model = define_open_api_object(controller_class, assoc_class, assoc_opts) if assoc.collection? property_hash[:type] = :array property_hash[:items] = { :'$ref' => assoc_model } if assoc_model.present? else property_hash[:'$ref'] = assoc_model if assoc_model.present? end property_hash end
class_model_base(metadata, controller_class, model_class, opts)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 187 def class_model_base(metadata, controller_class, model_class, opts) properties = {} opts = opts.merge(attr_types: attr_types_from_columns(model_class)) metadata.each do |attr, attr_metadata| properties[ModelApi::Utils.ext_attr(attr, attr_metadata)] = open_api_attr_hash( controller_class, model_class, attr, attr_metadata, opts) end controller_class.send(:open_api_object, opts[:object_context].to_sym, properties) end
class_model_base_property(model_class, attr, attr_metadata)
click to toggle source
rubocop:enable Metrics/ParameterLists
# File lib/model-api/open_api_extensions.rb, line 218 def class_model_base_property(model_class, attr, attr_metadata) if (required = attr_metadata[:required]).nil? required_attrs ||= required_attrs_from_validators(model_class) required = required_attrs.include?(attr) end property_hash = { required: required ? true : false } if (description = attr_metadata[:description]).present? property_hash[:description] = description end property_hash end
define_api_collection_response(controller_class, model_class, opts = {})
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 124 def define_api_collection_response(controller_class, model_class, opts = {}) object_name = define_open_api_object(controller_class, model_class, opts) return nil unless object_name.present? wrapper_object_name = "#{object_name}:response" array_metadata = { type: :array, required: true } array_metadata[:'$ref'] = object_name if object_name.present? controller_class.send(:open_api_object, wrapper_object_name, successful: { type: :boolean, required: true, description: 'Returns true if successfully processed; otherwise false' }, status: { type: :string, description: 'HTTP status', required: true }, statusCode: { type: :integer, description: 'Numeric HTTP status code', required: true }, ModelApi::Utils.model_name(model_class).plural => array_metadata, count: { type: :integer, description: 'Total items available', required: true }, page: { type: :integer, description: 'Index (1-based) of page returned', required: true }, pageCount: { type: :integer, description: 'Total number of pages available', required: true }, pageSize: { type: :integer, description: 'Maximum item count per page returned', required: true }) wrapper_object_name end
define_api_response(controller_class, model_class, opts = {})
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 43 def define_api_response(controller_class, model_class, opts = {}) object_name = define_open_api_object(controller_class, model_class, opts) return nil unless object_name.present? wrapper_object_name = "#{object_name}:response" response_object_metadata = { type: :object, required: true } response_object_metadata[:'$ref'] = object_name if object_name.present? controller_class.send(:open_api_object, wrapper_object_name, successful: { type: :boolean, required: true, description: 'Returns true if successfully processed; otherwise false' }, status: { type: :string, required: true, description: 'HTTP status' }, statusCode: { type: :integer, required: true, description: 'Numeric HTTP status code' }, ModelApi::Utils.ext_attr(opts[:root] || ModelApi::Utils.model_name(model_class).singular) => response_object_metadata) wrapper_object_name end
define_open_api_object(controller_class, define_open_api_object, opts = {})
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 147 def define_open_api_object(controller_class, define_open_api_object, opts = {}) define_open_api_objects(controller_class, define_open_api_object, opts).first end
define_open_api_object_from_model(controller_class, model_class, opts = {})
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 164 def define_open_api_object_from_model(controller_class, model_class, opts = {}) operation = opts[:operation] || :show metadata_opts = opts.merge(ModelApi::Utils.contextual_metadata_opts(opts)) metadata = ModelApi::Utils.filtered_attrs(model_class, operation, metadata_opts) return nil unless metadata.present? action = (opts = opts.dup).delete(:action) # Prevent inheritance object_name = ModelApi::Utils.model_name(model_class).name if (parent_object_context = opts[:object_context]).present? object_name = "#{parent_object_context}|#{object_name}" end object_name = "#{object_name}|#{action}" if action.present? @open_api_views_processed ||= {} return object_name if @open_api_views_processed[object_name] @open_api_views_processed[object_name] = model_class class_model_base(metadata, controller_class, model_class, opts.merge(object_context: object_name)) object_name end
define_open_api_objects(controller_class, *define_open_api_objects)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 151 def define_open_api_objects(controller_class, *define_open_api_objects) if define_open_api_objects.size > 1 && (opts = define_open_api_objects.last).is_a?(Hash) define_open_api_objects = define_open_api_objects[0..-2] else opts = {} end object_names = [] define_open_api_objects.compact.uniq.each do |model_class| object_names << define_open_api_object_from_model(controller_class, model_class, opts) end object_names.compact end
filter_and_sort_params(controller_class, model_class, opts = {})
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 60 def filter_and_sort_params(controller_class, model_class, opts = {}) params = opts[:parameters] || {} opts = opts.merge(attr_types: attr_types_from_columns(model_class)) attr_prefix = opts[:attr_prefix] sort_attrs = [] filter_metadata = ModelApi::Utils.filtered_ext_attrs(model_class, :filter, opts) filter_metadata.each do |attr, attr_metadata| if attr_metadata[:type] == :association next unless (assoc = attr_metadata[:association]).present? && assoc.respond_to?(:klass) assoc_params = filter_and_sort_params(controller_class, assoc.klass, opts.merge(attr_prefix: "#{attr}.")) sort_attrs += assoc_params.delete(:sort_by) || [] assoc_params.each { |assoc_attr, property_hash| params[assoc_attr] ||= property_hash } else property_hash = open_api_attr_hash(controller_class, model_class, attr, attr_metadata, opts) property_hash.merge!( description: filter_description(attr_prefix, attr, property_hash, attr_metadata), required: false) next if property_hash.include?(:'$ref') params[:"#{attr_prefix}#{attr}"] ||= property_hash end end add_sort_params(params, model_class, sort_attrs, opts) end
filter_description(attr_prefix, attr, property_hash, attr_metadata)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 104 def filter_description(attr_prefix, attr, property_hash, attr_metadata) return attr_metadata[:filter_description] if attr_metadata[:filter_description].present? desc = "Filter by #{attr_prefix}#{attr}" case property_hash[:type] when :string case property_hash[:format] when :date, :'date-time' "#{desc} (supports <, <=, !=, >= > operator prefixes, comma-delimited criteria)" else "#{desc} (supports comma-delimited values)" end when :boolean "#{desc} (must be true or false)" when :integer, :number "#{desc} (supports comma-delimited values, <, <=, !=, >= > operator prefixes)" else desc end end
open_api_attr_hash(controller_class, model_class, attr, attr_metadata, opts)
click to toggle source
rubocop:disable Metrics/ParameterLists
# File lib/model-api/open_api_extensions.rb, line 198 def open_api_attr_hash(controller_class, model_class, attr, attr_metadata, opts) property_hash = class_model_base_property(model_class, attr, attr_metadata) if (attr_type = attr_metadata[:type]).is_a?(Symbol) && ![:attribute, :association].include?(attr_type) ModelApi::Utils.set_open_api_type_and_format(property_hash, attr_type) else attr_types = opts[:attr_types] || attr_types_from_columns(model_class) if (attr_type = attr_types[attr_metadata[:key]]).present? ModelApi::Utils.set_open_api_type_and_format(property_hash, attr_type) elsif (assoc = model_class.reflect_on_association(attr)).present? property_hash = class_model_assoc_property(property_hash, controller_class, attr_metadata, opts.merge(association: assoc)) end end property_hash[:type] ||= :string unless property_hash.include?(:'$ref') property_hash end
required_attrs_from_validators(model_class)
click to toggle source
# File lib/model-api/open_api_extensions.rb, line 252 def required_attrs_from_validators(model_class) model_class.validators .select { |v| v.is_a?(ActiveRecord::Validations::PresenceValidator) } .map(&:attributes) .flatten end