Skip to content

Commit 479ec57

Browse files
committed
Customise meta.py to support strict boolean values.
1 parent ad54888 commit 479ec57

File tree

3 files changed

+150
-1
lines changed

3 files changed

+150
-1
lines changed

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ ENV/
105105
ckan
106106
ckan/
107107
ckan-*.tar.gz
108-
109108
# Env
110109
env*
111110
!env.tmpl

contrib/ckan/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,8 @@ ARG CKAN_VERSION=2.8.3
77
RUN pip install -U -q pip setuptools
88

99
RUN pip install -q -e "git+https://github.com/ckan/ckan.git@ckan-${CKAN_VERSION}#egg=ckan"
10+
11+
ADD meta.py /src/ckan/ckan/model/meta.py
12+
1013
RUN pip install -q -r /src/ckan/requirements.txt
1114
RUN pip install -q vdm==0.15 sqlalchemy==1.2.19

contrib/ckan/meta.py

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
# encoding: utf-8
2+
3+
import datetime
4+
5+
from paste.deploy.converters import asbool
6+
from ckan.common import config
7+
"""SQLAlchemy Metadata and Session object"""
8+
from sqlalchemy import MetaData, and_
9+
import sqlalchemy.orm as orm
10+
from sqlalchemy.orm.session import SessionExtension
11+
12+
import extension
13+
import ckan.lib.activity_streams_session_extension as activity
14+
15+
__all__ = ['Session', 'engine_is_sqlite', 'engine_is_pg']
16+
17+
18+
class CkanCacheExtension(SessionExtension):
19+
''' This extension checks what tables have been affected by
20+
database access and allows us to act on them. Currently this is
21+
used by the page cache to flush the cache when data in the database
22+
is altered. '''
23+
24+
def __init__(self, *args, **kw):
25+
super(CkanCacheExtension, self).__init__(*args, **kw)
26+
27+
def after_commit(self, session):
28+
if hasattr(session, '_object_cache'):
29+
oc = session._object_cache
30+
oc_list = oc['new']
31+
oc_list.update(oc['changed'])
32+
oc_list.update(oc['deleted'])
33+
objs = set()
34+
for item in oc_list:
35+
objs.add(item.__class__.__name__)
36+
37+
38+
class CkanSessionExtension(SessionExtension):
39+
40+
def before_flush(self, session, flush_context, instances):
41+
if not hasattr(session, '_object_cache'):
42+
session._object_cache= {'new': set(),
43+
'deleted': set(),
44+
'changed': set()}
45+
46+
changed = [obj for obj in session.dirty if
47+
session.is_modified(obj, include_collections=False, passive=True)]
48+
49+
session._object_cache['new'].update(session.new)
50+
session._object_cache['deleted'].update(session.deleted)
51+
session._object_cache['changed'].update(changed)
52+
53+
54+
def before_commit(self, session):
55+
session.flush()
56+
try:
57+
obj_cache = session._object_cache
58+
revision = session.revision
59+
except AttributeError:
60+
return
61+
if getattr(session, 'revisioning_disabled', False):
62+
return
63+
new = obj_cache['new']
64+
changed = obj_cache['changed']
65+
deleted = obj_cache['deleted']
66+
for obj in new | changed | deleted:
67+
if not hasattr(obj, '__revision_class__'):
68+
continue
69+
revision_cls = obj.__revision_class__
70+
revision_table = orm.class_mapper(revision_cls).mapped_table
71+
## when a normal active transaction happens
72+
73+
### this is an sql statement as we do not want it in object cache
74+
session.execute(
75+
revision_table.update().where(
76+
and_(revision_table.c.id == obj.id,
77+
revision_table.c.current == True)
78+
).values(current=False)
79+
)
80+
81+
q = session.query(revision_cls)
82+
q = q.filter_by(expired_timestamp=datetime.datetime(9999, 12, 31), id=obj.id)
83+
results = q.all()
84+
for rev_obj in results:
85+
values = {}
86+
if rev_obj.revision_id == revision.id:
87+
values['revision_timestamp'] = revision.timestamp
88+
else:
89+
values['expired_timestamp'] = revision.timestamp
90+
session.execute(
91+
revision_table.update().where(
92+
and_(revision_table.c.id == rev_obj.id,
93+
revision_table.c.revision_id == rev_obj.revision_id)
94+
).values(**values)
95+
)
96+
97+
def after_commit(self, session):
98+
if hasattr(session, '_object_cache'):
99+
del session._object_cache
100+
101+
def after_rollback(self, session):
102+
if hasattr(session, '_object_cache'):
103+
del session._object_cache
104+
105+
# __all__ = ['Session', 'engine', 'metadata', 'mapper']
106+
107+
# SQLAlchemy database engine. Updated by model.init_model()
108+
engine = None
109+
110+
Session = orm.scoped_session(orm.sessionmaker(
111+
autoflush=False,
112+
autocommit=False,
113+
expire_on_commit=False,
114+
extension=[CkanCacheExtension(),
115+
CkanSessionExtension(),
116+
extension.PluginSessionExtension(),
117+
activity.DatasetActivitySessionExtension()],
118+
))
119+
120+
create_local_session = orm.sessionmaker(
121+
autoflush=False,
122+
autocommit=False,
123+
expire_on_commit=False,
124+
extension=[CkanCacheExtension(),
125+
CkanSessionExtension(),
126+
extension.PluginSessionExtension(),
127+
activity.DatasetActivitySessionExtension()],
128+
)
129+
130+
#mapper = Session.mapper
131+
mapper = orm.mapper
132+
133+
# Global metadata. If you have multiple databases with overlapping table
134+
# names, you'll need a metadata for each database
135+
metadata = MetaData()
136+
137+
138+
def engine_is_sqlite(sa_engine=None):
139+
# Returns true iff the engine is connected to a sqlite database.
140+
return (sa_engine or engine).url.drivername == 'sqlite'
141+
142+
143+
def engine_is_pg(sa_engine=None):
144+
# Returns true iff the engine is connected to a postgresql database.
145+
# According to http://docs.sqlalchemy.org/en/latest/core/engines.html#postgresql
146+
# all Postgres driver names start with `postgres`
147+
return (sa_engine or engine).url.drivername.startswith('postgres')

0 commit comments

Comments
 (0)