class InterMine::Metadata::Path

A representation of a path through the data model, starting at a table/class, and descending ultimately to an attribute. A path represents a valid sequence of joins and column accesses according to the webservice's database schema.

In string format, a path can be represented using dotted notation:

Gene.proteins.proteinDomains.name

Which is a valid path through the data-model, starting in the gene table, following a reference to the protein table (via x-to-many relationship) and then to the protein-domain table and then finally to the name column in the protein domain table. Joins are implicitly implied.

author

Alex Kalderimis dev@intermine.org

homepage

www.intermine.org

Licence

Copyright (C) 2002-2011 FlyMine

This code may be freely distributed and modified under the terms of the GNU Lesser General Public Licence. This should be distributed with the code. See the LICENSE file for more information or www.gnu.org/copyleft/lesser.html.

Attributes

elements[R]

The objects represented by each section of the path. The first is always a ClassDescriptor.

model[R]

The data model that this path describes.

rootClass[R]

The root class of this path. This is the same as the first element.

subclasses[R]

The subclass information used to create this path.

Public Class Methods

new(pathstring, model=nil, subclasses={}) click to toggle source

Construct a Path

The standard mechanism is to parse a string representing a path with information about the model and the subclasses that are in force. However, it is also possible to clone a path by passing a Path through as the first element, and also to construct a path from a ClassDescriptor. In both cases the new Path will inherit the model of the object used to construct it, this avoid the need for a model in these cases.

    # File lib/intermine/model.rb
726 def initialize(pathstring, model=nil, subclasses={})
727     @model = model
728     @subclasses = subclasses
729     @elements = []
730     @rootClass = nil
731     parse(pathstring)
732 end

Public Instance Methods

==(other) click to toggle source

Two paths can be said to be equal when they stringify to the same representation.

    # File lib/intermine/model.rb
781 def ==(other)
782     return self.to_s == other.to_s
783 end
end_cd → ClassDescriptor click to toggle source

Return the last ClassDescriptor mentioned in this path. eg:

Gene

Gene

Gene.symbol

Gene

Gene.proteins

Protein

Gene.proteins.name

Protein

    # File lib/intermine/model.rb
764 def end_cd
765     last = @elements.last
766     if last.is_a?(ClassDescriptor)
767         return last
768     elsif last.respond_to?(:referencedType)
769         return last.referencedType
770     else
771         penult = @elements[-2]
772         if penult.is_a?(ClassDescriptor)
773             return penult
774         else
775             return penult.referencedType
776         end
777     end
778 end
end_type → String click to toggle source

Return the string that describes the kind of thing this path represents. eg:

Gene

“Gene”

Gene.symbol

“java.lang.String”

Gene.proteins

“Protein”

    # File lib/intermine/model.rb
743 def end_type
744     last = @elements.last
745     if last.is_a?(ClassDescriptor)
746         return last.name
747     elsif last.respond_to?(:referencedType)
748         return last.referencedType.name
749     else
750         return last.dataType
751     end
752 end
is_attribute?() click to toggle source

Return true if the Path ends in an attribute

    # File lib/intermine/model.rb
801 def is_attribute?
802     return @elements.last.is_a?(AttributeDescriptor)
803 end
is_class?() click to toggle source

Return true if the last element is a class (ie. a path of length 1)

    # File lib/intermine/model.rb
806 def is_class?
807     return @elements.last.is_a?(ClassDescriptor)
808 end
is_collection?() click to toggle source

Return true if the last element is a collection

    # File lib/intermine/model.rb
816 def is_collection?
817     return @elements.last.is_a?(CollectionDescriptor)
818 end
is_reference?() click to toggle source

Return true if the last element is a reference.

    # File lib/intermine/model.rb
811 def is_reference?
812     return @elements.last.is_a?(ReferenceDescriptor)
813 end
length() click to toggle source

Get the number of elements in the path

    # File lib/intermine/model.rb
786 def length
787     return @elements.length
788 end
to_headless_s() click to toggle source

Returns a string as to_s without the first element. eg: “proteins.name”

    # File lib/intermine/model.rb
796 def to_headless_s
797     return @elements[1, @elements.size - 1].map {|x| x.name}.join(".")
798 end
to_s() click to toggle source

Return the string representation of this path, eg: “Gene.proteins.name”

    # File lib/intermine/model.rb
791 def to_s 
792     return @elements.map {|x| x.name}.join(".")
793 end

Private Instance Methods

parse(pathstring) click to toggle source

Perform the parsing of the input into a sequence of elements.

    # File lib/intermine/model.rb
823     def parse(pathstring)
824         if pathstring.is_a?(ClassDescriptor)
825             @rootClass = pathstring
826             @elements << pathstring
827             @model = pathstring.model
828             return
829         elsif pathstring.is_a?(Path)
830             @rootClass = pathstring.rootClass
831             @elements = pathstring.elements
832             @model = pathstring.model
833             @subclasses = pathstring.subclasses
834             return
835         end
836 
837         bits = pathstring.split(".")
838         rootName = bits.shift
839         @rootClass = @model.get_cd(rootName)
840         if @rootClass.nil?
841             raise PathException.new(pathstring, subclasses, "Invalid root class '#{rootName}'")
842         end
843 
844         @elements << @rootClass
845         processed = [rootName]
846 
847         current_cd = @rootClass
848 
849         while (bits.length > 0)
850             this_bit = bits.shift
851             fd = current_cd.get_field(this_bit)
852             if fd.nil?
853                 subclassKey = processed.join(".")
854                 if @subclasses.has_key?(subclassKey)
855                     subclass = model.get_cd(@subclasses[subclassKey])
856                     if subclass.nil?
857                         raise PathException.new(pathstring, subclasses,
858 "'#{subclassKey}' constrained to be a '#{@subclasses[subclassKey]}', but that is not a valid class in the model")
859                     end
860                     current_cd = subclass
861                     fd = current_cd.get_field(this_bit)
862                 end
863                 if fd.nil?
864                     raise PathException.new(pathstring, subclasses,
865 "giving up at '#{subclassKey}.#{this_bit}'. Could not find '#{this_bit}' in '#{current_cd}'")
866                 end
867             end
868             @elements << fd
869             if fd.respond_to?(:referencedType)
870                 current_cd = fd.referencedType
871             elsif bits.length > 0
872                 raise PathException.new(pathstring, subclasses, 
873 "Attributes must be at the end of the path. Giving up at '#{this_bit}'")
874             else
875                 current_cd = nil
876             end
877             processed << this_bit
878         end
879     end