abstractor 2.1.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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