demarches-normaliennes/app/models/columns/json_path_column.rb

59 lines
1.8 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
class Columns::JSONPathColumn < Column
def column
"#{@column}->#{value_column}" # override column otherwise json path facets will have same id as other
end
def filtered_ids(dossiers, search_occurences)
queries = Array.new(search_occurences.count, "(#{json_path_query_part} ILIKE ?)").join(' OR ')
dossiers.with_type_de_champ(stable_id)
.where(queries, *(search_occurences.map { |value| "%#{value}%" }))
.ids
end
def options_for_select
case value_column.last
when 'departement_code'
APIGeoService.departements.map { ["#{_1[:code]} #{_1[:name]}", _1[:code]] }
when 'region_name'
APIGeoService.regions.map { [_1[:name], _1[:name]] }
else
[]
end
end
private
def typed_value(champ)
2024-10-29 16:38:17 +01:00
champ.value_json&.dig(*value_column)
end
def stable_id
@column
end
# given a value_column as ['value_json', 'address', 'postal_code']
# build SQL query as 'champs'.'value_json'->'address'->>'postal_code'
# see: https://www.postgresql.org/docs/9.5/functions-json.html
def json_path_query_part
*json_segments, key = value_column
if json_segments.blank? # not nested, only access using ->> Get JSON array element as text
"#{quote_table_column('champs')}.#{quote_table_column('value_json')}->>#{quote_json_segment(key)}"
else # nested, have to dig in json using -> Get JSON object field by key
field_accessor = json_segments.map(&method(:quote_json_segment)).join('->')
"#{quote_table_column('champs')}.#{quote_table_column('value_json')}->#{field_accessor}->>#{quote_json_segment(key)}"
end
end
def quote_table_column(table_or_column)
ActiveRecord::Base.connection.quote_column_name(table_or_column)
end
def quote_json_segment(path)
"'#{path}'"
end
end