module StandardAPI::Helpers

Public Instance Methods

association_cache_key(record, relation, subincludes) click to toggle source
# File lib/standard_api/helpers.rb, line 93
def association_cache_key(record, relation, subincludes)
  timestamp = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
  timestamp = (timestamp & record.class.column_names).map! { |col| record.send(col) }
  timestamp = timestamp.max

  case association = record.class.reflect_on_association(relation)
  when ActiveRecord::Reflection::HasManyReflection, ActiveRecord::Reflection::HasAndBelongsToManyReflection, ActiveRecord::Reflection::HasOneReflection, ActiveRecord::Reflection::ThroughReflection
    "#{record.model_name.cache_key}/#{record.id}/#{includes_to_cache_key(relation, subincludes)}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
  when ActiveRecord::Reflection::BelongsToReflection
    klass = association.options[:polymorphic] ? record.send(association.foreign_type).constantize : association.klass
    if subincludes.empty?
      "#{klass.model_name.cache_key}/#{record.send(association.foreign_key)}-#{timestamp.utc.to_s(klass.cache_timestamp_format)}"
    else
      "#{klass.model_name.cache_key}/#{record.send(association.foreign_key)}/#{digest_hash(sort_hash(subincludes))}-#{timestamp.utc.to_s(klass.cache_timestamp_format)}"
    end
  else
    raise ArgumentError, 'Unkown association type'
  end
end
cache_key(record, includes) click to toggle source
# File lib/standard_api/helpers.rb, line 73
def cache_key(record, includes)
  timestamp_keys = ['cached_at'] + record.class.column_names.select{|x| x.ends_with? "_cached_at"}
  if includes.empty?
    record.cache_key(*timestamp_keys)
  else
    timestamp = timestamp_keys.map { |attr| record[attr]&.to_time }.compact.max
    "#{record.model_name.cache_key}/#{record.id}-#{digest_hash(sort_hash(includes))}-#{timestamp.utc.to_s(record.cache_timestamp_format)}"
  end
end
cached_at_columns_for_includes(includes) click to toggle source
# File lib/standard_api/helpers.rb, line 113
def cached_at_columns_for_includes(includes)
  includes.select { |k,v| !['when', 'where', 'limit', 'order', 'distinct', 'distinct_on'].include?(k) }.map do |k, v|
    ["#{k}_cached_at"] + cached_at_columns_for_includes(v).map { |v2| "#{k}_#{v2}" }
  end.flatten
end
can_cache?(klass, includes) click to toggle source
# File lib/standard_api/helpers.rb, line 64
def can_cache?(klass, includes)
  cache_columns = ['cached_at'] + cached_at_columns_for_includes(includes)
  if (cache_columns - klass.column_names).empty?
    true
  else
    false
  end
end
can_cache_relation?(record, relation, subincludes) click to toggle source
# File lib/standard_api/helpers.rb, line 83
def can_cache_relation?(record, relation, subincludes)
  return false if record.new_record?
  cache_columns = ["#{relation}_cached_at"] + cached_at_columns_for_includes(subincludes).map {|c| "#{relation}_#{c}"}
  if (cache_columns - record.class.column_names).empty?
    true
  else
    false
  end
end
digest_hash(*hashes) click to toggle source
# File lib/standard_api/helpers.rb, line 138
def digest_hash(*hashes)
  hashes.compact!
  hashes.map! { |h| sort_hash(h) }

  digest =  Digest::MD5.new()
  hashes.each do |hash|
    hash.each do |key, value|
      digest << key.to_s
      if value.is_a?(Hash)
        digest << digest_hash(value)
      else
        digest << value.to_s
      end
    end
  end

  digest.hexdigest
end
includes_to_cache_key(relation, subincludes) click to toggle source
# File lib/standard_api/helpers.rb, line 119
def includes_to_cache_key(relation, subincludes)
  if subincludes.empty?
    relation.to_s
  else
    "#{relation}-#{digest_hash(sort_hash(subincludes))}"
  end
end
json_column_type(sql_type) click to toggle source
# File lib/standard_api/helpers.rb, line 157
def json_column_type(sql_type)
  case sql_type
  when 'timestamp without time zone'
    'datetime'
  when 'time without time zone'
    'datetime'
  when 'text'
    'string'
  when 'json'
    'hash'
  when 'bigint'
    'integer'
  when 'integer'
    'integer'
  when 'jsonb'
    'hash'
  when 'inet'
    'string' # TODO: should be inet
  when 'hstore'
    'hash'
  when 'date'
    'datetime'
  when /numeric(\(\d+(,\d+)?\))?/
    'decimal'
  when 'double precision'
    'decimal'
  when 'ltree'
   'string'
  when 'boolean'
    'boolean'
  when 'uuid' # TODO: should be uuid
    'string'
  when /character varying(\(\d+\))?/
    'string'
  when /^geometry/
    'ewkb'
  end
end
model_partial(record) click to toggle source
# File lib/standard_api/helpers.rb, line 56
def model_partial(record)
  if lookup_context.exists?(record.model_name.element, record.model_name.plural, true)
    [record.model_name.plural, record.model_name.element].join('/')
  else
    'application/record'
  end
end
preloadables(record, includes) click to toggle source
# File lib/standard_api/helpers.rb, line 4
def preloadables(record, includes)
  preloads = {}

  includes.each do |key, value|
    if reflection = record.klass.reflections[key]
      case value
      when true
        preloads[key] = value
      when Hash, ActiveSupport::HashWithIndifferentAccess
        if !value.keys.any? { |x| ['when', 'where', 'limit', 'offset', 'order', 'distinct'].include?(x) }
          if !reflection.polymorphic?
            preloads[key] = preloadables_hash(reflection.klass, value)
          end
        end
      end
    end
  end

  preloads.empty? ? record : record.preload(preloads)
end
preloadables_hash(klass, iclds) click to toggle source
# File lib/standard_api/helpers.rb, line 25
def preloadables_hash(klass, iclds)
  preloads = {}

  iclds.each do |key, value|
    if reflection = klass.reflections[key]
      case value
      when true
        preloads[key] = value
      when Hash, ActiveSupport::HashWithIndifferentAccess
        if !value.keys.any? { |x| ['when', 'where', 'limit', 'offset', 'order', 'distinct'].include?(x) }
          if !reflection.polymorphic?
            preloads[key] = preloadables_hash(reflection.klass, value)
          end
        end
      end
    end
  end

  preloads
end
schema_partial(model) click to toggle source
# File lib/standard_api/helpers.rb, line 46
def schema_partial(model)
  path = model.model_name.plural

  if lookup_context.exists?("schema", path, true)
    [path, "schema"].join('/')
  else
    'application/schema'
  end
end
sort_hash(hash) click to toggle source
# File lib/standard_api/helpers.rb, line 127
def sort_hash(hash)
  hash.keys.sort.reduce({}) do |seed, key|
    if seed[key].is_a?(Hash)
      seed[key] = sort_hash(hash[key])
    else
      seed[key] = hash[key]
    end
    seed
  end
end