Skip to content

Commit f7e64dd

Browse files
authored
Merge pull request #1693 from davestgermain/dcs/sqla-2
Support for SQLAlchemy 2.0
2 parents 47615f6 + 9b7a96c commit f7e64dd

File tree

3 files changed

+46
-24
lines changed

3 files changed

+46
-24
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ dependencies = [
5454
"whoosh >= 2.7.0", # needed for indexed search
5555
"pdfminer.six", # pdf -> text/plain conversion
5656
"passlib >= 1.6.0", # strong password hashing (1.6 needed for consteq)
57-
"sqlalchemy < 2.0", # used by sqla store
57+
"sqlalchemy >= 2.0", # used by sqla store
5858
"XStatic >= 0.0.2", # support for static file pypi packages
5959
"XStatic-Bootstrap == 3.1.1.2",
6060
"XStatic-Font-Awesome >= 6.2.1.0",

src/moin/storage/backends/_tests/test_stores.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
from moin.storage.stores.memory import FileStore as MemoryFileStore
1919
from moin.storage.stores.fs import BytesStore as FSBytesStore
2020
from moin.storage.stores.fs import FileStore as FSFileStore
21+
from moin.storage.stores.sqla import BytesStore as SQLABytesStore
22+
from moin.storage.stores.sqla import FileStore as SQLAFileStore
2123

2224

2325
class TestMemoryBackend(MutableBackendTestBase):
@@ -40,3 +42,14 @@ def setup_method(self, method):
4042
self.be = MutableBackend(meta_store, data_store)
4143
self.be.create()
4244
self.be.open()
45+
46+
47+
class TestSQLABackend(MutableBackendTestBase):
48+
def setup_method(self, method):
49+
meta_path = tempfile.mktemp()
50+
data_path = tempfile.mktemp()
51+
meta_store = SQLABytesStore(f"sqlite:///{meta_path}")
52+
data_store = SQLAFileStore(f"sqlite:///{data_path}")
53+
self.be = MutableBackend(meta_store, data_store)
54+
self.be.create()
55+
self.be.open()

src/moin/storage/stores/sqla.py

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(self, db_uri=None, table_name="store", verbose=False):
5252
self.table_name = table_name
5353
if db_uri.startswith("sqlite:///"):
5454
db_path = os.path.dirname(self.db_uri.split("sqlite:///")[1])
55-
if not os.path.exists(db_path):
55+
if db_path and not os.path.exists(db_path):
5656
os.makedirs(db_path)
5757

5858
def open(self):
@@ -65,11 +65,10 @@ def open(self):
6565
else:
6666
self.engine = create_engine(db_uri, echo=self.verbose, echo_pool=self.verbose)
6767

68-
metadata = MetaData()
69-
metadata.bind = self.engine
68+
self.metadata = MetaData()
7069
self.table = Table(
7170
self.table_name,
72-
metadata,
71+
self.metadata,
7372
Column("key", String(KEY_LEN), primary_key=True),
7473
Column("value", LargeBinary(VALUE_LEN)),
7574
)
@@ -80,38 +79,48 @@ def close(self):
8079

8180
def create(self):
8281
self.open()
83-
self.table.create()
82+
with self.engine.connect() as conn:
83+
with conn.begin():
84+
self.metadata.create_all(conn)
8485
self.close()
8586

8687
def destroy(self):
8788
self.open()
88-
self.table.drop()
89+
with self.engine.connect() as conn:
90+
with conn.begin():
91+
self.metadata.drop_all(conn)
8992
self.close()
9093

9194
def __iter__(self):
92-
rows = select([self.table.c.key]).execute().fetchall()
93-
for row in rows:
94-
yield row[0]
95+
with self.engine.connect() as conn:
96+
rows = conn.execute(select(self.table.c.key))
97+
for row in rows:
98+
yield row[0]
9599

96100
def __delitem__(self, key):
97-
self.table.delete().where(self.table.c.key == key).execute()
101+
with self.engine.connect() as conn:
102+
with conn.begin():
103+
conn.execute(self.table.delete().where(self.table.c.key == key))
98104

99105
def __getitem__(self, key):
100-
value = select([self.table.c.value], self.table.c.key == key).execute().fetchone()
101-
if value is not None:
102-
return value[0]
103-
else:
104-
raise KeyError(key)
106+
with self.engine.connect() as conn:
107+
value = conn.execute(select(self.table.c.value).where(self.table.c.key == key)).fetchone()
108+
if value is not None:
109+
return value[0]
110+
else:
111+
raise KeyError(key)
105112

106113
def __setitem__(self, key, value):
107-
try:
108-
self.table.insert().execute(key=key, value=value)
109-
except IntegrityError:
110-
if NAMESPACE_USERPROFILES in self.db_uri:
111-
# userprofiles namespace does support revisions so we update existing row
112-
self.table.update().execute(key=key, value=value)
113-
else:
114-
raise
114+
with self.engine.connect() as conn:
115+
with conn.begin():
116+
try:
117+
conn.execute(self.table.insert().values(key=key, value=value))
118+
except IntegrityError:
119+
if NAMESPACE_USERPROFILES in self.db_uri:
120+
# userprofiles namespace does support revisions so we update existing row
121+
conn.execute(self.table.update().values(key=key, value=value))
122+
else:
123+
raise
115124

116125

117126
class FileStore(FileMutableStoreMixin, BytesStore, FileMutableStoreBase):

0 commit comments

Comments
 (0)