[Bio] / Sprout / ERDBQuery.pm Repository:
ViewVC logotype

Annotation of /Sprout/ERDBQuery.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.3 - (view) (download) (as text)

1 : parrello 1.1 package ERDBQuery;
2 :    
3 :     use strict;
4 :     use DBKernel;
5 :     use ERDBObject;
6 :     use DBI;
7 :     use Tracer;
8 :    
9 :     =head1 Entity-Relationship Database Package Query Iterator
10 :    
11 :     =head2 Introduction
12 :    
13 :     This package defines the Iteration object for an Entity-Relationship Database. The iteration object
14 :     represents a filtered SELECT statement against an Entity-Relationship Database, and provides
15 :     methods for getting the appropriate records.
16 :    
17 :     There are two common ways an iteration object can be created. An I<entity iterator> is created when the
18 :     client asks for objects of a given entity type. A I<relationship iterator> is created when the
19 :     client asks for objects across a relationship starting from a specific entity instance. The
20 :     entity iterator returns a single object at each position; the relationship iterator returns two
21 :     objects at each position-- one for the target entity, and one for the relationship instance
22 :     that connects it to the source entity.
23 :    
24 :     For example, a client could ask for all B<Feature> instances that are marked active. This would
25 :     return an entity iterator. Each position in the iteration would consist of a single
26 :     B<Feature> instance. From a specific B<Feature> instance, the client could decide to cross the
27 :     B<IsLocatedIn> relationship to get all the B<Contig> instances which contain residues that
28 :     participate in the feature. This would return a relationship iterator. Each position in the
29 :     iterator would contain a single B<IsLocatedIn> instance and a single B<Contig> instance.
30 :    
31 :     At each point in the result set, the iterator returns a B<ERDBObject>. The ERDBObject allows the
32 :     client to access the fields of the current entity or relationship instance.
33 :    
34 :     It is also possible to ask for many different objects in a single iterator by chaining long
35 :     sequences of entities together by relationships. This is discussed in the documentation for the
36 :     B<ERDB> object's C<Get> method.
37 :    
38 :     Finally, objects of this type should never by created directly. Instead, they are created
39 :     by the aforementioned C<Get> method and the B<ERDBObject>'s C<Cross> method.
40 :    
41 :     =head2 Public Methods
42 :    
43 :     =head3 Fetch
44 :    
45 :     my $dbObject = $dbQuery->Fetch();
46 :    
47 :     Retrieve a record from this query. The record returned will be a B<ERDBObject>, which
48 :     may represent a single entity instance or a list of entity instances joined by relationships.
49 :     The first time this method is called it will return the first result from query. After that it
50 :     will continue sequentially. It will return an undefined value if we've reached the end of the
51 :     result set.
52 :    
53 :     =cut
54 :    
55 :     sub Fetch {
56 :     # Get the parameters;
57 :     my ($self) = @_;
58 :     # Declare the return variable.
59 :     my $retVal;
60 :     # Fetch the next row in the query result set.
61 :     my $sth = $self->{_sth};
62 :     my @row = $sth->fetchrow;
63 :     # Check to see if we got any results.
64 :     if (@row == 0) {
65 :     # Here we have no result. If we're at the end of the result set, this is okay, because
66 :     # we'll be returning an undefined value in $retVal. If an error occurred, we need to abort.
67 :     if ($sth->err) {
68 :     Confess("FETCH error: " . $sth->err);
69 :     } else {
70 :     # Trace the number of results returned.
71 :     Trace("$self->{_results} rows processed by query.") if T(SQL => 4);
72 :     }
73 :     } else {
74 :     # Here we have a result, so we need to turn it into an instance object.
75 :     $retVal = ERDBObject->_new($self, @row);
76 :     $self->{_results}++;
77 :     }
78 :     # Return the result.
79 :     return $retVal;
80 :     }
81 :    
82 : parrello 1.2 =head3 DefaultObjectName
83 :    
84 :     my $objectName = $query->DefaultObjectName();
85 :    
86 :     Return the name of this query's default entity or relationship.
87 :    
88 :     =cut
89 :    
90 :     sub DefaultObjectName {
91 :     # Get the parameters.
92 :     my ($self) = @_;
93 :     # Get the relation map.
94 :     my $map = $self->{_objectNames};
95 :     # Get the default object alias. This is always the first alias in the
96 :     # relation map.
97 :     my $retVal = $map->[0][0];
98 :     # Return the result.
99 :     return $retVal;
100 :     }
101 :    
102 :    
103 : parrello 1.1 =head3 AnalyzeFieldName
104 :    
105 :     my ($objectName, $fieldName, $type) = $query->AnalyzeFieldName($name);
106 :    
107 :     Analyze a field name (such as might be found in a [[ErdbPm#GetAll]]
108 :     parameter list) and return the real name of the relevant entity or
109 :     relationship, the field name itself, and the associated type object
110 :     (which will be a subclass of [[ERDBTypePm]].
111 :    
112 :     =over 4
113 :    
114 :     =item name
115 :    
116 :     Field name to examine, in the standard field name format used by [[ErdbPm]].
117 :    
118 :     =item RETURN
119 :    
120 :     Returns a 3-tuple containing the name of the object containing the field, the
121 :     base field name, and a type object describing the field's type.
122 :    
123 :     =back
124 :    
125 :     =cut
126 :    
127 :     sub AnalyzeFieldName {
128 :     # Get the parameters.
129 :     my ($self, $name) = @_;
130 : parrello 1.3 # Attempt to find the field's data.
131 :     my ($objectName, $fieldName, $type) = $self->CheckFieldName($name);
132 :     # Process errors.
133 :     if (! defined $objectName) {
134 :     Confess("Field identifier \"$name\" has an invalid format.");
135 :     } elsif (! defined $fieldName) {
136 :     Confess("Object name \"$objectName\" not found in query.");
137 :     } elsif (! defined $type) {
138 :     Confess("Field name \"$fieldName\" not found in \"$objectName\".");
139 :     }
140 :     # Return the results.
141 :     return ($objectName, $fieldName, $type);
142 :     }
143 :    
144 :    
145 :     =head3 CheckFieldName
146 :    
147 :     my ($objectName, $fieldName, $type) = $query->CheckFieldName($name);
148 :    
149 :     Analyze a field name (such as might be found in a [[ErdbPm#GetAll]]
150 :     parameter list) and return the real name of the relevant entity or
151 :     relationship, the field name itself, and the associated type object
152 :     (which will be a subclass of [[ERDBTypePm]]. Unlink L</AnalyzeFIeldName>,
153 :     this method always returns results. If the field name is invalid, one
154 :     or more of the three results will be undefined.
155 :    
156 :     =over 4
157 :    
158 :     =item name
159 :    
160 :     Field name to examine, in the standard field name format used by [[ErdbPm]].
161 :    
162 :     =item RETURN
163 :    
164 :     Returns a 3-tuple containing the name of the object containing the field, the
165 :     base field name, and a type object describing the field's type. If the field
166 :     descriptor is invalid, the returned object name will be undefined. If the object
167 :     name is invalid, the returned field name will be undefined, and if the field
168 :     name is invalid, the returned type will be undefined.
169 :    
170 :     =back
171 :    
172 :     =cut
173 :    
174 :     sub CheckFieldName {
175 :     # Get the parameters.
176 :     my ($self, $name) = @_;
177 : parrello 1.1 # Declare the return variables.
178 :     my ($objectName, $fieldName, $type);
179 :     # Get the relation map.
180 :     my $map = $self->{_objectNames};
181 :     # Get the default object alias. This is always the first alias in the
182 :     # relation map.
183 :     my $defaultName = $map->[0][0];
184 :     # Parse the field name.
185 : parrello 1.3 my ($alias, $fieldThing) = ERDB::ParseFieldName($name, $defaultName);
186 :     # Only proceed if we could successfully parse the field. If we couldn't,
187 :     # everything will be going back undefined.
188 :     if (defined $alias) {
189 : parrello 1.1 # Find the alias in the relation map.
190 :     my ($aliasTuple) = grep { $_->[0] eq $alias } @$map;
191 :     if (! defined $aliasTuple) {
192 : parrello 1.3 # We have a bad object name, so the object name is all
193 :     # we return.
194 :     $objectName = $alias;
195 : parrello 1.1 } else {
196 :     # Get the real object name.
197 : parrello 1.3 $objectName = $aliasTuple->[1];
198 :     # Now it's safe to return the field name.
199 :     $fieldName = $fieldThing;
200 : parrello 1.1 # Ask the database for the field descriptor. If the field name is
201 :     # invalid, this will throw an error.
202 : parrello 1.3 my $fieldData = $self->{_db}->_CheckField($objectName, $fieldName);
203 :     # Only proceed if the field exists.
204 :     if (defined $fieldData) {
205 :     # Extract the field type.
206 :     my $typeName = $fieldData->{type};
207 :     # Get the corresponding type object.
208 :     $type = ERDB::GetDataTypes()->{$typeName};
209 :     }
210 : parrello 1.1 }
211 :     }
212 :     # Return the results.
213 :     return ($objectName, $fieldName, $type);
214 :     }
215 :    
216 :    
217 :     =head2 Internal Methods
218 :    
219 :     =head3 _new
220 :    
221 :     my $query = ERDBQuery->new($database, $sth, $relationMap, $searchObject);
222 :    
223 :     Create a new query object.
224 :    
225 :     =over 4
226 :    
227 :     =item database
228 :    
229 :     ERDB object for the relevant database.
230 :    
231 :     =item sth
232 :    
233 :     Statement handle for the SELECT clause generated by the query.
234 :    
235 :     =item relationMap
236 :    
237 :     Reference to a list of 2-tuples. Each tuple consists of an object name as used
238 :     in the query followed by the actual name of that object. This enables the
239 :     B<ERDBObject> to determine the order of the tables in the query and which object
240 :     name belongs to each mapped object name. Most of the time these two values are
241 :     the same; however, if a relation occurs twice in the query, the relation name in
242 :     the field list and WHERE clause will use a mapped name (generally the actual
243 :     relation name with a numeric suffix) that does not match the actual relation
244 :     name.
245 :    
246 :     =item searchObject (optional)
247 :    
248 :     If specified, then the query is a full-text search, and the first field will be a
249 :     relevance indicator for the named table.
250 :    
251 :     =back
252 :    
253 :     =cut
254 :    
255 :     sub _new {
256 :     # Get the parameters.
257 :     my ($database, $sth, $relationMap, $searchObject) = @_;
258 :     # Create this object.
259 :     my $self = { _db => $database, _sth => $sth, _objectNames => $relationMap,
260 :     _fullText => $searchObject, _results => 0 };
261 :     # Bless and return it.
262 :     bless $self;
263 :     return $self;
264 :     }
265 :    
266 :     1;

MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3