[Zope-CVS] CVS: Packages/pypes/pypes - query.py:1.1
exceptions.py:1.4
Casey Duncan
casey at zope.com
Tue Mar 30 23:58:39 EST 2004
Update of /cvs-repository/Packages/pypes/pypes
In directory cvs.zope.org:/tmp/cvs-serv9981
Modified Files:
exceptions.py
Added Files:
query.py
Log Message:
Add basic scan and sort query primitives w/tests
=== Added File Packages/pypes/pypes/query.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Pypes declarative object queries
Queries consist of inputs and operations. Operations denote query search
criteria and output format. When executed, queries return a result which is
the output of the query operations applied in succession to the inputs.
Inputs for queries are collections of identified persistent objects in the
database, e.g. sets, extents or query results. The inputs define the maximal
extent of the query; the objects which will be considered by the operations.
Queries results cannot contain objects that do not appear in the inputs, other
than None.
Each input must provide a name, or have a name provided for it. These names can
be used by operations to refer to members of the cooresponding input
collection.
Operations define the semantics of the query; the process performed on the
inputs to derive the results. Operations are typically of the following kinds:
filter -- filters determine which objects occur in the results.
join -- joins determine how members of multiple input collections are
combined.
sort -- sorts determine the order of the results.
projection -- projections determines how the the result values are derived.
Operations are typically declared using Python expression strings. These
expressions describe the operation's behavior by using the query inputs
and other objects provided by the calling program.
$Id: query.py,v 1.1 2004/03/31 04:58:08 caseman Exp $"""
from zope.interface import implements
from pypes.interfaces import IQueryEngine
from pypes.exceptions import PypesLookupError, PypesQueryInputError
## Exported constants ##
descending = 'descending'
ascending = 'ascending'
## Query Operations ##
def scan(*named_inputs, **inputs):
"""A generator of dicts comprising the product of the inputs which
are iterable sequence of objects.
The yielded dicts have each input name and one input member as their
respective keys and values. inputs are either self-named on which case
their name is derived from their __name__ attribute. self-named inputs
are provided as positional arguments (order is not significant). Inputs
which are not named, or for which an alias is desired are passed in as
keyword arguments where the keyword denotes the name.
Inputs may be any iterable sequence of objects. In general inputs are
homogenous sets of objects.
Note that the yielded dict object is reused for each generation. Because
of this, the application *must* make a copy of this dict if it wishes
to persist a reference to it after the next one is generated.
This is to efficiently handle the common case, where the generated
product will be filtered and only a fraction of the generated "rows"
will be used. Since scan_inputs generates a quantity of results equal
to all of the inputs multiplied together, this greatly reduces the
number of objects created by the scan
"""
for ipt in named_inputs:
try:
name = ipt.__name__
except AttributeError:
raise PypesQueryInputError, 'unamed input %r' % ipt
if name not in inputs:
inputs[name] = ipt
else:
raise PypesQueryInputError, 'duplicate input name %s' % name
# Prime the input iterators and get the first row
row = {}
input_iters = []
for name, ipt in inputs.items():
obj_iter = iter(ipt)
input_iters.append((name, obj_iter))
row[name] = obj_iter.next()
yield row
# Get subsequent rows by combining inputs
i = 0
while True:
try:
name, obj_iter = input_iters[i]
except IndexError:
break
while True:
try:
row[name] = obj_iter.next()
except StopIteration:
obj_iter = iter(inputs[name])
input_iters[i] = name, obj_iter
row[name] = obj_iter.next()
i += 1
break
else:
yield row
if i > 0:
i = 0
break
def sort(iterable, expression, order=ascending, limit=None):
"""Return a sequence containing the elements of iterable sorted in order
by the values returned by applying expression, a callable object accepting
a single argument, to each element.
order may be the constants ascending and descending to specify the
resulting sort order. limit, if specified is an integer value representing
the number of elements to sort. When limit is specified, a partial sort
will be performed and sort will return as soon as the limit count is
reached.
In order for the sort to perform properly, the expression should generate
a homogenous set of values that support total ordering.
"""
sortable = [(expression(i), i) for i in iterable]
sortable.sort()
if order == descending:
sortable.reverse()
if limit is not None:
# XXX Implement N-Best algorithm for this
sortable = sortable[:limit]
# XXX We should be make this lazy
return [i for key, i in sortable]
=== Packages/pypes/pypes/exceptions.py 1.3 => 1.4 ===
--- Packages/pypes/pypes/exceptions.py:1.3 Mon Feb 9 16:14:57 2004
+++ Packages/pypes/pypes/exceptions.py Tue Mar 30 23:58:08 2004
@@ -46,3 +46,9 @@
class GraphCycleError(PypesError):
"""Cycle detected during operation for acyclic graph"""
+
+class PypesQueryError(PypesError):
+ """General error performing query"""
+
+class PypesQueryInputError(PypesQueryError):
+ """Invalid input to pypes query"""
More information about the Zope-CVS
mailing list