module Abstractor::Abstractable::ClassMethods
Public Instance Methods
Returns the abstractor abstraction schemas associated with the abstractable entity.
By default, the method will return all abstractor abstraction schemas.
@param [Hash] options the options to filter the abstaction schemas. @option options [Boolean] :grouped Filters the list of Abstractor::AbstractorAbstractionSchema
objects to grouped and non-grouped. Defaults to nil which returns all abstraction schemas. @option options [String] :namespace_type The type parameter of the namespace to filter the abstaction schemas. @option options [Integer] :namespace_id The instance parameter of the namespace to filter the abstaction schemas. @return ActiveRecord::Relation list of Abstactor::AbstractorAbstractionSchema objects
# File lib/abstractor/abstractable.rb, line 592 def abstractor_abstraction_schemas(options = {}) options = { grouped: nil, namespace_type: nil, namespace_id: nil }.merge(options) abstractor_subjects(options).map(&:abstractor_abstraction_schema) end
# File lib/abstractor/abstractable.rb, line 597 def abstractor_subject_groups(options = {}) options = { grouped: true, namespace_type: nil, namespace_id: nil }.merge(options) Abstractor::AbstractorSubjectGroup.find(abstractor_subjects(options).map{|s| s.abstractor_subject_group.id}) end
Returns the abstractor subjects associated with the abstractable entity.
By default, the method will return all abstractor subjects.
@param [Hash] options the options to filter the subjects returned. @option options [Boolean] :grouped Filters the list of Abstactor::AbstractorSubject objects to grouped and non-grouped. Defaults to nil which returns all objects. @option options [String] :namespace_type The type parameter of the namespace to filter the subjects. @option options [Integer] :namespace_id The instance parameter of the namespace to filter the subjects. @return ActiveRecord::Relation list of Abstactor::AbstractorSubject objects
# File lib/abstractor/abstractable.rb, line 561 def abstractor_subjects(options = {}) options = { grouped: nil, namespace_type: nil, namespace_id: nil, abstractor_abstraction_schema_ids: [] }.merge(options) subjects = Abstractor::AbstractorSubject.where(subject_type: self.to_s) if options[:namespace_type] || options[:namespace_id] subjects = subjects.where(namespace_type: options[:namespace_type], namespace_id: options[:namespace_id]) end if options[:abstractor_abstraction_schema_ids].any? subjects = subjects.where(abstractor_abstraction_schema_id: options[:abstractor_abstraction_schema_ids]) end subjects = case options[:grouped] when true subjects.joins(:abstractor_subject_group).includes(:abstractor_subject_group) when false subjects.where("not exists (select 'a' from abstractor_subject_group_members where abstractor_subject_id = abstractor_subjects.id)") when nil subjects end end
Returns all abstractable entities filtered by the parameter abstractor_abstraction_status:
-
‘needs_review’: Filter abstractable entites having at least one abstraction without a determined value (value, unknown or not_applicable).
-
‘reviewed’: Filter abstractable entites having no abstractions without a determined value (value, unknown or not_applicable).
-
‘partially reviewed’: Filter abstractable entites having both abstractions with determned values (value, unknown or not_applicable) and abstractions without determined values.
-
‘actually answered’: Filter abstractable entites having no abstractions without an actual value (exluding blank, unknown or not_applicable).
@param [String] abstractor_abstraction_status Filter abstactable entities that an abstraction that ‘needs_review’ or are all abstractions are ‘reviewed’. @param [Hash] options the options to filter the entities returned. @option options [String] :namespace_type The type parameter of the namespace to filter the entities. @option options [Integer] :namespace_id The instance parameter of the namespace to filter the entities. @return [ActiveRecord::Relation] List of abstractable entities.
# File lib/abstractor/abstractable.rb, line 403 def by_abstractor_abstraction_status(abstractor_abstraction_status, options = {}) options = { namespace_type: nil, namespace_id: nil }.merge(options) if options[:namespace_type] || options[:namespace_id] case abstractor_abstraction_status when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW 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]) when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED 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]) when Abstractor::Enum::ABSTRACTION_STATUS_PARTIALLY_REVIEWED 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 = ?) ) AND 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, '') != '' OR COALESCE(aa.unknown, ?) = ? OR COALESCE(aa.not_applicable, ?) = ?) )", options[:namespace_type], options[:namespace_id], false, false, options[:namespace_type], options[:namespace_id], false, true, false, true]) when Abstractor::Enum::ABSTRACTION_STATUS_ACTUALLY_ANSWERED 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, '') = '' )", options[:namespace_type], options[:namespace_id], options[:namespace_type], options[:namespace_id]]) else 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]]) end else case abstractor_abstraction_status when Abstractor::Enum::ABSTRACTION_STATUS_NEEDS_REVIEW 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]) when Abstractor::Enum::ABSTRACTION_STATUS_REVIEWED 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]) when Abstractor::Enum::ABSTRACTION_STATUS_PARTIALLY_REVIEWED 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 = ?) ) AND 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, '') != '' OR COALESCE(aa.unknown, ?) = ? OR COALESCE(aa.not_applicable, ?) = ?) )", false, false, false, true, false, true]) when Abstractor::Enum::ABSTRACTION_STATUS_ACTUALLY_ANSWERED 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, '') = '')"]) else where(nil) end end end
Returns all abstractable entities filtered by the parameter abstractor_suggestion_type:
-
‘unknown’: Filter abstractable entites having at least one suggestion withat a suggested value of ‘unknown’
-
‘suggested’: Filter abstractable entites having at least one suggestion with an acutal value
@param [String] abstractor_suggestion_type Filter abstactable entities that have a least one ‘unknwon’ or at least one ‘not unknown’ suggestion @param [Hash] options The options to filter the entities returned. @option options [String] :namespace_type The type parameter of the namespace to filter the entities. @option options [Integer] :namespace_id The instance parameter of the namespace to filter the entities. @option options [List of Integer, List of ActiveRecord::Relation] :abstractor_abstraction_schemas The list of abstractor abstraction schemas to filter upon. Defaults to all abstractor abstraction schemas if not specified. @return [ActiveRecord::Relation] List of abstractable entities.
# File lib/abstractor/abstractable.rb, line 367 def by_abstractor_suggestion_type(abstractor_suggestion_type, options = {}) options = { namespace_type: nil, namespace_id: nil }.merge(options) options = { abstractor_abstraction_schemas: abstractor_abstraction_schemas }.merge(options) if options[:namespace_type] || options[:namespace_id] case abstractor_suggestion_type when Abstractor::Enum::ABSTRACTION_SUGGESTION_TYPE_UNKNOWN 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 = ? AND sub.abstractor_abstraction_schema_id IN (?) JOIN abstractor_suggestions sug ON aa.id = sug.abstractor_abstraction_id WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND sug.unknown = ?)", options[:namespace_type], options[:namespace_id], options[:abstractor_abstraction_schemas], true]) when Abstractor::Enum::ABSTRACTION_SUGGESTION_TYPE_SUGGESTED 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 = ? AND sub.abstractor_abstraction_schema_id IN (?) JOIN abstractor_suggestions sug ON aa.id = sug.abstractor_abstraction_id WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(sug.unknown, ?) = ? AND sug.suggested_value IS NOT NULL AND COALESCE(sug.suggested_value, '') != '' )", options[:namespace_type], options[:namespace_id], options[:abstractor_abstraction_schemas], false, false]) else 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 = ? AND sub.abstractor_abstraction_schema_id IN (?) 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], options[:abstractor_abstraction_schemas]]) end else case abstractor_suggestion_type when Abstractor::Enum::ABSTRACTION_SUGGESTION_TYPE_UNKNOWN where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.abstractor_abstraction_schema_id IN (?) JOIN abstractor_suggestions sug ON aa.id = sug.abstractor_abstraction_id WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND sug.unknown = ?)", options[:abstractor_abstraction_schemas], true]) when Abstractor::Enum::ABSTRACTION_SUGGESTION_TYPE_SUGGESTED where(["EXISTS (SELECT 1 FROM abstractor_abstractions aa JOIN abstractor_subjects sub ON aa.abstractor_subject_id = sub.id AND sub.abstractor_abstraction_schema_id IN (?) JOIN abstractor_suggestions sug ON aa.id = sug.abstractor_abstraction_id WHERE aa.deleted_at IS NULL AND aa.about_type = '#{self.to_s}' AND #{self.table_name}.id = aa.about_id AND COALESCE(sug.unknown, ?) = ? AND sug.suggested_value IS NOT NULL AND COALESCE(sug.suggested_value, '') != '' )", options[:abstractor_abstraction_schemas], false, false]) else where(nil) end end end
Pivot abstractions to simulate regular columns on an abstractable entity.
Example: an ActiveRecod model PathologyCaseReport with the columns
-
‘collection_date’
-
‘report_text’
And the abstraction ‘has_cancer_diagnosis’.
This method allows for the querying of the pathology_cases table as if it was strucutred like so: ‘select id, collection_date, report_text, has_cancer_diagnosis from pathology_cases’
@param [Hash] options the options to pivot the abstractions. @option options [String] :namespace_type The type parameter of the namespace to pivot abstractions. @option options [Integer] :namespace_id The instance parameter of the namespace to pivot abstractions. @return ActiveRecord::Relation
# File lib/abstractor/abstractable.rb, line 618 def pivot_abstractions(options = {}) options = { grouped: false, namespace_type: nil, namespace_id: nil }.merge(options) select = prepare_pivot_select(options) adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter] j = case adapter when 'sqlite3' prepare_pivot_joins(select, "'t'", options) when 'sqlserver' prepare_pivot_joins(select, '1', options) when 'postgresql' prepare_pivot_joins(select, 'true', options) end joins(j).select("#{self.table_name}.*, pivoted_abstractions.*") end
Pivot grouped abstractions to simulate regular columns on an abstractable entity.
Example: an ActiveRecod model RadationTreatment with the columns
-
‘treatment_date’
-
‘total_dose’
And the abstractions grouped together with the name ‘has_treatment_target’:
-
‘has_anatomical_location’.
-
‘has_laterality’
This method allows for the querying of the radiation_treatments table as if it was strucutred like so: ‘select id, treatment_date, toatl_dose, has_anatomical_location, has_laterality from radiation_treatments’
If an abstractable entity has multiple instances of grouped abstractions the entity will be returned mutlple times.
@param [String] abstractor_subject_groups_name name of {Abstractor::Methods::Models:AbtractorSubjectGroup} @param [Hash] options the options to pivot the grouped abstractions. @option options [String] :namespace_type The type parameter of the namespace to pivot grouped abstractions. @option options [Integer] :namespace_id The instance parameter of the namespace to pivot grouped abstractions. @return ActiveRecord::Relation @see Abstractor::Methods::Models
:AbstractorSubjectGroup
# File lib/abstractor/abstractable.rb, line 655 def pivot_grouped_abstractions(abstractor_subject_groups_name, options = {}) options = { grouped: true, namespace_type: nil, namespace_id: nil }.merge(options) select = prepare_pivot_select(options) adapter = ActiveRecord::Base.connection.instance_values["config"][:adapter] j = case adapter when 'sqlite3' prepare_grouped_pivot_joins(select, "'t'", abstractor_subject_groups_name, options) when 'sqlserver' prepare_grouped_pivot_joins(select, '1', abstractor_subject_groups_name, options) when 'postgresql' prepare_grouped_pivot_joins(select, 'true', abstractor_subject_groups_name, options) end joins(j).select("#{self.table_name}.*, pivoted_abstractions.*") end
Private Instance Methods
# File lib/abstractor/abstractable.rb, line 734 def prepare_grouped_pivot_joins(select, bool, abstractor_subject_groups_name, options = {}) abstractor_subject_group = abstractor_subject_groups(options).detect { |abstractor_subject_group| abstractor_subject_group.name == abstractor_subject_groups_name } if options[:namespace_type] || options[:namespace_id] "JOIN ( SELECT #{self.table_name}.id AS subject_id, #{select} FROM (SELECT aas.predicate , aas.id AS abstraction_schema_id , asb.subject_type , aa.about_id , 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 , aag.id AS abstractor_abstraction_group_id FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id JOIN abstractor_abstraction_group_members aagm ON aa.id = aagm.abstractor_abstraction_id JOIN abstractor_abstraction_groups aag ON aagm.abstractor_abstraction_group_id= aag.id WHERE asb.subject_type = '#{self.to_s}' AND asb.namespace_type = '#{options[:namespace_type]}' AND asb.namespace_id = #{options[:namespace_id]} AND aag.abstractor_subject_group_id = #{abstractor_subject_group.id} ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id GROUP BY #{self.table_name}.id, abstractor_abstraction_group_id ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id " else "JOIN ( SELECT #{self.table_name}.id AS subject_id, #{select} FROM (SELECT aas.predicate , aas.id AS abstraction_schema_id , asb.subject_type , aa.about_id , 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 , aag.id AS abstractor_abstraction_group_id FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id JOIN abstractor_abstraction_group_members aagm ON aa.id = aagm.abstractor_abstraction_id JOIN abstractor_abstraction_groups aag ON aagm.abstractor_abstraction_group_id= aag.id WHERE asb.subject_type = '#{self.to_s}' AND aag.abstractor_subject_group_id = #{abstractor_subject_group.id} ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id GROUP BY #{self.table_name}.id, abstractor_abstraction_group_id ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id " end end
# File lib/abstractor/abstractable.rb, line 682 def prepare_pivot_joins(select, bool, options = {}) if options[:namespace_type] || options[:namespace_id] "LEFT JOIN ( SELECT #{self.table_name}.id AS subject_id, #{select} FROM (SELECT aas.predicate , aas.id AS abstractor_abstraction_schema_id , asb.subject_type , aa.about_id , 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 FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id WHERE asb.subject_type = '#{self.to_s}' AND asb.namespace_type = '#{options[:namespace_type]}' AND asb.namespace_id = #{options[:namespace_id]} AND NOT EXISTS ( SELECT 1 FROM abstractor_abstraction_group_members aagm WHERE aa.id = aagm.abstractor_abstraction_id ) ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id GROUP BY #{self.table_name}.id ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id " else "LEFT JOIN ( SELECT #{self.table_name}.id AS subject_id, #{select} FROM (SELECT aas.predicate , aas.id AS abstractor_abstraction_schema_id , asb.subject_type , aa.about_id , 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 FROM abstractor_abstractions aa JOIN abstractor_subjects asb ON aa.abstractor_subject_id = asb.id JOIN abstractor_abstraction_schemas aas ON asb.abstractor_abstraction_schema_id = aas.id WHERE asb.subject_type = '#{self.to_s}' AND NOT EXISTS ( SELECT 1 FROM abstractor_abstraction_group_members aagm WHERE aa.id = aagm.abstractor_abstraction_id ) ) data join #{self.table_name} ON data.about_id = #{self.table_name}.id GROUP BY #{self.table_name}.id ) pivoted_abstractions ON pivoted_abstractions.subject_id = #{self.table_name}.id " end end
# File lib/abstractor/abstractable.rb, line 672 def prepare_pivot_select(options= {}) options.reverse_merge!({ grouped: nil }) options = { grouped: nil }.merge(options) select =[] abstractor_abstraction_schemas(options).map(&:predicate).each do |predicate| select << "MAX(CASE WHEN data.predicate = '#{predicate}' THEN data.value ELSE NULL END) AS #{predicate}" end select = select.join(',') end