[Zope-CVS] CVS: Products/AdaptableStorage/gateway_sql - SQLGatewayBase.py:1.1 SQLObjectData.py:1.1 PsycopgConnection.py:1.4 SQLClassification.py:1.3 SQLFolderItems.py:1.4 SQLItemId.py:1.4 SQLKeychainGenerator.py:1.3 SQLRemainder.py:1.4 public.py:1.2
Shane Hathaway
shane@zope.com
Mon, 23 Dec 2002 23:30:03 -0500
Update of /cvs-repository/Products/AdaptableStorage/gateway_sql
In directory cvs.zope.org:/tmp/cvs-serv30532/gateway_sql
Modified Files:
PsycopgConnection.py SQLClassification.py SQLFolderItems.py
SQLItemId.py SQLKeychainGenerator.py SQLRemainder.py public.py
Added Files:
SQLGatewayBase.py SQLObjectData.py
Log Message:
Provided a way to configure ObjectMappers, with the intent of making
AdaptableStorage easier to explain. Added IConfigurableObjectMapper
and converted all the mapper setup code to use it. Included a
checkConfiguration() method which validates the entire object mapper
tree. Then converted the DBTab-based configuration to use a mapper
factory, which can point to any mapper factory function installed
anywhere. Tangents to this:
- Refactored Zope2FS and Zope2SQL to use the same code for setting up
mappers, leaving "holes" for the gateways.
- Added connect() and close() methods to ITPCConnection (which doesn't
technically exist yet since I need to choose a name for it. ;-) )
- Factored out common parts of the SQL gateways.
- Implemented the newKey() method of IKeyedObjectSystem, which will
help ZEO environments, in theory.
=== Added File Products/AdaptableStorage/gateway_sql/SQLGatewayBase.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.
#
##############################################################################
"""SQL gateway base class
$Id: SQLGatewayBase.py,v 1.1 2002/12/24 04:29:32 shane Exp $
"""
class SQLGatewayBase:
table_base_name = '(override this)'
checkexist_sql = '(override this)'
create_sql = '(override this)'
clear_sql = 'DELETE FROM %(table)s'
def __init__(self, conn):
self.conn = conn
self.table = conn.prefix + '_' + self.table_base_name
if conn.isConnected():
self.setupTables()
else:
conn.addConnectCallback(self.setupTables)
def setupTables(self):
conn = self.conn
try:
self.execute(self.checkexist_sql)
except conn.error:
conn.db.rollback()
self.execute(self.create_sql)
conn.db.commit()
def execute(self, text, *args, **kw):
text = text.replace('%(table)s', self.table) # XXX workaround
return self.conn.execute(text, *args, **kw)
def clear(self):
self.execute(self.clear_sql)
=== Added File Products/AdaptableStorage/gateway_sql/SQLObjectData.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.
#
##############################################################################
"""SQL object data gateway
$Id: SQLObjectData.py,v 1.1 2002/12/24 04:29:32 shane Exp $
"""
from serial_public import IGateway, FieldSchema
from SQLGatewayBase import SQLGatewayBase
class SQLObjectData (SQLGatewayBase):
__implements__ = IGateway
schema = FieldSchema('data', 'string')
table_base_name = 'object_data'
checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
create_sql = '''CREATE TABLE %(table)s (
key int PRIMARY KEY,
data bytea
)'''
read_sql = '''SELECT data from %(table)s
WHERE key = %(key)s'''
update_sql = '''UPDATE %(table)s
SET data = %(data)s
WHERE key = %(key)s'''
insert_sql = '''INSERT INTO %(table)s
(key, data)
VALUES (%(key)s, %(data)s)'''
def getSchema(self):
return self.schema
def load(self, event):
key = int(event.getKeychain()[-1])
items = self.execute(self.read_sql, 1, key=key)
if items:
state = items[0][0]
else:
state = ''
return state, state
def store(self, event, state):
key = int(event.getKeychain()[-1])
items = self.execute(self.read_sql, 1, key=key)
kw = {'key': key, 'data': self.conn.asBinary(state)}
if items:
# update.
self.execute(self.update_sql, **kw)
else:
# insert.
self.execute(self.insert_sql, **kw)
return state
=== Products/AdaptableStorage/gateway_sql/PsycopgConnection.py 1.3 => 1.4 ===
--- Products/AdaptableStorage/gateway_sql/PsycopgConnection.py:1.3 Tue Dec 10 17:51:37 2002
+++ Products/AdaptableStorage/gateway_sql/PsycopgConnection.py Mon Dec 23 23:29:32 2002
@@ -22,23 +22,43 @@
class PsycopgConnection:
_final = 0
+ db = None
+ cursor = None
+ error = psycopg.DatabaseError
def __init__(self, params='', prefix='zodb'):
self.params = params
- self.db = psycopg.connect(params)
- self.cursor = self.db.cursor()
self.prefix = prefix
- self.error = psycopg.DatabaseError
+ self.connect_callbacks = []
+
+ def isConnected(self):
+ return (self.db is not None)
+
+ def addConnectCallback(self, f):
+ self.connect_callbacks.append(f)
+
+ def connect(self):
+ self.db = psycopg.connect(self.params)
+ self.cursor = self.db.cursor()
+ for f in self.connect_callbacks:
+ f()
+ self.connect_callbacks = []
def sortKey(self):
- return self.getName()
+ return repr(self)
def getName(self):
- return 'Psycopg connection "%s"' % self.params
+ return repr(self)
+
+ def __repr__(self):
+ return 'PsycopgConnection(%s, %s)' % (
+ repr(self.params), repr(self.prefix))
def execute(self, text, fetch=0, cursor=None, **kw):
if cursor is None:
cursor = self.cursor
+ if cursor is None:
+ raise RuntimeError('Not connected')
cursor.execute(text, kw)
if fetch:
return cursor.fetchall()
@@ -68,4 +88,11 @@
self.db.commit()
finally:
self.reset()
+
+ def close(self):
+ if self.isConnected():
+ self.cursor.close()
+ self.cursor = None
+ self.db.close()
+ self.db = None
=== Products/AdaptableStorage/gateway_sql/SQLClassification.py 1.2 => 1.3 ===
--- Products/AdaptableStorage/gateway_sql/SQLClassification.py:1.2 Tue Dec 10 17:27:00 2002
+++ Products/AdaptableStorage/gateway_sql/SQLClassification.py Mon Dec 23 23:29:32 2002
@@ -18,57 +18,43 @@
from serial_public import IGateway, FieldSchema
-checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
+from SQLGatewayBase import SQLGatewayBase
-create_sql = '''CREATE TABLE %(table)s (
- key int PRIMARY KEY,
- meta_type character varying(255),
- class_name character varying(255)
-)'''
-read_sql = '''SELECT meta_type, class_name from %(table)s
- WHERE key = %(key)s'''
+class SQLClassification (SQLGatewayBase):
-update_sql = '''UPDATE %(table)s
- SET meta_type=%(meta_type)s, class_name=%(class_name)s
- WHERE key = %(key)s'''
-
-insert_sql = '''INSERT INTO %(table)s
- (key, meta_type, class_name)
- VALUES (%(key)s, %(meta_type)s, %(class_name)s)'''
-
-clear_sql = '''DELETE FROM %(table)s'''
+ __implements__ = IGateway
+ schema = FieldSchema('classification', 'classification')
-class SQLClassification:
+ table_base_name = 'classification'
- __implements__ = IGateway
+ checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
- schema = FieldSchema('classification', 'classification')
+ create_sql = '''CREATE TABLE %(table)s (
+ key int PRIMARY KEY,
+ meta_type character varying(255),
+ class_name character varying(255)
+ )'''
+
+ read_sql = '''SELECT meta_type, class_name from %(table)s
+ WHERE key = %(key)s'''
+
+ update_sql = '''UPDATE %(table)s
+ SET meta_type=%(meta_type)s, class_name=%(class_name)s
+ WHERE key = %(key)s'''
+
+ insert_sql = '''INSERT INTO %(table)s
+ (key, meta_type, class_name)
+ VALUES (%(key)s, %(meta_type)s, %(class_name)s)'''
- def __init__(self, conn):
- self.conn = conn
- self.table = conn.prefix + '_classification'
- try:
- self.execute(checkexist_sql)
- except conn.error:
- conn.db.rollback()
- self.execute(create_sql)
- conn.db.commit()
def getSchema(self):
return self.schema
- def execute(self, text, *args, **kw):
- text = text.replace('%(table)s', self.table) # XXX workaround
- return self.conn.execute(text, *args, **kw)
-
- def clear(self):
- self.execute(clear_sql)
-
def load(self, event):
key = int(event.getKeychain()[-1])
- items = self.execute(read_sql, 1, key=key)
+ items = self.execute(self.read_sql, 1, key=key)
classification = {}
if items:
rec = items[0]
@@ -82,15 +68,15 @@
def store(self, event, classification):
key = int(event.getKeychain()[-1])
- items = self.execute(read_sql, 1, key=key)
+ items = self.execute(self.read_sql, 1, key=key)
mt = classification.get('meta_type', '')
cn = classification.get('class_name', '')
kw = {'key': key, 'meta_type': mt, 'class_name': cn}
if items:
# update.
- self.execute(update_sql, **kw)
+ self.execute(self.update_sql, **kw)
else:
# insert.
- self.execute(insert_sql, **kw)
+ self.execute(self.insert_sql, **kw)
return (mt, cn)
=== Products/AdaptableStorage/gateway_sql/SQLFolderItems.py 1.3 => 1.4 ===
--- Products/AdaptableStorage/gateway_sql/SQLFolderItems.py:1.3 Fri Dec 13 16:21:45 2002
+++ Products/AdaptableStorage/gateway_sql/SQLFolderItems.py Mon Dec 23 23:29:32 2002
@@ -16,67 +16,51 @@
$Id$
"""
+from SQLGatewayBase import SQLGatewayBase
from serial_public import IGateway, RowSequenceSchema
-checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
+class SQLFolderItems (SQLGatewayBase):
-create_sql = '''CREATE TABLE %(table)s (
- key int,
- name character varying(255),
- child_key int
-)'''
+ __implements__ = IGateway
-read_sql = '''SELECT name, child_key FROM %(table)s
- WHERE key = %(key)s'''
+ schema = RowSequenceSchema()
+ schema.addField('id', 'string', 1)
+ schema.addField('keychain', 'keychain')
-update_sql = '''UPDATE %(table)s
- SET child_key=%(child_key)s
- WHERE key = %(key)s and name = %(name)s'''
+ table_base_name = 'folder_items'
-insert_sql = '''INSERT INTO %(table)s
- (key, name, child_key)
- VALUES (%(key)s, %(name)s, %(child_key)s)'''
+ checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
-delete_sql = '''DELETE FROM %(table)s
- WHERE key = %(key)s and name = %(name)s'''
+ create_sql = '''CREATE TABLE %(table)s (
+ key int,
+ name character varying(255),
+ child_key int
+ )'''
-clear_sql = '''DELETE FROM %(table)s'''
+ read_sql = '''SELECT name, child_key FROM %(table)s
+ WHERE key = %(key)s'''
+ update_sql = '''UPDATE %(table)s
+ SET child_key=%(child_key)s
+ WHERE key = %(key)s and name = %(name)s'''
-class SQLFolderItems:
+ insert_sql = '''INSERT INTO %(table)s
+ (key, name, child_key)
+ VALUES (%(key)s, %(name)s, %(child_key)s)'''
- __implements__ = IGateway
+ delete_sql = '''DELETE FROM %(table)s
+ WHERE key = %(key)s and name = %(name)s'''
- schema = RowSequenceSchema()
- schema.addField('id', 'string', 1)
- schema.addField('keychain', 'keychain')
-
- def __init__(self, conn):
- self.conn = conn
- self.table = conn.prefix + '_folder_items'
- try:
- self.execute(checkexist_sql)
- except conn.error:
- conn.db.rollback()
- self.execute(create_sql)
- conn.db.commit()
def getSchema(self):
return self.schema
- def execute(self, text, *args, **kw):
- text = text.replace('%(table)s', self.table) # XXX workaround
- return self.conn.execute(text, *args, **kw)
-
- def clear(self):
- self.execute(clear_sql)
-
def load(self, event):
keychain = event.getKeychain()
key = int(keychain[-1])
prefix = keychain[:-1]
- rows = self.execute(read_sql, 1, key=key)
+ rows = self.execute(self.read_sql, 1, key=key)
rows.sort()
res = [(row[0], prefix + (row[1],)) for row in rows]
return res, tuple(res)
@@ -89,14 +73,14 @@
for name, child_keychain in state:
state_dict[name] = 1
- rows = self.execute(read_sql, 1, key=key)
+ rows = self.execute(self.read_sql, 1, key=key)
db_dict = {}
for name, child_key in rows:
if state_dict.has_key(name):
db_dict[name] = child_key
else:
# Remove this item from the database.
- self.execute(delete_sql, key=key, name=name)
+ self.execute(self.delete_sql, key=key, name=name)
state = list(state)
state.sort()
@@ -109,9 +93,9 @@
if db_dict.has_key(name):
if db_dict[name] != child_key:
# Change the OID of this item.
- self.execute(update_sql, **kw)
+ self.execute(self.update_sql, **kw)
else:
# Add this item to the database.
- self.execute(insert_sql, **kw)
+ self.execute(self.insert_sql, **kw)
return tuple(state)
=== Products/AdaptableStorage/gateway_sql/SQLItemId.py 1.3 => 1.4 ===
--- Products/AdaptableStorage/gateway_sql/SQLItemId.py:1.3 Fri Dec 13 16:21:45 2002
+++ Products/AdaptableStorage/gateway_sql/SQLItemId.py Mon Dec 23 23:29:32 2002
@@ -19,33 +19,31 @@
from serial_public import IGateway, FieldSchema
+from SQLGatewayBase import SQLGatewayBase
-read_sql = '''SELECT name from %(table)s
- WHERE child_key = %(child_key)s'''
-
-class SQLItemId:
+class SQLItemId (SQLGatewayBase):
__implements__ = IGateway
schema = FieldSchema('id', 'string')
- def __init__(self, conn):
- self.conn = conn
- self.table = conn.prefix + '_folder_items'
+ table_base_name = 'folder_items'
+
+ read_sql = 'SELECT name from %(table)s WHERE child_key = %(child_key)s'
+
+ def setupTables(self):
+ # No action necessary
+ pass
def getSchema(self):
return self.schema
- def execute(self, text, *args, **kw):
- text = text.replace('%(table)s', self.table) # XXX workaround
- return self.conn.execute(text, *args, **kw)
-
def load(self, event):
key = int(event.getKeychain()[-1])
- rows = self.execute(read_sql, 1, child_key=key)
+ rows = self.execute(self.read_sql, 1, child_key=key)
assert len(rows) >= 1
- name = rows[0][0]
+ name = rows[0][0] # Other names will be ignored
return name, None
def store(self, event, state):
=== Products/AdaptableStorage/gateway_sql/SQLKeychainGenerator.py 1.2 => 1.3 ===
--- Products/AdaptableStorage/gateway_sql/SQLKeychainGenerator.py:1.2 Tue Dec 10 17:27:00 2002
+++ Products/AdaptableStorage/gateway_sql/SQLKeychainGenerator.py Mon Dec 23 23:29:32 2002
@@ -16,46 +16,34 @@
$Id$
"""
-from serial_public import IKeychainGenerator
+from serial_public import FieldSchema, IKeychainGenerator, IAspectEvent
+from SQLGatewayBase import SQLGatewayBase
-checkexist_sql = '''SELECT last_value FROM %(sequence)s'''
-create_sql = '''CREATE SEQUENCE %(sequence)s'''
+class SQLKeychainGenerator (SQLGatewayBase):
-read_sql = """SELECT nextval('%(sequence)s')"""
+ __implements__ = IKeychainGenerator
-clear_sql = """SELECT setval('%(sequence)s', 1)"""
+ table_base_name = 'key_seq'
+ checkexist_sql = "SELECT last_value FROM %(table)s"
-class SQLKeychainGenerator:
+ create_sql = "CREATE SEQUENCE %(table)s"
- __implements__ = IKeychainGenerator
+ read_sql = "SELECT nextval('%(table)s')"
+
+ clear_sql = "SELECT setval('%(table)s', 1)"
- def __init__(self, conn):
- self.conn = conn
- self.sequence = conn.prefix + '_key_seq'
- try:
- self.execute(checkexist_sql)
- except conn.error:
- conn.db.rollback()
- self.execute(create_sql)
- conn.db.commit()
-
- def getSchema(self):
- return self.schema
-
- def execute(self, text, *args, **kw):
- text = text.replace('%(sequence)s', self.sequence) # XXX workaround
- return self.conn.execute(text, *args, **kw)
def makeKeychain(self, event, name, stored):
if not stored:
raise RuntimeError(
'Keychains generated by SQLKeychain must be stored')
- n = self.execute(read_sql, 1)[0][0]
+ if IAspectEvent.isImplementedBy(event):
+ # Request that the other side do the work (for ZEO)
+ n = event.getKeyedObjectSystem().newKey()
+ else:
+ n = self.execute(self.read_sql, 1)[0][0]
return event.getKeychain()[:-1] + (n,)
-
- def clear(self):
- self.execute(clear_sql)
=== Products/AdaptableStorage/gateway_sql/SQLRemainder.py 1.3 => 1.4 ===
--- Products/AdaptableStorage/gateway_sql/SQLRemainder.py:1.3 Tue Dec 10 17:51:37 2002
+++ Products/AdaptableStorage/gateway_sql/SQLRemainder.py Mon Dec 23 23:29:32 2002
@@ -16,74 +16,28 @@
$Id$
"""
-from serial_public import IGateway, FieldSchema
+from SQLObjectData import SQLObjectData
-checkexist_sql = '''SELECT key FROM %(table)s LIMIT 1'''
+class SQLRemainder (SQLObjectData):
-create_sql = '''CREATE TABLE %(table)s (
- key int PRIMARY KEY,
- pickle bytea
-)'''
-
-read_sql = '''SELECT pickle from %(table)s
- WHERE key = %(key)s'''
-
-update_sql = '''UPDATE %(table)s
- SET pickle=%(pickle)s
- WHERE key = %(key)s'''
-
-insert_sql = '''INSERT INTO %(table)s
- (key, pickle)
- VALUES (%(key)s, %(pickle)s)'''
-
-clear_sql = '''DELETE FROM %(table)s'''
-
-
-class SQLRemainder:
-
- __implements__ = IGateway
-
- schema = FieldSchema('data', 'string')
-
- def __init__(self, conn):
- self.conn = conn
- self.table = conn.prefix + '_remainder'
- try:
- self.execute(checkexist_sql)
- except conn.error:
- conn.db.rollback()
- self.execute(create_sql)
- conn.db.commit()
-
- def getSchema(self):
- return self.schema
-
- def execute(self, text, *args, **kw):
- text = text.replace('%(table)s', self.table) # XXX workaround
- return self.conn.execute(text, *args, **kw)
-
- def clear(self):
- self.execute(clear_sql)
-
- def load(self, event):
- key = int(event.getKeychain()[-1])
- items = self.execute(read_sql, 1, key=key)
- if items:
- state = items[0][0]
- else:
- state = ''
- return state, state
-
- def store(self, event, state):
- key = int(event.getKeychain()[-1])
- items = self.execute(read_sql, 1, key=key)
- kw = {'key': key, 'pickle': self.conn.asBinary(state)}
- if items:
- # update.
- self.execute(update_sql, **kw)
- else:
- # insert.
- self.execute(insert_sql, **kw)
- return state
+ __implements__ = SQLObjectData.__implements__
+
+ table_base_name = 'remainder'
+
+ create_sql = '''CREATE TABLE %(table)s (
+ key int PRIMARY KEY,
+ pickle bytea
+ )'''
+
+ read_sql = '''SELECT pickle from %(table)s
+ WHERE key = %(key)s'''
+
+ update_sql = '''UPDATE %(table)s
+ SET pickle = %(data)s
+ WHERE key = %(key)s'''
+
+ insert_sql = '''INSERT INTO %(table)s
+ (key, pickle)
+ VALUES (%(key)s, %(data)s)'''
=== Products/AdaptableStorage/gateway_sql/public.py 1.1 => 1.2 ===
--- Products/AdaptableStorage/gateway_sql/public.py:1.1 Tue Dec 10 15:37:52 2002
+++ Products/AdaptableStorage/gateway_sql/public.py Mon Dec 23 23:29:32 2002
@@ -18,8 +18,10 @@
from PsycopgConnection import PsycopgConnection
from SQLClassification import SQLClassification
+from SQLGatewayBase import SQLGatewayBase
from SQLFolderItems import SQLFolderItems
from SQLItemId import SQLItemId
from SQLKeychainGenerator import SQLKeychainGenerator
+from SQLObjectData import SQLObjectData
from SQLRemainder import SQLRemainder