Queries¶
Norman features a flexible and extensible query API, the basis of which is
the Query class. Queries are constructed by manipulating Field and other
Query objects; the result of each operation is another Query.
Examples¶
The following examples explain the basic concepts behind Norman queries.
Queries are constructed as a series of field comparisons, for example:
q1 = MyTable.age > 4
q2 = MyTable.parent.name == 'Bill'
These can be joined together with set combination operators:
q3 = (MyTable.age > 4) | (MyTable.parent.name == 'Bill')
Containment in an iterable can be checked using the & operator. This
is the same usage as in set:
q4 = MyTable.parent.name & ['Bill', 'Bob', 'Bruce']
Since queries are themselves iterable, another query can be used as the container:
q5 = MyTable.age & OtherTable.age
A custom function can be used for filtering records from a Table or
another Query:
def isvalid(record):
return record.parrot.endswith('notlob')
q6 = query(isvalid, q5)
If the filter function is omitted, then all records are assumed to pass. This is useful for creating a query of a whole table:
q7 = query(MyTable)
The result of each of these is a Query object, which can be iterated over
to yield records. The query is not evaluated until a result is requested
from it (including len). An existing query can be refreshed after the
base data has changed by calling it as a function. The return value is the
query iteself, so to ensure that the result is up to date, you could call:
latest_size = len(q7())
API¶
-
norman.query([func, ]table)¶ Return a new
Queryfor records in table for which func isTrue.table is a
TableorQueryobject. If func is missing, all records are assumed to pass. If it is specified, is should accept a record as its argument and returnTruefor passing records.
-
class
norman.Query(op, *args, **kwargs)¶ This object should never be instantiated directly, instead it should be created as the result of a
Fieldcomparison or by using thequeryfunction. The interface allows most operations permitted on sets, such as unions and intersections, but returns a newQueryobject instead of any results. The following operations are supported:Operation Description r in qReturn Trueif recordris in the results of queryq.len(q)Return the number of results in q.iter(q)Return an iterator over records in q.q1 == q2Return Trueifq1andq2contain the same records.q1 != q2Return Trueifnot a == bq1 & q2Return a new Queryobject containing records in bothq1andq2.q1 | q2Return a new Queryobject containing records in eitherq1orq2.q1 ^ q2Return a new Queryobject containing records in eitherq1orq2, but not both.q1 - q2Return a new Queryobject containing records inq1which are not inq2.Queries evaluate to
Trueif they contain any results, andFalseif they do not.Calling a query forces it to be re-evaluated, and the query object is returned.
-
add([arg, **kwargs])¶ Add a record based on the query criteria, and return the new record. There are two modes of operation for this method, depending on the query. For either mode, the query must be defined by a clear set of field values for a single
Table. This includes queries such as(MyTable.field1` == 1) & (MyTable.field2` == 2)but notMyTable.field1` > 1.The first mode accepts keyword arguments, which are combined with the parameters used to construct the query and passed to the table constructor. For example:
``((MyTable.a` == 1) & (MyTable.b` == 2)).add(c=3)``
evaluates to:
MyTable(a=1, b=2, c=3)
The second mode is used when the query has been created by
field. In this case, a single argument is expected which is the record to apply to the field. For example:(Table1.id == 4).field('table2').add(table2_instance)
is the same as:
(Table1.id == 4).add(table2=table2_instance)
-
delete()¶ Delete all records matching the query from their table. If no records match, nothing is deleted.
-
field(fieldname)¶ Return a new
Querycontaining records in a single field.The set of records returned by this is similar to:
set(getattr(r, fieldname) for r in query)
However, the returned object is another
Queryinstead of a set. Only instances of aTablesubclass are contained in the results, other values are dropped. This is functionally similar to a SQL query on a foreign key. If the target field is aJoin, then all the results of each join are concatenated.
-
one([default])¶ Return a single value from the query results. If the query is empty and default is specified, then it is returned instead, otherwise an
IndexErroris raised.
-