provide access to SQLite, with functions and variables for db-specific variants
This commit is contained in:
parent
83071842c8
commit
592e653561
7 changed files with 69 additions and 22 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,3 +10,4 @@
|
||||||
*#*#
|
*#*#
|
||||||
*.#*
|
*.#*
|
||||||
__pycache__
|
__pycache__
|
||||||
|
var
|
||||||
|
|
|
@ -4,19 +4,28 @@
|
||||||
|
|
||||||
import base64
|
import base64
|
||||||
from sqlalchemy import create_engine, MetaData, text
|
from sqlalchemy import create_engine, MetaData, text
|
||||||
from sqlalchemy.orm import scoped_session, sessionmaker
|
from sqlalchemy import Integer
|
||||||
|
from sqlalchemy.dialects.sqlite import JSON
|
||||||
import threading
|
import threading
|
||||||
import zope.sqlalchemy
|
|
||||||
|
|
||||||
|
|
||||||
def getEngine(dbtype, dbname, user, pw, host='localhost', port=5432, **kw):
|
# predefined db-specific definitions, usable for SQLite;
|
||||||
return create_engine('%s://%s:%s@%s:%s/%s' % (
|
# may be overriden by import of ``scopes.storage.db.<dbname>``
|
||||||
dbtype, user, pw, host, port, dbname), **kw)
|
|
||||||
|
|
||||||
def sessionFactory(engine):
|
def sessionFactory(engine):
|
||||||
Session = scoped_session(sessionmaker(bind=engine, twophase=True))
|
return engine.connect
|
||||||
zope.sqlalchemy.register(Session)
|
|
||||||
return Session
|
def getEngine(dbtype, dbname, user, pw, host='localhost', port=5432, **kw):
|
||||||
|
return create_engine('%s:///%s' % (dbtype, dbname), **kw)
|
||||||
|
|
||||||
|
def mark_changed(session):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def commit(conn):
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
IdType = Integer
|
||||||
|
JsonType = JSON
|
||||||
|
|
||||||
# put something like this in code before first creating a Storage object
|
# put something like this in code before first creating a Storage object
|
||||||
#engine = getEngine('postgresql+psycopg', 'testdb', 'testuser', 'secret')
|
#engine = getEngine('postgresql+psycopg', 'testdb', 'testuser', 'secret')
|
||||||
|
@ -57,7 +66,8 @@ class Storage(object):
|
||||||
|
|
||||||
def dropTable(self, tableName):
|
def dropTable(self, tableName):
|
||||||
with self.engine.begin() as conn:
|
with self.engine.begin() as conn:
|
||||||
conn.execute(text('drop table if exists %s.%s' % (self.schema, tableName)))
|
prefix = self.schema and self.schema + '.' or ''
|
||||||
|
conn.execute(text('drop table if exists %s%s' % (prefix, tableName)))
|
||||||
|
|
||||||
def resetSequence(self, tableName, colName, v):
|
def resetSequence(self, tableName, colName, v):
|
||||||
sq = ('alter sequence %s.%s_%s_seq restart %i' %
|
sq = ('alter sequence %s.%s_%s_seq restart %i' %
|
||||||
|
|
1
scopes/storage/db/__init__.py
Normal file
1
scopes/storage/db/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
"""scopes.storage.db"""
|
23
scopes/storage/db/postgres.py
Normal file
23
scopes/storage/db/postgres.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
# scopes.storage.db.postgres
|
||||||
|
|
||||||
|
"""Database-related code specific for PostgreSQL."""
|
||||||
|
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from sqlalchemy import BigInteger, JSONB
|
||||||
|
from sqlalchemy.dialects.postgresql import JSONB
|
||||||
|
from sqlalchemy.orm import scoped_session, sessionmaker
|
||||||
|
import transaction
|
||||||
|
from zope.sqlalchemy import register, mark_changed
|
||||||
|
|
||||||
|
|
||||||
|
def sessionFactory(engine):
|
||||||
|
Session = scoped_session(sessionmaker(bind=engine, twophase=True))
|
||||||
|
register(Session)
|
||||||
|
return Session
|
||||||
|
|
||||||
|
def getEngine(dbtype, dbname, user, pw, host='localhost', port=5432, **kw):
|
||||||
|
return create_engine('%s://%s:%s@%s:%s/%s' % (
|
||||||
|
dbtype, user, pw, host, port, dbname), **kw)
|
||||||
|
|
||||||
|
def commit(conn):
|
||||||
|
transaction.commit()
|
|
@ -9,12 +9,10 @@ data (payload) represented as a dict.
|
||||||
import base64
|
import base64
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sqlalchemy import Table, Column, Index
|
from sqlalchemy import Table, Column, Index
|
||||||
from sqlalchemy import BigInteger, DateTime, Text, func
|
from sqlalchemy import DateTime, Text, func
|
||||||
from sqlalchemy import and_
|
from sqlalchemy import and_
|
||||||
from sqlalchemy.dialects.postgresql import JSONB
|
|
||||||
import transaction
|
|
||||||
from zope.sqlalchemy import register, mark_changed
|
|
||||||
|
|
||||||
|
from scopes.storage.common import commit, IdType, JsonType, mark_changed
|
||||||
from scopes.storage.common import registerContainerClass
|
from scopes.storage.common import registerContainerClass
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,7 +175,7 @@ class Container(object):
|
||||||
|
|
||||||
def createTable(storage, tableName, headcols, indexes=None):
|
def createTable(storage, tableName, headcols, indexes=None):
|
||||||
metadata = storage.metadata
|
metadata = storage.metadata
|
||||||
cols = [Column('trackid', BigInteger, primary_key=True)]
|
cols = [Column('trackid', IdType, primary_key=True)]
|
||||||
idxs = []
|
idxs = []
|
||||||
for ix, f in enumerate(headcols):
|
for ix, f in enumerate(headcols):
|
||||||
cols.append(Column(f.lower(), Text, nullable=False, server_default=''))
|
cols.append(Column(f.lower(), Text, nullable=False, server_default=''))
|
||||||
|
@ -187,7 +185,7 @@ def createTable(storage, tableName, headcols, indexes=None):
|
||||||
indexName = 'idx_%s_%d' % (tableName, (ix + 1))
|
indexName = 'idx_%s_%d' % (tableName, (ix + 1))
|
||||||
idxs.append(Index(indexName, *idef))
|
idxs.append(Index(indexName, *idef))
|
||||||
idxs.append(Index('idx_%s_ts' % tableName, 'timestamp'))
|
idxs.append(Index('idx_%s_ts' % tableName, 'timestamp'))
|
||||||
cols.append(Column('data', JSONB, nullable=False, server_default='{}'))
|
cols.append(Column('data', JsonType, nullable=False, server_default='{}'))
|
||||||
table = Table(tableName, metadata, *(cols+idxs), extend_existing=True)
|
table = Table(tableName, metadata, *(cols+idxs), extend_existing=True)
|
||||||
metadata.create_all(storage.engine)
|
metadata.create_all(storage.engine)
|
||||||
return table
|
return table
|
||||||
|
|
|
@ -7,8 +7,16 @@ server_port = '8999'
|
||||||
app = zope_app
|
app = zope_app
|
||||||
|
|
||||||
# storage settings
|
# storage settings
|
||||||
|
|
||||||
|
# PostgreSQL
|
||||||
dbengine = 'postgresql+psycopg'
|
dbengine = 'postgresql+psycopg'
|
||||||
dbname = 'testdb'
|
dbname = 'testdb'
|
||||||
dbuser = 'testuser'
|
dbuser = 'testuser'
|
||||||
dbpassword = 'secret'
|
dbpassword = 'secret'
|
||||||
|
dbschema = 'testing'
|
||||||
|
|
||||||
|
# SQLite
|
||||||
|
dbengine = 'sqlite'
|
||||||
|
dbname = 'var/test.db'
|
||||||
|
dbschema = None
|
||||||
|
|
||||||
|
|
|
@ -2,27 +2,30 @@
|
||||||
|
|
||||||
"""Tests for the 'scopes.storage' package."""
|
"""Tests for the 'scopes.storage' package."""
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import transaction
|
import transaction
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
import scopes.storage.common
|
import scopes.storage.common
|
||||||
from scopes.storage.common import Storage, getEngine, sessionFactory
|
from scopes.storage.common import commit, Storage, getEngine, sessionFactory
|
||||||
from scopes.storage import proxy
|
from scopes.storage import proxy
|
||||||
from scopes.storage import folder, tracking
|
from scopes.storage import folder, tracking
|
||||||
|
|
||||||
import config
|
|
||||||
engine = getEngine(config.dbengine, config.dbname, config.dbuser, config.dbpassword)
|
engine = getEngine(config.dbengine, config.dbname, config.dbuser, config.dbpassword)
|
||||||
scopes.storage.common.engine = engine
|
scopes.storage.common.engine = engine
|
||||||
scopes.storage.common.Session = sessionFactory(engine)
|
scopes.storage.common.Session = sessionFactory(engine)
|
||||||
|
|
||||||
storage = Storage(schema='testing')
|
#storage = Storage(schema='testing')
|
||||||
|
#storage = Storage(schema=config.dbschema)
|
||||||
|
storage = Storage()
|
||||||
|
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
"Basic tests for the cco.storage package."
|
"Basic tests for the cco.storage package."
|
||||||
|
|
||||||
def testTracking(self):
|
def test_001_tracking(self):
|
||||||
storage.dropTable('tracks')
|
storage.dropTable('tracks')
|
||||||
tracks = storage.create(tracking.Container)
|
tracks = storage.create(tracking.Container)
|
||||||
|
|
||||||
|
@ -68,9 +71,9 @@ class Test(unittest.TestCase):
|
||||||
self.assertEqual(n, 1)
|
self.assertEqual(n, 1)
|
||||||
self.assertEqual(tracks.get(31), None)
|
self.assertEqual(tracks.get(31), None)
|
||||||
|
|
||||||
transaction.commit()
|
commit(storage.session)
|
||||||
|
|
||||||
def testFolder(self):
|
def test_002_folder(self):
|
||||||
storage.dropTable('folders')
|
storage.dropTable('folders')
|
||||||
root = folder.Root(storage)
|
root = folder.Root(storage)
|
||||||
self.assertEqual(list(root.keys()), [])
|
self.assertEqual(list(root.keys()), [])
|
||||||
|
@ -83,6 +86,9 @@ class Test(unittest.TestCase):
|
||||||
self.assertEqual(ch1.parent, top.rid)
|
self.assertEqual(ch1.parent, top.rid)
|
||||||
assert list(top.keys()) == ['child1']
|
assert list(top.keys()) == ['child1']
|
||||||
|
|
||||||
|
#transaction.commit()
|
||||||
|
storage.session.commit()
|
||||||
|
|
||||||
def suite():
|
def suite():
|
||||||
return unittest.TestSuite((
|
return unittest.TestSuite((
|
||||||
unittest.TestLoader().loadTestsFromTestCase(Test),
|
unittest.TestLoader().loadTestsFromTestCase(Test),
|
||||||
|
|
Loading…
Add table
Reference in a new issue