2024-05-03 03:04:43 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
class ApplicationRecord < ActiveRecord::Base
|
|
|
|
primary_abstract_class
|
|
|
|
|
|
|
|
module ApiMethods
|
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
|
|
|
def as_json(options = {})
|
|
|
|
options ||= {}
|
|
|
|
options[:except] ||= []
|
|
|
|
options[:except] += hidden_attributes
|
|
|
|
|
|
|
|
options[:methods] ||= []
|
|
|
|
options[:methods] += method_attributes
|
|
|
|
|
|
|
|
super(options)
|
|
|
|
end
|
|
|
|
|
|
|
|
def serializable_hash(*args)
|
|
|
|
hash = super(*args)
|
|
|
|
hash.transform_keys { |key| key.delete("?") }
|
|
|
|
end
|
|
|
|
|
|
|
|
protected
|
|
|
|
|
|
|
|
def hidden_attributes
|
|
|
|
%i[uploader_ip_addr updater_ip_addr creator_ip_addr user_ip_addr ip_addr]
|
|
|
|
end
|
|
|
|
|
|
|
|
def method_attributes
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module UserMethods
|
|
|
|
def belongs_to_creator(options = {})
|
|
|
|
field = options.delete(:field) || :creator
|
|
|
|
class_eval do
|
|
|
|
belongs_to(field, **options.merge(class_name: "APIUser"))
|
|
|
|
before_validation(on: :create) do |rec|
|
|
|
|
rec.send("#{field}_id=", CurrentUser.id) if rec.send("#{field}_id").nil?
|
|
|
|
rec.send("#{field}_ip_addr=", CurrentUser.ip_addr) if rec.respond_to?(:"#{field}_ip_addr=") && rec.send("#{field}_ip_addr").nil?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
module SearchMethods
|
|
|
|
def attribute_matches(attribute, value, **)
|
|
|
|
return all if value.nil?
|
|
|
|
|
|
|
|
column = column_for_attribute(attribute)
|
|
|
|
case column.sql_type_metadata.type
|
|
|
|
when :boolean
|
|
|
|
boolean_attribute_matches(attribute, value, **)
|
|
|
|
when :integer, :datetime
|
|
|
|
numeric_attribute_matches(attribute, value, **)
|
|
|
|
when :string, :text
|
|
|
|
text_attribute_matches(attribute, value, **)
|
2024-05-07 06:57:00 +00:00
|
|
|
when :uuid
|
|
|
|
where(attribute => value)
|
2024-05-03 03:04:43 +00:00
|
|
|
else
|
2024-05-07 06:57:00 +00:00
|
|
|
raise(ArgumentError, "unhandled attribute type: #{column.sql_type_metadata.type}")
|
2024-05-03 03:04:43 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def boolean_attribute_matches(attribute, value)
|
|
|
|
if value.to_s.truthy?
|
|
|
|
value = true
|
|
|
|
elsif value.to_s.falsy?
|
|
|
|
value = false
|
|
|
|
else
|
|
|
|
raise(ArgumentError, "value must be truthy or falsy")
|
|
|
|
end
|
|
|
|
|
|
|
|
where(attribute => value)
|
|
|
|
end
|
|
|
|
|
|
|
|
# range: "5", ">5", "<5", ">=5", "<=5", "5..10", "5,6,7"
|
|
|
|
def numeric_attribute_matches(attribute, range)
|
|
|
|
column = column_for_attribute(attribute)
|
|
|
|
qualified_column = "#{table_name}.#{column.name}"
|
|
|
|
parsed_range = ParseValue.range(range, column.type)
|
|
|
|
|
|
|
|
add_range_relation(parsed_range, qualified_column)
|
|
|
|
end
|
|
|
|
|
|
|
|
def add_range_relation(arr, field)
|
|
|
|
return all if arr.nil?
|
|
|
|
|
|
|
|
case arr[0]
|
|
|
|
when :eq
|
|
|
|
if arr[1].is_a?(Time)
|
|
|
|
where("#{field} between ? and ?", arr[1].beginning_of_day, arr[1].end_of_day)
|
|
|
|
else
|
|
|
|
where(["#{field} = ?", arr[1]])
|
|
|
|
end
|
|
|
|
when :gt
|
|
|
|
where(["#{field} > ?", arr[1]])
|
|
|
|
when :gte
|
|
|
|
where(["#{field} >= ?", arr[1]])
|
|
|
|
when :lt
|
|
|
|
where(["#{field} < ?", arr[1]])
|
|
|
|
when :lte
|
|
|
|
where(["#{field} <= ?", arr[1]])
|
|
|
|
when :in
|
|
|
|
where(["#{field} in (?)", arr[1]])
|
|
|
|
when :between
|
|
|
|
where(["#{field} BETWEEN ? AND ?", arr[1], arr[2]])
|
|
|
|
else
|
|
|
|
all
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def text_attribute_matches(attribute, value, convert_to_wildcard: false)
|
|
|
|
column = column_for_attribute(attribute)
|
|
|
|
qualified_column = "#{table_name}.#{column.name}"
|
|
|
|
value = "*#{value}*" if convert_to_wildcard && value.exclude?("*")
|
|
|
|
|
|
|
|
if value =~ /\*/
|
|
|
|
where("lower(#{qualified_column}) LIKE :value ESCAPE E'\\\\'", value: value.downcase.to_escaped_for_sql_like)
|
|
|
|
else
|
|
|
|
where("to_tsvector(:ts_config, #{qualified_column}) @@ plainto_tsquery(:ts_config, :value)", ts_config: "english", value: value)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def apply_basic_order(params)
|
|
|
|
case params[:order]
|
|
|
|
when "id_asc"
|
|
|
|
order(id: :asc)
|
|
|
|
when "id_desc"
|
|
|
|
order(id: :desc)
|
|
|
|
else
|
|
|
|
default_order
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def default_order
|
|
|
|
order(id: :desc)
|
|
|
|
end
|
|
|
|
|
|
|
|
def search(params)
|
|
|
|
params ||= {}
|
|
|
|
|
|
|
|
q = all
|
|
|
|
q = q.attribute_matches(:id, params[:id])
|
|
|
|
q = q.attribute_matches(:created_at, params[:created_at]) if attribute_names.include?("created_at")
|
|
|
|
q = q.attribute_matches(:updated_at, params[:updated_at]) if attribute_names.include?("updated_at")
|
|
|
|
|
|
|
|
q
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
include ApiMethods
|
|
|
|
extend SearchMethods
|
|
|
|
extend UserMethods
|
|
|
|
end
|