2021-04-18 13:34:55 +02:00
# frozen_string_literal: true
2018-12-22 14:26:14 +01:00
module AdditionalsQuery
2023-06-23 12:45:08 +02:00
NO_RESULT_CONDITION = '1=0'
WITH_TRUE_CONDITION = '1=1'
2022-01-30 14:21:43 +01:00
def label_me_value
self . class . label_me_value
end
2020-08-06 08:18:30 +02:00
def column_with_prefix? ( prefix )
2021-04-18 13:34:55 +02:00
columns . detect { | c | c . name . to_s . start_with? " #{ prefix } . " } . present?
2018-12-22 14:26:14 +01:00
end
2022-01-02 08:21:43 +01:00
def available_column_names ( only_sortable : false , only_groupable : false , only_totalable : false , type : nil )
2022-01-01 18:24:42 +01:00
method_name = [ 'available_' ]
if type
method_name << type
method_name << '_'
end
method_name << 'columns'
names = send ( method_name . join ) . dup
2020-08-06 08:18:30 +02:00
names . flatten!
2021-04-18 13:34:55 +02:00
names . select! { | col | col . sortable . present? } if only_sortable
2022-03-30 18:05:59 +02:00
names . select! ( & :groupable? ) if only_groupable
2022-01-02 08:21:43 +01:00
names . select! ( & :totalable ) if only_totalable
2020-08-06 08:18:30 +02:00
names . map ( & :name )
end
2020-05-12 10:50:50 +02:00
2020-08-06 08:18:30 +02:00
def sql_for_enabled_module ( table_field , module_names )
2021-04-18 13:34:55 +02:00
module_names = Array module_names
2019-12-20 12:58:12 +01:00
2020-08-06 08:18:30 +02:00
sql = [ ]
module_names . each do | module_name |
sql << " EXISTS(SELECT 1 FROM #{ EnabledModule . table_name } WHERE #{ EnabledModule . table_name } .project_id= #{ table_field } " \
" AND #{ EnabledModule . table_name } .name=' #{ module_name } ') "
end
2019-05-22 12:26:14 +02:00
2021-04-18 13:34:55 +02:00
sql . join ' AND '
2020-08-06 08:18:30 +02:00
end
2019-05-22 12:26:14 +02:00
2021-01-06 13:18:58 +01:00
def fix_sql_for_text_field ( field , operator , value , table_name = nil , target_field = nil )
table_name = queried_table_name if table_name . blank?
target_field = field if target_field . blank?
sql = [ ]
2021-04-18 13:34:55 +02:00
sql << " ( #{ sql_for_field field , operator , value , table_name , target_field } ) "
2021-01-06 13:18:58 +01:00
sql << " #{ table_name } . #{ target_field } != '' " if operator == '*'
2021-04-18 13:34:55 +02:00
sql . join ' AND '
2021-01-06 13:18:58 +01:00
end
2021-04-18 13:34:55 +02:00
def initialize_ids_filter ( label : nil )
if label
add_available_filter 'ids' , type : :integer , label : label
2020-08-06 08:18:30 +02:00
else
add_available_filter 'ids' , type : :integer , name : '#'
2019-05-22 12:26:14 +02:00
end
2020-08-06 08:18:30 +02:00
end
2019-05-22 12:26:14 +02:00
2020-08-06 08:18:30 +02:00
def sql_for_ids_field ( _field , operator , value )
if operator == '='
# accepts a comma separated list of ids
2023-01-21 10:42:53 +01:00
ids = ids_from_string value . first
2021-09-18 14:47:56 +02:00
if ids . any?
2020-08-08 18:44:40 +02:00
" #{ queried_table_name } .id IN ( #{ ids . join ',' } ) "
2019-02-09 16:39:12 +01:00
else
2023-06-23 12:45:08 +02:00
NO_RESULT_CONDITION
2019-02-09 16:39:12 +01:00
end
2020-08-06 08:18:30 +02:00
else
2020-08-09 12:51:01 +02:00
sql_for_field 'id' , operator , value , queried_table_name , 'id'
2018-12-22 14:26:14 +01:00
end
2020-08-06 08:18:30 +02:00
end
2018-12-22 14:26:14 +01:00
2021-03-09 06:04:39 +01:00
def sql_for_project_identifier_field ( field , operator , values )
value = values . first
2022-06-08 20:01:59 +02:00
values = value . strip_split if [ '=' , '!' ] . include? ( operator ) && value . include? ( ',' )
2021-03-09 06:04:39 +01:00
sql_for_field field , operator , values , Project . table_name , 'identifier'
end
2020-08-06 08:18:30 +02:00
def sql_for_project_status_field ( field , operator , value )
2020-08-09 12:51:01 +02:00
sql_for_field field , operator , value , Project . table_name , 'status'
2020-08-06 08:18:30 +02:00
end
2018-12-22 14:26:14 +01:00
2021-03-09 06:04:39 +01:00
def initialize_project_identifier_filter
return if project
add_available_filter 'project.identifier' ,
type : :string ,
name : l ( :label_attribute_of_project , name : l ( :field_identifier ) )
end
2020-08-06 08:18:30 +02:00
def initialize_project_status_filter
2021-03-09 06:38:28 +01:00
return if project
2019-12-17 16:34:36 +01:00
2020-12-02 19:06:53 +01:00
add_available_filter 'project.status' ,
2020-08-06 08:18:30 +02:00
type : :list ,
name : l ( :label_attribute_of_project , name : l ( :field_status ) ) ,
2020-12-02 19:06:53 +01:00
values : - > { project_statuses_values }
2020-08-06 08:18:30 +02:00
end
2019-12-17 16:34:36 +01:00
2022-01-30 14:21:43 +01:00
def initialize_project_filter ( always : false , position : nil , without_subprojects : false )
2021-04-18 13:34:55 +02:00
if project . nil? || always
add_available_filter 'project_id' , order : position ,
2020-08-06 08:18:30 +02:00
type : :list ,
2020-12-02 19:06:53 +01:00
values : - > { project_values }
2019-12-17 16:34:36 +01:00
end
2022-01-30 14:21:43 +01:00
return if without_subprojects || project . nil? || project . leaf? || subproject_values . empty?
2019-12-17 16:34:36 +01:00
2021-04-18 13:34:55 +02:00
add_available_filter 'subproject_id' , order : position ,
2020-08-06 08:18:30 +02:00
type : :list_subprojects ,
2020-12-02 19:06:53 +01:00
values : - > { subproject_values }
2020-08-06 08:18:30 +02:00
end
2019-02-09 16:39:12 +01:00
2021-04-18 13:34:55 +02:00
def initialize_created_filter ( position : nil , label : nil )
add_available_filter 'created_on' , order : position ,
2020-08-06 08:18:30 +02:00
type : :date_past ,
2021-04-18 13:34:55 +02:00
label : label
2020-08-06 08:18:30 +02:00
end
2019-02-09 16:39:12 +01:00
2021-04-18 13:34:55 +02:00
def initialize_updated_filter ( position : nil , label : nil )
add_available_filter 'updated_on' , order : position ,
2020-08-06 08:18:30 +02:00
type : :date_past ,
2021-04-18 13:34:55 +02:00
label : label
2020-08-06 08:18:30 +02:00
end
2019-02-09 16:39:12 +01:00
2020-08-06 08:18:30 +02:00
def initialize_approved_filter
add_available_filter 'approved' ,
type : :list ,
values : [ [ l ( :label_hrm_approved ) , '1' ] ,
[ l ( :label_hrm_not_approved ) , '0' ] ,
[ l ( :label_hrm_to_approval ) , '2' ] ,
[ l ( :label_hrm_without_approval ) , '3' ] ] ,
label : :field_approved
end
2019-11-19 10:02:07 +01:00
2021-04-18 13:34:55 +02:00
def initialize_author_filter ( position : nil )
2022-02-26 17:39:59 +01:00
add_available_filter 'author_id' , order : position ,
type : :author
2020-08-06 08:18:30 +02:00
end
2019-02-08 18:19:20 +01:00
2021-04-18 13:34:55 +02:00
def initialize_assignee_filter ( position : nil )
2022-02-26 17:39:59 +01:00
add_available_filter 'assigned_to_id' , order : position ,
type : :assignee
2020-08-06 08:18:30 +02:00
end
2019-02-09 16:39:12 +01:00
2021-04-18 13:34:55 +02:00
def initialize_watcher_filter ( position : nil )
2020-11-05 14:39:35 +01:00
return unless User . current . logged?
2019-02-09 16:39:12 +01:00
2022-02-26 17:39:59 +01:00
add_available_filter 'watcher_id' , order : position ,
type : :user_with_me
2020-08-06 08:18:30 +02:00
end
2019-11-15 18:27:16 +01:00
2022-12-07 15:25:45 +01:00
def initialize_last_notes_filter ( order : nil )
options = { type : :date_past ,
label : :label_last_notes }
options [ :order ] = order if order
add_available_filter 'last_notes' , ** options
end
2022-01-30 14:21:43 +01:00
# not required for: assigned_to_id author_id user_id watcher_id updated_by last_updated_by
# this fields are replaced by Query::statement
def values_without_me ( values )
return values unless values . delete 'me'
values << if User . current . logged?
User . current . id . to_s
else
'0'
end
values
end
2022-06-13 07:42:26 +02:00
def initialize_notes_filter ( position : nil )
add_available_filter 'notes' , type : :text , order : position
end
def sql_for_notes_field ( field , operator , value )
subquery = " SELECT 1 FROM #{ Journal . table_name } " \
" WHERE #{ Journal . table_name } .journalized_type=' #{ queried_class } ' " \
" AND #{ Journal . table_name } .journalized_id= #{ queried_table_name } .id " \
" AND ( #{ sql_for_field field , operator . sub ( / ^! / , '' ) , value , Journal . table_name , 'notes' } ) " \
" AND ( #{ Journal . visible_notes_condition User . current , skip_pre_condition : true } ) "
" #{ / ^ ! / .match?(operator) ? 'NOT EXISTS' : 'EXISTS'} ( #{ subquery } )"
end
2022-12-07 15:25:45 +01:00
def sql_for_last_notes_field ( field , operator , value )
journalized_type = queried_class . name
journal_table = Journal . table_name
case operator
2022-12-07 18:09:14 +01:00
when '*' , '!*'
op = operator == '*' ? 'EXISTS' : 'NOT EXISTS'
" #{ op } (SELECT 1 FROM #{ queried_table_name } AS ii INNER JOIN #{ journal_table } " \
" ON #{ journal_table } .journalized_id = ii.id AND #{ journal_table } .journalized_type = ' #{ journalized_type } ' " \
" WHERE #{ queried_table_name } .id = ii.id AND #{ journal_table } .notes IS NOT NULL AND #{ journal_table } .notes != '') "
2022-12-07 15:25:45 +01:00
else
" #{ queried_table_name } .id IN ( " \
" SELECT #{ journal_table } .journalized_id " \
" FROM #{ journal_table } " \
2022-12-07 18:09:14 +01:00
" WHERE #{ journal_table } .journalized_type=' #{ journalized_type } ' AND #{ journal_table } .id IN " \
2022-12-07 15:25:45 +01:00
" (SELECT MAX( #{ journal_table } .id) " \
" FROM #{ journal_table } " \
" WHERE #{ journal_table } .journalized_type=' #{ journalized_type } ' " \
2023-08-01 14:05:42 +02:00
" AND #{ journal_table } .notes IS NOT NULL AND #{ journal_table } .notes != '' " \
2022-12-07 15:25:45 +01:00
" GROUP BY #{ journal_table } .journalized_id) " \
" AND #{ sql_for_field field , operator , value , journal_table , 'created_on' } ) "
end
end
2020-08-06 08:18:30 +02:00
def sql_for_watcher_id_field ( field , operator , value )
watchable_type = queried_class == User ? 'Principal' : queried_class . to_s
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
db_table = Watcher . table_name
" #{ queried_table_name } .id #{ operator == '=' ? 'IN' : 'NOT IN' } " \
2021-06-30 19:30:58 +02:00
" (SELECT #{ db_table } .watchable_id FROM #{ db_table } WHERE #{ db_table } .watchable_type=' #{ watchable_type } ' AND " \
" #{ sql_for_field field , '=' , value , db_table , 'user_id' } ) "
2020-08-06 08:18:30 +02:00
end
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
def sql_for_is_private_field ( _field , operator , value )
2021-04-18 13:34:55 +02:00
if bool_operator operator , value
2020-08-06 08:18:30 +02:00
return '' if value . count > 1
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
" #{ queried_table_name } .is_private = #{ self . class . connection . quoted_true } "
else
2023-06-23 12:45:08 +02:00
return NO_RESULT_CONDITION if value . count > 1
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
" #{ queried_table_name } .is_private = #{ self . class . connection . quoted_false } "
2018-12-22 14:26:14 +01:00
end
2020-08-06 08:18:30 +02:00
end
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
# use for list fields with to values 1 (true) and 0 (false)
def bool_operator ( operator , values )
operator == '=' && values . first == '1' || operator != '=' && values . first != '1'
end
2018-12-22 14:26:14 +01:00
2020-08-06 08:18:30 +02:00
# use for list
def bool_values
[ [ l ( :general_text_yes ) , '1' ] , [ l ( :general_text_no ) , '0' ] ]
end
2018-12-22 14:26:14 +01:00
2022-03-14 18:42:32 +01:00
# all results (without search_string limit)
2020-08-06 08:18:30 +02:00
def query_count
2022-03-14 18:42:32 +01:00
@query_count || = search_string . present? ? objects_scope ( search : search_string ) . count : objects_scope . count
2020-08-06 08:18:30 +02:00
rescue :: ActiveRecord :: StatementInvalid = > e
raise queried_class :: StatementInvalid , e . message if defined? queried_class :: StatementInvalid
2019-09-08 21:53:27 +02:00
2020-08-06 08:18:30 +02:00
raise :: Query :: StatementInvalid , e . message
end
2018-12-22 14:26:14 +01:00
2022-03-14 18:42:32 +01:00
def entries_init_options ( ** options )
# set default limit to export limit, if limit is not set
options [ :limit ] = export_limit unless options . key? :limit
options [ :search ] = search_string if search_string
options
end
# query results
def entries ( ** _ )
raise 'overwrite it'
end
2021-04-18 13:34:55 +02:00
def results_scope ( ** options )
2022-03-30 18:05:59 +02:00
order_option = [ group_by_sort_order , ( options [ :order ] || sort_clause ) ] . flatten! . to_a . compact_blank
2018-12-22 14:26:14 +01:00
2021-04-18 13:34:55 +02:00
objects_scope ( ** options . except ( :order , :limit , :offset ) )
2020-08-06 08:18:30 +02:00
. order ( order_option )
. joins ( joins_for_order_statement ( order_option . join ( ',' ) ) )
. limit ( options [ :limit ] )
. offset ( options [ :offset ] )
rescue :: ActiveRecord :: StatementInvalid = > e
raise queried_class :: StatementInvalid , e . message if defined? queried_class :: StatementInvalid
2019-09-08 21:53:27 +02:00
2020-08-06 08:18:30 +02:00
raise :: Query :: StatementInvalid , e . message
2018-12-22 14:26:14 +01:00
end
2020-09-25 15:16:03 +02:00
2022-04-02 15:50:50 +02:00
# NOTE: alias can be used, if results_scope is not usable (because it was overwritten)
alias additionals_results_scope results_scope
2020-09-25 15:16:03 +02:00
def grouped_name_for ( group_name , replace_fields = { } )
return unless group_name
if grouped? && group_by_column . present?
replace_fields . each do | field , new_name |
return new_name . presence || group_name if group_by_column . name == field
end
end
group_name
end
2018-12-22 14:26:14 +01:00
end