noventius 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|