Class: Reporting
- Inherits:
-
ActiveRecord::Base
- Object
- ActiveRecord::Base
- Reporting
- Defined in:
- lib/reporting/reporting.rb
Overview
Super class for reportings to be rendered with Google visualizations Encapsulates the aggregation of the reporting data based on a configuration.
The configuration is implemented by inherting from ActiveRecord
and switching off the database stuff. Thus the regular ActiveRecord
validators and parameter assignments including type casting cab be used
The ActiveRecord extension is copied from the ActiveForm plugin (github.com/remvee/active_form)
Direct Known Subclasses
Instance Attribute Summary collapse
-
#group_by ⇒ Object
Returns the grouping columns as array.
-
#id ⇒ Object
Returns an ID which is used by frontend components to generate unique dom ids Defaults to the underscoreized classname.
-
#limit ⇒ Object
Returns the value of attribute limit.
-
#offset ⇒ Object
Returns the value of attribute offset.
-
#order_by ⇒ Object
Returns the value of attribute order_by.
-
#query ⇒ Object
Returns the value of attribute query.
-
#select ⇒ Object
Returns the select columns as array.
-
#virtual_columns ⇒ Object
readonly
, :required_columns.
Class Method Summary collapse
-
.abstract_class ⇒ Object
:nodoc:.
-
.column(name, options = {}) ⇒ Object
Defines a displayable column of the datasource Type defaults to string.
-
.column_defaults(*args) ⇒ Object
Returns a hash with column name as key and default value as value.
-
.columns ⇒ Object
TODO: merge with columns hash.
-
.columns_hash ⇒ Object
ActiveRecord overrides.
-
.connection ⇒ Object
Returns an instance of our own connection adapter.
-
.defaults ⇒ Object
Returns the defaults class variable.
-
.deserialize(value) ⇒ Object
Returns a reporting from a serialized representation.
-
.filter(name, options = {}) ⇒ Object
Marks a column as filterable / adds it in the background.
-
.from_params(params, key = self.name.underscore.gsub('/', '_')) ⇒ Object
Uses the
simple_parse
method of the SqlParser to setup a reporting from a query. -
.group_by_default(group_by) ⇒ Object
Sets the default value for group_by.
- .primary_key ⇒ Object
-
.select_default(select) ⇒ Object
Sets the default value for select.
Instance Method Summary collapse
-
#add_required_columns(*columns) ⇒ Object
Adds required columns.
-
#add_virtual_column(name, type = :string) ⇒ Object
add a virtual column.
-
#aggregate ⇒ Object
‘Abstract’ method that has to be overridden by subclasses Returns an array of rows written to #rows and accessible in DataSource compatible format in #rows_as_datasource.
-
#all_columns ⇒ Object
Returns a list of all columns (real and virtual).
-
#column_label(column, default = nil) ⇒ Object
Retrieves the I18n translation of the column label.
-
#columns ⇒ Object
Lazy getter for the columns object.
-
#data(options = {}) ⇒ Object
Returns the data rows Calls the aggregate method first if rows do not exist.
-
#datasource_columns ⇒ Object
Attribute reader for datasource_columns.
-
#defaults ⇒ Object
Returns the
defaults
Hash Convenience wrapper for instance access. -
#filterable_by?(column_name) ⇒ Boolean
Returns true if the given column is available for filtering.
-
#groupable_columns ⇒ Object
Returns an array of columns which are allowed for grouping.
-
#initialize(*args) ⇒ Reporting
constructor
A new instance of Reporting.
-
#required_columns ⇒ Object
Returns the columns that have to be selected.
-
#required_columns_for(column, start = nil) ⇒ Object
helper method used by required_columns Returns all columns required by a certain column resolving the dependencies recursively.
-
#save ⇒ Object
ActiveRecord overrides.
-
#save! ⇒ Object
:nodoc:.
-
#serialize ⇒ Object
Returns a serialized representation of the reporting.
-
#to_param ⇒ Object
:nodoc:.
-
#to_params(key = self.class.name.underscore.gsub('/', '_')) ⇒ Object
Returns the serialized Reporting in a Hash that can be used for links and which is deserialized by from_params.
Constructor Details
#initialize(*args) ⇒ Reporting
Returns a new instance of Reporting.
21 22 23 24 25 |
# File 'lib/reporting/reporting.rb', line 21 def initialize(*args) @required_columns = [] @virtual_columns = {} super(*args) end |
Instance Attribute Details
#group_by ⇒ Object
Returns the grouping columns as array
107 108 109 |
# File 'lib/reporting/reporting.rb', line 107 def group_by @group_by end |
#id ⇒ Object
Returns an ID which is used by frontend components to generate unique dom ids Defaults to the underscoreized classname
35 36 37 |
# File 'lib/reporting/reporting.rb', line 35 def id @id || self.class.name.underscore.split('/').last #gsub('/', '_') end |
#limit ⇒ Object
Returns the value of attribute limit.
12 13 14 |
# File 'lib/reporting/reporting.rb', line 12 def limit @limit end |
#offset ⇒ Object
Returns the value of attribute offset.
12 13 14 |
# File 'lib/reporting/reporting.rb', line 12 def offset @offset end |
#order_by ⇒ Object
Returns the value of attribute order_by.
12 13 14 |
# File 'lib/reporting/reporting.rb', line 12 def order_by @order_by end |
#query ⇒ Object
Returns the value of attribute query.
12 13 14 |
# File 'lib/reporting/reporting.rb', line 12 def query @query end |
#select ⇒ Object
Returns the select columns as array
102 103 104 |
# File 'lib/reporting/reporting.rb', line 102 def select @select end |
#virtual_columns ⇒ Object (readonly)
, :required_columns
13 14 15 |
# File 'lib/reporting/reporting.rb', line 13 def virtual_columns @virtual_columns end |
Class Method Details
.abstract_class ⇒ Object
:nodoc:
300 301 302 |
# File 'lib/reporting/reporting.rb', line 300 def abstract_class # :nodoc: true end |
.column(name, options = {}) ⇒ Object
Defines a displayable column of the datasource Type defaults to string
176 177 178 179 |
# File 'lib/reporting/reporting.rb', line 176 def column(name, = {}) self.datasource_columns ||= Hash.new.freeze self.datasource_columns = column_or_filter(name, , self.datasource_columns) end |
.column_defaults(*args) ⇒ Object
Returns a hash with column name as key and default value as value
284 285 286 287 288 289 |
# File 'lib/reporting/reporting.rb', line 284 def column_defaults(*args) columns_hash.keys.inject({}) do |mem, var| mem[var] = columns_hash[var].default mem end end |
.columns ⇒ Object
TODO: merge with columns hash
292 293 294 |
# File 'lib/reporting/reporting.rb', line 292 def columns columns_hash.values end |
.columns_hash ⇒ Object
ActiveRecord overrides
Needed to build column accessors
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 |
# File 'lib/reporting/reporting.rb', line 257 def columns_hash @columns_hash ||= begin ret = { } data = { } data.update(self.datasource_columns) if self.datasource_columns data.update(self.datasource_filters) if self.datasource_filters data.each do |k, v| ret[k.to_s] = ActiveRecord::ConnectionAdapters::Column.new(k.to_s, v[:default], v[:type].to_s, v.key?(:null) ? v[:null] : true) # define a humanize method which returns the human name if v.key?(:human_name) ret[k.to_s].define_singleton_method(:humanize) do v[:human_name] end end end ret end end |
.connection ⇒ Object
Returns an instance of our own connection adapter
29 30 31 |
# File 'lib/reporting/reporting.rb', line 29 def self.connection @adapter ||= ActiveRecord::ConnectionAdapters::ReportingAdapter.new end |
.defaults ⇒ Object
Returns the defaults class variable
192 193 194 |
# File 'lib/reporting/reporting.rb', line 192 def defaults self.datasource_defaults ||= Hash.new.freeze end |
.deserialize(value) ⇒ Object
Returns a reporting from a serialized representation
207 208 209 |
# File 'lib/reporting/reporting.rb', line 207 def deserialize(value) self.new(JSON.parse(value)) end |
.filter(name, options = {}) ⇒ Object
Marks a column as filterable / adds it in the background
184 185 186 187 188 189 |
# File 'lib/reporting/reporting.rb', line 184 def filter(name, = {}) self.datasource_filters ||= Hash.new.freeze # update the column options self.datasource_filters = column_or_filter(name, , self.datasource_filters) end |
.from_params(params, key = self.name.underscore.gsub('/', '_')) ⇒ Object
Uses the simple_parse
method of the SqlParser to setup a reporting from a query. The where clause is intepreted as reporting configuration (activerecord attributes)
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/reporting/reporting.rb', line 213 def from_params(params, key = self.name.underscore.gsub('/', '_')) return self.deserialize(params[key]) if params.has_key?(key) && params[key].is_a?(String) reporting = self.new(params[key]) reporting = from_query_params(params["query"]) if params.has_key?("query") return reporting unless params.has_key?(:tq) query = GoogleDataSource::DataSource::SqlParser.simple_parse(params[:tq]) attributes = Hash.new query.conditions.each do |k, v| if v.is_a?(Array) v.each do |condition| case condition.op when '<=' attributes["to_#{k}"] = condition.value when '>=' attributes["from_#{k}"] = condition.value when 'in' attributes["in_#{k}"] = condition.value else # raise exception for unsupported operator? end end else attributes[k] = v end end attributes[:group_by] = query.groupby attributes[:select] = query.select attributes[:order_by] = query.orderby attributes[:limit] = query.limit attributes[:offset] = query.offset attributes.merge!(params[key]) if params.has_key?(key) #reporting.update_attributes(attributes) reporting.attributes = attributes reporting.query = params[:tq] reporting end |
.group_by_default(group_by) ⇒ Object
Sets the default value for group_by
202 203 204 |
# File 'lib/reporting/reporting.rb', line 202 def group_by_default(group_by) self.datasource_defaults = defaults.merge({:group_by => group_by}) end |
.primary_key ⇒ Object
296 297 298 |
# File 'lib/reporting/reporting.rb', line 296 def primary_key 'id' end |
.select_default(select) ⇒ Object
Sets the default value for select
197 198 199 |
# File 'lib/reporting/reporting.rb', line 197 def select_default(select) self.datasource_defaults = defaults.merge({:select => select}) end |
Instance Method Details
#add_required_columns(*columns) ⇒ Object
Adds required columns
57 58 59 |
# File 'lib/reporting/reporting.rb', line 57 def add_required_columns(*columns) @required_columns = (@required_columns + columns.flatten.collect(&:to_s)).uniq end |
#add_virtual_column(name, type = :string) ⇒ Object
add a virtual column
112 113 114 115 116 |
# File 'lib/reporting/reporting.rb', line 112 def add_virtual_column(name, type = :string) virtual_columns[name.to_s] = { :type => type } end |
#aggregate ⇒ Object
‘Abstract’ method that has to be overridden by subclasses Returns an array of rows written to #rows and accessible in DataSource compatible format in #rows_as_datasource
64 65 66 |
# File 'lib/reporting/reporting.rb', line 64 def aggregate [] end |
#all_columns ⇒ Object
Returns a list of all columns (real and virtual)
119 120 121 |
# File 'lib/reporting/reporting.rb', line 119 def all_columns datasource_columns.merge(virtual_columns) end |
#column_label(column, default = nil) ⇒ Object
Retrieves the I18n translation of the column label
91 92 93 94 95 96 97 98 99 |
# File 'lib/reporting/reporting.rb', line 91 def column_label(column, default = nil) return '' if column.blank? defaults = ['reportings.{{model}}.{{column}}', 'models.attributes.{{model}}.{{column}}'].collect do |scope| scope.gsub!('{{model}}', self.class.name.underscore.gsub('/', '.')) scope.gsub('{{column}}', column.to_s) end.collect(&:to_sym) defaults << column.to_s.humanize I18n.t(defaults.shift, :default => defaults) end |
#columns ⇒ Object
Lazy getter for the columns object
77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/reporting/reporting.rb', line 77 def columns select.inject([]) do |columns, column| columns << { :type => all_columns[column][:type] }.merge({ :id => column.to_s, :label => column_label(column) }) if all_columns.key?(column) columns end end |
#data(options = {}) ⇒ Object
Returns the data rows Calls the aggregate method first if rows do not exist
71 72 73 74 |
# File 'lib/reporting/reporting.rb', line 71 def data( = {}) add_required_columns([:required_columns]) @rows ||= aggregate end |
#datasource_columns ⇒ Object
Attribute reader for datasource_columns
138 139 140 |
# File 'lib/reporting/reporting.rb', line 138 def datasource_columns self.class.datasource_columns || { }.freeze end |
#defaults ⇒ Object
Returns the defaults
Hash Convenience wrapper for instance access
133 134 135 |
# File 'lib/reporting/reporting.rb', line 133 def defaults self.class.defaults #.merge(@defaults || {}) end |
#filterable_by?(column_name) ⇒ Boolean
Returns true if the given column is available for filtering
169 170 171 |
# File 'lib/reporting/reporting.rb', line 169 def filterable_by?(column_name) self.class.datasource_filters.key?(column_name.to_s) end |
#groupable_columns ⇒ Object
Returns an array of columns which are allowed for grouping
125 126 127 128 129 |
# File 'lib/reporting/reporting.rb', line 125 def groupable_columns datasource_columns.collect do |key, | key.to_sym if [:grouping] end.compact end |
#required_columns ⇒ Object
Returns the columns that have to be selected
49 50 51 52 53 54 |
# File 'lib/reporting/reporting.rb', line 49 def required_columns (select + group_by + @required_columns).inject([]) do |columns, column| columns << required_columns_for(column) columns << column end.flatten.map(&:to_s).uniq end |
#required_columns_for(column, start = nil) ⇒ Object
helper method used by required_columns Returns all columns required by a certain column resolving the dependencies recursively
41 42 43 44 45 46 |
# File 'lib/reporting/reporting.rb', line 41 def required_columns_for(column, start = nil) return [] unless self.datasource_columns.has_key?(column) raise CircularDependencyException.new("Column #{start} has a circular dependency") if column.to_sym == start columns = [ self.datasource_columns[column][:requires] ].flatten.compact.collect(&:to_s) columns.collect { |c| [c, required_columns_for(c, start || column.to_sym)] }.flatten end |
#save ⇒ Object
ActiveRecord overrides
342 343 344 345 346 347 |
# File 'lib/reporting/reporting.rb', line 342 def save # :nodoc: if result = valid? end result end |
#save! ⇒ Object
:nodoc:
349 350 351 |
# File 'lib/reporting/reporting.rb', line 349 def save! # :nodoc: save or raise ActiveRecord::RecordInvalid.new(self) end |
#serialize ⇒ Object
Returns a serialized representation of the reporting
143 144 145 |
# File 'lib/reporting/reporting.rb', line 143 def serialize to_param.to_json end |
#to_param ⇒ Object
:nodoc:
147 148 149 150 151 152 153 154 155 |
# File 'lib/reporting/reporting.rb', line 147 def to_param # :nodoc: attributes.merge({ :select => select, :group_by => group_by, :order_by => order_by, :limit => limit, :offset => offset }) end |
#to_params(key = self.class.name.underscore.gsub('/', '_')) ⇒ Object
Returns the serialized Reporting in a Hash that can be used for links and which is deserialized by from_params
163 164 165 |
# File 'lib/reporting/reporting.rb', line 163 def to_params(key = self.class.name.underscore.gsub('/', '_')) HashWithIndifferentAccess.new( key => to_param ) end |