lib/mongoid/report.rb in mongoid-report-0.1.9 vs lib/mongoid/report.rb in mongoid-report-0.2.0

- old
+ new

@@ -3,10 +3,15 @@ require_relative 'report/config' require_relative 'report/queries_builder' require_relative 'report/attach_proxy' require_relative 'report/collection' +require_relative 'report/batches' +require_relative 'report/merger' +require_relative 'report/collections' +require_relative 'report/output' +require_relative 'report/input' require_relative 'report/scope' require_relative 'report/scope_collection' require_relative 'report/report_proxy' module Mongoid @@ -16,52 +21,122 @@ included do extend ClassMethods class_attribute :settings + # TODO: rewrite this module adding clone method for the all settings + # defined for the mongoid-report. for now it's creating the duplicates. + # check out the mongoid library for the best example. self.settings = {} def self.inherited(subclass) - subclass.settings = self.settings.dup + subclass.settings = {} end # Variable for copying internal class settings to the instance because of - # possible modifications in case of using filters with lambda + # possible modifications in case of using maches with lambda # expressions. attr_reader :report_module_settings def initialize_report_module # Lets store settings under created instance. - @report_module_settings = self.class.settings.dup + @report_module_settings = self.settings.inject({}) do |hash_module, (report_module, module_settings)| + hash_module.merge!( + report_module => + { + fields: module_settings[:fields], + group_by: module_settings[:group_by], + batches: module_settings[:batches], + columns: module_settings[:columns], + mapping: module_settings[:mapping], + queries: (module_settings[:queries] || []).dup, + reports: (module_settings[:reports] || {}).inject({}) do |hash_report, (report_name, report_settings)| + hash_report.merge!( + report_name => { + collection: report_settings[:collection], + fields: report_settings[:fields], + group_by: report_settings[:group_by], + batches: report_settings[:batches], + columns: report_settings[:columns], + mapping: report_settings[:mapping], + queries: (report_settings[:queries] || []).dup, + }) + end + }) + end - @report_module_settings.each do |klass, configuration| - builder = QueriesBuilder.new(configuration) + @report_module_settings.each do |report_module, module_configuration| + # Lets do not run queries builder in case of missing queries or group + # by parameters + unless module_configuration[:queries].empty? && module_configuration[:group_by].empty? + builder = QueriesBuilder.new(module_configuration) - # Prepare group queries depends on the configuration in the included - # class. - @queries = builder.do + # Prepare group queries depends on the configuration in the included + # class. + queries = builder.do - # Now we have access to compiled queries to run it in aggregation - # framework. - configuration[:queries].concat(@queries) + # Now we have access to compiled queries to run it in aggregation + # framework. + module_configuration[:queries] = module_configuration[:queries] + queries + end + + # For now we are filtering by $match queries only. + matches = module_configuration[:queries].select do |query| + query['$match'].present? + end + + module_configuration[:reports].each do |report_name, report_configuration| + # Lets merge report and module settings together. + report_configuration[:fields] = report_configuration[:fields] | module_configuration[:fields] + report_configuration[:group_by] = report_configuration[:group_by] | module_configuration[:group_by] + report_configuration[:columns] = report_configuration[:columns].merge(module_configuration[:columns]) + report_configuration[:mapping] = report_configuration[:mapping].merge(module_configuration[:mapping]) + + builder = QueriesBuilder.new(report_configuration) + + # Prepare group queries depends on the configuration in the included + # class. + queries = builder.do + + # Now we have access to compiled queries to run it in aggregation + # framework. + report_configuration[:queries] = report_configuration[:queries] + matches + queries + end end end alias :initialize :initialize_report_module - def queries(klass) - report_module_settings[klass][:queries] + def queries(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:queries] end - def mapping(klass) - report_module_settings[klass][:mapping] + def mapping(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:mapping] end - # We should pass here mongoid document - def aggregate_for(report_name) - Scope.new(self, report_name) + def batches(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:batches] end + def groups(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:group_by] + end + + def fields(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:fields] + end + + def columns(report_module, report_name) + report_module_settings[report_module][:reports][report_name][:columns] + end + + # Method for preparing of aggregation scope where you can apply query, + # yield and other grouping methods. + def aggregate_for(report_module, report_name) + Scope.new(self, report_module, report_name) + end + def aggregate ScopeCollection.new(self) end end @@ -69,112 +144,156 @@ def report(name, &block) proxy = ReportProxy.new(self, name) proxy.instance_eval(&block) end - def attach_to(collection, options = {}, &block) - proxy = AttachProxy.new(self, collection, options) - proxy.instance_eval(&block) + def attach_to(*fields, &block) + options = fields.extract_options! + collection = fields[0] + + options.merge!(report_name: options[:as]) if options[:as] + + define_report_method(options.merge(collection: collection)) do + proxy = AttachProxy.new(self, collection, options) + proxy.instance_eval(&block) + end end - def filter(*fields) - define_report_method(*fields) do |_, report_name, options| - queries = self.settings_property(report_name, :queries) + def batches(*fields) + define_report_method(*fields) do |_, report_module, report_name, batches| + self.set_settings(report_module, report_name, :batches, batches.stringify_keys!) + end + end + def match(*fields) + define_report_method(*fields) do |_, report_module, report_name, options| + queries = self.get_settings(report_module, report_name, :queries) + options.each do |key, value| queries .concat([{ '$match' => { key => value } }]) end end end + def query(*fields) + define_report_method(*fields) do |_, report_module, report_name, options| + queries = self.get_settings(report_module, report_name, :queries) + + options.each do |key, value| + queries.concat([{ key => value }]) + end + end + end + def group_by(*fields) - define_report_method(*fields) do |groups, report_name, _| - settings[report_name][:group_by] = groups.map(&:to_s) + define_report_method(*fields) do |groups, report_module, report_name, _| + self.set_settings(report_module, report_name, :group_by, groups.map(&:to_s)) end end def column(*fields) - define_report_method(*fields) do |columns, report_name, options| - columns.each do |column| - name = options.fetch(:as) { column } - add_field(report_name, column, name) + define_report_method(*fields) do |columns, report_module, report_name, _| + columns.each do |field| + self.get_settings(report_module, report_name, :fields) << field.to_s end end end def columns(*fields) - define_report_method(*fields) do |_, report_name, columns| - self.settings[report_name][:columns] = columns.stringify_keys! + define_report_method(*fields) do |_, report_module, report_name, columns| + self.set_settings(report_module, report_name, :columns, columns.stringify_keys!) end end def mapping(*fields) - define_report_method(*fields) do |_, report_name, mapping| + define_report_method(*fields) do |_, report_module, report_name, mapping| mapping.stringify_keys! mapping.each do |key, value| mapping[key] = value.to_s end - self.settings[report_name][:mapping] = mapping + self.set_settings(report_module, report_name, :mapping, mapping) end end - def fields(collection) - settings_property(collection, :fields, {}) + def get_settings(report_module, report_name, field) + unless report_name + self.settings[report_module][field] + else + self.settings[report_module][:reports][report_name][field] + end end - def groups(collection) - settings_property(collection, :group_by, []) + def set_settings(report_module, report_name, field, value) + unless report_name + self.settings[report_module][field] = value + else + self.settings[report_module][:reports][report_name][field] = value + end end - def settings_property(collection, key, default = []) - settings - .fetch(collection) { {} } - .fetch(key) { default } - end - private def define_report_method(*fields) options = fields.extract_options! # We should always specify model to attach fields, groups - collection = options.fetch(:for) - options.delete(:for) + collection = options.fetch(:collection) + options.delete(:collection) - # If user didn't pass as option to name the report we are using - # collection class as key for settings. - attach_name = options.fetch(:attach_name) { collection } - options.delete(:attach_name) + # In case if user passed mongoid model we should get name of collection + # instead of using mongoid models. on deep_dup operations it will work + # find with strings. + collection = Collections.name(collection) + report_module = options.delete(:report_module) + report_module ||= self.name + + report_name = options.delete(:report_name) + report_name ||= Collections.name(collection) + # We should always have for option - initialize_settings_by(attach_name, collection) + initialize_settings_by(report_module, report_name, collection) # Because of modifying fields(usign exract options method of # ActiveSupport) lets pass fields to the next block with collection. - yield fields, attach_name, options || {} + yield fields, report_module, report_name, options || {} end - def initialize_settings_by(attach_name, collection) - settings[attach_name] ||= settings.fetch(attach_name) do + def initialize_settings_by(report_module, report_name, collection) + # Global settings for the report block + settings[report_module] ||= settings.fetch(report_module) do { - for: collection, - fields: ActiveSupport::OrderedHash.new, + reports: {}, + fields: [], group_by: [], - queries: [], + batches: {}, columns: {}, mapping: {}, - compiled: false, + # needs to be cloned + queries: [], } end - end - def add_field(attach_name, field, name) - settings[attach_name][:fields][field.to_s] = name.to_s + return unless report_name + + settings[report_module][:reports][report_name] ||= + settings[report_module][:reports].fetch(report_name) do + { + collection: collection, + fields: [], + group_by: [], + batches: {}, + columns: {}, + mapping: {}, + # needs to be cloned + queries: [], + } + end end end end end