noventius 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +22 -0
- data/app/assets/javascripts/nuntius/application.js +39 -0
- data/app/assets/javascripts/nuntius/columns.js +57 -0
- data/app/assets/javascripts/nuntius/filters/select.js +88 -0
- data/app/assets/javascripts/nuntius/filters.js +44 -0
- data/app/assets/javascripts/nuntius/forms.js +38 -0
- data/app/assets/javascripts/nuntius/nested.js +25 -0
- data/app/assets/javascripts/nuntius/reports.js +7 -0
- data/app/assets/stylesheets/nuntius/application.css +36 -0
- data/app/assets/stylesheets/nuntius/nested.css +8 -0
- data/app/assets/stylesheets/nuntius/reports.css +17 -0
- data/app/controllers/concerns/nuntius/filter_params.rb +23 -0
- data/app/controllers/nuntius/application_controller.rb +17 -0
- data/app/controllers/nuntius/reports_controller.rb +45 -0
- data/app/helpers/concerns/nuntius/filter_wrappers.rb +86 -0
- data/app/helpers/nuntius/alerts_helper.rb +48 -0
- data/app/helpers/nuntius/application_helper.rb +19 -0
- data/app/helpers/nuntius/cells_helper.rb +24 -0
- data/app/helpers/nuntius/columns_helper.rb +47 -0
- data/app/helpers/nuntius/filters_helper.rb +147 -0
- data/app/helpers/nuntius/forms_helper.rb +18 -0
- data/app/helpers/nuntius/rows_helper.rb +21 -0
- data/app/views/layouts/nuntius/application.html.erb +21 -0
- data/app/views/nuntius/reports/_filter.erb +10 -0
- data/app/views/nuntius/reports/_form.erb +26 -0
- data/app/views/nuntius/reports/_table.erb +21 -0
- data/app/views/nuntius/reports/index.erb +0 -0
- data/app/views/nuntius/reports/nested.erb +1 -0
- data/app/views/nuntius/reports/show.erb +8 -0
- data/app/views/shared/nuntius/_header.erb +16 -0
- data/config/initializers/assets.rb +1 -0
- data/config/routes.rb +5 -0
- data/lib/nuntius/column.rb +64 -0
- data/lib/nuntius/columns_group.rb +38 -0
- data/lib/nuntius/engine.rb +15 -0
- data/lib/nuntius/extensions/date_query.rb +62 -0
- data/lib/nuntius/filter.rb +46 -0
- data/lib/nuntius/post_processors/date_ranges.rb +120 -0
- data/lib/nuntius/report/dsl/columns.rb +132 -0
- data/lib/nuntius/report/dsl/filters.rb +50 -0
- data/lib/nuntius/report/dsl/nested.rb +66 -0
- data/lib/nuntius/report/dsl/post_processors.rb +40 -0
- data/lib/nuntius/report/dsl/validations.rb +40 -0
- data/lib/nuntius/report/dsl.rb +42 -0
- data/lib/nuntius/report/interpolator.rb +75 -0
- data/lib/nuntius/report.rb +81 -0
- data/lib/nuntius/serializers/csv.rb +54 -0
- data/lib/nuntius/validation.rb +30 -0
- data/lib/nuntius/version.rb +5 -0
- data/lib/nuntius.rb +13 -0
- data/lib/tasks/nuntius_tasks.rake +4 -0
- metadata +251 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
module ColumnsHelper
|
4
|
+
|
5
|
+
def column_table_header_tag(column)
|
6
|
+
options = column.html_options.deep_merge(colspan: column.html_options.fetch(:colspan, 1),
|
7
|
+
rowspan: column.html_options.fetch(:rowspan, 1),
|
8
|
+
class: class_for_column_header(column),
|
9
|
+
data: data_for_column_header(column))
|
10
|
+
|
11
|
+
content_tag(:th, column.label, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def number_of_header_levels(columns)
|
15
|
+
columns.map(&:depth).max
|
16
|
+
end
|
17
|
+
|
18
|
+
def header_columns_for_level(columns, level)
|
19
|
+
if level == 0
|
20
|
+
columns
|
21
|
+
else
|
22
|
+
columns.select { |column| column.is_a?(ColumnsGroup) }
|
23
|
+
.flat_map { |column| column.columns_for_level(level) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def class_for_column_header(column)
|
28
|
+
css_class = if column.is_a?(Column)
|
29
|
+
'column-header'
|
30
|
+
elsif column.is_a?(ColumnsGroup)
|
31
|
+
'column-group-header'
|
32
|
+
end
|
33
|
+
|
34
|
+
[column.html_options[:class], css_class].compact.join(' ')
|
35
|
+
end
|
36
|
+
|
37
|
+
def data_for_column_header(column)
|
38
|
+
if column.is_a?(Column)
|
39
|
+
{ type: column.type }
|
40
|
+
elsif column.is_a?(ColumnsGroup)
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# rubocop:disable all
|
2
|
+
module Nuntius
|
3
|
+
|
4
|
+
module FiltersHelper
|
5
|
+
|
6
|
+
include Nuntius::FilterWrappers
|
7
|
+
|
8
|
+
RESERVED_OPTIONS = [:dependent]
|
9
|
+
|
10
|
+
def filter_tag(filter, report, options = {})
|
11
|
+
tag_options = set_current_filter_value(filter, report)
|
12
|
+
tag_options = merge_filter_options(filter, options, tag_options)
|
13
|
+
tag_options = add_filter_options(filter, report, tag_options)
|
14
|
+
|
15
|
+
send(:"#{filter.type}_filter_tag", scope_name(filter.name), tag_options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def class_for_filter_wrapper(filter)
|
19
|
+
classes = ['form-group']
|
20
|
+
|
21
|
+
if filter.type == :select
|
22
|
+
classes << 'select-filter-wrapper'
|
23
|
+
end
|
24
|
+
|
25
|
+
classes.join(' ')
|
26
|
+
end
|
27
|
+
|
28
|
+
def class_for_filter(filter)
|
29
|
+
classes = ['nuntius-filter']
|
30
|
+
|
31
|
+
unless filter.type == :select
|
32
|
+
classes << 'form-control'
|
33
|
+
end
|
34
|
+
|
35
|
+
classes.join(' ')
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_current_filter_value(filter, report)
|
39
|
+
tag_options = filter.args.dup
|
40
|
+
current_value = report.filter_params[filter.name]
|
41
|
+
|
42
|
+
case filter.type
|
43
|
+
when :select
|
44
|
+
tag_options[:option_tags] = compile_select_option_tags(filter, report)
|
45
|
+
when :check_box
|
46
|
+
tag_options[:checked] = current_value == (tag_options[:value] || DEFAULT_CHECK_BOX_VALUE)
|
47
|
+
when :radio_button
|
48
|
+
tag_options[:checked] = current_value == (tag_options[:value] || DEFAULT_RADIO_BUTTON_VALUE)
|
49
|
+
when :text_area
|
50
|
+
tag_options[:content] = current_value || tag_options[:content]
|
51
|
+
else
|
52
|
+
tag_options[:value] = current_value || tag_options[:value]
|
53
|
+
end
|
54
|
+
|
55
|
+
tag_options
|
56
|
+
end
|
57
|
+
|
58
|
+
def compile_select_option_tags(filter, report)
|
59
|
+
option_tags = filter.args[:option_tags]
|
60
|
+
option_tags = option_tags.is_a?(Symbol) ? report.send(option_tags) : option_tags
|
61
|
+
current_value = report.filter_params[filter.name]
|
62
|
+
|
63
|
+
if filter.args[:dependent].present? && option_tags.is_a?(Hash)
|
64
|
+
return ''
|
65
|
+
elsif filter.args[:dependent].present?
|
66
|
+
fail ArgumentError, 'when a dependent select option_tags can only be a Hash.'
|
67
|
+
end
|
68
|
+
|
69
|
+
if option_tags.is_a?(String)
|
70
|
+
option_tags.html_safe
|
71
|
+
elsif option_tags.is_a?(Array)
|
72
|
+
if option_tags.size == 1 || option_tags.size == 2
|
73
|
+
if option_tags.size == 2
|
74
|
+
option_tags[1] = current_value || option_tags[1]
|
75
|
+
else
|
76
|
+
option_tags << current_value
|
77
|
+
end
|
78
|
+
options_for_select(*option_tags)
|
79
|
+
elsif option_tags.size == 3 || option_tags.size == 4
|
80
|
+
if option_tags.size == 4
|
81
|
+
option_tags[3] = current_value || option_tags[3]
|
82
|
+
else
|
83
|
+
option_tags << current_value
|
84
|
+
end
|
85
|
+
options_from_collection_for_select(*option_tags)
|
86
|
+
else
|
87
|
+
fail ArgumentError, 'option_tags can only be a String, an Array(max size 4) or a Symbol.'
|
88
|
+
end
|
89
|
+
else
|
90
|
+
fail ArgumentError, 'option_tags can only be a String, an Array(max size 4) or a Symbol.'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
protected
|
95
|
+
|
96
|
+
def merge_filter_options(filter, options, tag_options)
|
97
|
+
tag_options.delete_if { |k, _| RESERVED_OPTIONS.include?(k) }
|
98
|
+
|
99
|
+
(tag_options[:options] ||= {}).each do |k, v|
|
100
|
+
opt = options.delete(k)
|
101
|
+
next unless opt
|
102
|
+
|
103
|
+
case v.class.to_s
|
104
|
+
when String.to_s
|
105
|
+
v << ' ' << opt
|
106
|
+
when Array.to_s
|
107
|
+
v.concat(opt)
|
108
|
+
when Hash.to_s
|
109
|
+
v.merge!(opt)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
tag_options[:options].merge!(options)
|
113
|
+
|
114
|
+
tag_options
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_filter_options(filter, report, tag_options)
|
118
|
+
tag_options = (tag_options || {}).dup
|
119
|
+
tag_options[:options] ||= {}
|
120
|
+
|
121
|
+
if filter.type == :select
|
122
|
+
include_blank = (filter.args[:options] || {})[:include_blank]
|
123
|
+
|
124
|
+
tag_options[:options].deep_merge!(data: { include_blank: include_blank })
|
125
|
+
end
|
126
|
+
|
127
|
+
if filter.type == :select && filter.args[:dependent].present?
|
128
|
+
options = filter.args[:option_tags]
|
129
|
+
options = options.is_a?(Symbol) ? report.send(options) : options
|
130
|
+
current_value = report.filter_params[filter.name]
|
131
|
+
|
132
|
+
options = options.inject({}) do |result, (key, value)|
|
133
|
+
result.merge(Array(key).join('_!_') => value)
|
134
|
+
end
|
135
|
+
|
136
|
+
tag_options[:options].deep_merge!(disabled: true,
|
137
|
+
data: { dependent: filter.args[:dependent],
|
138
|
+
options: options, current_value: current_value })
|
139
|
+
end
|
140
|
+
|
141
|
+
tag_options
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
end
|
147
|
+
# rubocop:enable all
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
module FormsHelper
|
4
|
+
|
5
|
+
def compile_filters(filters)
|
6
|
+
filters.each_with_object({}) { |filter, memo| memo.merge!(scope_keys(filter.to_js)) }
|
7
|
+
end
|
8
|
+
|
9
|
+
def compile_validations(validations)
|
10
|
+
validations.each_with_object(rules: {}, messages: {}) do |validation, memo|
|
11
|
+
memo[:rules].merge!(scope_keys(validation.to_js[:rules]))
|
12
|
+
memo[:messages].merge!(scope_keys(validation.to_js[:messages]))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
module RowsHelper
|
4
|
+
|
5
|
+
def row_tag(row, report, &block)
|
6
|
+
options = { data: data_for_row(row, report) }
|
7
|
+
|
8
|
+
content_tag(:tr, options, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def data_for_row(row, report)
|
12
|
+
return unless report.enable_nested?
|
13
|
+
|
14
|
+
{ nested: { url: nested_report_path(name: report.class.name),
|
15
|
+
row: row,
|
16
|
+
filters: { q: report.filter_params } } }
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Nuntius</title>
|
5
|
+
<%= stylesheet_link_tag "nuntius/application", media: "all" %>
|
6
|
+
<%= csrf_meta_tags %>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<header>
|
10
|
+
<%= render partial: 'shared/nuntius/header' %>
|
11
|
+
</header>
|
12
|
+
<main>
|
13
|
+
<div class='container-fluid'>
|
14
|
+
<%= flash_alert %>
|
15
|
+
<%= yield %>
|
16
|
+
</div>
|
17
|
+
</main>
|
18
|
+
<footer></footer>
|
19
|
+
<%= javascript_include_tag 'nuntius/application' %>
|
20
|
+
</body>
|
21
|
+
</html>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<% if filter.options[:icon].present? %>
|
2
|
+
<div class="input-group">
|
3
|
+
<%= filter_tag filter, report, class: class_for_filter(filter) %>
|
4
|
+
<span class="input-group-addon">
|
5
|
+
<span class="glyphicon glyphicon-<%= filter.options[:icon] %>"></span>
|
6
|
+
</span>
|
7
|
+
</div>
|
8
|
+
<% else %>
|
9
|
+
<%= filter_tag filter, report, class: class_for_filter(filter) %>
|
10
|
+
<% end %>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<script>
|
2
|
+
var FILTERS = <%= raw compile_filters(report.filters).to_json %>;
|
3
|
+
var FILTER_PARAMS = <%= raw scope_keys(filter_params).to_json %>;
|
4
|
+
var VALIDATIONS = <%= raw compile_validations(report.validations).to_json %>
|
5
|
+
</script>
|
6
|
+
|
7
|
+
<%= form_tag report_path(name: report.class.name), id: 'filter-form', method: :get, class: 'form-inline' do %>
|
8
|
+
<%= hidden_field_tag :format, :html %>
|
9
|
+
|
10
|
+
<% report.filters.each do |filter| %>
|
11
|
+
<div class='<%= class_for_filter_wrapper(filter) %>'>
|
12
|
+
<%= label_tag filter.name, nil, class: 'control-label' %>
|
13
|
+
<%= render partial: 'filter', locals: { filter: filter, report: report } %>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
<div>
|
17
|
+
<div class='form-group pull-right'>
|
18
|
+
<%= submit_tag 'Filter', class: 'btn btn-success' %>
|
19
|
+
<%= link_to '#', class: 'btn btn-default download' do %>
|
20
|
+
<i class='glyphicon glyphicon-download-alt'></i>
|
21
|
+
Download
|
22
|
+
<% end %>
|
23
|
+
</div>
|
24
|
+
<div class='clearfix'></div>
|
25
|
+
</div>
|
26
|
+
<% end %>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<% nested = local_assigns.fetch(:nested, false) %>
|
2
|
+
<table class='table table-hover <%= 'nested' if nested %>'>
|
3
|
+
<thead>
|
4
|
+
<% number_of_header_levels(report.columns).times do |level| %>
|
5
|
+
<tr>
|
6
|
+
<% header_columns_for_level(report.columns, level).each do |column| %>
|
7
|
+
<%= column_table_header_tag(column) %>
|
8
|
+
<% end %>
|
9
|
+
</tr>
|
10
|
+
<% end %>
|
11
|
+
</thead>
|
12
|
+
<tbody>
|
13
|
+
<% report.processed_rows.each do |row| %>
|
14
|
+
<%= row_tag(row, report) do %>
|
15
|
+
<% report.columns_without_groups.each do |column|%>
|
16
|
+
<%= cell_tag(cell_for_row_column(report, row, column)) %>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
</tbody>
|
21
|
+
</table>
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= render partial: 'table', locals: { report: @nested_report, nested: true } %>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<nav class="navbar navbar-default">
|
2
|
+
<div class="container-fluid">
|
3
|
+
<div class="navbar-header">
|
4
|
+
<a class="navbar-brand" href='#'>
|
5
|
+
Reports
|
6
|
+
</a>
|
7
|
+
</div>
|
8
|
+
</div>
|
9
|
+
<ul class="nav nav-tabs">
|
10
|
+
<%- reports.each do |report| %>
|
11
|
+
<li class="<%= report == @report.class ? 'active' : '' %>">
|
12
|
+
<%= link_to report.tab_title, report_path(name: report.name) %>
|
13
|
+
</li>
|
14
|
+
<%- end %>
|
15
|
+
</ul>
|
16
|
+
</nav>
|
@@ -0,0 +1 @@
|
|
1
|
+
Nuntius::Engine.config.assets.paths << Nuntius::Engine.root.join('vendor', 'assets', 'bower_components')
|
data/config/routes.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
class Column
|
4
|
+
|
5
|
+
TYPES = %i(string integer float datetime date)
|
6
|
+
|
7
|
+
attr_reader :name, :type, :label
|
8
|
+
|
9
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
10
|
+
def initialize(name, type, options = {})
|
11
|
+
fail ArgumentError, "ColumnType: [#{type}] not yet implemented." unless TYPES.include?(type.to_sym)
|
12
|
+
|
13
|
+
@name = name.to_sym
|
14
|
+
@type = type.to_sym
|
15
|
+
@label = options.delete(:label) || @name.to_s
|
16
|
+
@label = instance_exec(&@label) if @label.is_a?(Proc)
|
17
|
+
@default_value = options[:default_value] || default_value_for_type
|
18
|
+
@value = options[:value] || default_value_block(@name, @default_value)
|
19
|
+
@options = options
|
20
|
+
@children = options[:children] || []
|
21
|
+
end
|
22
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
23
|
+
|
24
|
+
def html_options
|
25
|
+
@options[:html_options] || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
def value(report, row)
|
29
|
+
if @value.is_a?(Proc)
|
30
|
+
report.instance_exec(row, &@value)
|
31
|
+
elsif @value.is_a?(Symbol)
|
32
|
+
report.public_send(@value, row)
|
33
|
+
else
|
34
|
+
@value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def depth
|
39
|
+
1
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def default_value_block(name, default_value)
|
45
|
+
lambda do |row|
|
46
|
+
if row.is_a?(Hash)
|
47
|
+
row[name.to_s] || row[name.to_sym]
|
48
|
+
else
|
49
|
+
row[column_index(name.to_sym)]
|
50
|
+
end || default_value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def default_value_for_type
|
55
|
+
case @type
|
56
|
+
when :integer then 0
|
57
|
+
when :float then 0.0
|
58
|
+
else ''
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
class ColumnsGroup
|
4
|
+
|
5
|
+
attr_reader :name, :columns, :label
|
6
|
+
|
7
|
+
def initialize(name, columns, options = {})
|
8
|
+
@name = name.to_sym
|
9
|
+
@columns = columns
|
10
|
+
@label = options.delete(:label) || @name.to_s
|
11
|
+
@label = instance_exec(&@label) if @label.is_a?(Proc)
|
12
|
+
@options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def html_options
|
16
|
+
@options[:html_options] || {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def deep_dup
|
20
|
+
Marshal.load(Marshal.dump(self))
|
21
|
+
end
|
22
|
+
|
23
|
+
def depth
|
24
|
+
1 + (@columns.map(&:depth).max || 0)
|
25
|
+
end
|
26
|
+
|
27
|
+
def columns_for_level(level)
|
28
|
+
if level == 1
|
29
|
+
@columns
|
30
|
+
else
|
31
|
+
@columns.select { |column| column.is_a?(ColumnsGroup) }
|
32
|
+
.flat_map { |child| child.columns_for_level(level - 1) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
module Extension
|
4
|
+
|
5
|
+
module DateQuery
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.send :include, InstanceMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
|
18
|
+
SQL_FUNCTIONS = {
|
19
|
+
'month' => "DATE_TRUNC('month', <%column%>::timestamptz AT TIME ZONE {time_zone})",
|
20
|
+
'day' => "DATE_TRUNC('day', <%column%>::timestamptz AT TIME ZONE {time_zone})",
|
21
|
+
'dow' => 'EXTRACT(DOW from <%column%>::timestamptz AT TIME ZONE {time_zone})::integer',
|
22
|
+
'hour' => 'EXTRACT(HOUR from <%column%>::timestamptz AT TIME ZONE {time_zone})::integer',
|
23
|
+
'moy' => 'EXTRACT(MONTH from <%column%>::timestamptz AT TIME ZONE {time_zone})::integer'
|
24
|
+
}
|
25
|
+
|
26
|
+
# The different component that can be extracted from a timestamp
|
27
|
+
#
|
28
|
+
# @return [Hash] The components
|
29
|
+
def date_extract_options
|
30
|
+
[
|
31
|
+
{
|
32
|
+
'Day' => 'day',
|
33
|
+
'Month' => 'month',
|
34
|
+
'Day of week' => 'dow',
|
35
|
+
'Hour of day' => 'hour',
|
36
|
+
'Month of year' => 'moy'
|
37
|
+
}
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
# SQL function for the extraction of the desired timestamp component
|
42
|
+
#
|
43
|
+
# @param [String] component The Date component to extract
|
44
|
+
# @param [String] column The column that has the timestamp
|
45
|
+
# @param [String] time_zone The time_zone of the timestamp. Default: 'America/Montevideo'
|
46
|
+
#
|
47
|
+
# @return [String] The SQL function
|
48
|
+
def date_extract(component:, column:, time_zone: 'America/Montevideo')
|
49
|
+
sql_function = SQL_FUNCTIONS[component].dup
|
50
|
+
|
51
|
+
Class.new(OpenStruct) {
|
52
|
+
include Nuntius::Report::Interpolator
|
53
|
+
}.new(column: column, time_zone: time_zone).interpolate(sql_function)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Nuntius
|
2
|
+
|
3
|
+
class Filter
|
4
|
+
|
5
|
+
RESERVED_ARGS = %i(icon priority)
|
6
|
+
DEFAULT_RESERVED_ARGS = { priority: 0 }
|
7
|
+
TYPES = %i(check_box color date datetime email month number phone radio_button range search select
|
8
|
+
telephone text_area text url week)
|
9
|
+
|
10
|
+
attr_reader :name, :type, :args, :options
|
11
|
+
|
12
|
+
def initialize(name, type, dirty_args = {})
|
13
|
+
fail ArgumentError, "FilterType: [#{type}] not yet implemented." unless TYPES.include?(type.to_sym)
|
14
|
+
|
15
|
+
@name = name.to_sym
|
16
|
+
@type = type.to_sym
|
17
|
+
@args = clean_args(dirty_args)
|
18
|
+
@options = DEFAULT_RESERVED_ARGS.merge(reserved_args(dirty_args))
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_js
|
22
|
+
{
|
23
|
+
"#{name}" => {
|
24
|
+
type: type,
|
25
|
+
options: options
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
def deep_dup
|
31
|
+
Marshal.load(Marshal.dump(self))
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def reserved_args(args)
|
37
|
+
args.except(*clean_args(args).keys) || {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def clean_args(args)
|
41
|
+
args.except(*RESERVED_ARGS) || {}
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|