GEAS Search APIs
================


(Note: all examples are in Python or pseudo-code.)


Loading a single object:
------------------------

The loadSingleObject() method in the Connection class allows a single
object to be located. It can only locate an object by searching on a single
field. If multiple objecvts match, there is no guarantee that the same
object will be returned each time.

eg: To locate an instance of the class geas::user with the username field
    matching "joe.bloggs" exactly:

    user = con.loadSingleObject("geas::user","username","joe.bloggs")

    This will not find the user "Joe.Bloggs" as that would not be an exact
match.


Loading a set of objects:
-------------------------

The loadObjects() method in the Connection class is used to load a set of
objects. It can only locate objects by searching on a single field. The
objects will use the default sorting for the class: either by object ID
(which may appear random, to a user) or the contents of an 'ORDER BY'
declaration in the GCD file.

eg: To locate all users with the password 'secret':

    users = con.loadObjects("geas::user","password","secret")


    This will not fiond users with the password "Secret" or "secretpassword"
as that would not be an exact match.



Complex queries:
----------------

More complex queries (ie, multiple fields, different comparisons, case
insensitive) can be performed by creating a Query object, and filling it
with appropriate data.

A query object is created using the newQuery() method in the Connection
class. This stores all data relating to the query, with each item added by
calling an appropriate method. [ TODO: In the future, GEAS will interpret an
OQL query to create this data (OQL is based on SQL). this will allow complex
queries to be created and entered in a single method call, using a format
that many developers prefer.]

The three main attributes of a Query object are 'classname', which specifies
the class to load, 'orderby' which selects a field to use for sorting, and
'reverse' which causes the sort to operate in descending order, if set to
true.

Example:
    To load instances of "addressbook::person", sorted alphabetically by
name, in ascending order:

    query = con.newQuery()
    query.classname = "addressbook::person"
    query.orderby = "name"
    query.reverse = false


The 'Constraint' class methods and attributes are then used to specify
restrictions on what objects are located by the search. (Note: As Query is a
subclass of Constraint, it provides these methods as well.

   A constraint contains one or more tests to perform on each instance of the
indicated class, and this test is used to select which objects to include in
the result set.

   A constraint has one attribute and two methods. The 'logic' attribute
determines if the constraint performs an AND or an OR operation on multiple
tests - ie: AND means 'all tests must be true' and OR means 'at least one
test must be true' in order to include an object in the result set.

    The addField() method adds a test to the constraint.

    The newConstraint() method allows a single test (for AND/OR purposes) to
be constructed from multiple tests.

    The 'field' structure allows a test to be specified in detail. The
members of this structure have the following meaning:

    field        : field in class to test
    test         : type of test to perform
    invert       : If true, means apply a 'not' to the result
    casesensitive: if TRUE then 'joe' and 'JOE' are considered to be different
    value        : The value to use in the test


    eg: Find all people with name starting with 'joe' and with the favourite
colour 'blue' (assumes appropriate fields in the class.)

    test1 = GEAS.Query.Field( field="name",test=GEAS.Query.startswith,
                 invert=CORBA.FALSE,casesensitive=CORBA.FALSE,value="joe" )
    test2 = GEAS.Query.Field( field="favourite_colour",test=GEAS.Query.equals,
                 invert=CORBA.FALSE,casesensitive=CORBA.FALSE,value="blue" )

    query.addField( test1 )
    query.addField( test2 )
    query.logic = GEAS.Query.AND

This is equivilent to: (Note: Not valid syntax in any query langauge)

  SELECT * FROM addressbook::person WHERE
         name startswith 'joe'      AND
         favourite_colour = 'blue'


It is also possible to build complex queries combining ANDs and ORs to
restrict the search in a variety of ways.

Example query: WHERE f1=X and ( f2=Y OR f3=Z )

This is produced from the following tree:

       AND
        |
   +-----------+
   |           |
  f1=X         OR
               |
           +-------+
	   |       |
          f2=Y   f3=Z

Example:
    q1 = con.newQuery()
    q1.logic = AND
    q1.classname = "class to load"

    q1.addField( f1 )

    c2 = q1.newConstraint
    c2.logic = OR
    c2.addField( f2 )
    c2.addField( f3 )

Explanation of each line:

q1 = con.newQuery()
    This line creates anew query, which stores the name of the class to
    load, and any sorting information (order by.) This is also a constraint
    object (via subclassing.)

q1.classname = "class to load"
    Store the class to load.

q1.logic = AND
    Rules in this constraint are AND'ed together.

q1.addField( f1 )
    The first rule (a test on a field)

c2 = q1.newConstraint
    The second rule: A nested constraint.

c2.logic = OR
    Rules in this constraint are OR'd together.

c2.addField( f2 )
    Another field test.

c2.addField( f3 )
    Another field test.


(See also: examples/python/querytest.py)


