2 # -*- coding: iso-8859-15 -*-
5 """Contains functions that maintain/update the cache tables."""
6 from sqlalchemy import schema
7 from sqlalchemy.sql import select
8 from sqlalchemy.sql.expression import func as sqlfunc
11 from wrpylib import mwdb, wrmwdb, mwmarkup, wrmwmarkup
14 class UpdateCacheError(RuntimeError):
18 def update_wrsledruncache(connection):
19 """Updates the wrsledruncache table from the wiki. If convert errors occur, an UpdateCacheError exception
20 is raised. No other exception type should be raised under normal circumstances.
22 >>> from sqlalchemy.engine import create_engine
23 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
24 >>> update_wrsledruncache(engine.connect())
26 metadata = schema.MetaData()
27 wrsledruncache = wrmwdb.wrsledruncache_table(metadata)
28 page = mwdb.page_table(metadata)
29 categorylinks = mwdb.categorylinks_table(metadata)
30 revision = mwdb.revision_table(metadata)
31 text = mwdb.text_table(metadata)
33 transaction = connection.begin()
36 q = select([page, categorylinks, revision, text], (page.c.page_latest==revision.c.rev_id) & (text.c.old_id==revision.c.rev_text_id) & (categorylinks.c.cl_from==page.c.page_id) & (categorylinks.c.cl_to=='Rodelbahn'))
37 sledrun_pages = connection.execute(q)
39 # sql = u"select page_id, rev_id, old_id, page_title, old_text, 'In_Arbeit' in (select cl_to from categorylinks where cl_from=page_id) as under_construction from page, revision, text, categorylinks where page_latest=rev_id and old_id=rev_text_id and cl_from=page_id and cl_to='Rodelbahn' order by page_title"
41 # Delete all existing entries in wrsledruncache
42 # We rely on transactions MySQL InnoDB
43 connection.execute(wrsledruncache.delete())
45 # Refill wrsledruncache table
46 for sledrun_page in sledrun_pages:
48 start, end, sledrun = wrmwmarkup.rodelbahnbox_to_sledrun(sledrun_page.old_text)
49 sledrun.page_id = sledrun_page.page_id
50 sledrun.page_title = sledrun_page.page_title
51 sledrun.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==sledrun_page.page_id) & (categorylinks.c.cl_to == 'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
52 connection.execute(wrsledruncache.insert(sledrun.__dict__))
53 except (RuntimeError, formencode.Invalid) as e:
54 transaction.rollback()
55 error_msg = "Error at sled run '{0}': {1}".format(sledrun_page.page_title, str(e))
56 raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
60 def update_wrinncache(connection):
61 """Updates the wrinncache table from the wiki. If convert errors occur, an UpdateCacheError exception
62 is raised. No other exception type should be raised under normal circumstances.
64 >>> from sqlalchemy.engine import create_engine
65 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
66 >>> update_wrinncache(engine.connect())
68 metadata = schema.MetaData()
69 wrinncache = wrmwdb.wrinncache_table(metadata)
70 page = mwdb.page_table(metadata)
71 categorylinks = mwdb.categorylinks_table(metadata)
72 revision = mwdb.revision_table(metadata)
73 text = mwdb.text_table(metadata)
75 transaction = connection.begin()
78 q = select([page, categorylinks, revision, text], (page.c.page_latest==revision.c.rev_id) & (text.c.old_id==revision.c.rev_text_id) & (categorylinks.c.cl_from==page.c.page_id) & (categorylinks.c.cl_to=='Gasthaus'))
79 inn_pages = connection.execute(q)
81 # Delete all existing entries in wrinncache
82 # We rely on transactions MySQL InnoDB
83 connection.execute(wrinncache.delete())
85 # Refill wrinncache table
86 for inn_page in inn_pages:
88 start, end, inn = wrmwmarkup.gasthausbox_to_inn(inn_page.old_text)
89 inn.page_id = inn_page.page_id
90 inn.page_title = inn_page.page_title
91 inn.under_construction = connection.execute(select([categorylinks], (categorylinks.c.cl_from==inn_page.page_id) & (categorylinks.c.cl_to == 'In_Arbeit')).alias('x').count()).fetchone()[0] > 0 # It would be better to do this in the query above
92 connection.execute(wrinncache.insert(inn.__dict__))
93 except (RuntimeError, formencode.Invalid) as e:
94 transaction.rollback()
95 error_msg = "Error as inn '{0}': {1}".format(inn_page.page_title, str(e))
96 raise UpdateCacheError(error_msg, inn_page.page_title, e)
100 def update_wrreportcache(connection, page_id=None):
101 """Updates the wrreportcache table.
102 :param connection: sqlalchemy connection
103 :param page_id: Updates only the reportcache table for the sledrun described on the Winterrodeln wiki page
104 with the specified page_id. Use None for this parameter to update the whole table.
106 >>> from sqlalchemy.engine import create_engine
107 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
108 >>> update_wrreportcache(engine.connect())
110 metadata = schema.MetaData()
111 wrreport = wrmwdb.wrreport_table(metadata)
112 wrreportcache = wrmwdb.wrreportcache_table(metadata)
113 transaction = connection.begin()
115 # Delete the datasets we are going to update
116 sql_del = wrreportcache.delete()
117 if not page_id is None: sql_del = sql_del.where(wrreportcache.c.page_id == page_id)
118 connection.execute(sql_del)
120 def insert_row(connection, rowlist):
121 if len(rowlist) == 0: return
123 row = dict(rowlist[0])
124 connection.execute(wrreportcache.insert(values=row))
126 # Select the rows to update
127 sql = 'select page_id, page_title, wrreport.id as report_id, date_report, `condition`, description, author_name, if(author_userid is null, null, author_username) as author_username from wrreport where {0}`condition` is not null and date_invalid > now() and delete_date is null order by page_id, date_report desc, date_entry desc'.format('' if page_id is None else 'page_id={0} and '.format(page_id))
128 cursor = connection.execute(sql)
132 if row.page_id != page_id:
133 insert_row(connection, rowlist)
134 page_id = row.page_id
137 insert_row(connection, rowlist)
141 def update_wrmapcache(connection):
142 """Updates the wrmappointcache and wrmappathcache tables from the wiki. If convert errors occur, an UpdateCacheError exception
143 is raised. No other exception type should be raised under normal circumstances.
145 >>> from sqlalchemy.engine import create_engine
146 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
147 >>> # or: engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1&passwd=XXXXX')
148 >>> update_wrmapcache(engine.connect())
150 metadata = schema.MetaData()
151 page = mwdb.page_table(metadata)
152 categorylinks = mwdb.categorylinks_table(metadata)
153 revision = mwdb.revision_table(metadata)
154 text = mwdb.text_table(metadata)
156 transaction = connection.begin()
159 q = select([page, categorylinks, revision, text], (page.c.page_latest==revision.c.rev_id) & (text.c.old_id==revision.c.rev_text_id) & (categorylinks.c.cl_from==page.c.page_id) & (categorylinks.c.cl_to=='Rodelbahn'))
160 sledrun_pages = connection.execute(q)
162 # sql = u"select page_id, rev_id, old_id, page_title, old_text, 'In_Arbeit' in (select cl_to from categorylinks where cl_from=page_id) as under_construction from page, revision, text, categorylinks where page_latest=rev_id and old_id=rev_text_id and cl_from=page_id and cl_to='Rodelbahn' order by page_title"
164 # Delete all existing entries in wrmappointcache
165 # We rely on transactions MySQL InnoDB
166 connection.execute('delete from wrmappointcache')
167 connection.execute('delete from wrmappathcache')
169 # Refill wrmappointcache and wrmappathcache tables
170 for sledrun_page in sledrun_pages:
172 start, content, endtag, end = mwmarkup.find_tag(sledrun_page.old_text, 'wrmap')
175 geojson = wrmwmarkup.parse_wrmap(sledrun_page.old_text[start:end])
177 for feature in geojson['features']:
178 properties = feature['properties']
179 coordinates = feature['geometry']['coordinates']
182 if properties['type'] in wrmwmarkup.WRMAP_POINT_TYPES:
183 lon, lat = coordinates
184 label = properties.get('name')
185 point_types = {'gasthaus': 'hut', 'haltestelle': 'busstop', 'parkplatz': 'carpark', 'achtung': 'warning', 'foto': 'photo', 'verleih': 'rental', 'punkt': 'point'}
186 point_type = point_types[properties['type']]
187 sql = 'insert into wrmappointcache (page_id, type, point, label) values (%s, %s, POINT(%s, %s), %s)'
188 connection.execute(sql, (sledrun_page.page_id, point_type, lon, lat, label))
191 elif properties['type'] in wrmwmarkup.WRMAP_LINE_TYPES:
192 path_types = {'rodelbahn': 'sledrun', 'gehweg': 'walkup', 'alternative': 'alternative', 'lift': 'lift', 'anfahrt': 'recommendedcarroute', 'linie': 'line'}
193 path_type = path_types[properties['type']]
194 path = ", ".join(["{0} {1}".format(lon, lat) for lon, lat in coordinates])
195 path = 'LineString({0})'.format(path)
196 if path_type == 'recommendedcarroute': continue
197 sql = 'insert into wrmappathcache (path, page_id, type) values (GeomFromText(%s), %s, %s)'
198 connection.execute(sql, (path, sledrun_page.page_id, path_type))
201 raise RuntimeError('Unknown feature type {0}'.format(properties['type']))
202 except RuntimeError as e:
203 error_msg = "Error at sledrun '{0}': {1}".format(sledrun_page.page_title, str(e))
204 transaction.rollback()
205 raise UpdateCacheError(error_msg, sledrun_page.page_title, e)
209 def update_wrregioncache(connection):
210 """Updates the wrregioncache table from the wiki.
211 It relays on the table wrsledruncache to be up-to-date.
212 No exceptions should be raised under normal circumstances.
214 >>> from sqlalchemy.engine import create_engine
215 >>> engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1')
216 >>> # or: engine = create_engine('mysql://philipp@localhost:3306/philipp_winterrodeln_wiki?charset=utf8&use_unicode=1&passwd=XXXXX')
217 >>> update_wrregioncache(engine.connect())
219 metadata = schema.MetaData()
220 wrregion = wrmwdb.wrregion_table(metadata)
221 wrsledruncache = wrmwdb.wrsledruncache_table(metadata)
222 wrregioncache = wrmwdb.wrregioncache_table(metadata)
224 transaction = connection.begin()
226 # Delete all existing entries in wrregioncache
227 # We rely on transactions MySQL InnoDB
228 connection.execute(wrregioncache.delete())
230 # Query all combinations of sledruns and regions
231 sel = select([wrregion.c.id.label('region_id'), sqlfunc.AsWKB(wrregion.c.border).label('border'), wrsledruncache.c.page_id, wrsledruncache.c.position_longitude, wrsledruncache.c.position_latitude], sqlfunc.contains(wrregion.c.border, sqlfunc.point(wrsledruncache.c.position_longitude, wrsledruncache.c.position_latitude)))
232 ins = wrregioncache.insert()
234 # Refill wrregioncache
235 point = ogr.Geometry(ogr.wkbPoint)
236 result = connection.execute(sel)
238 point.SetPoint(0, row.position_longitude, row.position_latitude)
239 if point.Within(ogr.CreateGeometryFromWkb(row.border)):
240 connection.execute(ins.values(region_id=row.region_id, page_id=row.page_id))