abstractor 2.1.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +9 -6
  3. data/app/assets/javascripts/abstractor/abstractor.js.coffee +115 -0
  4. data/app/assets/javascripts/abstractor/application.js +0 -8
  5. data/app/assets/stylesheets/abstractor/abstractor_abstractions.css +21 -1
  6. data/app/views/abstractor/abstractor_abstraction_groups/_form.html.haml +3 -3
  7. data/app/views/abstractor/abstractor_abstractions/_fields.html.haml +15 -5
  8. data/app/views/abstractor/abstractor_abstractions/_list.html.haml +9 -13
  9. data/app/views/abstractor/abstractor_abstractions/edit.html.haml +3 -3
  10. data/db/migrate/20140816005228_add_namespace_to_abstractor_subjects.rb +6 -0
  11. data/lib/abstractor/abstractable.rb +228 -87
  12. data/lib/abstractor/enum.rb +4 -0
  13. data/lib/abstractor/methods/controllers/abstractor_abstractions_controller.rb +7 -1
  14. data/lib/abstractor/methods/controllers/abstractor_suggestions_controller.rb +6 -2
  15. data/lib/abstractor/methods/models/abstractor_abstraction.rb +1 -1
  16. data/lib/abstractor/methods/models/abstractor_abstraction_group.rb +1 -1
  17. data/lib/abstractor/methods/models/abstractor_abstraction_group_member.rb +1 -1
  18. data/lib/abstractor/methods/models/abstractor_abstraction_schema.rb +1 -1
  19. data/lib/abstractor/methods/models/abstractor_abstraction_schema_object_value.rb +1 -1
  20. data/lib/abstractor/methods/models/abstractor_abstraction_schema_predicate_variant.rb +1 -1
  21. data/lib/abstractor/methods/models/abstractor_abstraction_schema_relation.rb +1 -1
  22. data/lib/abstractor/methods/models/abstractor_abstraction_source.rb +1 -1
  23. data/lib/abstractor/methods/models/abstractor_abstraction_source_type.rb +1 -1
  24. data/lib/abstractor/methods/models/abstractor_indirect_source.rb +1 -1
  25. data/lib/abstractor/methods/models/abstractor_object_type.rb +1 -1
  26. data/lib/abstractor/methods/models/abstractor_object_value.rb +1 -2
  27. data/lib/abstractor/methods/models/abstractor_object_value_variant.rb +1 -1
  28. data/lib/abstractor/methods/models/abstractor_relation_type.rb +2 -1
  29. data/lib/abstractor/methods/models/abstractor_rule_type.rb +1 -1
  30. data/lib/abstractor/methods/models/abstractor_subject.rb +22 -18
  31. data/lib/abstractor/methods/models/abstractor_subject_group.rb +1 -1
  32. data/lib/abstractor/methods/models/abstractor_subject_group_member.rb +1 -1
  33. data/lib/abstractor/methods/models/abstractor_subject_relation.rb +1 -1
  34. data/lib/abstractor/methods/models/abstractor_suggestion.rb +1 -1
  35. data/lib/abstractor/methods/models/abstractor_suggestion_object_value.rb +1 -1
  36. data/lib/abstractor/methods/models/abstractor_suggestion_source.rb +1 -1
  37. data/lib/abstractor/methods/models/abstractor_suggestion_status.rb +1 -1
  38. data/lib/abstractor/negation_detection.rb +1 -1
  39. data/lib/abstractor/setup.rb +18 -18
  40. data/lib/abstractor/version.rb +1 -1
  41. data/lib/generators/abstractor/install/install_generator.rb +1 -1
  42. metadata +54 -34
  43. data/app/assets/javascripts/abstractor/abstractor.js +0 -108
  44. data/app/assets/javascripts/abstractor/nested_attributes.js +0 -69
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NGYyMTA2ODY2YWM5ZTgzNzNhM2Y4NmM3ZDBiMDhlZWRmYjcwZmVmYg==
4
+ MjcxMTgwOGI0Y2QwNDNjMjc4NDE2Y2I0YmIwYWQ2ZTg5YzU0NjI2Zg==
5
5
  data.tar.gz: !binary |-
6
- YjhkNzBiNTMwMzAzNTQyYWZlNTJmMzgzYjc2ZTcyYjc3NWM0YzcyMQ==
6
+ ZTJmNWM0ZTcwMzZmMzk5YTRjYjBiMWU5Y2JkZWI1NTFkZjc5NGU1NA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OGQ3NWMwNmNmYzlkYzgyZjUxNDYyOTg4M2E0MmNjMmFkOTAwMjU1Yzg0YTAz
10
- NDVmN2Q2MzVmY2VmYWI5MjkwMjZjZDcyN2VlOTYwNmFmZjVhZjFmNzJmZDZi
11
- NDIzYTA3YTgwY2M4MWU2ZWVjMGU0NTY0NzE4MzUwM2MwZTEyNzg=
9
+ ZjE5NjUwNDVjNDcwMGVlZWEwNjM3MDQ2ODI5NzdiOTExNjZjZjY0Y2RmNzc5
10
+ NjcwMjljNDg4YmU2MDkwMmUxNjk2MTg0MWQ4NTM0OTlkZWUxMjc3YTI2Mzk1
11
+ YjE4NmIyODlkMjRhMDYwZGQ1NTgwMDg0NGYwMWM4OTExMmNlODg=
12
12
  data.tar.gz: !binary |-
13
- ZTI0YmIyMDI2N2Q0ODk5ZDdmYzU3YTI0NDUzYTBlZjQ1OTA1OWY4Mjg1OWU1
14
- MTVmNzQ0YjI2NjQxZmJmODc1MGE4OWU1ZjU1OTA0ZGM5MjJiNzNhNTQxMDBi
15
- ZWJlZTZiZWJjYjlmYmE0YTRjN2U0NDNmYzQxMWMzOTNmMjYzYmU=
13
+ MTNmMjNjZDQ1OGNmM2U5MGFhODFlNWZjNDZkOWVlODE5OWZiYjMwNDAwYjU0
14
+ OTFjZTI5MjQ5OGZmYWZlNzczZDVhMThmMzEwN2QxMWYxZWJjMGI4YWY2ZTEx
15
+ OTJiMDdiMzM2YTVhZTdkMzNkNmNkMGRjYTM4ZTA5MWJmZWI4MmI=
data/README.md CHANGED
@@ -5,10 +5,6 @@ from narrative text via natural language processing. The gem includes
5
5
  a user interface to present the abstracted data points for
6
6
  confirmation/revision by a curator.
7
7
 
8
- Reader's note: this README uses [YARD][] markup to provide links to
9
- Abstractor's API documentation. If you aren't already, consider reading it
10
- on [rubydoc.info][] so that the links will be followable.
11
-
12
8
  [YARD]: http://yardoc.org/
13
9
  [rubydoc.info]: http://rubydoc.info/github/NUBIC/abstractor/master/file/README.md
14
10
 
@@ -20,7 +16,9 @@ on [rubydoc.info][] so that the links will be followable.
20
16
  Abstractor works with:
21
17
 
22
18
  * Ruby 1.9.3, 2.0.0 and 2.1.1
23
- * Rails 3.2 (not Rails 4.0 or later yet)
19
+ * >= Rails 4.1
20
+ * Rails 3.2 branch now available [here][]
21
+ [here]: https://github.com/NUBIC/abstractor/tree/rails-3
24
22
 
25
23
  Some key dependencies are:
26
24
 
@@ -47,11 +45,16 @@ Add abstractor to your Gemfile:
47
45
  ```ruby
48
46
  gem 'abstractor'
49
47
  ```
48
+ or if using Rails 3
49
+
50
+ ```ruby
51
+ gem 'abstractor', :git => 'https://github.com/NUBIC/abstractor', branch: 'rails-3'
52
+ ```
50
53
 
51
54
  Add the stanford-core-nlp gem to your Gemfile. Currently need to use the master branch of the official repository until a new version of the gem is released:
52
55
 
53
56
  ```ruby
54
- gem 'stanford-core-nlp', :git => 'https://github.com/louismullie/stanford-core-nlp', :branch => 'master',
57
+ gem 'stanford-core-nlp', :git => 'https://github.com/louismullie/stanford-core-nlp', branch: 'master'
55
58
  ```
56
59
 
57
60
  Also add the paper\_trail gem to your Gemfile (if it is not already there):
@@ -0,0 +1,115 @@
1
+ Abstractor = {}
2
+ Abstractor.AbstractionUI = ->
3
+ $(document).on "click", ".abstractor_abstraction_value a.edit_link", (e) ->
4
+ e.preventDefault()
5
+ parent_div = $(this).closest(".abstractor_abstraction")
6
+ parent_div.load $(this).attr("href"), ->
7
+ parent_div.find(".combobox").combobox watermark: "a value"
8
+ $(".abstractor_datepicker").datepicker
9
+ altFormat: "yy-mm-dd"
10
+ dateFormat: "yy-mm-dd"
11
+ changeMonth: true
12
+ changeYear: true
13
+
14
+ return
15
+
16
+ parent_div.addClass "highlighted"
17
+ return
18
+
19
+ $(document).on "ajax:success", "form.edit_abstractor_abstraction", (e, data, status, xhr) ->
20
+ parent_div = $(this).closest(".abstractor_abstraction")
21
+ parent_div.html xhr.responseText
22
+
23
+ parent_div.removeClass "highlighted"
24
+ return
25
+
26
+ $(document).on "click", ".edit_abstractor_abstraction input[type='radio']", ->
27
+ $(this).siblings("input[type='checkbox']").prop "checked", false
28
+ return
29
+
30
+ $(document).on "click", ".edit_abstractor_abstraction input[type='checkbox']", ->
31
+ $(this).siblings("input[type='checkbox']").prop "checked", false
32
+ $(this).siblings("input[type='text']").prop "value", ""
33
+ autocompleters = $(this).siblings("select.combobox")
34
+ autocompleters.combobox "setValue", ""
35
+ autocompleters.change()
36
+ $.each $(this).siblings("input[type='radio']"), ->
37
+ if $(this).prop("value") is ""
38
+ $(this).prop "checked", true
39
+ else
40
+ $(this).prop "checked", false
41
+ return
42
+
43
+ return
44
+
45
+ $(document).on "change", ".edit_abstractor_abstraction select.combobox", ->
46
+ $(this).siblings("input[type='checkbox']").prop "checked", false if $(this).find("option:selected").prop("value").length
47
+ return
48
+
49
+ $(document).on "change", ".edit_abstractor_abstraction input[type='text']", ->
50
+ $(this).siblings("input[type='checkbox']").prop "checked", false
51
+ return
52
+
53
+ $(document).on "click", ".abstractor_abstraction_source_tooltip_img", (evt) ->
54
+ target = $(this).attr("rel")
55
+ html = $(target).html()
56
+ title = $(this).attr("title")
57
+ evt.preventDefault()
58
+ $("#abstractor_abstraction_dialog_tooltip").dialog
59
+ maxHeight: 400
60
+ autoOpen: false
61
+ width: 600
62
+ zIndex: 40000
63
+ dialogClass: "ui-dialog_abstractor"
64
+ $("#abstractor_abstraction_dialog_tooltip").html html
65
+ $("#abstractor_abstraction_dialog_tooltip").dialog "option", "title", title
66
+ $("#abstractor_abstraction_dialog_tooltip").dialog "option", "width", ($(window).width() * 0.80)
67
+ $("#abstractor_abstraction_dialog_tooltip").dialog "open"
68
+ return
69
+
70
+ $(document).on "change", "select.indirect_source_list", ->
71
+ source_type = $(this).attr("rel")
72
+ value = $(this).find("option:selected").prop("value")
73
+ $(this).siblings(".indirect_source_text").addClass "hidden"
74
+ $(this).siblings("." + source_type + "_" + value).removeClass "hidden"
75
+ return
76
+
77
+ return
78
+
79
+ Abstractor.AbstractionSuggestionUI = ->
80
+ $(document).on "change", ".abstractor_suggestion_status_selection", ->
81
+ $(this).closest("form").submit()
82
+ return
83
+
84
+ $(document).on "ajax:success", "form.edit_abstractor_suggestion", (e, data, status, xhr) ->
85
+ $(this).closest(".abstractor_abstraction").html xhr.responseText
86
+ return
87
+
88
+ return
89
+
90
+ Abstractor.AbstractionGroupUI = ->
91
+ $(document).on "ajax:success", ".abstractor_abstraction_group .abstractor_group_delete_link", (e, data, status, xhr) ->
92
+ parent_div = $(this).closest(".abstractor_abstraction_group")
93
+ parent_div.html xhr.responseText
94
+ return
95
+
96
+ $(document).on "ajax:success", ".abstractor_subject_groups_container .abstractor_group_add_link", (e, data, status, xhr) ->
97
+ parent_div = $(this).closest(".abstractor_subject_groups_container")
98
+ parent_div.find(".abstractor_subject_groups").append xhr.responseText
99
+ return
100
+
101
+ $(document).on "ajax:success", ".abstractor_abstraction_group .abstractor_group_not_applicable_all_link", (e, data, status, xhr) ->
102
+ parent_div = $(this).closest(".abstractor_abstraction_group")
103
+ parent_div.html xhr.responseText
104
+ return
105
+
106
+ $(document).on "ajax:success", ".abstractor_abstraction_group .abstractor_group_unknown_all_link", (e, data, status, xhr) ->
107
+ parent_div = $(this).closest(".abstractor_abstraction_group")
108
+ parent_div.html xhr.responseText
109
+ return
110
+
111
+ return
112
+
113
+ new Abstractor.AbstractionUI()
114
+ new Abstractor.AbstractionSuggestionUI()
115
+ new Abstractor.AbstractionGroupUI()
@@ -10,12 +10,4 @@
10
10
  // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11
11
  // GO AFTER THE REQUIRES BELOW.
12
12
  //
13
- //= require jquery
14
- //= require jquery_ujs
15
- //= require jquery.ui.widget
16
- //= require jquery.ui.autocomplete
17
- //= require jquery.ui.datepicker
18
- //= require jquery.ui.button
19
- //= require jquery.ui.dialog
20
-
21
13
  //= require_tree .
@@ -207,8 +207,27 @@
207
207
  margin-bottom: 0.5em;
208
208
  }
209
209
 
210
+ .abstractor_abstractions fieldset .abstractor_abstraction_value .version {
211
+ margin-top: .5em;
212
+ margin-bottom: .5em;
213
+ border-bottom: 1px #969696 dashed;
214
+ }
215
+
216
+ .abstractor_abstractions fieldset .abstractor_abstraction_value .version .version_date {
217
+ margin-bottom: .5em;
218
+ }
219
+
220
+ .abstractor_abstractions fieldset .abstractor_abstraction_value .version .version_value {
221
+ margin-bottom: .5em;
222
+ }
223
+
224
+ .abstractor_abstractions fieldset .abstractor_abstraction_value .version .version_user {
225
+ margin-bottom: .5em;
226
+ }
227
+
210
228
  .abstractor_abstractions fieldset .editable_abstraction {
211
229
  border-bottom: 1px #969696 dashed;
230
+ margin-right: .5em;
212
231
  }
213
232
 
214
233
  .abstractor_abstractions fieldset .abstractor_abstraction_source_tooltip_img img {
@@ -321,7 +340,8 @@ span.tooltip_img {
321
340
  }
322
341
 
323
342
  .indirect_source_list {
324
- width: 35%;
343
+ width: 50%;
344
+ height: auto;
325
345
  }
326
346
 
327
347
  .indirect_source_text {
@@ -6,8 +6,8 @@
6
6
  = render :partial => 'abstractor/abstractor_abstractions/fields', :locals => {:abstractor_abstraction => abstractor_abstraction}
7
7
 
8
8
  .abstractor_abstraction_actions
9
- = link_to 'Not applicable group ', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group, abstractor_abstraction_value: 'not applicable')), :confirm => 'Are you sure?', :method => :put, :class => "icon_link update_link", :remote => true
10
- = link_to 'Unknown group ', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group, abstractor_abstraction_value: 'unknown')), :confirm => 'Are you sure?', :method => :put, :class => "icon_link update_link", :remote => true
9
+ = link_to 'Not applicable group ', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group, abstractor_abstraction_value: 'not applicable')), data: { confirm: 'Are you sure?'} , method: :put, class: "abstractor_group_not_applicable_all_link", remote: true
10
+ = link_to 'Unknown group ', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group, abstractor_abstraction_value: 'unknown')), data: { confirm: 'Are you sure?'}, method: :put, class: 'abstractor_group_unknown_all_link', remote: true
11
11
  - if abstractor_abstraction_group.removable?
12
- = link_to 'Delete group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group)), :confirm => 'Are you sure?', :method => :delete, :class => "icon_link delete_link", :remote => true
12
+ = link_to 'Delete group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_group_path(abstractor_abstraction_group)), data: { confirm: 'Are you sure?'}, method: :delete, class: "abstractor_group_delete_link", remote: true
13
13
  %hr
@@ -22,9 +22,19 @@
22
22
  %br
23
23
  %b History:
24
24
  - versions.each do |version|
25
- %br
26
- %i
27
- = "#{version.reify.display_value} - #{version.created_at.to_date.to_s(:date)} (#{version.originator})"
25
+ .version
26
+ .version_date
27
+ %i
28
+ Date:
29
+ = "#{version.created_at.to_date.to_s(:date)}"
30
+ .version_value
31
+ %i
32
+ Value:
33
+ = "#{version.reify.display_value}"
34
+ .version_user
35
+ %i
36
+ User:
37
+ = "#{version.originator}"
28
38
  - if abstractor_suggestions.any?
29
39
  .column-9
30
40
  - abstractor_suggestions.each do |abstractor_suggestion|
@@ -38,7 +48,7 @@
38
48
  - source_about = abstractor_suggestion_source.source_type.constantize.find(abstractor_suggestion_source.source_id)
39
49
  - from_method = abstractor_suggestion_source.source_method
40
50
  - if from_method && source_about.respond_to?(from_method)
41
- %span{ :class => 'abstractor_abstraction_source_tooltip_img label', :rel => "#abstraction_text_#{abstractor_suggestion_source.id}", :title => "#{source_about.class.to_s} #{from_method}"}
51
+ %span{ :class => 'abstractor_abstraction_source_tooltip_img', :rel => "#abstraction_text_#{abstractor_suggestion_source.id}", :title => "#{source_about.class.to_s} #{from_method}"}
42
52
  = image_tag('abstractor/page.png', :id => "abstraction_text_link_#{abstractor_suggestion_source.id}")
43
53
  %div{ :id => "abstraction_text_#{abstractor_suggestion_source.id}", :class => 'abstractor_abstraction_source_tooltip'}
44
54
  - abstractable_from_column = source_about.send(from_method)
@@ -67,7 +77,7 @@
67
77
  - abstractor_abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name == 'nlp suggestion' }.each do |abstractor_abstraction_source|
68
78
  - abstractor_abstraction_source.normalize_from_method_to_sources(abstractor_abstraction.about).each do |source|
69
79
  - dom_id = "#{abstractor_abstraction_source.id}_#{source[:source_type]}_#{source[:source_id]}_#{source[:source_method]}"
70
- %span{ :class => 'abstractor_abstraction_source_tooltip_img label', :rel =>"#abstraction_text_#{dom_id}", :title => "#{source[:source_type].to_s} #{source[:source_method]}"}
80
+ %span{ :class => 'abstractor_abstraction_source_tooltip_img', :rel =>"#abstraction_text_#{dom_id}", :title => "#{source[:source_type].to_s} #{source[:source_method]}"}
71
81
  = image_tag('abstractor/page.png', :id => "abstraction_text_link_#{dom_id}")
72
82
  %br
73
83
  %div{ :id => "abstraction_text_#{dom_id}", :class => 'tooltip'}
@@ -1,8 +1,10 @@
1
1
  - about ||= @about
2
+ - namespace_type ||= @namespace_type
3
+ - namespace_id ||= @namespace_id
2
4
  .abstractor_abstractions
3
- = link_to 'Not applicable all', Abstractor::UserInterface.abstractor_relative_path(abstractor.update_all_abstractor_abstractions_path(about_type: about.class, about_id: about.id, abstractor_abstraction_value: 'not applicable')), :confirm => 'Are you sure?', :method => :put, :class => "icon_link update_link"
4
- = link_to 'Unknown all', Abstractor::UserInterface.abstractor_relative_path(abstractor.update_all_abstractor_abstractions_path(about_type: about.class, about_id: about.id, abstractor_abstraction_value: 'unknown')), :confirm => 'Are you sure?', :method => :put, :class => "icon_link update_link"
5
- - abstractor_subject_groups = Abstractor::AbstractorSubjectGroup.joins(:abstractor_subjects).where(:abstractor_subjects => {:subject_type => about.class}).order('abstractor_subject_groups.id').not_deleted.to_a.uniq
5
+ = link_to 'Not applicable all', Abstractor::UserInterface.abstractor_relative_path(abstractor.update_all_abstractor_abstractions_path(about_type: about.class, about_id: about.id, abstractor_abstraction_value: 'not applicable')), data: { confirm: 'Are you sure?'}, method: :put, class: 'abstractor_not_applicable_all_link'
6
+ = link_to 'Unknown all', Abstractor::UserInterface.abstractor_relative_path(abstractor.update_all_abstractor_abstractions_path(about_type: about.class, about_id: about.id, abstractor_abstraction_value: 'unknown')), data: { confirm: 'Are you sure?'}, method: :put, class: 'abstractor_unknown_all_link'
7
+ - abstractor_subject_groups = about.class.abstractor_subject_groups(namespace_type: namespace_type, namespace_id: namespace_id)
6
8
  - abstractor_subject_groups.each do |abstractor_subject_group|
7
9
  .abstractor_subject_groups_container
8
10
  %b= abstractor_subject_group.name
@@ -17,13 +19,12 @@
17
19
  %b Status
18
20
  %hr
19
21
  .abstractor_subject_groups
20
- - abstractor_abstraction_groups = abstractor_subject_group.abstractor_abstraction_groups.not_deleted.joins(:abstractor_abstractions).where(:abstractor_abstractions => {:about_id => about.id}).order('abstractor_abstraction_groups.id').to_a.uniq
22
+ - abstractor_abstraction_groups = about.abstractor_abstraction_groups_by_namespace(namespace_type: namespace_type, namespace_id: namespace_id)
21
23
  - abstractor_abstraction_groups.each_with_index do |abstractor_abstraction_group, index|
22
24
  = render partial: 'abstractor/abstractor_abstraction_groups/form', locals: {abstractor_abstraction_group: abstractor_abstraction_group}
23
- = link_to 'Add group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_groups_path(about_id: about.id, about_type: about.class.name, abstractor_subject_group_id: abstractor_subject_group.id)), method: :post, class: "icon_link add_link", remote: true
24
-
25
+ = link_to 'Add group', Abstractor::UserInterface.abstractor_relative_path(abstractor.abstractor_abstraction_groups_path(about_id: about.id, about_type: about.class.name, abstractor_subject_group_id: abstractor_subject_group.id)), data: { confirm: 'Are you sure?'}, method: :post, class: 'abstractor_group_add_link', remote: true
25
26
  .clear
26
- - ungrouped_subjects = Abstractor::AbstractorSubject.not_deleted.includes(:abstractor_subject_group_member).where(:subject_type => about.class.to_s, :abstractor_subject_group_members => {:id => nil})
27
+ - ungrouped_subjects = about.class.abstractor_subjects(grouped: false, namespace_type: namespace_type, namespace_id: namespace_id)
27
28
  - if ungrouped_subjects.any?
28
29
  %fieldset
29
30
  .column-3
@@ -39,9 +40,4 @@
39
40
  - ungrouped_subject.abstractor_abstractions.not_deleted.where(:about_id => about.id).each do |abstractor_abstraction|
40
41
  %div{ class: "abstractor_abstraction #{Abstractor::Utility.dehumanize(abstractor_abstraction.abstractor_subject.abstractor_abstraction_schema.predicate)}" }
41
42
  = render :partial => 'abstractor/abstractor_abstractions/fields', :locals => {:abstractor_abstraction => abstractor_abstraction}
42
- :javascript
43
- $(function () {
44
- new Abstractor.AbstractionUI();
45
- new Abstractor.AbstractionSuggestionUI();
46
- new Abstractor.AbstractionGroupUI();
47
- });
43
+ #abstractor_abstraction_dialog_tooltip
@@ -48,14 +48,14 @@
48
48
  - abstraction_source.normalize_from_method_to_sources(abstractor_abstraction.about).each do |source|
49
49
  - if source[:source_type] && source[:source_id] && source[:source_method]
50
50
  - dom_id = "#{abstraction_source.id}_#{source[:source_type]}_#{source[:source_id]}_#{source[:source_method]}"
51
- %span{ :class => 'abstractor_abstraction_source_tooltip_img label', :rel =>"#abstraction_text_#{dom_id}", :title => "#{source[:source_type].to_s} #{source[:source_method]}"}
51
+ %span{ :class => 'abstractor_abstraction_source_tooltip_img', :rel =>"#abstraction_text_#{dom_id}", :title => "#{source[:source_type].to_s} #{source[:source_method]}"}
52
52
  = image_tag('abstractor/page.png', :id => "abstraction_text_link_#{dom_id}")
53
53
  %br
54
54
  %div{ :id => "abstraction_text_#{dom_id}", :class => 'tooltip'}
55
55
  = simple_format(source[:source_type].find(source[:source_id]).send(source[:source_method]))
56
56
  .column-4
57
- = f.submit 'Save', :class => 'button positive'
58
- = link_to 'Cancel', abstractor_abstraction, :class => 'button negative', :remote => true
57
+ = f.submit 'Save'
58
+ = link_to 'Cancel', abstractor_abstraction, :remote => true
59
59
  .clear
60
60
  .indirect_sources
61
61
  - abstraction_sources = abstractor_abstraction.abstractor_subject.abstractor_abstraction_sources.select { |s| s.abstractor_abstraction_source_type.name == 'indirect' }
@@ -0,0 +1,6 @@
1
+ class AddNamespaceToAbstractorSubjects < ActiveRecord::Migration
2
+ def change
3
+ add_column :abstractor_subjects, :namespace_type, :string
4
+ add_column :abstractor_subjects, :namespace_id, :integer
5
+ end
6
+ end
@@ -15,8 +15,57 @@ module Abstractor
15
15
  end
16
16
 
17
17
  module InstanceMethods
18
- def abstract
19
- self.class.abstractor_subjects.each do |abstractor_subject|
18
+ ##
19
+ # Returns all abstractions for the abstractable entity by a namespace.
20
+ #
21
+ # @param [Hash] options the options to filter the list of abstractions to a namespace.
22
+ # @option options [String] :namespace_type The type parameter of the namespace.
23
+ # @option options [Integer] :namespace_id The instance parameter of the namespace.
24
+ # @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction].
25
+ def abstractor_abstractions_by_namespace(options = {})
26
+ options = { namespace_type: nil, namespace_id: nil }.merge(options)
27
+ if options[:namespace_type] || options[:namespace_id]
28
+ abstractor_abstractions.not_deleted.where(abstractor_subject_id: self.class.abstractor_subjects(options).map(&:id))
29
+ else
30
+ abstractor_abstractions.not_deleted
31
+ end
32
+ end
33
+ ##
34
+ # Returns all abstraction groups for the abstractable entity by a namespace.
35
+ #
36
+ # @param [Hash] options the options to filter the list of abstraction groups to a namespace.
37
+ # @option options [String] :namespace_type The type parameter of the namespace.
38
+ # @option options [Integer] :namespace_id The instance parameter of the namespace.
39
+ # @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstractionGroup].
40
+ def abstractor_abstraction_groups_by_namespace(options = {})
41
+ options = { namespace_type: nil, namespace_id: nil }.merge(options)
42
+ if options[:namespace_type] || options[:namespace_id]
43
+ abstractor_abstractions_by_namespace(options).map(&:abstractor_abstraction_group).compact.uniq
44
+ else
45
+ abstractor_abstraction_groups.not_deleted
46
+ end
47
+ end
48
+
49
+ ##
50
+ # The method for generating abstractions from the abstractable entity.
51
+ #
52
+ # The generation of abstactions is based on the setup of Abstactor::AbstractorAbstactionSchema,
53
+ # Abstractor::AbstractorSubject, Abstractor::AbstractorSubjectGroup and Abstractor::AbstractorAbstractionSource associated to the abstractable entity.
54
+ #
55
+ # Namespacing allows for different sets data points to be associated to the same abstractable entity.
56
+ #
57
+ # Namespacing is achieved by setting the Abstractor::AbstractorSubject#namespace_type and Abstractor::AbstractorSubject#namespace_id attributes.
58
+ #
59
+ # Passing a namespace to this method will restrict the generation of abstractions to the given namespace. Otherwise, all configured abstractions associated to the abstractable entity will be generated.
60
+ #
61
+ # A practical example of the use of a namespace would be two different clincal departments wanting to chart abstract two distinct sets of datapoints for progress notes extracted from an electronic medical record system.
62
+ # @param [Hash] options the options to filter the generation of abstractions to a namespace.
63
+ # @option options [String] :namespace_type The type parameter of the namespace.
64
+ # @option options [Integer] :namespace_id The instance parameter of the namespace.
65
+ # @return [void]
66
+ def abstract(options = {})
67
+ options = { namespace_type: nil, namespace_id: nil }.merge(options)
68
+ self.class.abstractor_subjects(options).each do |abstractor_subject|
20
69
  abstractor_subject.abstract(self)
21
70
  end
22
71
  end
@@ -56,24 +105,32 @@ module Abstractor
56
105
  # * 'reviewed': Filter abstractions having a determined value (value, unknown or not_applicable).
57
106
  #
58
107
  # @param [String] abstractor_abstraction_status Filter abstractions that need review or are reviews.
59
- # @return [ActiveRecord::Relation] List of [Abstractor::AbstractorAbstraction].
60
- def abstractor_abstractions_by_abstractor_abstraction_status(abstractor_abstraction_status)
108
+ # @param [Hash] options the options to filter abstractions to a namespace.
109
+ # @option options [String] :namespace_type the type parameter of the namespace.
110
+ # @option options [Integer] :namespace_id the instance parameter of the namespace.
111
+ # @return [ActiveRecord::Relation] list of [Abstractor::AbstractorAbstraction].
112
+ def abstractor_abstractions_by_abstractor_abstraction_status(abstractor_abstraction_status, options = {})
113
+ options = { namespace_type: nil, namespace_id: nil }.merge(options)
61
114
  case abstractor_abstraction_status
62
- when 'needs_review'
63
- abstractor_abstractions.not_deleted.select { |abstractor_abstraction| abstractor_abstraction.value.blank? && abstractor_abstraction.unknown.blank? && abstractor_abstraction.not_applicable.blank? }
64
- when 'reviewed'
65
- abstractor_abstractions.not_deleted.select { |abstractor_abstraction| !abstractor_abstraction.value.blank? || !abstractor_abstraction.unknown.blank? || !abstractor_abstraction.not_applicable.blank? }
115
+ when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW
116
+ abstractor_abstractions_by_namespace(options).select { |abstractor_abstraction| abstractor_abstraction.value.blank? && abstractor_abstraction.unknown.blank? && abstractor_abstraction.not_applicable.blank? }
117
+ when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED
118
+ abstractor_abstractions_by_namespace(options).select { |abstractor_abstraction| !abstractor_abstraction.value.blank? || !abstractor_abstraction.unknown.blank? || !abstractor_abstraction.not_applicable.blank? }
66
119
  end
67
120
  end
68
121
 
69
122
  ##
70
- # Removes all abstractions, suggestions and indirect sources for the abstractable entity. Optionally filtred to only 'unreviewd' abstractions.
123
+ # Removes all abstractions, suggestions and indirect sources for the abstractable entity. Optionally filtred to only 'unreviewed' abstractions and to a given namespace.
71
124
  #
72
- # @param [Boolean] only_unreviewed Instructs whther to confine removal to only 'unreviewd' abstractions.
125
+ # @param [Hash] options the options to filter the removal of abstractions.
126
+ # @option options [Booelan] :only_unreviewed Instructs whether to confine removal to only 'unreviewed' abstractions.
127
+ # @option options [String] :namespace_type The type parameter of the namespace to remove.
128
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to remove.
73
129
  # @return [void]
74
- def remove_abstractions(only_unreviewed = true)
75
- abstractor_abstractions.each do |abstractor_abstraction|
76
- if !only_unreviewed || (only_unreviewed && abstractor_abstraction.unreviewed?)
130
+ def remove_abstractions(options = {})
131
+ options = { only_unreviewed: true, namespace_type: nil, namespace_id: nil }.merge(options)
132
+ abstractor_abstractions_by_namespace(options).each do |abstractor_abstraction|
133
+ if !options[:only_unreviewed] || (options[:only_unreviewed] && abstractor_abstraction.unreviewed?)
77
134
  abstractor_abstraction.abstractor_suggestions.each do |abstractor_suggestion|
78
135
  abstractor_suggestion.abstractor_suggestion_sources.destroy_all
79
136
  abstractor_suggestion.abstractor_suggestion_object_value.destroy if abstractor_suggestion.abstractor_suggestion_object_value
@@ -96,15 +153,31 @@ module Abstractor
96
153
  # * 'reviewed': Filter abstractable entites having no abstractions without a determined value (value, unknown or not_applicable).
97
154
  #
98
155
  # @param [String] abstractor_abstraction_status Filter abstactable entities that an abstraction that 'needs_review' or are all abstractions are 'reviewed'.
156
+ # @param [Hash] options the options to filter the entities returned.
157
+ # @option options [String] :namespace_type The type parameter of the namespace to filter the entities.
158
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to filter the entities.
99
159
  # @return [ActiveRecord::Relation] List of abstractable entities.
100
- def by_abstractor_abstraction_status(abstractor_abstraction_status)
101
- case abstractor_abstraction_status
102
- when 'needs_review'
103
- where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND (aa.value IS NULL OR aa.value = '') AND (aa.unknown IS NULL OR aa.unknown = ?) AND (aa.not_applicable IS NULL OR aa.not_applicable = ?))", false, false])
104
- when 'reviewed'
105
- where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id) AND NOT EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(aa.value, '') = '' AND COALESCE(aa.unknown, ?) != ? AND COALESCE(aa.not_applicable, ?) != ?)", false, true, false, true])
160
+ def by_abstractor_abstraction_status(abstractor_abstraction_status, options = {})
161
+ options = { namespace_type: nil, namespace_id: nil }.merge(options)
162
+
163
+ if options[:namespace_type] || options[:namespace_id]
164
+ case abstractor_abstraction_status
165
+ when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW
166
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.namespace_type = ? AND sub.namespace_id = ? WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND (aa.value IS NULL OR aa.value = '') AND (aa.unknown IS NULL OR aa.unknown = ?) AND (aa.not_applicable IS NULL OR aa.not_applicable = ?))", options[:namespace_type], options[:namespace_id], false, false])
167
+ when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED
168
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.namespace_type = ? AND sub.namespace_id = ? WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id) AND NOT EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.namespace_type = ? AND sub.namespace_id = ? WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(aa.value, '') = '' AND COALESCE(aa.unknown, ?) != ? AND COALESCE(aa.not_applicable, ?) != ?)", options[:namespace_type], options[:namespace_id], options[:namespace_type], options[:namespace_id], false, true, false, true])
169
+ else
170
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.namespace_type = ? AND sub.namespace_id = ? WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id)", options[:namespace_type], options[:namespace_id]])
171
+ end
106
172
  else
107
- where(nil)
173
+ case abstractor_abstraction_status
174
+ when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW
175
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND (aa.value IS NULL OR aa.value = '') AND (aa.unknown IS NULL OR aa.unknown = ?) AND (aa.not_applicable IS NULL OR aa.not_applicable = ?))", false, false])
176
+ when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED
177
+ where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id) AND NOT EXISTS (SELECT 1 FROM abstractor_abstractions aa WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(aa.value, '') = '' AND COALESCE(aa.unknown, ?) != ? AND COALESCE(aa.not_applicable, ?) != ?)", false, true, false, true])
178
+ else
179
+ where(nil)
180
+ end
108
181
  end
109
182
  end
110
183
 
@@ -113,21 +186,25 @@ module Abstractor
113
186
  #
114
187
  # By default, the method will return all abstractor subjects.
115
188
  #
116
- # @param [Hash] options the options to filter the objects returned
189
+ # @param [Hash] options the options to filter the subjects returned.
117
190
  # @option options [Boolean] :grouped Filters the list of Abstactor::AbstractorSubject objects to grouped and non-grouped. Defaults to nil which returns all objects.
191
+ # @option options [String] :namespace_type The type parameter of the namespace to filter the subjects.
192
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to filter the subjects.
118
193
  # @return ActiveRecord::Relation list of Abstactor::AbstractorSubject objects
119
194
  def abstractor_subjects(options = {})
120
- options = { grouped: nil }.merge(options)
195
+ options = { grouped: nil, namespace_type: nil, namespace_id: nil }.merge(options)
121
196
  subjects = Abstractor::AbstractorSubject.where(subject_type: self.to_s)
197
+ if options[:namespace_type] || options[:namespace_id]
198
+ subjects = subjects.select { |subject| subject.namespace_type == options[:namespace_type] && subject.namespace_id == options[:namespace_id] }
199
+ end
122
200
  subjects = case options[:grouped]
123
201
  when true
124
- subjects.select{ |s| s.abstractor_subject_group_member}
202
+ subjects.select{ |s| s.abstractor_subject_group_member }
125
203
  when false
126
- subjects.reject{ |s| s.abstractor_subject_group_member}
204
+ subjects.reject{ |s| s.abstractor_subject_group_member }
127
205
  when nil
128
206
  subjects
129
207
  end
130
- subjects
131
208
  end
132
209
 
133
210
  ##
@@ -135,16 +212,19 @@ module Abstractor
135
212
  #
136
213
  # By default, the method will return all abstractor abstraction schemas.
137
214
  #
138
- # @param [Hash] options the options to filter the objects returned
139
- # @option options [Boolean] :grouped Filters the list of Abstractor::AbstractorAbstractionSchema objects to grouped and non-grouped. Defaults to nil which returns all objects.
215
+ # @param [Hash] options the options to filter the abstaction schemas.
216
+ # @option options [Boolean] :grouped Filters the list of Abstractor::AbstractorAbstractionSchema objects to grouped and non-grouped. Defaults to nil which returns all abstraction schemas.
217
+ # @option options [String] :namespace_type The type parameter of the namespace to filter the abstaction schemas.
218
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to filter the abstaction schemas.
140
219
  # @return ActiveRecord::Relation list of Abstactor::AbstractorAbstractionSchema objects
141
- def abstractor_abstraction_schemas(options= {})
142
- options = { grouped: nil }.merge(options)
220
+ def abstractor_abstraction_schemas(options = {})
221
+ options = { grouped: nil, namespace_type: nil, namespace_id: nil }.merge(options)
143
222
  abstractor_subjects(options).map(&:abstractor_abstraction_schema)
144
223
  end
145
224
 
146
- def abstractor_subject_groups
147
- abstractor_subjects.map(&:abstractor_subject_group).compact.uniq
225
+ def abstractor_subject_groups(options = {})
226
+ options = { grouped: true, namespace_type: nil, namespace_id: nil }.merge(options)
227
+ abstractor_subjects(options).map(&:abstractor_subject_group).compact.uniq
148
228
  end
149
229
 
150
230
  ##
@@ -159,17 +239,21 @@ module Abstractor
159
239
  # it was strucutred like so:
160
240
  # 'select id, collection_date, report_text, has_cancer_diagnosis from pathology_cases'
161
241
  #
242
+ # @param [Hash] options the options to pivot the abstractions.
243
+ # @option options [String] :namespace_type The type parameter of the namespace to pivot abstractions.
244
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to pivot abstractions.
162
245
  # @return ActiveRecord::Relation
163
- def pivot_abstractions
164
- select = prepare_pivot_select(grouped: false)
246
+ def pivot_abstractions(options = {})
247
+ options = { grouped: false, namespace_type: nil, namespace_id: nil }.merge(options)
248
+ select = prepare_pivot_select(options)
165
249
  adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
166
250
  j = case adapter
167
251
  when 'sqlite3'
168
- prepare_pivot_joins(select, "'t'")
252
+ prepare_pivot_joins(select, "'t'", options)
169
253
  when 'sqlserver'
170
- prepare_pivot_joins(select, '1')
254
+ prepare_pivot_joins(select, '1', options)
171
255
  when 'postgresql'
172
- prepare_pivot_joins(select, 'true')
256
+ prepare_pivot_joins(select, 'true', options)
173
257
  end
174
258
  joins(j).select("#{self.table_name}.*, pivoted_abstractions.*")
175
259
  end
@@ -191,18 +275,22 @@ module Abstractor
191
275
  # If an abstractable entity has multiple instances of grouped abstractions the entity will be returned mutlple times.
192
276
  #
193
277
  # @param [String] abstractor_subject_groups_name name of {Abstractor::Methods::Models:AbtractorSubjectGroup}
278
+ # @param [Hash] options the options to pivot the grouped abstractions.
279
+ # @option options [String] :namespace_type The type parameter of the namespace to pivot grouped abstractions.
280
+ # @option options [Integer] :namespace_id The instance parameter of the namespace to pivot grouped abstractions.
194
281
  # @return ActiveRecord::Relation
195
282
  # @see Abstractor::Methods::Models:AbstractorSubjectGroup
196
- def pivot_grouped_abstractions(abstractor_subject_groups_name)
197
- select = prepare_pivot_select(grouped: true)
283
+ def pivot_grouped_abstractions(abstractor_subject_groups_name, options = {})
284
+ options = { grouped: true, namespace_type: nil, namespace_id: nil }.merge(options)
285
+ select = prepare_pivot_select(options)
198
286
  adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter]
199
287
  j = case adapter
200
288
  when 'sqlite3'
201
- prepare_grouped_pivot_joins(select, "'t'", abstractor_subject_groups_name)
289
+ prepare_grouped_pivot_joins(select, "'t'", abstractor_subject_groups_name, options)
202
290
  when 'sqlserver'
203
- prepare_grouped_pivot_joins(select, '1', abstractor_subject_groups_name)
291
+ prepare_grouped_pivot_joins(select, '1', abstractor_subject_groups_name, options)
204
292
  when 'postgresql'
205
- prepare_grouped_pivot_joins(select, 'true', abstractor_subject_groups_name)
293
+ prepare_grouped_pivot_joins(select, 'true', abstractor_subject_groups_name, options)
206
294
  end
207
295
  joins(j).select("#{self.table_name}.*, pivoted_abstractions.*")
208
296
  end
@@ -219,55 +307,108 @@ module Abstractor
219
307
  select = select.join(',')
220
308
  end
221
309
 
222
- def prepare_pivot_joins(select, bool)
223
- "LEFT JOIN
224
- (
225
- SELECT #{self.table_name}.id AS subject_id,
226
- #{select}
227
- FROM
228
- (SELECT aas.predicate
229
- , aas.id AS abstractor_abstraction_schema_id
230
- , asb.subject_type
231
- , aa.about_id
232
- , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
233
- FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
234
- JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
235
- WHERE asb.subject_type = '#{self.to_s}'
236
- AND NOT EXISTS (
237
- SELECT 1
238
- FROM abstractor_abstraction_group_members aagm
239
- WHERE aa.id = aagm.abstractor_abstraction_id
240
- )
241
- ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
242
- GROUP BY #{self.table_name}.id
243
- ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
244
- "
310
+ def prepare_pivot_joins(select, bool, options = {})
311
+ if options[:namespace_type] || options[:namespace_id]
312
+ "LEFT JOIN
313
+ (
314
+ SELECT #{self.table_name}.id AS subject_id,
315
+ #{select}
316
+ FROM
317
+ (SELECT aas.predicate
318
+ , aas.id AS abstractor_abstraction_schema_id
319
+ , asb.subject_type
320
+ , aa.about_id
321
+ , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
322
+ FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
323
+ JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
324
+ WHERE asb.subject_type = '#{self.to_s}'
325
+ AND asb.namespace_type = '#{options[:namespace_type]}'
326
+ AND asb.namespace_id = #{options[:namespace_id]}
327
+ AND NOT EXISTS (
328
+ SELECT 1
329
+ FROM abstractor_abstraction_group_members aagm
330
+ WHERE aa.id = aagm.abstractor_abstraction_id
331
+ )
332
+ ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
333
+ GROUP BY #{self.table_name}.id
334
+ ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
335
+ "
336
+ else
337
+ "LEFT JOIN
338
+ (
339
+ SELECT #{self.table_name}.id AS subject_id,
340
+ #{select}
341
+ FROM
342
+ (SELECT aas.predicate
343
+ , aas.id AS abstractor_abstraction_schema_id
344
+ , asb.subject_type
345
+ , aa.about_id
346
+ , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
347
+ FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
348
+ JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
349
+ WHERE asb.subject_type = '#{self.to_s}'
350
+ AND NOT EXISTS (
351
+ SELECT 1
352
+ FROM abstractor_abstraction_group_members aagm
353
+ WHERE aa.id = aagm.abstractor_abstraction_id
354
+ )
355
+ ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
356
+ GROUP BY #{self.table_name}.id
357
+ ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
358
+ "
359
+ end
245
360
  end
246
361
 
247
- def prepare_grouped_pivot_joins(select, bool, abstractor_subject_groups_name)
248
- abstractor_subject_group = abstractor_subject_groups.detect { |abstractor_subject_group| abstractor_subject_group.name == abstractor_subject_groups_name }
362
+ def prepare_grouped_pivot_joins(select, bool, abstractor_subject_groups_name, options = {})
363
+ abstractor_subject_group = abstractor_subject_groups(options).detect { |abstractor_subject_group| abstractor_subject_group.name == abstractor_subject_groups_name }
249
364
 
250
- "JOIN
251
- (
252
- SELECT #{self.table_name}.id AS subject_id,
253
- #{select}
254
- FROM
255
- (SELECT aas.predicate
256
- , aas.id AS abstraction_schema_id
257
- , asb.subject_type
258
- , aa.about_id
259
- , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
260
- , aag.id AS abstractor_abstraction_group_id
261
- FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
262
- JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
263
- JOIN abstractor_abstraction_group_members aagm ON aa.id = aagm.abstractor_abstraction_id
264
- JOIN abstractor_abstraction_groups aag ON aagm.abstractor_abstraction_group_id= aag.id
265
- WHERE asb.subject_type = '#{self.to_s}'
266
- AND aag.abstractor_subject_group_id = #{abstractor_subject_group.id}
267
- ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
268
- GROUP BY #{self.table_name}.id, abstractor_abstraction_group_id
269
- ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
270
- "
365
+ if options[:namespace_type] || options[:namespace_id]
366
+ "JOIN
367
+ (
368
+ SELECT #{self.table_name}.id AS subject_id,
369
+ #{select}
370
+ FROM
371
+ (SELECT aas.predicate
372
+ , aas.id AS abstraction_schema_id
373
+ , asb.subject_type
374
+ , aa.about_id
375
+ , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
376
+ , aag.id AS abstractor_abstraction_group_id
377
+ FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
378
+ JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
379
+ JOIN abstractor_abstraction_group_members aagm ON aa.id = aagm.abstractor_abstraction_id
380
+ JOIN abstractor_abstraction_groups aag ON aagm.abstractor_abstraction_group_id= aag.id
381
+ WHERE asb.subject_type = '#{self.to_s}'
382
+ AND asb.namespace_type = '#{options[:namespace_type]}'
383
+ AND asb.namespace_id = #{options[:namespace_id]}
384
+ AND aag.abstractor_subject_group_id = #{abstractor_subject_group.id}
385
+ ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
386
+ GROUP BY #{self.table_name}.id, abstractor_abstraction_group_id
387
+ ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
388
+ "
389
+ else
390
+ "JOIN
391
+ (
392
+ SELECT #{self.table_name}.id AS subject_id,
393
+ #{select}
394
+ FROM
395
+ (SELECT aas.predicate
396
+ , aas.id AS abstraction_schema_id
397
+ , asb.subject_type
398
+ , aa.about_id
399
+ , CASE WHEN aa.value IS NOT NULL AND aa.value != '' THEN aa.value WHEN aa.unknown = #{bool} THEN 'unknown' WHEN aa.not_applicable = #{bool} THEN 'not applicable' END AS value
400
+ , aag.id AS abstractor_abstraction_group_id
401
+ FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id
402
+ JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id
403
+ JOIN abstractor_abstraction_group_members aagm ON aa.id = aagm.abstractor_abstraction_id
404
+ JOIN abstractor_abstraction_groups aag ON aagm.abstractor_abstraction_group_id= aag.id
405
+ WHERE asb.subject_type = '#{self.to_s}'
406
+ AND aag.abstractor_subject_group_id = #{abstractor_subject_group.id}
407
+ ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id
408
+ GROUP BY #{self.table_name}.id, abstractor_abstraction_group_id
409
+ ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id
410
+ "
411
+ end
271
412
  end
272
413
  end
273
414
  end