Merge pull request #11376 from opf/bug/44265-group-by-options-in-cost-report-are-broken

[#44265] "Group by" options in Cost report are broken
pull/11405/head
ulferts 2 years ago committed by GitHub
commit 88d21ca853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      frontend/src/app/features/reporting/reporting-page/functionality/reporting_engine/group_bys.js
  2. 8
      frontend/src/app/features/reporting/reporting-page/styles/_reporting_group_by.sass
  3. 2
      modules/reporting/app/models/cost_query/group_by/author_id.rb
  4. 10
      modules/reporting/lib/widget/group_bys.rb
  5. 133
      modules/reporting/spec/models/cost_query/chaining_spec.rb
  6. 120
      modules/reporting/spec/models/cost_query/filter_spec.rb
  7. 125
      modules/reporting/spec/models/cost_query/group_by_spec.rb
  8. 32
      modules/reporting/spec/models/cost_query/integration_spec.rb
  9. 134
      modules/reporting/spec/models/cost_query/operator_spec.rb
  10. 26
      modules/reporting/spec/models/cost_query/result_spec.rb
  11. 22
      modules/reporting/spec/models/cost_query/walker_spec.rb
  12. 5
      modules/reporting/spec/support/query_helper.rb

@ -27,7 +27,7 @@
//++
/*jslint white: false, nomen: true, devel: true, on: true, debug: false, evil: true, onevar: false, browser: true, white: false, indent: 2 */
/*global window, $, $$, Reporting, Effect, Ajax, selectAllOptions, moveOptions, moveOptionUp, moveOptionDown */
/*global _, dragula, I18n, jQuery, Reporting*/
Reporting.GroupBys = (function($){
var group_by_container_ids = function() {
@ -59,6 +59,7 @@ Reporting.GroupBys = (function($){
.attr('class', 'in_row group-by--label')
.attr('for', group_by.attr('id'))
.attr('id', group_by.attr('id') + '_label')
.attr('title', text)
.html(text);
};
@ -106,7 +107,7 @@ Reporting.GroupBys = (function($){
};
var create_group_by = function(field, caption) {
var group_by, label, right_arrow, left_arrow, remove_button;
var group_by, label, remove_button;
group_by = $('<span></span>');
group_by.attr('class', 'group-by--selected-element');
group_by.attr('data-group-by', field);
@ -146,8 +147,7 @@ Reporting.GroupBys = (function($){
};
var add_group_by = function(field, caption, container) {
var group_by, add_groups_select_box, added_container;
add_groups_select_box = container.find('select').first();
var group_by, added_container;
group_by = Reporting.GroupBys.create_group_by(field, caption);
added_container = container.find('.group-by--selected-elements');
added_container.append(group_by);

@ -21,6 +21,8 @@
padding-left: 14px
margin-left: 18px
min-width: 145px
display: flex
align-items: center
fieldset.collapsible.header_collapsible legend.in_row
width: inherit
@ -31,8 +33,8 @@ fieldset.collapsible.header_collapsible legend.in_row
.group-by--label
margin: 0px
padding: 0px 18px 0 0
min-width: 60px
max-width: 110px
text-align: center
white-space: nowrap
font-weight: bold
@ -40,6 +42,8 @@ fieldset.collapsible.header_collapsible legend.in_row
height: 36px
line-height: 36px
cursor: move
overflow: hidden
text-overflow: ellipsis
.group-by--selected-element:after, .group-by--selected-element:before
border: solid transparent
@ -77,6 +81,7 @@ fieldset.collapsible.header_collapsible legend.in_row
line-height: normal
cursor: pointer
color: #FFFFFF
padding: 0 0 0 5px
.group-by--remove:hover
background-color: #3493B3 !important
@ -86,6 +91,7 @@ fieldset.collapsible.header_collapsible legend.in_row
.group-by--control
margin: 0
padding: 0
max-width: 200px
.group-by--selected-elements
background-color: #EEE

@ -27,6 +27,8 @@
#++
class CostQuery::GroupBy::AuthorId < Report::GroupBy::Base
join_table WorkPackage
def self.label
WorkPackage.human_attribute_name(:author)
end

@ -30,9 +30,11 @@ class Widget::GroupBys < Widget::Base
def render_options(group_by_ary)
group_by_ary.sort_by(&:label).map do |group_by|
next unless group_by.selectable?
content_tag :option, value: group_by.underscore_name, 'data-label': CGI::escapeHTML(h(group_by.label)).to_s do
h(group_by.label)
label_text = CGI::escapeHTML(h(group_by.label)).to_s
option_tags = { value: group_by.underscore_name, 'data-label': label_text }
option_tags[:title] = label_text if group_by.label.length > 40
content_tag :option, option_tags do
h(truncate_single_line(group_by.label, length: 40))
end
end.join.html_safe
end
@ -65,7 +67,7 @@ class Widget::GroupBys < Widget::Base
class: 'hidden-for-sighted'
label += content_tag :select, id: "group-by--add-#{type}", class: 'advanced-filters--select' do
content = content_tag :option, I18n.t(:label_group_by_add), value: ''
content = content_tag :option, I18n.t(:label_group_by_add), value: '', disabled: true, selected: true
content += engine::GroupBy.all_grouped.sort_by do |label, _group_by_ary|
I18n.t(label)

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
describe CostQuery, type: :model, reporting_query_helper: true do
let(:project) { create(:project) }
@ -37,72 +37,72 @@ describe CostQuery, type: :model, reporting_query_helper: true do
before do
# FIXME: is there a better way to load all filter and groups?
CostQuery::Filter.all && CostQuery::GroupBy.all
CostQuery.chain_initializer.clear
described_class.chain_initializer.clear
end
after(:all) do
CostQuery.chain_initializer.clear
described_class.chain_initializer.clear
end
it "contains NoFilter" do
expect(@query.chain).to be_a(CostQuery::Filter::NoFilter)
expect(query.chain).to be_a(CostQuery::Filter::NoFilter)
end
it "keeps NoFilter at bottom" do
@query.filter :project_id
expect(@query.chain.bottom).to be_a(CostQuery::Filter::NoFilter)
expect(@query.chain.top).not_to be_a(CostQuery::Filter::NoFilter)
query.filter :project_id
expect(query.chain.bottom).to be_a(CostQuery::Filter::NoFilter)
expect(query.chain.top).not_to be_a(CostQuery::Filter::NoFilter)
end
it "remembers it's correct parent" do
@query.group_by :project_id
@query.filter :project_id
expect(@query.chain.top.child.child.parent).to eq(@query.chain.top.child)
query.group_by :project_id
query.filter :project_id
expect(query.chain.top.child.child.parent).to eq(query.chain.top.child)
end
it "places filter after a group_by" do
@query.group_by :project_id
expect(@query.chain.bottom.parent).to be_a(CostQuery::GroupBy::ProjectId)
expect(@query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
query.group_by :project_id
expect(query.chain.bottom.parent).to be_a(CostQuery::GroupBy::ProjectId)
expect(query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
@query.filter :project_id
expect(@query.chain.bottom.parent).to be_a(CostQuery::Filter::ProjectId)
expect(@query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
query.filter :project_id
expect(query.chain.bottom.parent).to be_a(CostQuery::Filter::ProjectId)
expect(query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
end
it "places rows in front of columns when adding a column first" do
@query.column :project_id
expect(@query.chain.bottom.parent.type).to eq(:column)
expect(@query.chain.top.type).to eq(:column)
query.column :project_id
expect(query.chain.bottom.parent.type).to eq(:column)
expect(query.chain.top.type).to eq(:column)
@query.row :project_id
expect(@query.chain.bottom.parent.type).to eq(:column)
expect(@query.chain.top.type).to eq(:row)
query.row :project_id
expect(query.chain.bottom.parent.type).to eq(:column)
expect(query.chain.top.type).to eq(:row)
end
it "places rows in front of filters" do
@query.row :project_id
expect(@query.chain.bottom.parent.type).to eq(:row)
expect(@query.chain.top.type).to eq(:row)
@query.filter :project_id
expect(@query.chain.bottom.parent).to be_a(CostQuery::Filter::ProjectId)
expect(@query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
expect(@query.chain.top.type).to eq(:row)
query.row :project_id
expect(query.chain.bottom.parent.type).to eq(:row)
expect(query.chain.top.type).to eq(:row)
query.filter :project_id
expect(query.chain.bottom.parent).to be_a(CostQuery::Filter::ProjectId)
expect(query.chain.top).to be_a(CostQuery::GroupBy::ProjectId)
expect(query.chain.top.type).to eq(:row)
end
it "returns all filters, including the NoFilter" do
@query.filter :project_id
@query.group_by :project_id
expect(@query.filters.size).to eq(2)
expect(@query.filters.map { |f| f.class.underscore_name }).to include "project_id"
query.filter :project_id
query.group_by :project_id
expect(query.filters.size).to eq(2)
expect(query.filters.map { |f| f.class.underscore_name }).to include "project_id"
end
it "returns all group_bys" do
@query.filter :project_id
@query.group_by :project_id
expect(@query.group_bys.size).to eq(1)
expect(@query.group_bys.map { |g| g.class.underscore_name }).to include "project_id"
query.filter :project_id
query.group_by :project_id
expect(query.group_bys.size).to eq(1)
expect(query.group_bys.map { |g| g.class.underscore_name }).to include "project_id"
end
it "initializes the chain through a block" do
@ -112,38 +112,39 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
end
TestFilter.send(:initialize_query_with) { |query| query.filter(:project_id, value: project.id) }
@query.build_new_chain
expect(@query.filters.map { |f| f.class.underscore_name }).to include "project_id"
expect(@query.filters.detect { |f| f.class.underscore_name == "project_id" }.values).to eq(Array(project.id))
query.build_new_chain
expect(query.filters.map { |f| f.class.underscore_name }).to include "project_id"
expect(query.filters.detect { |f| f.class.underscore_name == "project_id" }.values).to eq(Array(project.id))
end
context "store and load" do
let(:new_query) { described_class.deserialize(query.serialize) }
before do
@query.filter :project_id, value: project.id
@query.filter :cost_type_id, value: CostQuery::Filter::CostTypeId.available_values.first
@query.filter :category_id, value: CostQuery::Filter::CategoryId.available_values.first
@query.group_by :activity_id
@query.group_by :budget_id
@query.group_by :cost_type_id
@new_query = CostQuery.deserialize(@query.serialize)
query.filter :project_id, value: project.id
query.filter :cost_type_id, value: CostQuery::Filter::CostTypeId.available_values.first
query.filter :category_id, value: CostQuery::Filter::CategoryId.available_values.first
query.group_by :activity_id
query.group_by :budget_id
query.group_by :cost_type_id
end
it "serializes the chain correctly" do
%i[filters group_bys].each do |type|
@query.send(type).each do |chainable|
expect(@query.serialize[type].collect { |c| c[0] }).to include chainable.class.name.demodulize
query.send(type).each do |chainable|
expect(query.serialize[type].collect { |c| c[0] }).to include chainable.class.name.demodulize
end
end
end
it "deserializes a serialized query correctly" do
expect(@new_query.serialize).to eq(@query.serialize)
expect(new_query.serialize).to eq(query.serialize)
end
it "keeps the order of group bys" do
@query.group_bys.each_with_index do |group_by, index|
query.group_bys.each_with_index do |group_by, index|
# check for order
@new_query.group_bys.each_with_index do |g, ix|
new_query.group_bys.each_with_index do |g, ix|
if g.instance_of?(group_by.class)
expect(ix).to eq(index)
end
@ -152,11 +153,11 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "keeps the right filter values" do
@query.filters.each_with_index do |filter, _index|
query.filters.each_with_index do |filter, _index|
# check for presence
expect(@new_query.filters.any? do |f|
expect(new_query.filters).to be_any do |f|
f.instance_of?(filter.class) && (filter.respond_to?(:values) ? f.values == filter.values : true)
end).to be_truthy
end
end
end
end
@ -164,33 +165,33 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe Report::Chainable do
describe '#top' do
before { @chain = Report::Chainable.new }
let(:chain) { described_class.new }
it "returns for an one element long chain that chain as top" do
expect(@chain.top).to eq(@chain)
expect(@chain).to be_top
expect(chain.top).to eq(chain)
expect(chain).to be_top
end
it "does not keep the old top when prepending elements" do
Report::Chainable.new @chain
expect(@chain.top).not_to eq(@chain)
expect(@chain).not_to be_top
described_class.new chain
expect(chain.top).not_to eq(chain)
expect(chain).not_to be_top
end
it "sets new top when prepending elements" do
current = @chain
current = chain
10.times do
old = current
current = Report::Chainable.new(current)
current = described_class.new(current)
expect(old.top).to eq(current)
expect(@chain.top).to eq(current)
expect(chain.top).to eq(current)
end
end
end
describe '#inherited_attribute' do
before do
@a = Class.new Report::Chainable
@a = Class.new described_class
@a.inherited_attribute :foo, default: 42
@b = Class.new @a
@c = Class.new @a

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
require File.join(File.dirname(__FILE__), '..', '..', 'support', 'custom_field_filter')
describe CostQuery, type: :model, reporting_query_helper: true do
@ -51,17 +51,17 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "shows all entries when no filter is applied" do
expect(@query.result.count).to eq(Entry.count)
expect(query.result.count).to eq(Entry.count)
end
it "always sets cost_type" do
@query.result.each do |result|
query.result.each do |result|
expect(result["cost_type"]).not_to be_nil
end
end
it "sets activity_id to -1 for cost entries" do
@query.result.each do |result|
query.result.each do |result|
expect(result["activity_id"].to_i).to eq(-1) if result["type"] != "TimeEntry"
end
end
@ -102,29 +102,29 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "onlies return entries from the given #{filter}" do
@query.filter field, value: object.id
@query.result.each do |result|
query.filter field, value: object.id
query.result.each do |result|
expect(result[field].to_s).to eq(object.id.to_s)
end
end
it "allows chaining the same filter" do
@query.filter field, value: object.id
@query.filter field, value: object.id
@query.result.each do |result|
query.filter field, value: object.id
query.filter field, value: object.id
query.result.each do |result|
expect(result[field].to_s).to eq(object.id.to_s)
end
end
it "returns no results for excluding filters" do
@query.filter field, value: object.id
@query.filter field, value: object.id + 1
expect(@query.result.count).to eq(0)
query.filter field, value: object.id
query.filter field, value: object.id + 1
expect(query.result.count).to eq(0)
end
it "computes the correct number of results" do
@query.filter field, value: object.id
expect(@query.result.count).to eq(expected_count)
query.filter field, value: object.id
expect(query.result.count).to eq(expected_count)
end
end
end
@ -157,49 +157,49 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "onlies return entries from the given CostQuery::Filter::AuthorId" do
@query.filter 'author_id', value: author.id
@query.result.each do |result|
query.filter 'author_id', value: author.id
query.result.each do |result|
work_package_id = result["work_package_id"]
expect(WorkPackage.find(work_package_id).author.id).to eq(author.id)
end
end
it "allows chaining the same filter" do
@query.filter 'author_id', value: author.id
@query.filter 'author_id', value: author.id
@query.result.each do |result|
query.filter 'author_id', value: author.id
query.filter 'author_id', value: author.id
query.result.each do |result|
work_package_id = result["work_package_id"]
expect(WorkPackage.find(work_package_id).author.id).to eq(author.id)
end
end
it "returns no results for excluding filters" do
@query.filter 'author_id', value: author.id
@query.filter 'author_id', value: author.id + 1
expect(@query.result.count).to eq(0)
query.filter 'author_id', value: author.id
query.filter 'author_id', value: author.id + 1
expect(query.result.count).to eq(0)
end
it "computes the correct number of results" do
@query.filter 'author_id', value: author.id
expect(@query.result.count).to eq(2)
query.filter 'author_id', value: author.id
expect(query.result.count).to eq(2)
end
end
it "filters spent_on" do
@query.filter :spent_on, operator: 'w'
expect(@query.result.count).to eq(Entry.all.select { |e| e.spent_on.cweek == TimeEntry.all.first.spent_on.cweek }.count)
query.filter :spent_on, operator: 'w'
expect(query.result.count).to eq(Entry.all.select { |e| e.spent_on.cweek == TimeEntry.all.first.spent_on.cweek }.count)
end
it "filters created_at" do
@query.filter :created_on, operator: 't'
query.filter :created_on, operator: 't'
# we assume that some of our fixtures set created_at to Time.now
expect(@query.result.count).to eq(Entry.all.select { |e| e.created_at.to_date == Date.today }.count)
expect(query.result.count).to eq(Entry.all.select { |e| e.created_at.to_date == Time.zone.today }.count)
end
it "filters updated_at" do
@query.filter :updated_on, value: Date.today.years_ago(20), operator: '>d'
query.filter :updated_on, value: Time.zone.today.years_ago(20), operator: '>d'
# we assume that our were updated in the last 20 years
expect(@query.result.count).to eq(Entry.all.select { |e| e.updated_at.to_date > Date.today.years_ago(20) }.count)
expect(query.result.count).to eq(Entry.all.select { |e| e.updated_at.to_date > Time.zone.today.years_ago(20) }.count)
end
it "filters user_id" do
@ -209,8 +209,8 @@ describe CostQuery, type: :model, reporting_query_helper: true do
create_work_package_with_time_entry({}, { user: anonymous })
# create matching entry
create_work_package_with_time_entry
@query.filter :user_id, value: user.id, operator: '='
expect(@query.result.count).to eq(1)
query.filter :user_id, value: user.id, operator: '='
expect(query.result.count).to eq(1)
end
describe "work_package-based filters" do
@ -227,79 +227,79 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "filters overridden_costs" do
@query.filter :overridden_costs, operator: 'y'
expect(@query.result.count).to eq(Entry.all.select { |e| not e.overridden_costs.nil? }.count)
query.filter :overridden_costs, operator: 'y'
expect(query.result.count).to eq(Entry.all.reject { |e| e.overridden_costs.nil? }.count)
end
it "filters status" do
matching_status = create(:status, is_closed: true)
create_work_packages_and_time_entries(3, status: matching_status)
@query.filter :status_id, operator: 'c'
expect(@query.result.count).to eq(3)
query.filter :status_id, operator: 'c'
expect(query.result.count).to eq(3)
end
it "filters types" do
matching_type = project.types.first
create_work_packages_and_time_entries(3, type: matching_type)
@query.filter :type_id, operator: '=', value: matching_type.id
expect(@query.result.count).to eq(3)
query.filter :type_id, operator: '=', value: matching_type.id
expect(query.result.count).to eq(3)
end
it "filters work_package authors" do
matching_author = create_matching_object_with_time_entries(:user, :author, 3)
@query.filter :author_id, operator: '=', value: matching_author.id
expect(@query.result.count).to eq(3)
query.filter :author_id, operator: '=', value: matching_author.id
expect(query.result.count).to eq(3)
end
it "filters priority" do
matching_priority = create_matching_object_with_time_entries(:priority, :priority, 3)
@query.filter :priority_id, operator: '=', value: matching_priority.id
expect(@query.result.count).to eq(3)
query.filter :priority_id, operator: '=', value: matching_priority.id
expect(query.result.count).to eq(3)
end
it "filters assigned to" do
matching_user = create_matching_object_with_time_entries(:user, :assigned_to, 3)
@query.filter :assigned_to_id, operator: '=', value: matching_user.id
expect(@query.result.count).to eq(3)
query.filter :assigned_to_id, operator: '=', value: matching_user.id
expect(query.result.count).to eq(3)
end
it "filters category" do
category = create(:category, project:)
create_work_packages_and_time_entries(3, category:)
@query.filter :category_id, operator: '=', value: category.id
expect(@query.result.count).to eq(3)
query.filter :category_id, operator: '=', value: category.id
expect(query.result.count).to eq(3)
end
it "filters target version" do
matching_version = create(:version, project:)
create_work_packages_and_time_entries(3, version: matching_version)
@query.filter :version_id, operator: '=', value: matching_version.id
expect(@query.result.count).to eq(3)
query.filter :version_id, operator: '=', value: matching_version.id
expect(query.result.count).to eq(3)
end
it "filters subject" do
matching_work_package = create_work_package_with_time_entry(subject: 'matching subject')
@query.filter :subject, operator: '=', value: 'matching subject'
expect(@query.result.count).to eq(1)
query.filter :subject, operator: '=', value: 'matching subject'
expect(query.result.count).to eq(1)
end
it "filters start" do
start_date = Date.new(2013, 1, 1)
matching_work_package = create_work_package_with_time_entry(start_date:)
@query.filter :start_date, operator: '=d', value: start_date
expect(@query.result.count).to eq(1)
query.filter :start_date, operator: '=d', value: start_date
expect(query.result.count).to eq(1)
end
it "filters due date" do
due_date = Date.new(2013, 1, 1)
matching_work_package = create_work_package_with_time_entry(due_date:)
@query.filter :due_date, operator: '=d', value: due_date
expect(@query.result.count).to eq(1)
query.filter :due_date, operator: '=d', value: due_date
expect(query.result.count).to eq(1)
end
it "raises an error if operator is not supported" do
expect { @query.filter :spent_on, operator: 'c' }.to raise_error(ArgumentError)
expect { query.filter :spent_on, operator: 'c' }.to raise_error(ArgumentError)
end
end
@ -426,7 +426,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
it "includes custom fields classes in CustomFieldEntries.all" do
custom_field
expect(CostQuery::Filter::CustomFieldEntries.all)
expect(described_class.all)
.to include(filter_class_name_string(custom_field).constantize)
end
@ -457,15 +457,15 @@ describe CostQuery, type: :model, reporting_query_helper: true do
it "is usable as filter" do
create_searchable_fields_and_values
id = WorkPackageCustomField.find_by(name: "Searchable Field").id
@query.filter "custom_field_#{id}".to_sym, operator: '=', value: "125"
expect(@query.result.count).to eq(2)
query.filter "custom_field_#{id}".to_sym, operator: '=', value: "125"
expect(query.result.count).to eq(2)
end
it "is usable as filter #2" do
create_searchable_fields_and_values
id = WorkPackageCustomField.find_by(name: "Searchable Field").id
@query.filter "custom_field_#{id}".to_sym, operator: '=', value: "finnlabs"
expect(@query.result.count).to eq(0)
query.filter "custom_field_#{id}".to_sym, operator: '=', value: "finnlabs"
expect(query.result.count).to eq(0)
end
end
end

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
require File.join(File.dirname(__FILE__), '..', '..', 'support', 'custom_field_filter')
describe CostQuery, type: :model, reporting_query_helper: true do
@ -75,75 +75,80 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe CostQuery::GroupBy do
it "computes group_by on projects" do
@query.group_by :project_id
expect(@query.result.size).to eq(2)
query.group_by :project_id
expect(query.result.size).to eq(2)
end
it "keeps own and all parents' group fields in all_group_fields" do
@query.group_by :project_id
@query.group_by :work_package_id
@query.group_by :cost_type_id
expect(@query.all_group_fields).to eq(%w[entries.cost_type_id])
expect(@query.child.all_group_fields).to eq(%w[entries.cost_type_id entries.work_package_id])
expect(@query.child.child.all_group_fields).to eq(%w[entries.cost_type_id entries.work_package_id entries.project_id])
query.group_by :project_id
query.group_by :work_package_id
query.group_by :cost_type_id
expect(query.all_group_fields).to eq(%w[entries.cost_type_id])
expect(query.child.all_group_fields).to eq(%w[entries.cost_type_id entries.work_package_id])
expect(query.child.child.all_group_fields).to eq(%w[entries.cost_type_id entries.work_package_id entries.project_id])
end
it "computes group_by WorkPackage" do
@query.group_by :work_package_id
expect(@query.result.size).to eq(2)
query.group_by :work_package_id
expect(query.result.size).to eq(2)
end
it "computes group_by CostType" do
@query.group_by :cost_type_id
query.group_by :cost_type_id
# type 'Labor' for time entries, 2 different cost types
expect(@query.result.size).to eq(3)
expect(query.result.size).to eq(3)
end
it "computes group_by Activity" do
@query.group_by :activity_id
query.group_by :activity_id
# "-1" for time entries, 2 different cost activities
expect(@query.result.size).to eq(3)
expect(query.result.size).to eq(3)
end
it "computes group_by Date (day)" do
@query.group_by :spent_on
expect(@query.result.size).to eq(2)
query.group_by :spent_on
expect(query.result.size).to eq(2)
end
it "computes group_by Date (week)" do
@query.group_by :tweek
expect(@query.result.size).to eq(2)
query.group_by :tweek
expect(query.result.size).to eq(2)
end
it "computes group_by Date (month)" do
@query.group_by :tmonth
expect(@query.result.size).to eq(2)
query.group_by :tmonth
expect(query.result.size).to eq(2)
end
it "computes group_by Date (year)" do
@query.group_by :tyear
expect(@query.result.size).to eq(2)
query.group_by :tyear
expect(query.result.size).to eq(2)
end
it "computes group_by User" do
@query.group_by :user_id
expect(@query.result.size).to eq(4)
query.group_by :user_id
expect(query.result.size).to eq(4)
end
it "computes group_by Author" do
query.group_by :author_id
expect(query.result.size).to eq(2)
end
it "computes group_by Type" do
@query.group_by :type_id
expect(@query.result.size).to eq(1)
query.group_by :type_id
expect(query.result.size).to eq(1)
end
it "computes group_by Budget" do
@query.group_by :budget_id
expect(@query.result.size).to eq(1)
query.group_by :budget_id
expect(query.result.size).to eq(1)
end
it "computes multiple group_by" do
@query.group_by :project_id
@query.group_by :user_id
sql_result = @query.result
query.group_by :project_id
query.group_by :user_id
sql_result = query.result
expect(sql_result.size).to eq(4)
# for each user the number of projects should be correct
@ -159,9 +164,9 @@ describe CostQuery, type: :model, reporting_query_helper: true do
# TODO: ?
it "computes multiple group_by with joins" do
@query.group_by :project_id
@query.group_by :type_id
sql_result = @query.result
query.group_by :project_id
query.group_by :type_id
sql_result = query.result
expect(sql_result.size).to eq(1)
# for each type the number of projects should be correct
sql_sizes = []
@ -175,39 +180,39 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "compute count correct with lots of group_by" do
@query.group_by :project_id
@query.group_by :work_package_id
@query.group_by :cost_type_id
@query.group_by :activity_id
@query.group_by :spent_on
@query.group_by :tweek
@query.group_by :type_id
@query.group_by :tmonth
@query.group_by :tyear
expect(@query.result.count).to eq(8)
query.group_by :project_id
query.group_by :work_package_id
query.group_by :cost_type_id
query.group_by :activity_id
query.group_by :spent_on
query.group_by :tweek
query.group_by :type_id
query.group_by :tmonth
query.group_by :tyear
expect(query.result.count).to eq(8)
end
it "accepts row as a specialised group_by" do
@query.row :project_id
expect(@query.chain.type).to eq(:row)
query.row :project_id
expect(query.chain.type).to eq(:row)
end
it "accepts column as a specialised group_by" do
@query.column :project_id
expect(@query.chain.type).to eq(:column)
query.column :project_id
expect(query.chain.type).to eq(:column)
end
it "has type :column as a default" do
@query.group_by :project_id
expect(@query.chain.type).to eq(:column)
query.group_by :project_id
expect(query.chain.type).to eq(:column)
end
it "aggregates a third group_by which owns at least 2 sub results" do
@query.group_by :tweek
@query.group_by :project_id
@query.group_by :user_id
sql_result = @query.result
query.group_by :tweek
query.group_by :project_id
query.group_by :user_id
sql_result = query.result
expect(sql_result.size).to eq(4)
# for each user the number of projects should be correct
@ -243,7 +248,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
before do
check_cache
CostQuery::GroupBy.all.merge CostQuery::GroupBy::CustomFieldEntries.all
CostQuery::GroupBy.all.merge described_class.all
end
def check_cache
@ -287,7 +292,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "includes custom fields classes in CustomFieldEntries.all" do
expect(CostQuery::GroupBy::CustomFieldEntries.all)
expect(described_class.all)
.to include(group_by_class_name_string(custom_field).constantize)
end
@ -301,8 +306,8 @@ describe CostQuery, type: :model, reporting_query_helper: true do
check_cache
@query.group_by "custom_field_#{custom_field2.id}".to_sym
footprint = @query.result.each_direct_result.map { |c| [c.count, c.units.to_i] }.sort
query.group_by "custom_field_#{custom_field2.id}".to_sym
footprint = query.result.each_direct_result.map { |c| [c.count, c.units.to_i] }.sort
expect(footprint).to eq([[8, 8]])
end
end

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
describe CostQuery, type: :model, reporting_query_helper: true do
minimal_query
@ -47,9 +47,9 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe "the reporting system" do
it "computes group_by and a filter" do
@query.group_by :project_id
@query.filter :status_id, operator: 'o'
sql_result = @query.result
query.group_by :project_id
query.filter :status_id, operator: 'o'
sql_result = query.result
expect(sql_result.size).to eq(2)
# for each project the number of entries should be correct
@ -63,11 +63,11 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "applies two filter and a group_by correctly" do
@query.filter :project_id, operator: '=', value: [project1.id]
@query.group_by :user_id
@query.filter :overridden_costs, operator: 'n'
query.filter :project_id, operator: '=', value: [project1.id]
query.group_by :user_id
query.filter :overridden_costs, operator: 'n'
sql_result = @query.result
sql_result = query.result
expect(sql_result.size).to eq(2)
# for each user the number of entries should be correct
sql_count = []
@ -80,10 +80,10 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "applies two different filters on the same field" do
@query.filter :project_id, operator: '=', value: [project1.id, project2.id]
@query.filter :project_id, operator: '!', value: [project2.id]
query.filter :project_id, operator: '=', value: [project1.id, project2.id]
query.filter :project_id, operator: '!', value: [project2.id]
sql_result = @query.result
sql_result = query.result
expect(sql_result.count).to eq(2)
end
@ -98,14 +98,14 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
# create a random query
@query.group_by :work_package_id
@query.column :tweek
@query.row :project_id
@query.row :user_id
query.group_by :work_package_id
query.column :tweek
query.row :project_id
query.row :user_id
# count how often a sql query was created
number_of_sql_queries = 0
# do some random things on it
walker = @query.transformer
walker = query.transformer
walker.row_first
walker.column_first
# TODO - to do something

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
describe CostQuery, type: :model, reporting_query_helper: true do
minimal_query
@ -35,7 +35,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
let!(:project2) { create(:project, name: "project2", created_at: 6.minutes.ago) }
describe CostQuery::Operator do
def query(table, field, operator, *values)
def cost_query(table, field, operator, *values)
sql = CostQuery::SqlStatement.new table
yield sql if block_given?
operator.to_operator.modify sql, field, *values
@ -53,11 +53,11 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "does =" do
expect(query('projects', 'id', '=', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '=', project1.id).size).to eq(1)
end
it "does = for multiple values" do
expect(query('projects', 'id', '=', project1.id, project2.id).size).to eq(2)
expect(cost_query('projects', 'id', '=', project1.id, project2.id).size).to eq(2)
end
it "does = for no values" do
@ -68,172 +68,172 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "does = for nil" do
expect(query('projects', 'id', '=', nil).size).to eq(0)
expect(cost_query('projects', 'id', '=', nil).size).to eq(0)
end
it "does = for empty string" do
expect(query('projects', 'id', '=', '').size).to eq(0)
expect(cost_query('projects', 'id', '=', '').size).to eq(0)
end
it "does <=" do
expect(query('projects', 'id', '<=', project2.id - 1).size).to eq(1)
expect(cost_query('projects', 'id', '<=', project2.id - 1).size).to eq(1)
end
it "does >=" do
expect(query('projects', 'id', '>=', project1.id + 1).size).to eq(1)
expect(cost_query('projects', 'id', '>=', project1.id + 1).size).to eq(1)
end
it "does !" do
expect(query('projects', 'id', '!', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '!', project1.id).size).to eq(1)
end
it "does ! for empty string" do
expect(query('projects', 'id', '!', '').size).to eq(0)
expect(cost_query('projects', 'id', '!', '').size).to eq(0)
end
it "does ! for multiple values" do
expect(query('projects', 'id', '!', project1.id, project2.id).size).to eq(0)
expect(cost_query('projects', 'id', '!', project1.id, project2.id).size).to eq(0)
end
it "does !*" do
expect(query('cost_entries', 'project_id', '!*', []).size).to eq(0)
expect(cost_query('cost_entries', 'project_id', '!*', []).size).to eq(0)
end
it "does ~ (contains)" do
expect(query('projects', 'name', '~', 'o').size).to eq(Project.all.select { |p| p.name =~ /o/ }.count)
expect(query('projects', 'name', '~', 'test').size).to eq(Project.all.select { |p| p.name =~ /test/ }.count)
expect(query('projects', 'name', '~', 'child').size).to eq(Project.all.select { |p| p.name =~ /child/ }.count)
expect(cost_query('projects', 'name', '~', 'o').size).to eq(Project.all.select { |p| p.name =~ /o/ }.count)
expect(cost_query('projects', 'name', '~', 'test').size).to eq(Project.all.select { |p| p.name =~ /test/ }.count)
expect(cost_query('projects', 'name', '~', 'child').size).to eq(Project.all.select { |p| p.name =~ /child/ }.count)
end
it "does !~ (not contains)" do
expect(query('projects', 'name', '!~', 'o').size).to eq(Project.all.select { |p| p.name !~ /o/ }.count)
expect(query('projects', 'name', '!~', 'test').size).to eq(Project.all.select { |p| p.name !~ /test/ }.count)
expect(query('projects', 'name', '!~', 'child').size).to eq(Project.all.select { |p| p.name !~ /child/ }.count)
expect(cost_query('projects', 'name', '!~', 'o').size).to eq(Project.all.reject { |p| p.name =~ /o/ }.count)
expect(cost_query('projects', 'name', '!~', 'test').size).to eq(Project.all.reject { |p| p.name =~ /test/ }.count)
expect(cost_query('projects', 'name', '!~', 'child').size).to eq(Project.all.reject { |p| p.name =~ /child/ }.count)
end
it "does c (closed work_package)" do
expect(query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0
expect(cost_query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0
end
it "does o (open work_package)" do
expect(query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0
expect(cost_query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size).to be >= 0
end
it "does give the correct number of results when counting closed and open work_packages" do
a = query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size
b = query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size
a = cost_query('work_packages', 'status_id', 'o') { |s| s.join Status => [WorkPackage, :status] }.size
b = cost_query('work_packages', 'status_id', 'c') { |s| s.join Status => [WorkPackage, :status] }.size
expect(WorkPackage.count).to eq(a + b)
end
it "does w (this week)" do
# somehow this test doesn't work on sundays
n = query('projects', 'created_at', 'w').size
day_in_this_week = Time.now.at_beginning_of_week + 1.day
n = cost_query('projects', 'created_at', 'w').size
day_in_this_week = Time.zone.now.at_beginning_of_week + 1.day
create(:project, created_at: day_in_this_week)
expect(query('projects', 'created_at', 'w').size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 'w').size).to eq(n + 1)
create(:project, created_at: day_in_this_week + 7.days)
create(:project, created_at: day_in_this_week - 7.days)
expect(query('projects', 'created_at', 'w').size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 'w').size).to eq(n + 1)
end
it "does t (today)" do
s = query('projects', 'created_at', 't').size
s = cost_query('projects', 'created_at', 't').size
create(:project, created_at: Date.yesterday)
expect(query('projects', 'created_at', 't').size).to eq(s)
create(:project, created_at: Time.now)
expect(query('projects', 'created_at', 't').size).to eq(s + 1)
expect(cost_query('projects', 'created_at', 't').size).to eq(s)
create(:project, created_at: Time.zone.now)
expect(cost_query('projects', 'created_at', 't').size).to eq(s + 1)
end
it "does <t+ (before the day which is n days in the future)" do
n = query('projects', 'created_at', '<t+', 2).size
n = cost_query('projects', 'created_at', '<t+', 2).size
create(:project, created_at: Date.tomorrow + 1)
expect(query('projects', 'created_at', '<t+', 2).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '<t+', 2).size).to eq(n + 1)
create(:project, created_at: Date.tomorrow + 2)
expect(query('projects', 'created_at', '<t+', 2).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '<t+', 2).size).to eq(n + 1)
end
it "does t+ (n days in the future)" do
n = query('projects', 'created_at', 't+', 1).size
n = cost_query('projects', 'created_at', 't+', 1).size
create(:project, created_at: Date.tomorrow)
expect(query('projects', 'created_at', 't+', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 't+', 1).size).to eq(n + 1)
create(:project, created_at: Date.tomorrow + 2)
expect(query('projects', 'created_at', 't+', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 't+', 1).size).to eq(n + 1)
end
it "does >t+ (after the day which is n days in the future)" do
n = query('projects', 'created_at', '>t+', 1).size
create(:project, created_at: Time.now)
expect(query('projects', 'created_at', '>t+', 1).size).to eq(n)
n = cost_query('projects', 'created_at', '>t+', 1).size
create(:project, created_at: Time.zone.now)
expect(cost_query('projects', 'created_at', '>t+', 1).size).to eq(n)
create(:project, created_at: Date.tomorrow + 1)
expect(query('projects', 'created_at', '>t+', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '>t+', 1).size).to eq(n + 1)
end
it "does >t- (after the day which is n days ago)" do
n = query('projects', 'created_at', '>t-', 1).size
n = cost_query('projects', 'created_at', '>t-', 1).size
create(:project, created_at: Date.today)
expect(query('projects', 'created_at', '>t-', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '>t-', 1).size).to eq(n + 1)
create(:project, created_at: Date.yesterday - 1)
expect(query('projects', 'created_at', '>t-', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '>t-', 1).size).to eq(n + 1)
end
it "does t- (n days ago)" do
n = query('projects', 'created_at', 't-', 1).size
n = cost_query('projects', 'created_at', 't-', 1).size
create(:project, created_at: Date.yesterday)
expect(query('projects', 'created_at', 't-', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 't-', 1).size).to eq(n + 1)
create(:project, created_at: Date.yesterday - 2)
expect(query('projects', 'created_at', 't-', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', 't-', 1).size).to eq(n + 1)
end
it "does <t- (before the day which is n days ago)" do
n = query('projects', 'created_at', '<t-', 1).size
n = cost_query('projects', 'created_at', '<t-', 1).size
create(:project, created_at: Date.today)
expect(query('projects', 'created_at', '<t-', 1).size).to eq(n)
expect(cost_query('projects', 'created_at', '<t-', 1).size).to eq(n)
create(:project, created_at: Date.yesterday - 1)
expect(query('projects', 'created_at', '<t-', 1).size).to eq(n + 1)
expect(cost_query('projects', 'created_at', '<t-', 1).size).to eq(n + 1)
end
# Our own operators
it "does =_child_projects" do
expect(query('projects', 'id', '=_child_projects', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '=_child_projects', project1.id).size).to eq(1)
p_c1 = create_project parent: project1
expect(query('projects', 'id', '=_child_projects', project1.id).size).to eq(2)
expect(cost_query('projects', 'id', '=_child_projects', project1.id).size).to eq(2)
create_project parent: p_c1
expect(query('projects', 'id', '=_child_projects', project1.id).size).to eq(3)
expect(cost_query('projects', 'id', '=_child_projects', project1.id).size).to eq(3)
end
it "does =_child_projects on multiple projects" do
expect(query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(2)
expect(cost_query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(2)
p1_c1 = create_project parent: project1
p2_c1 = create_project parent: project2
expect(query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(4)
expect(cost_query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(4)
p1_c1_c1 = create_project parent: p1_c1
create_project parent: p1_c1_c1
create_project parent: p2_c1
expect(query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(7)
expect(cost_query('projects', 'id', '=_child_projects', project1.id, project2.id).size).to eq(7)
end
it "does !_child_projects" do
expect(query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
p_c1 = create_project parent: project1
expect(query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
create_project parent: project1
create_project parent: p_c1
expect(query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
expect(cost_query('projects', 'id', '!_child_projects', project1.id).size).to eq(1)
create_project
expect(query('projects', 'id', '!_child_projects', project1.id).size).to eq(2)
expect(cost_query('projects', 'id', '!_child_projects', project1.id).size).to eq(2)
end
it "does !_child_projects on multiple projects" do
expect(query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(0)
expect(cost_query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(0)
p1_c1 = create_project parent: project1
p2_c1 = create_project parent: project2
create_project
expect(query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(1)
expect(cost_query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(1)
p1_c1_c1 = create_project parent: p1_c1
create_project parent: p1_c1_c1
create_project parent: p2_c1
create_project
expect(query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(2)
expect(cost_query('projects', 'id', '!_child_projects', project1.id, project2.id).size).to eq(2)
end
it "does =n" do
@ -248,7 +248,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
# y/n seem are for filtering overridden costs
it "does y" do
expect(query_on_entries('overridden_costs', 'y').size).to eq(Entry.all.select { |e| !e.overridden_costs.nil? }.count)
expect(query_on_entries('overridden_costs', 'y').size).to eq(Entry.all.reject { |e| e.overridden_costs.nil? }.count)
end
it "does n" do
@ -257,20 +257,20 @@ describe CostQuery, type: :model, reporting_query_helper: true do
it "does =d" do
# assuming that there aren't more than one project created at the same time
expect(query('projects', 'created_at', '=d', Project.order(Arel.sql('id ASC')).first.created_at).size).to eq(1)
expect(cost_query('projects', 'created_at', '=d', Project.order(Arel.sql('id ASC')).first.created_at).size).to eq(1)
end
it "does <d" do
expect(query('projects', 'created_at', '<d', Time.now).size).to eq(Project.count)
expect(cost_query('projects', 'created_at', '<d', Time.zone.now).size).to eq(Project.count)
end
it "does <>d" do
expect(query('projects', 'created_at', '<>d', Time.now, 5.minutes.from_now).size).to eq(0)
expect(cost_query('projects', 'created_at', '<>d', Time.zone.now, 5.minutes.from_now).size).to eq(0)
end
it "does >d" do
# assuming that all projects were created in the past
expect(query('projects', 'created_at', '>d', Time.now).size).to eq(0)
expect(cost_query('projects', 'created_at', '>d', Time.zone.now).size).to eq(0)
end
describe 'arity' do

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
describe CostQuery, type: :model, reporting_query_helper: true do
before do
@ -105,23 +105,23 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "computes count correctly" do
expect(@query.result.count).to eq(Entry.count)
expect(query.result.count).to eq(Entry.count)
end
it "computes units correctly" do
expect(@query.result.units).to eq(Entry.all.map { |e| e.units }.sum)
expect(query.result.units).to eq(Entry.all.map(&:units).sum)
end
it "computes real_costs correctly" do
expect(@query.result.real_costs).to eq(Entry.all.map { |e| e.overridden_costs || e.costs }.sum)
expect(query.result.real_costs).to eq(Entry.all.map { |e| e.overridden_costs || e.costs }.sum)
end
it "computes count for DirectResults" do
expect(@query.result.values[0].count).to eq(1)
expect(query.result.values[0].count).to eq(1)
end
it "computes units for DirectResults" do
id_sorted = @query.result.values.sort_by { |r| r[:id] }
id_sorted = query.result.values.sort_by { |r| r[:id] }
te_result = id_sorted.select { |r| r[:type] == TimeEntry.to_s }.first
ce_result = id_sorted.select { |r| r[:type] == CostEntry.to_s }.first
expect(te_result.units.to_s).to eq("1.0")
@ -129,7 +129,7 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "computes real_costs for DirectResults" do
id_sorted = @query.result.values.sort_by { |r| r[:id] }
id_sorted = query.result.values.sort_by { |r| r[:id] }
[CostEntry].each do |type|
result = id_sorted.select { |r| r[:type] == type.to_s }.first
first = type.all.first
@ -138,18 +138,18 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "is a column if created with CostQuery.column" do
@query.column :project_id
expect(@query.result.type).to eq(:column)
query.column :project_id
expect(query.result.type).to eq(:column)
end
it "is a row if created with CostQuery.row" do
@query.row :project_id
expect(@query.result.type).to eq(:row)
query.row :project_id
expect(query.result.type).to eq(:row)
end
it "shows the type :direct for its direct results" do
@query.column :project_id
expect(@query.result.first.first.type).to eq(:direct)
query.column :project_id
expect(query.result.first.first.type).to eq(:direct)
end
end
end

@ -26,7 +26,7 @@
# See COPYRIGHT and LICENSE files for more details.
#++
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require File.expand_path("#{File.dirname(__FILE__)}/../../spec_helper")
describe CostQuery, type: :model, reporting_query_helper: true do
minimal_query
@ -40,12 +40,12 @@ describe CostQuery, type: :model, reporting_query_helper: true do
describe Report::Transformer do
it "walks down row_first" do
@query.group_by :work_package_id
@query.column :tweek
@query.row :project_id
@query.row :user_id
query.group_by :work_package_id
query.column :tweek
query.row :project_id
query.row :user_id
result = @query.transformer.row_first.values.first
result = query.transformer.row_first.values.first
%i[user_id project_id tweek].each do |field|
expect(result.fields).to include(field)
result = result.values.first
@ -53,12 +53,12 @@ describe CostQuery, type: :model, reporting_query_helper: true do
end
it "walks down column_first" do
@query.group_by :work_package_id
@query.column :tweek
@query.row :project_id
@query.row :user_id
query.group_by :work_package_id
query.column :tweek
query.row :project_id
query.row :user_id
result = @query.transformer.column_first.values.first
result = query.transformer.column_first.values.first
%i[tweek work_package_id].each do |field|
expect(result.fields).to include(field)
result = result.values.first

@ -32,9 +32,10 @@ require 'cost_query/operator'
module OpenProject::Reporting
module QueryHelper
def minimal_query
let(:query) { CostQuery.new }
before do
@query = CostQuery.new
@query.send(:minimal_chain!)
query.send(:minimal_chain!)
end
end
end

Loading…
Cancel
Save