module Pureapi::Controller
Implement methods use for handle with table records like
-
Pagination
-
Sort
-
Search
-
Include
Constants
- AFTER_REGEX
- BEFORE_REGEX
- FIELD_NAME
Define constants of regex table and column name
- FULLBEFORE_REGEX
- NAME_REGEX
Public Instance Methods
Strong parameters for default advanced search query
# File lib/pureapi/controller.rb, line 622 def advanced_search_params params.permit() end
Begin setup new version of feature comparison conditions
Filter conditions of object criteria
# File lib/pureapi/controller.rb, line 334 def core_cond_filter(objects) # Default +compcond_params+ for query compcond_params = {} # Collaborate params, operators, model to get +compcond_params+ if params[:compconds].is_a?(ActionController::Parameters) compcond_params = parse_compcond_fields(params[:compconds], objects) end # Assign params[:compconds] after parse params[:compconds] = deparse_compcond_fields(compcond_params) # Add conditions of +compcond_params+ to objects objects.compcond_search(compcond_params) end
Begin 3 main API for GET data
Filter list objects contain search, sort, paginate
# File lib/pureapi/controller.rb, line 20 def core_index_filter(objects) # 1. search objects = default_search_filter(objects) # 2. sort and default sort is id.desc objects = default_sort_filter(objects) # 3. conditions (replace for +default_cond|incond_filter+) objects = core_cond_filter(objects) # 4. paginate objects = paging_standard(objects) end
Begin setup of feature comparison conditions
Filter conditions of object criteria Need upgrade calculate compcond_params
# File lib/pureapi/controller.rb, line 247 def default_cond_filter(objects) compcond_params = [] objects.compcond_columns.each do |column_name| Pureapi::Model::COMPARISON_OPERATORS.each do |key, value| compcond_params << [column_name, key].join('.') end end compconds = parse_compconds(params.permit(compconds: compcond_params)[:compconds].to_h, objects.column_names) params[:compconds] = {} compconds.each do |compcond| params[:compconds]["#{compcond[:f]}.#{Pureapi::Model::COMPARISON_OPERATORS_INVERT[compcond[:o]]}"] = compcond[:v] end objects.compconds(compconds) end
Begin setup of feature in conditions (logical)
Filter conditions of object criteria Need upgrade calculate compcond_params
# File lib/pureapi/controller.rb, line 296 def default_incond_filter(objects) logic_params = [] objects.incond_columns.each do |column_name| logic_params << {[column_name, :in].join('.') => []} end logics = parse_logicconds(params.permit(logics: logic_params)[:logics].to_h, objects.column_names) params[:logics] = {} logics.each do |logic| params[:logics]["#{logic[:f]}.#{Pureapi::Model::LOGICAL_OPERATORS_INVERT[logic[:o]]}"] = logic[:v] end objects.logicconds(logics) end
Filter list objects contain search, sort, paginate
# File lib/pureapi/controller.rb, line 32 def default_index_filter(objects) # 1. search # 2. sort and default sort is id.desc objects = default_sort_filter(objects) # 3. conditions objects = default_cond_filter(objects) objects = default_incond_filter(objects) # 4. paginate objects = paging_standard(objects) end
Filter list objects contain search, sort, limit
# File lib/pureapi/controller.rb, line 44 def default_report_filter(objects) # 1. search # 2. sort and default sort is id.desc # 3. conditions objects = default_cond_filter(objects) objects = default_incond_filter(objects) # 4. limit similar paginate end
Begin setup of default_search_filter
Filter searchs of object criteria
# File lib/pureapi/controller.rb, line 212 def default_search_filter(objects) params[:searches] = search_params advanced_search_params.each{|k, v| params[:searches][k] = v} objects = objects.full_search(search_params, advanced_search_params) end
Begin setup of default_sort_filter (.order asc|desc)
Filter orders of object criteria
# File lib/pureapi/controller.rb, line 222 def default_sort_filter(objects) orders = parse_orders(params.permit(orders: [])[:orders], objects.column_names) orders[:id] = :desc if orders.blank? params[:orders] = orders.map{|field, order_type| "#{field}.#{order_type}"}.uniq objects.order(orders) end
# File lib/pureapi/controller.rb, line 375 def deparse_compcond_fields compcond_params # Default results _results = {} # Assign from +compcond_params[:only]+ compcond_params[:only] && compcond_params[:only].each do |item| _results["#{item[:f]}.#{item[:o]}"] = item[:v] end # Assign from +compcond_params[:include]+ compcond_params[:include] && compcond_params[:include].each do |key, item| _results[key] = deparse_compcond_fields(item) end _results end
Hash fields
return String is params query
# File lib/pureapi/controller.rb, line 521 def deparse_fields(fields) return '' unless fields.is_a? Hash _arr = [] if fields[:only].is_a? Array _arr += fields[:only] end if fields[:methods].is_a? Array _arr += fields[:methods] end if fields[:include].is_a?(Hash) && !fields[:include].blank? fields[:include].each do |k, v| _arr << "#{k}{#{deparse_fields(v)}}" end end _arr.join(',') end
Define json filters for params in render json api
# File lib/pureapi/controller.rb, line 157 def filter_jsons { paging: { page: params[:page], per_page: params[:per_page], page_total: params[:page_total], record_total: params[:record_total], next: params[:page] < params[:page_total] ? (params[:page] + 1) : nil, prev: params[:page] > 1 ? (params[:page] - 1) : nil, }, orders: params[:orders] || [], searches: params[:searches] || {}, compconds: params[:compconds] || {}, logics: params[:logics] || {}, fields: params[:fields] || '' } end
return all relations be included by fields
# File lib/pureapi/controller.rb, line 574 def include_relations(fields) result = [] if fields[:include].is_a? Hash fields[:include].each do |k, v| if (v.is_a? Hash) && (v[:include].is_a? Hash) result << { k => include_relations(v)} else result << k end end end result end
Begin feature records_json and record_json which render format json
Merge target from request params, source from model
Arguments:
target: (Hash) source: (Hash)
# File lib/pureapi/controller.rb, line 433 def merge_as_json(target ,source) result = {} if source[:only].is_a?(Array) result[:only] = target[:only].is_a?(Array) ? (target[:only] & source[:only]) : source[:only] end if source[:methods].is_a?(Array) && target[:only].is_a?(Array) result[:methods] = target[:only] & source[:methods] end if source[:include].is_a?(Hash) && target[:include].is_a?(Hash) result[:include] = {} (source[:include].keys & target[:include].keys).each do |k| result[:include][k] = merge_as_json(target[:include][k], source[:include][k]) end end result.delete_if { |k, v| v.blank? } end
# File lib/pureapi/controller.rb, line 590 def merge_includes(target ,source) result = {} target.each do |k, v| result[k] = {} if v.is_a?(Hash) && source[k].is_a?(Hash) if source[k][:only].is_a?(Array) result[k][:only] = v[:only].is_a?(Array) ? (v[:only] & source[k][:only]) : source[k][:only] end if v[:include].is_a?(Hash) && source[k][:include].is_a?(Hash) result[k][:include] = merge_includes(v[:include], source[k][:include]) end end end result.delete_if { |k, v| v.blank? } end
Require length of before and after is equal +before.length == after.length > 1+
# File lib/pureapi/controller.rb, line 545 def openandclose(before, after) results = {} index = 0 results[before[index]] = after[index] before.each_with_index do |value, i| if results[before[index]] > value results[before[index]] = after[i] else index = i results[before[index]] = after[index] end end return results end
Begin declare strong parameters
# File lib/pureapi/controller.rb, line 612 def paging_params params.permit(:page, :per_page) end
Paging standard Criteria model that will be pagination Return criteria_model.paginate and params[:page, :per_page, :page_total]
# File lib/pureapi/controller.rb, line 406 def paging_standard(criteria_model) per_page = [paging_params[:per_page].try(:to_i) || Pureapi::Model::Pagination::DEFAULT_PER_PAGE, 1].max # Paging standard record_total = criteria_model.count per_page = record_total if paging_params[:per_page] == Pureapi::Model::Pagination::INFINITE_PER_PAGE\ && record_total > 0 page_total = (record_total.to_f / per_page).ceil page = validate_page(paging_params[:page].try(:to_i) || 1, page_total) page = [page, 1].max # Assign paging params to params helper params[:page] = page params[:per_page] = per_page params[:page_total] = page_total params[:record_total] = record_total criteria_model.paginate(page: page, per_page: per_page) end
# File lib/pureapi/controller.rb, line 350 def parse_compcond_fields params, model, limit = 10 # Default results _results = {only: [], include: {}} params.keys.each do |key| # Get field and operator from +key+ of model matchs = model.compcond_match(key) if matchs matchs[:v] = params.permit(permit_operator(key, matchs[:o]))[key] _results[:only] << matchs end # Process for belongs_to relations entity = model.of_entities[key.to_sym] if limit > 1 && entity && params[key].is_a?(ActionController::Parameters) _results[:include][key.to_sym] = parse_compcond_fields(params[key], entity, limit - 1) end end _results end
Not use under code because lte => lt matchs = /([a-z0-9_]+).(#{Pureapi::Model::COMPARISON_OPERATORS.keys.join('|')})/.match(key) if matchs && column_names.include?(matchs)
results << {f: matchs[1], o: Pureapi::Model::COMPARISON_OPERATORS[matchs[2].to_sym], v: value}
end
# File lib/pureapi/controller.rb, line 271 def parse_compconds(compconds = {}, column_names = []) results = [] compconds.map do |key, value| splits = key.split('.') if splits.length == 2 && column_names.include?(splits[0]) if splits[1].to_sym == :eq && Pureapi::Model::NULL_OPERATOR_KEYS.include?(value) results << { f: splits[0], o: Pureapi::Model::COMPARISON_OPERATORS[splits[1].to_sym], v: Pureapi::Model::NULL_OPERATORS[value]} else results << {f: splits[0], o: Pureapi::Model::COMPARISON_OPERATORS[splits[1].to_sym], v: value} end end end unless compconds.blank? results end
Methods parse string fields user for as_json Example str = “a,b, c,d,e,f,g{k,l,h{b,i}},w{n, m},j,t{ww, gh, l{bb}}, f{k, mm}, vv” return result = {:only=>[“a”, “b”, “c”, “d”, “e”, “f”, “j”, “vv”], :include=>{“g”=>{:only=>[“k”, “l”], :include=>{“h”=>{:only=>[“b”, “i”]}}}, “w”=>{:only=>[“n”, “m”]}, “t”=>{:only=>[“ww”, “gh”], :include=>{“l”=>{:only=>}}}, “f”=>{:only=>[“k”, “mm”]}}}
# File lib/pureapi/controller.rb, line 481 def parse_fields(str, deep = 2) result = { only: [], include: {} } fullbefore = substr_index(str, FULLBEFORE_REGEX) after = substr_index(str, AFTER_REGEX) if fullbefore.length == after.length if fullbefore.length == 0 result[:only] = str.scan(NAME_REGEX) else kvs = openandclose(fullbefore, after) _kvs = openandclose(substr_index(str, BEFORE_REGEX), after).invert s = 0 kvs.each do |k, v| if s < k result[:only] += str[s..(k - 1)].scan(NAME_REGEX) s = v + 1 elsif s = v + 1 end if k < v && deep > 0 result[:include][str[k..v][NAME_REGEX].to_sym] =\ parse_fields(str[(_kvs[v] + 1)..(v - 1)], deep - 1) end end if s < (str.length - 1) result[:only] += str[s..-1].scan(NAME_REGEX) end end end result[:only] = result[:only].map(&:to_sym) return result.delete_if { |k, v| v.blank? } end
Methods return hash contain full params use for ActiveRecord includes() and ActiveModel::Serializers::JSON as_json()
# File lib/pureapi/controller.rb, line 457 def parse_includes(fields, model, includes_deep_level = 2) _fields = parse_fields(fields, includes_deep_level) if _fields[:only].is_a?(Array) && !_fields[:only].blank? _fields[:methods] = _fields[:only] & model.json_methods _fields[:only] = _fields[:only] & model.column_names.map(&:to_sym) end if _fields[:include].is_a?(Hash) && !_fields[:include].blank? _fields[:include] = merge_includes(_fields[:include], model.asjson_fields) end { includes: include_relations(_fields), as_json: _fields.delete_if { |k, v| v.blank? } } end
References from parse_compconds
methods Upgrade results.push(!value.blank?) >> parse_compconds
# File lib/pureapi/controller.rb, line 315 def parse_logicconds(compconds = {}, column_names = []) results = [] compconds.map do |key, value| next if value.blank? splits = key.split('.') if splits.length == 2 && column_names.include?(splits[0]) results << {f: splits[0], o: Pureapi::Model::LOGICAL_OPERATORS[splits[1].to_sym], v: value} end end unless compconds.blank? results end
array orders contains field.asc or field array column_names contains valid fields return hash of field => sort type (asc, desc)
# File lib/pureapi/controller.rb, line 232 def parse_orders(orders = [], column_names = []) results = {} orders.map do |order| matchs = /(#{FIELD_NAME})\.(asc|desc)/.match(order) || /(#{FIELD_NAME})/i.match(order) results[matchs[1]] = matchs[2] || 'asc' if matchs && column_names.include?(matchs[1]) end unless orders.blank? results end
# File lib/pureapi/controller.rb, line 392 def permit_operator key, operator Pureapi::Model::PERMIT_OPERATORS[operator] ? { key => Pureapi::Model::PERMIT_OPERATORS[operator] } : key end
New version of return json for show action
# File lib/pureapi/controller.rb, line 143 def record_as_json(model, includes_deep_level = 2) options = {} if params.permit(:fields)[:fields] # Get fields from params _fields = parse_fields(params.permit(:fields)[:fields], includes_deep_level) # Merge with as_json_fields of entity options = merge_as_json(_fields, model.class.as_json_fields) end model.as_json(options) end
Return json for show action
# File lib/pureapi/controller.rb, line 107 def record_asjson(model) options = {} if params.permit(:fields)[:fields] jsons = parse_includes(params.permit(:fields)[:fields], model.class) options = jsons[:as_json] if !jsons[:as_json].blank? end options[:only] = options[:only].blank? ? model.class.default_onlyasjsons : options[:only] model.as_json(options) end
Return json for show action
# File lib/pureapi/controller.rb, line 73 def record_json(model, includes_deep_level = 2) options = {} if params.permit(:fields)[:fields] jsons = parse_includes(params.permit(:fields)[:fields], model.class, includes_deep_level) options = jsons[:as_json] if !jsons[:as_json].blank? end options[:only] = options[:only].blank? ? model.class.default_onlyasjsons : options[:only] options[:methods] = model.class.json_methods model.as_json(options) end
New version of return json for index action
# File lib/pureapi/controller.rb, line 121 def records_as_json(criterias, includes_deep_level = 2) options = {} includes = [] if params.permit(:fields)[:fields] # Get fields from params _fields = parse_fields(params.permit(:fields)[:fields], includes_deep_level) # Merge with as_json_fields of entity options = merge_as_json(_fields, criterias.as_json_fields) # Get relations for includes includes += include_relations(options) end # Reflect options to params params[:fields] = deparse_fields(options) # Get relations for includes from methods includes += criterias.json_method_includes.slice(*options[:methods]).values if !options[:methods].blank? criterias.includes(includes).as_json(options) end
Return json for index action
# File lib/pureapi/controller.rb, line 88 def records_asjson(criterias) options = {} includes = [] if params.permit(:fields)[:fields] jsons = parse_includes(params.permit(:fields)[:fields], criterias) includes += jsons[:includes] if !jsons[:includes].blank? options = jsons[:as_json] if !jsons[:as_json].blank? end params[:fields] = deparse_fields(options) options[:only] = options[:only].blank? ? criterias.default_onlyasjsons : options[:only] includes += criterias.json_method_includes.slice(*options[:methods]).values if !options[:methods].blank? criterias.includes(includes.uniq).as_json(options) end
Return json for index action
# File lib/pureapi/controller.rb, line 54 def records_json(criterias, includes_deep_level = 2) options = {} includes = criterias.default_includes if params.permit(:fields)[:fields] jsons = parse_includes(params.permit(:fields)[:fields], criterias, includes_deep_level) includes += jsons[:includes] if !jsons[:includes].blank? options = jsons[:as_json] if !jsons[:as_json].blank? end params[:fields] = deparse_fields(options) options[:methods] = criterias.json_methods options[:only] = options[:only].blank? ? criterias.default_onlyasjsons : options[:only] criterias = criterias.includes(includes) if !includes.blank? criterias.as_json(options) end
# File lib/pureapi/controller.rb, line 175 def report_filter_jsons { searches: params[:searches] || {}, compconds: params[:compconds] || {}, logics: params[:logics] || {}, } end
Strong parameters for default search query
# File lib/pureapi/controller.rb, line 617 def search_params params.permit() end
Begin options API for GET data
Filter list objects contain search, sort, paginate
# File lib/pureapi/controller.rb, line 186 def standard_index_filter(objects) # 1. search objects = default_search_filter(objects) # 2. sort and default sort is id.desc objects = default_sort_filter(objects) # 3. conditions objects = default_cond_filter(objects) objects = default_incond_filter(objects) # 4. paginate objects = paging_standard(objects) end
return Array all index of sub_str in str
# File lib/pureapi/controller.rb, line 563 def substr_index(str, sub_str) i = 0 all = [] while (i = str.index(sub_str, i)).is_a? Integer all << i i += str[i..-1][sub_str].length end all end
Begin setup of paging_standard. If not use will_paginate, write in mode class
Method validate page number (like page params)
# File lib/pureapi/controller.rb, line 399 def validate_page(page, page_total) page.blank? || page <= 0 ? 1 : (page > page_total ? page_total : page) end
Filter list objects contain search, sort
# File lib/pureapi/controller.rb, line 199 def without_paging_index_filter(objects) # 1. search objects = default_search_filter(objects) # 2. sort and default sort is id.desc objects = default_sort_filter(objects) # 3. conditions objects = default_cond_filter(objects) objects = default_incond_filter(objects) end