Re: [sqlalchemy] Re: hierarchical data storage and searching

2010-09-09 Thread Chris Withers

On 08/09/2010 19:23, Gunnlaugur Briem wrote:

http://communities.bmc.com/communities/docs/DOC-9902


Thanks for all of the references, but this one in particular.
Materialized paths looks like its the closest to what I'm after.

However, with materialized paths, I'm wondering with a structure like:

/
/a/
/a/b
/a/b/1
/a/b/2
/a/c
/b/
/b/1
/b/2

How to phrases the sql to answer the question:

Does the current user have access to anything in /a or below

...particularly where the user is granted access only to /a/b/1, for 
example.



and here for links to more than you really want to know on the
subject:

http://troels.arvin.dk/db/rdbms/links/#hierarchical


Hah, excellent, thanks :-)


SQLAlchemy support any of these approaches well enough that I don't
think you need to factor SQLAlchemy into your choice of relational
design at all. Check out /examples/nested_sets/ and /examples/
adjacency_list/ (in the SQLAlchemy distribution) for what are probably
the two most common approaches.


Cool, I'd forgotten about them, although the nested sets example doesn't 
appear to show the delete or modify implementations, which are the 
tricky bits ;-)


cheers,

Chris

PS: I appreciate that while I need to get any solution working with 
SQLAlchemy, this is a generic relational database question; if anyone 
can point me at a more correct forum to ask, I'll be happy to do so 
there :-)


--
Simplistix - Content Management, Batch Processing  Python Consulting
- http://www.simplistix.co.uk

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



[sqlalchemy] SQL / SQLAlchemy'centric approach to problem

2010-09-09 Thread Warwick Prince
Hi All

I'm new to SQLAlchemy (love it) and also new to SQL in general, although I have 
25 years experience in a range of obscure databases.  I have what I hope will 
be a simple question as I believe I'm missing a critical understanding of some 
of the underlying SQL machinery.

This is the situation (dumbed down for the example);

1) I have selected a row from a table somewhere else and therefore have a 
session.query resulted mapped class instance of that row (Or the primary 
key(s), which ever is most useful).   We'll call this row Fred.
2) I have an ordered_by x result of a query on the same table (with many 
rows) that I wish to navigate with first/next/prev/last type controls.  This I 
have implemented using the cool result[position] syntax and that all works 
fine. (Gets a little slow over several million rows, but that's outside the 
scope of the design requirement)

My problem is this;  I want to find out what position my recordFred is within 
the larger result set.. so that I can then locate myself onto fred and move 
to the next or previous row in that query as normal.  To do that, I need the 
position value so I can do the slice.

Sure, I could do an .all() on the query and then loop through until I found 
fred counting as I go, but that's horrible and smacks of you don't know what 
you are doing..

Picture it like this;

table has rows 1, 2, 3, 4, 5, 6, 7, 8, 9, 10.   I query that and order it by 
something else which gives me an ordered result of

1, 3, 5, 7, 9, 2, 4, 6, 8, 0

I know that fred's key is 9, so I want to determine that in the ordered list 
(above), 9 is the 4th (zero based) element.  I can then locate fred by saying 
result[4] and next is simply result[5] etc.

Is there a good way?  I suspect I could do something with a secondary query 
that would produce the results 1, 3, 5, 7 and then I could count that and that 
would be my position, but it's all sounding a little amateurish to me.

Any advice would be most appreciated.  :-)

Cheers
Warwick


Warwick Prince 
Managing Director 
mobile: +61 411 026 992 
skype: warwickprince  
 
phone: +61 7 3102 3730 
fax:  +61 7 3319 6734 
web: www.mushroomsys.com 


-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Combining aliases with labels

2010-09-09 Thread Conor
On 09/08/2010 01:05 PM, Jack Kordas wrote:
 When I try to use both aliases and labels, the results are not named
 as expected.

 Instead of being able to access the columns as label-name_column-
 name it appears as original-table-name_numeric-sequence_column-
 name

 Thanks,
   Jack

 Sample code follows:

 parent = Table('parent', metadata,
 Column('id', INTEGER(), primary_key=True),
 Column('name', VARCHAR(length=128)),
 Column('first_id', INTEGER(),
 ForeignKey(u'child.id')),
   )

 child = Table('child', metadata,
 Column('id', INTEGER(), primary_key=True),
 Column('name', VARCHAR(length=128))
   )

 def test_labels1(conn):
 s = select([parent,child], use_labels=True)
 s = s.where(parent.c.first_id==child.c.id)
 return conn.execute(s).fetchone()

 def test_alias1(conn):
 firstchild = child.alias()
 s = select([parent,firstchild], use_labels=True)
 s = s.where(parent.c.first_id==firstchild.c.id)
 return conn.execute(s).fetchone()

 conn = engine.connect()

 results = test_labels1(conn)
 print results.parent_name
 print results.child_name

 results = test_alias1(conn)
 print 'alias1 results: '
 print results.parent_name
 #print results.firstchild_name # expected this to work
 print results.child_1_name # this worked instead
   

You need to set an explicit name for the alias to prevent SQLAlchemy
from generating an anonymous name[1]:

firstchild = child.alias(firstchild)

-Conor

[1]
http://www.sqlalchemy.org/docs/core/expression_api.html#sqlalchemy.sql.expression.FromClause.alias

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: hierarchical data storage and searching

2010-09-09 Thread Conor
On 09/09/2010 02:18 AM, Chris Withers wrote:
 On 08/09/2010 19:23, Gunnlaugur Briem wrote:
 http://communities.bmc.com/communities/docs/DOC-9902

 Thanks for all of the references, but this one in particular.
 Materialized paths looks like its the closest to what I'm after.

 However, with materialized paths, I'm wondering with a structure like:

 /
 /a/
 /a/b
 /a/b/1
 /a/b/2
 /a/c
 /b/
 /b/1
 /b/2

 How to phrases the sql to answer the question:

 Does the current user have access to anything in /a or below

 ...particularly where the user is granted access only to /a/b/1, for
 example.

It's hard to give specifics without knowing what kind of access control
you are using (e.g. separate read/write permissions, inherited
permissions, full ACLs), but here is one attempt:

SELECT EXISTS (SELECT 1 FROM access_control WHERE (path = '/a' OR path LIKE 
'/a/%') AND user = :user AND permission = :permission)

Most materialized path queries use LIKE a lot. As long as you keep the %
character at the end, a good DB will be able to use an index to speed up
the query.

-Conor

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Re: hierarchical data storage and searching

2010-09-09 Thread Chris Withers

Conor wrote:

SELECT EXISTS (SELECT 1 FROM access_control WHERE (path = '/a' OR path LIKE 
'/a/%') AND user = :user AND permission = :permission)

Most materialized path queries use LIKE a lot. As long as you keep the % 
character at the end, a good DB will be able to use an index to speed up 
the query.


Ah, of course, many thanks! :-)

Chris

--
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] Copying instances from old to new schema DB

2010-09-09 Thread chaouche yacine
Thank you Michael, that's for the catch-the-error part. How about the 
set-relations-right part, if I decided to go with my fix-as-you go recipe ? do 
you have any idea ? the dictionary approach seems good, but I still am curious 
about how to set relations generically on models. I think I'll use it somewhere 
else in my code.

By the way, I think the pseudo should have been : 

instance = next_instance_from_csv()
try:
session.commit()
except IntegrityError,e :
session.rollback()
if e.orig == UniqueConstraintError : 
original_instance = ModelClass.get(instance.id)
for relation_name in instance.get_relation_names() :
# Is this correct ?
path_to_attribute= mapper.+ relation +.inverse # I don't know 
where to find this ?
instance.set_attribute(path_to_attribute,original_instance)
session.commit()

class BaseModel (DeclarativeBase):
...
def set_attribute(self,path,value):
nodes= path.explode(.)
current_node = self
for next_node in nodes :
current_node = getattr(current_node,next_node,None)
if not current_node:
raise InvalidAttribute
set_attribute(current_node,value) # sqla's set_attribute, for whatever 
reason... 


Y.Chaouche


--- On Thu, 9/9/10, Michael Bayer mike...@zzzcomputing.com wrote:

 From: Michael Bayer mike...@zzzcomputing.com
 Subject: Re: [sqlalchemy] Copying instances from old to new schema DB
 To: sqlalchemy@googlegroups.com
 Date: Thursday, September 9, 2010, 5:59 AM
 
 On Sep 9, 2010, at 6:31 AM, chaouche yacine wrote:
 
  Hello list,
  
  My schema has changed, and now I want to retrieve my
 old data (of the old schema) to the new database (with the
 new schema) from csv files (I export the tables of the old
 database to csv files and then load those csv files to the
 new database with some column mapping and some gap filling
 for new columns)
  
  The problem is that my new schema have a
 UniqueConstraint for some tables (like : the name column of
 the city table should be unique within a country). This
 constraint was not present in the old schema and data is
 corrupt (two cities with the same name in the same country).
 So when I try to insert them in the new database, I have
 IntegrityErrors. 
  
  The solution I thought of was :
  * Catch the IntegrityError exception 
  * If it's a problem on a UniqueConstraint, then the
 exception was raised because I tried to insert instance B
 that has the same key as instance A that was inserted
 before.
  * So for all children of B (B's relations), set their
 parent to A. For example, for all citizens of B, set their
 city to A, beause A and B ought to be the same. 
  * Then, safely ignore B and move on to the next
 instance.
  
  Here's what has been done so far (that works, I just
 use psuedo code for illustration purpose. If necessary,
 you can look at the actual attached source files): 
  
  line       =
 csvloader.next_row()
  ModelClass = get_current_model()
  instance   =
 ModelClass.create_instance(**(to_dict(line)))
  session.add(instance) 
  
  I wish I could do something like this : 
  try:    
     session.commit()
  except IntegrityError,e : 
     session.rollback()
     errror = get_error()
     if type_of(error) ==
 UniqueConstraintError :
         original_instance =
 ModelClass.get(instance.id)
         for relation in
 instance.get_relations() : 
             # Is this
 correct ? 
         
 instance.relation.inverse = original_instance
         session.commit()
  
  My questions are : how to write get_error, type_of,
 where to get UniqueContraintError, how to write
 get_relations, how to set the inverse of a relation (is
 instance.realtion.inverse the right thing to set ?) and is
 this approach correct ?
 
 There's no portable way to detect unique constraint
 errors across DBAPIs, you'd have to catch the specific error
 that you've observed your DBAPI emits as well as the
 message/codes contained within it, and code against
 that.   SQLAlchemy wraps DBAPI exceptions in
 its own same-named wrapper and the object emitted by the
 DBAPI is available under the .orig member.
 
 One improvement to the recipe would be if you used
 savepoints, if supported by your database, so that when you
 issue rollback() inside a savepoint block, the whole
 transaction isn't rolled back and you can maintain the whole
 operation in one transaction.   The session
 can start a savepoint using begin_nested().
 
 When I do csv loads like these however I usually load the
 full list of identifiers to be checked into memory ahead of
 time.  If the csv is less than 100K rows and represents
 the full table of data, I just load the whole thing into a
 dictionary, formatted according to whatever these are the
 fields that are unique I'm dealing with, and consult the
 dictionary as I go along.    Otherwise, I load
 individual blocks of data in as I scan through portions of
 the csv (like, give me all the 

Re: [sqlalchemy] Copying instances from old to new schema DB

2010-09-09 Thread Michael Bayer

On Sep 9, 2010, at 11:31 AM, chaouche yacine wrote:

 Thank you Michael, that's for the catch-the-error part. How about the 
 set-relations-right part, if I decided to go with my fix-as-you go recipe ? 
 do you have any idea ? the dictionary approach seems good, but I still am 
 curious about how to set relations generically on models. I think I'll use it 
 somewhere else in my code.

You don't need to set any relations.   If your new B has a fully populated 
primary key, you should just be using session.merge() for the whole thing.
This can work with your integrity error scheme, or more simply with the 
select first schemes below:


for row in csv:
new_object = make_an_object_from_csv_row(row)
new_object = session.merge(new_object)
session.commit()


if new_object does *not* have the correct primary key, then:

for row in csv:
new_object = make_an_object_from_csv_row(row)
existing_object = 
session.query(cls).filter(cls.the_unique_column==new_object.the_unique_column).first()
if existing_object is not None:
new_object.id = existing_object.id
new_object = session.merge(new_object)
session.commit()


if you don't like the many indvidual SELECT statements, then

# load a dictionary of (unique attr, primary key)
lookup = dict(
session.query(cls.the_unique_column, cls.id)
)
for row in csv:
new_object = make_an_object_from_csv_row(row)
if new_object.the_unique_column in lookup:
new_object.id = lookup[new_object.the_unique_column]
new_object = session.merge(new_object)
session.commit()

or if most of your rows are replacement rows, quicker to preload everything:


# load a dictionary of (unique attr, instance)
lookup = dict(
session.query(cls.the_unique_column, cls)
)
for row in csv:
new_object = make_an_object_from_csv_row(row)
if new_object.the_unique_column in lookup:
new_object.id = lookup[new_object.the_unique_column].id
new_object = session.merge(new_object)
session.commit()





 
 By the way, I think the pseudo should have been : 
 
 instance = next_instance_from_csv()
 try:
session.commit()
 except IntegrityError,e :
session.rollback()
if e.orig == UniqueConstraintError : 
original_instance = ModelClass.get(instance.id)
for relation_name in instance.get_relation_names() :
# Is this correct ?
path_to_attribute= mapper.+ relation +.inverse # I don't know 
 where to find this ?
instance.set_attribute(path_to_attribute,original_instance)
session.commit()
 
 class BaseModel (DeclarativeBase):
...
def set_attribute(self,path,value):
nodes= path.explode(.)
current_node = self
for next_node in nodes :
current_node = getattr(current_node,next_node,None)
if not current_node:
raise InvalidAttribute
set_attribute(current_node,value) # sqla's set_attribute, for whatever 
 reason... 
 
 
 Y.Chaouche
 
 
 --- On Thu, 9/9/10, Michael Bayer mike...@zzzcomputing.com wrote:
 
 From: Michael Bayer mike...@zzzcomputing.com
 Subject: Re: [sqlalchemy] Copying instances from old to new schema DB
 To: sqlalchemy@googlegroups.com
 Date: Thursday, September 9, 2010, 5:59 AM
 
 On Sep 9, 2010, at 6:31 AM, chaouche yacine wrote:
 
 Hello list,
 
 My schema has changed, and now I want to retrieve my
 old data (of the old schema) to the new database (with the
 new schema) from csv files (I export the tables of the old
 database to csv files and then load those csv files to the
 new database with some column mapping and some gap filling
 for new columns)
 
 The problem is that my new schema have a
 UniqueConstraint for some tables (like : the name column of
 the city table should be unique within a country). This
 constraint was not present in the old schema and data is
 corrupt (two cities with the same name in the same country).
 So when I try to insert them in the new database, I have
 IntegrityErrors. 
 
 The solution I thought of was :
 * Catch the IntegrityError exception 
 * If it's a problem on a UniqueConstraint, then the
 exception was raised because I tried to insert instance B
 that has the same key as instance A that was inserted
 before.
 * So for all children of B (B's relations), set their
 parent to A. For example, for all citizens of B, set their
 city to A, beause A and B ought to be the same. 
 * Then, safely ignore B and move on to the next
 instance.
 
 Here's what has been done so far (that works, I just
 use psuedo code for illustration purpose. If necessary,
 you can look at the actual attached source files): 
 
 line   =
 csvloader.next_row()
 ModelClass = get_current_model()
 instance   =
 ModelClass.create_instance(**(to_dict(line)))
 session.add(instance) 
 
 I wish I could do something like this : 
 try:
 session.commit()
 except IntegrityError,e : 
 session.rollback()
 

[sqlalchemy] SQLAlchemy / Turbogears2.0 transaction rollbacks

2010-09-09 Thread ozwyzard
Hello,

I am trying to use Turbogears 2.x with SQLAlchemy 0.5.1.

TG2 uses scoped sessions and uses an additional layer of transaction
manager.  If I have a scenario as follows:

import transaction

def main()
try:
add main_record to session
query main_record to get primary key
call foo()
except Exception, e:
transaction.abort()

def foo(pid):
add dependent record with main_record_primary_key as foreign_key
raise exception for testing


The above code is not rolling back the transaction.  I realize the
'query main_record' will flush the main_record to the DB.  But I am
wondering if it is also 'commiting' the record.  How do I debug this?
Is there a debug flag in sqlalchemy which logs a commit operation?


The associated initialization code in TG2 is:

from zope.sqlalchemy import ZopeTransactionExtension
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# Global session manager: DBSession() returns the Thread-local
# session object appropriate for the current web request.
maker = sessionmaker(autoflush=True, autocommit=False,
 extension=ZopeTransactionExtension())
DBSession = scoped_session(maker)
metadata = DeclarativeBase.metadata


The link to the thread on turbogears group is:

http://groups.google.com/group/turbogears/browse_thread/thread/363c2e5ac7211a8


Thanks!

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.



Re: [sqlalchemy] SQLAlchemy / Turbogears2.0 transaction rollbacks

2010-09-09 Thread Michael Bayer

On Sep 9, 2010, at 3:51 PM, ozwyzard wrote:

 Hello,
 
 I am trying to use Turbogears 2.x with SQLAlchemy 0.5.1.
 
 TG2 uses scoped sessions and uses an additional layer of transaction
 manager.  If I have a scenario as follows:
 
 import transaction
 
 def main()
try:
add main_record to session
query main_record to get primary key
call foo()
except Exception, e:
transaction.abort()
 
 def foo(pid):
add dependent record with main_record_primary_key as foreign_key
raise exception for testing
 
 
 The above code is not rolling back the transaction.  I realize the
 'query main_record' will flush the main_record to the DB.  But I am
 wondering if it is also 'commiting' the record.  How do I debug this?
 Is there a debug flag in sqlalchemy which logs a commit operation?

the regular engine logging will show the string COMMIT and ROLLBACK in the 
logs.  See the Engine documentation for how to use the echo flag as well as 
more comprehensive logging.



 
 
 The associated initialization code in TG2 is:
 
 from zope.sqlalchemy import ZopeTransactionExtension
 from sqlalchemy.orm import scoped_session, sessionmaker
 from sqlalchemy.ext.declarative import declarative_base
 
 # Global session manager: DBSession() returns the Thread-local
 # session object appropriate for the current web request.
 maker = sessionmaker(autoflush=True, autocommit=False,
 extension=ZopeTransactionExtension())
 DBSession = scoped_session(maker)
 metadata = DeclarativeBase.metadata
 
 
 The link to the thread on turbogears group is:
 
 http://groups.google.com/group/turbogears/browse_thread/thread/363c2e5ac7211a8
 
 
 Thanks!
 
 -- 
 You received this message because you are subscribed to the Google Groups 
 sqlalchemy group.
 To post to this group, send email to sqlalch...@googlegroups.com.
 To unsubscribe from this group, send email to 
 sqlalchemy+unsubscr...@googlegroups.com.
 For more options, visit this group at 
 http://groups.google.com/group/sqlalchemy?hl=en.
 

-- 
You received this message because you are subscribed to the Google Groups 
sqlalchemy group.
To post to this group, send email to sqlalch...@googlegroups.com.
To unsubscribe from this group, send email to 
sqlalchemy+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en.