[Zope] (sort of teaser) Re: [Zope] Recursive aquisition: good or bad?

Anthony Baxter Anthony Baxter <anthony@interlink.com.au>
Tue, 08 Jun 1999 19:56:33 +1000


>>> Tom Schwaller wrote
> > It's _incredibly_ useful. For my current toy, an SQL data mining tool,
> > I have a folder with a bunch of filters, ('cons_date', 'group_by_refcode',
> > 'add_revenue', &c.) I can then build SQL queries with a URL like
> > datamine/cons_date/group_by_refcode/add_revenue/show and it walks back
> > through the objects and builds the SQL. More on this when it's released
> > (hopefully shortly, but I keep finding new stuff to add :)
> 
> wow, this sounds like a killer app for Zope (I hear ESR say "publish
> early" ;-))
> I think I changed my view on the topic by 180 degree now :-)

Yeah - everyone I've shown it to here has been happy. I'm very happy, as
it means I can avoid writing ad-hoc queries for people who want to
produce correlations between hair-color and call duration. 

There's a couple of really unpleasant bugs in it that I'd like to fix, but 
one (dealing with Acquisition, and Persistence) in particular I'm a bit 
stumped by. 

The system builds up a URL of the datamine contraints (DMCs) to apply.
This might look like this:
http://burswood:9080/ekorp/datamine_tnt/cons_day/opge1999.05.25/cons_day/cons_item/opeqTIME%20USED/cons_refcode/data_minutes/showgraph

or indeed might just look like this:
http://blah/datamine/cons_day/data_minutes/showcsv

The latter is the easier one, and works fine - so I'll talk about it
first. cons_day and data_minutes are both DMCs. When applied in a chain like
this, they will produce SQL of:

SELECT
billing.date date, 
sum(billing.quantity) minutes
 FROM 
billing
 GROUP BY
billing.date

and then show the output as a CSV file. All well and good, and pretty
easy. Each DMC has configured into it what to insert in a select clause,
in the from clause, and in the group by clause. So for cons_day, it has
a select clause of 'billing.date date', select_from of 'billing', and 
group_by of 'billing.date'. 
data_minutes is select: sum(billing.quantity) minutes, select_from: billing,
and no group_by.
(yes it will insert join clauses if the DMCs span multiple tables)

Now, back to the first, more complex example (the one that's causing me
pain)
http://burswood:9080/ekorp/datamine_tnt/cons_day/opge1999.05.25/cons_day/cons_item/opeqTIME%20USED/cons_refcode/data_minutes/showgraph

Say we don't just want to get all the dates in the system, but want to only
get the ones greater than a certain number? A DMC has a __bobo_traverse__
function, so that a URL fragment of: cons_day/opge1999.05.25/ 
will cause the cons_day fragment to apply "op"eration of "ge" (greater or
equal) to 1999.05.25. Unfortunately in doing this, it modifies 'self',
so it writes something to the ZODB each time. What I need is a way to
say 'hey, don't pay any attention to me for a minute, I'm just fiddling
some stuff, but I don't want it to be persistent'.

So that example again, broken down a bit:
http://blah/datamine/       -- folder containing all this.
cons_day/opge1999.05.25/    -- constrain where date > 1999.05.25
cons_day/                   -- but also group by, and select date
cons_item/opeqTIME%20USED/  -- pick entries where the 'item' is 'TIME USED'
cons_refcode/ -- group by refcode
data_minutes/  -- select sum(quantity)
showgraph  -- display it as a graph

this produces SQL of:
SELECT
billing.date date,
accounts.account_group refcode,
sum(billing.quantity) minutes
 FROM 
billing, accounts
 WHERE 
billing.account = accounts.account
 AND
billing.date >= '1999.05.25' and
billing.item = 'TIME USED'
 GROUP BY
billing.date, accounts.account_group

and then gives me back an image of a graph with the x-axis of dates, y-axis
of 'minutes' and multiple lines, (one for each refcode) and a little legend
in a box on the left-hand-side. This is about a moderate-complexity query -
there's some here that span 5 tables and do all sorts of interesting joins.

In more detail, the problem I have is that in the bobo_traverse method, if
I get a constraint, I want to store this. The way I do this is to instantiate
a new DMC - but one that's non-persistant, populate it, then return it.
Unfortunately to get it to acquire everything else it needs, I need to 
attach it to the 'self' object with something like 

  self.new = DMC_nonP(self.id, self.name, ....)
  ... set the magic in the new object ...
  return self.new

Unfortunately this self.new assignment makes an entry in the ZODB. Blah.

Anyway, I plan to fling a release of some sort out tonight, bug or no
bug.

Anthony