class LoadFromRepositoryProtocolsDatatable < CustomDatatable
# Needed for sanitize_sql_like method
include ActiveRecord::Sanitization::ClassMethods
include InputSanitizeHelper
PREFIXED_ID_SQL = "('#{Protocol::ID_PREFIX}' || COALESCE(\"protocols\".\"parent_id\", \"protocols\".\"id\"))".freeze
def initialize(view, team, user)
super(view)
@team = team
@user = user
end
def sortable_columns
@sortable_columns ||= [
'Protocol.name',
'Protocol.version_number',
'adjusted_parent_id',
'protocol_keywords_str',
'full_username_str',
'Protocol.published_on'
]
end
def searchable_columns
@searchable_columns ||= [
'Protocol.name',
"Protocol.#{PREFIXED_ID_SQL}",
'Protocol.published_on',
'Protocol.version_number',
'ProtocolKeyword.name'
]
end
def as_json(_options = {})
{
draw: dt_params[:draw].to_i,
recordsTotal: get_raw_records_base.distinct.count,
recordsFiltered: records.present? ? records.first.filtered_count : 0,
data: data
}
end
private
# Returns json of current protocols (already paginated)
def data
records.map do |record|
parent = record.parent || record
{
DT_RowId: parent.id,
'0': escape_input(record.name),
'1': record.version_number,
'2': parent.code,
'3': keywords_html(record),
'4': escape_input(record.published_by.full_name),
'5': I18n.l(record.published_on, format: :full)
}
end
end
def new_search_condition(column, value)
model, column = column.split('.', 2)
model = model.constantize
casted_column = case column
when PREFIXED_ID_SQL
::Arel::Nodes::SqlLiteral.new(PREFIXED_ID_SQL)
when 'published_on'
::Arel::Nodes::NamedFunction.new(
'CAST', [Arel.sql("to_char( protocols.published_on, '#{formated_date}' ) AS VARCHAR")]
)
else
::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
end
casted_column.matches("%#{ActiveRecord::Base.sanitize_sql_like(value)}%")
end
def fetch_records
super.select('COUNT("protocols"."id") OVER() AS filtered_count')
end
def get_raw_records_base
original_without_versions = @team.protocols
.left_outer_joins(:published_versions)
.where(protocol_type: Protocol.protocol_types[:in_repository_published_original])
.where(published_versions: { id: nil })
.select(:id)
published_versions = @team.protocols
.where(protocol_type: Protocol.protocol_types[:in_repository_published_version])
.order('parent_id, version_number DESC')
.select('DISTINCT ON (parent_id) id')
Protocol.where("protocols.id IN ((#{original_without_versions.to_sql}) UNION (#{published_versions.to_sql}))")
.active
.with_granted_permissions(@user, ProtocolPermissions::READ)
end
# OVERRIDE - query database for records (this will be
# later paginated and filtered) after that "data" function
# will return json
def get_raw_records
get_raw_records_base
.preload(:parent, :protocol_keywords, user_assignments: %i(user user_role))
.joins('LEFT OUTER JOIN "protocol_protocol_keywords" ' \
'ON "protocol_protocol_keywords"."protocol_id" = "protocols"."id"')
.joins('LEFT OUTER JOIN "protocol_keywords" ' \
'ON "protocol_protocol_keywords"."protocol_keyword_id" = "protocol_keywords"."id"')
.joins('LEFT OUTER JOIN "users" ON "users"."id" = "protocols"."published_by_id"')
.group('"protocols"."id"')
.select(
'"protocols".*',
'COALESCE("protocols"."parent_id", "protocols"."id") AS adjusted_parent_id',
'STRING_AGG(DISTINCT("protocol_keywords"."name"), \', \') AS "protocol_keywords_str"',
'MAX("users"."full_name") AS "full_username_str"'
)
end
# Various helper methods
def keywords_html(record)
if record.protocol_keywords.blank?
"#{I18n.t('protocols.no_keywords')}"
else
res = []
record.protocol_keywords.sort_by { |kw| kw.name.downcase }.each do |kw|
sanitized_kw = sanitize_input(kw.name)
res << "#{sanitized_kw}"
end
res.join(', ')
end
end
end