diff --git a/Gemfile.lock b/Gemfile.lock index 5f79fbee974ea44a99a89b3bcad3247968b42d33..2dc79b46329e2f327e568ef3b5f724a1406f68b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - quby-compiler (0.3.4) + quby-compiler (0.3.5) actionview (>= 5.0) activemodel (>= 5.0) activesupport (>= 5.0) @@ -21,8 +21,8 @@ GEM erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - active_interaction (3.8.3) - activemodel (>= 4, < 7) + active_interaction (4.0.2) + activemodel (>= 5, < 7) activemodel (6.0.4) activesupport (= 6.0.4) activerecord (6.0.4) @@ -34,7 +34,7 @@ GEM minitest (~> 5.1) tzinfo (~> 1.1) zeitwerk (~> 2.2, >= 2.2.2) - appsignal (2.10.12) + appsignal (3.0.8) rack builder (3.2.4) coderay (1.1.3) @@ -44,13 +44,13 @@ GEM dry-configurable (0.12.1) concurrent-ruby (~> 1.0) dry-core (~> 0.5, >= 0.5.0) - dry-container (0.7.2) + dry-container (0.8.0) concurrent-ruby (~> 1.0) dry-configurable (~> 0.1, >= 0.1.3) - dry-core (0.5.0) + dry-core (0.6.0) concurrent-ruby (~> 1.0) dry-inflector (0.2.0) - dry-logic (1.1.0) + dry-logic (1.2.0) concurrent-ruby (~> 1.0) dry-core (~> 0.5, >= 0.5) dry-struct (1.4.0) @@ -91,10 +91,10 @@ GEM loofah (~> 2.3) rake (12.3.3) redcarpet (3.5.1) - roqua-support (0.3.5) - active_interaction (~> 3.0) - activesupport (>= 5.1, < 6.1) - appsignal (>= 2.9, < 2.11) + roqua-support (0.4.0) + active_interaction (>= 3.0, < 5.0) + activesupport (>= 5.2, < 6.2) + appsignal (>= 2.9, < 3.1) naught (~> 1.0) with_advisory_lock (~> 3.2) rspec (3.9.0) diff --git a/lib/quby/compiler/entities/outcome_table.rb b/lib/quby/compiler/entities/outcome_table.rb index 64d042e178f8e269ea4839bbd3acec183441820d..06654c0c9448cf077b93a2e3e6457664c41ab46f 100644 --- a/lib/quby/compiler/entities/outcome_table.rb +++ b/lib/quby/compiler/entities/outcome_table.rb @@ -15,6 +15,7 @@ module Quby validates :score_keys, :subscore_keys, :questionnaire, :key, presence: true validates :name, presence: true, if: proc { |table| table.default_collapsed } validate :references_existing_score_keys + validate :no_outcome_tables_defined_in_score_schemas def references_existing_score_keys (score_keys - questionnaire.score_schemas.values.map(&:key)).each do |missing_key| @@ -25,6 +26,17 @@ module Quby errors.add :subscore_keys, "#{missing_key.inspect} not found in subscore schemas" end end + + def no_outcome_tables_defined_in_score_schemas + if questionnaire.score_schemas.values.any? do |schema| + schema.subscore_schemas.any? do |subscore| + subscore.outcome_table != :main + end + end + errors.add :score_schemas, + "Outcome table associations defined in score schemas should not be combined with explicit outcome tables" + end + end end end end diff --git a/lib/quby/compiler/outputs/roqua_serializer.rb b/lib/quby/compiler/outputs/roqua_serializer.rb index bf0307256e68d302ccdeacb2ff728b1ce3509e5c..4ffc9002e0acc64b83ebb52e90fe048da48ef419 100644 --- a/lib/quby/compiler/outputs/roqua_serializer.rb +++ b/lib/quby/compiler/outputs/roqua_serializer.rb @@ -84,11 +84,47 @@ module Quby # <subscore_key:Symbol>: <subscore.label:String> # headers for each subscore key for all tables. def outcome_tables_schema + if questionnaire.outcome_tables.present? + outcome_tables_from_definition + else + outcome_tables_from_score_schemas + end + end + + def outcome_tables_from_definition + # hash of tables, with the score keys (rows) and subscore keys (columns) used for each + tables = {} + # hash of `subscore_key: subscore_label` pairs used in tables + headers = {} + + questionnaire.outcome_tables.each do |table| + tables[table.key] = {name: table.name, + default_collapsed: table.default_collapsed, + score_keys: table.score_keys, + subscore_keys: table.subscore_keys}.compact + + table.subscore_keys.each do |subscore_key| + table.score_keys.find do |score_key| + subschema = questionnaire.score_schemas[score_key].subscore_schemas.find do |subschema| + subschema.key == subscore_key + end + headers[subscore_key] = subschema&.label + end + end + end + + { + headers: headers, + tables: tables, + } + end + + def outcome_tables_from_score_schemas # hash of tables, with the score keys (rows) and subscore keys (columns) used for each tables = Hash.new{ |hash, key| hash[key] = {score_keys: Set.new, subscore_keys: Set.new } } # hash of `subscore_key: subscore_label` pairs used in tables headers = {} - + questionnaire.score_schemas.values.each do |schema| schema.subscore_schemas.each do |subschema| next if subschema.outcome_table.blank? @@ -97,7 +133,7 @@ module Quby headers[subschema.key] = subschema.label end end - + { headers: headers, tables: tables, diff --git a/spec/quby/compiler/entities/outcome_table_spec.rb b/spec/quby/compiler/entities/outcome_table_spec.rb index f87e919b79a58fe1b2ce001cdefbe86d7e63cefb..c2ef7e6b529194925e4d52a4883bf838505fc5e3 100644 --- a/spec/quby/compiler/entities/outcome_table_spec.rb +++ b/spec/quby/compiler/entities/outcome_table_spec.rb @@ -29,5 +29,25 @@ module Quby::Compiler::Entities "Subscore keys :unknown_key_2 not found in subscore schemas"]) end end + + describe '#no_outcome_tables_defined_in_score_schemas' do + let(:questionnaire) do + Quby::Compiler::DSL.build("test") do + score(:key, + label: 'score', + schema: [{key: :value, label: 'Score', export_key: :key, outcome_table: :something}]) { {value: 'oh1'} } + score(:key2, label: 'score2', schema: [{key: :value, label: 'Score 2', export_key: :key2}]) { {value: 'oh2'} } + end + end + it 'checks all score schemas don\'t have a outcome table defined already' do + table = described_class.new(key: :test_outcome_table, + score_keys: %i[key key2], + subscore_keys: [:value], + questionnaire: questionnaire) + table.valid? + expect(table.errors.full_messages).to \ + eq(["Score schemas Outcome table associations defined in score schemas should not be combined with explicit outcome tables"]) + end + end end end diff --git a/spec/quby/compiler/outputs/roqua_serializer_spec.rb b/spec/quby/compiler/outputs/roqua_serializer_spec.rb index 47f0a85323230a8aba39d470f5930e27cfe47f9c..033c88c92f23b22f3b6191703d0e454f6a825ec4 100644 --- a/spec/quby/compiler/outputs/roqua_serializer_spec.rb +++ b/spec/quby/compiler/outputs/roqua_serializer_spec.rb @@ -1,7 +1,47 @@ require 'spec_helper' describe Quby::Compiler::Outputs::RoquaSerializer do - it 'generates outcome schemas' do + it 'generates outcome tables schema from questionnaire defined outcome tables' do + questionnaire = dsl("test") do + title "Test Quest" + + score_schema :score1, 'Score 1' do + subscore(:value, 'Waarde', export_key: :score1) { 1 } + subscore(:int, 'Interpretatie', export_key: :score1_i) { 'Wah' } + end + + score_schema :score0, 'Score 0' do + subscore(:value, 'Nog iets', export_key: :score0) { 'Iets' } + end + + outcome_table name: 'Alleen score 0', + key: :only_score0, + score_keys: [:score0], + default_collapsed: true, + subscore_keys: %i[value] + + outcome_table name: 'Scores', + key: :scores, + score_keys: [:score0, :score1], + subscore_keys: %i[value int] + end + serializer = described_class.new(questionnaire) + + expected = { + outcome_tables_schema: + {headers: {int: "Interpretatie", value: "Nog iets"}, + tables: {only_score0: {default_collapsed: true, + name: "Alleen score 0", + score_keys: [:score0], + subscore_keys: [:value]}, + scores: {name: "Scores", + score_keys: [:score0, :score1], + subscore_keys: [:value, :int]}}} + } + expect(serializer.as_json).to include(expected) + end + + it 'generates outcome tables schema from score schema outcome tables' do questionnaire = dsl("test") do title "Test Quest" @@ -50,9 +90,9 @@ describe Quby::Compiler::Outputs::RoquaSerializer do outcome_tables_schema: { headers: {int: "Interpretatie", mean: "Gemiddelde", something: "Nog iets", value: "Waarde"}, tables: { - main: {:score_keys => [:score0], :subscore_keys => [:something]}, - values: {:score_keys => [:score1, :score2], :subscore_keys => [:value, :int]}, - means: {:score_keys => [:score3, :score4], :subscore_keys => [:mean]} + main: {score_keys: [:score0], subscore_keys: [:something]}, + values: {score_keys: [:score1, :score2], subscore_keys: [:value, :int]}, + means: {score_keys: [:score3, :score4], subscore_keys: [:mean]} } } })