Searching a module
A program accesses an EMu module (or table, the terms are used interchangeably)
using the IMu::Module
class. The name of the table to be accessed is passed
to the IMu::Module
constructor. For example:
use IMu::Module; # ⋯ my $parties = IMu::Module->new('eparties', $session);
This code assumes that a IMu::Session
object called session has already
been created. If a IMu::Session
object is not passed to the IMu::Module
constructor, a session will be created automatically using the defaultHost
and defaultPort
class properties. See Connecting to an IMu server for details.
Once a IMu::Module
object has been created, it can be used to search the
specified module and retrieve records.
Any one of the following methods can be used to search for records within a module:
The findKey
method searches for a single record by its key.
For example, the following code searches for a record with a key of 42 in the Parties module:
use IMu::Module; # ⋯my $parties = IMu::Module->new('eparties', $session);my $hits = $parties->findKey(42);
The method returns the number of matches found, which is either 1 if the record exists or 0 if it does not.
The findKeys
method searches for a set of key values. The keys are passed
as an array reference:
my $parties = IMu::Module->new('eparties', $session);my $keys = [52, 42, 17];my $hits = $parties->findKeys($keys);
The method returns the number of records found.
The findTerms
method is the most flexible and powerful way to search for
records within a module. It can be used to run simple single term queries or
complex multi-term searches.
The terms are specified using a IMu::Terms
object. Once a IMu::Terms
object has been created, add specific terms to it (using the add
method)
and then pass the IMu::Terms
object to the findTerms
method. For
example, to specify a Parties search for records that contain a first name of John
and a last name
of Smith
:
use IMu::Terms; my $search = IMu::Terms->new(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith'); my $hits = $parties->findTerms($search);
There are several points to note:
- The first argument passed to the
add
method element contains the name of the column or an alias in the module to be searched. - An alias associates a supplied value with one or more actual columns.
Aliases are created using the
addSearchAlias
oraddSearchAliases
methods. - The second argument contains the value to search for.
- Optionally, a comparison operator can be supplied as a third argument (see
example here).
The operator specifies how the value supplied as the second argument should
be matched. Operators are the same as those used in TexQL (See Texpress Query Language Guide for details). If not supplied, the operator
defaults to "matches". This is not a real TexQL operator, but is translated
by the search engine as the most "natural" operator for the type of column
being searched. For example, for text columns "matches" is translated as
the
contains
TexQL operator and for integer columns it is translated as the=
TexQL operator.
Note: Unless it is really necessary to specify an operator, consider using
the matches
operator, or better still supplying no operator at
all as this allows the server to determine the best type of search.
Examples
- To search for the name
Smith
in the last name field of the Parties module, the following term can be used:my $search = IMu::Terms->new(); $search->add('NamLast', 'Smith');
- Specifying search terms for other types of columns is straightforward. For
example, to search for records inserted on April 4, 2011:
my $search = IMu::Terms->new(); $search->add('AdmDateInserted', 'Apr 4 2011');
- To search for records inserted before April 4, 2011, it is necessary to
add an operator:
my $search = IMu::Terms->new(); $search->add('AdmDateInserted', 'Apr 4 2011', '<');
- By default, the relationship between the terms is a Boolean
AND
. This means that to find records which match both a first name containingJohn
and a last name containingSmith
theIMu::Terms
object can be created as follows:my $search = IMu::Terms->new(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith');
- A
IMu::Terms
object where the relationship between the terms is a BooleanOR
can be created by passing the string value'OR'
to theIMu::Terms
constructor:my $search = IMu::Terms->new('OR'); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith');
This specifies a search for records where either the first name contains
John
or the last name containsSmith
. - Combinations of
AND
andOR
search terms can be created. TheaddAnd
method adds a new set ofAND
terms to the originalIMu::Terms
object. Similarly, theaddOr
method adds a new set ofOR
terms. For example, to restrict the search for a first name ofJohn
and a last name ofSmith
to matching records inserted before April 4, 2011 or on May 1, 2011, specify:my $search = IMu::Terms->new(); $search->add('NamFirst', 'John'); $search->add('NamLast', 'Smith');my $dates = $search->addOr(); $dates->add('AdmDateInserted', 'Apr 4 2011', '<'); $dates->add('AdmDateInserted', 'May 1 2011');
- To run a search, pass the
IMu::Terms
object to thefindTerms
method:my $parties = IMu::Module->new('eparties', $session);my $search = IMu::Terms->new(); $search->add('NamLast', 'Smith');my $hits = $parties->findTerms($search);
As with other find methods, the return value contains the estimated number of matches.
- To use a search alias, call the
addSearchAlias
method to associate the alias with one or more real column names before callingfindTerms
. Suppose we want to allow a user to search the Catalogue module for keywords. Our definition of a keywords search is to search the SummaryData, CatSubjects_tab and NotNotes columns. We could do this by building anOR
search:my $keyword = '⋯'; # ⋯my $search = IMu::Terms->new('OR'); $search->add('SummaryData', $keyword); $search->add('CatSubjects_tab', $keyword); $search->add('NotNotes', $keyword);
Another way of doing this is to register the association between the name keywords and the three columns we are interested in and then pass the name keywords as the column to be searched:
my $keyword = '⋯'; # ⋯my $catalogue = IMu::Module->new('ecatalogue', $session);my $columns = [ 'SummaryData', 'CatSubjects_tab', 'NotNotes' ]; $catalogue->addSearchAlias('keywords', $columns); # ⋯my $search = IMu::Terms->new(); $search->add('keywords', $keyword); $catalogue->findTerms($search);
An alternative to passing the columns as a reference to an array of strings is to pass a single string, with the column names separated by semi-colons:
my $keyword = '⋯'; # ⋯my $catalogue = IMu::Module->new('ecatalogue', $session);my $columns = 'SummaryData;CatSubjects_tab;NotNotes'; $catalogue->addSearchAlias('keywords', $columns); # ⋯my $search = IMu::Terms->new(); $search->add('keywords', $keyword); $catalogue->findTerms($search);
The advantage of using a search alias is that once the alias is registered a simple name can be used to specify a more complex
OR
search. - To add more than one alias at a time, build a hash of names and columns and
call the
addSearchAliases
method:my $aliases = { 'keywords' => 'SummaryData;CatSubjects_tab;NotNotes', 'title' => 'SummaryData;TitMainTitle' }; $catalogue->addSearchAliases($aliases);
With the findWhere
method it is possible to submit a complete TexQL
where clause:
my $parties = IMu::Module->new('eparties', $session);my $where = "NamLast contains 'Smith'";my $hits = $parties->findWhere($where);
Although this method provides complete control over exactly how a search is
run, it is generally better to use findTerms
to submit a search rather than
building a where clause. There are (at least) two reasons to prefer
findTerms
over findWhere
:
- Building the where clause requires the code to have detailed knowledge
of the data type and structure of each column. The
findTerms
method leaves this task to the server. For example, specifying the term to search for a particular value in a nested table is straightforward. To find Parties records where the Roles nested table contains Artist,findTerms
simply requires:$search->add('NamRoles_tab', 'Artist');
On the other hand, the equivalent TexQL clause is:
exists(NamRoles_tab where NamRoles contains 'Artist')
The TexQL for double nested tables is even more complex.
- More importantly,
findTerms
is more secure.With
findTerms
a set of terms is submitted to the server which then builds the TexQL where clause. This makes it much easier for the server to check for terms which may contain SQL-injection style attacks and to avoid them. If your code builds a where clause from user-entered data so it can be run usingfindWhere
, it is much more difficult, if not impossible, for the server to check and avoid SQL-injection. The responsibility for checking for SQL-injection becomes yours.
All of the find methods return the number of matches found by the search. For
findKey
and findKeys
this number is always the exact number of matches
found. The number returned by findTerms
and findWhere
is best thought
of as an estimate. This estimate is almost always correct but because of the
nature of the indexing used by the server's data engine (Texpress) the number
can sometimes be an over-estimate of the real number of matches. This is
similar to the estimated number of hits returned by a Google search.