def query_functions(stat): ret = strip_includes(resource_stream(__name__, conn.database_type + '/db_functions.py'), stat) for k, v in stat['config'].items(): if re.match('^[a-zA-Z\.\-_0-9]+$', k): ret = ret.replace('{' + k + '}', str(v)) return ret
def query_functions(stat): ret = strip_includes( resource_stream(__name__, conn.database_type + '/db_functions.py'), stat) for k, v in stat['config'].items(): if re.match('^[a-zA-Z\.\-_0-9]+$', k): ret = ret.replace('{' + k + '}', str(v)) return ret
def compile_function_match(stat): scale_denominators = sorted(stat.all_scale_denominators(), reverse=True) check_functions = compile_build_result(stat) max_scale = None for min_scale in scale_denominators: check_functions += compile_function_check([ v for v in stat['statements'] if v['selector']['min_scale'] <= min_scale and (v['selector']['max_scale'] == None or v['selector']['max_scale'] >= (max_scale or 10E+10)) ], min_scale, max_scale, stat) check_functions += '\n' max_scale = min_scale check_chooser = "if render_context['scale_denominator'] is None:\n" check_chooser += " check = check_0\n" for i in scale_denominators: check_chooser += "elif render_context['scale_denominator'] >= %i:\n" % i check_chooser += " check = check_%s\n" % str(i).replace('.', '_') stat['global_data'] = {} # get global data from type for prop in stat.properties(): prop_type = pgmapcss.types.get(prop, stat) d = prop_type.get_global_data() if d: stat['global_data'][prop] = d stat.clear_property_values_cache() replacement = { 'style_id': stat['id'], 'host': stat['args'].host, 'password': stat['args'].password, 'database': stat['args'].database, 'default_lang': repr(stat['lang']), 'user': stat['args'].user, 'srs': stat['config']['srs'], 'style_element_property': repr({ k: v['value'].split(';') for k, v in stat['defines']['style_element_property'].items() }), 'all_style_elements': repr({ k for k, v in stat['defines']['style_element_property'].items() }), 'scale_denominators': repr(scale_denominators), 'db_selects': compile_db_selects(stat['id'], stat), 'db_query': db.query_functions(stat), 'function_check': check_functions, 'check_chooser': check_chooser, 'eval_functions': \ resource_string(pgmapcss.eval.__name__, 'base.py').decode('utf-8') +\ pgmapcss.eval.functions().print(indent='') +\ include_text(), } replacement['fake_plpy'] = strip_includes(resource_stream(pgmapcss.misc.__name__, 'fake_plpy.py'), stat).format(**replacement) # add all config options as replacement patterns, in the form # 'config|foo|bar', were 'foo.bar' was the config option ('.' not allowed # in patterns) for k, v in stat['config'].items(): replacement['config|' + k.replace('.', '|')] = v ret = '''\ import re import math import datetime import copy '''.format(**replacement) if stat['config'].get('debug.profiler', False): ret += 'time_start = datetime.datetime.now() # profiling\n' ret += '''\ global current global render_context current = None if not 'lang' in parameters: parameters['lang'] = {default_lang} if not 'srs' in parameters: parameters['srs' ] = {srs} if type(bbox) == list and len(bbox) == 4: plan = plpy.prepare('select ST_SetSRID(ST_MakeBox2D(ST_Point($1, $2), ST_Point($3, $4)), $5) as bounds', ['float', 'float', 'float', 'float', 'int']) res = plpy.execute(plan, [float(b) for b in bbox] + [ parameters['in.srs'] if 'in.srs' in parameters else parameters['srs'] ]) _bbox = res[0]['bounds'] else: _bbox = bbox plan = plpy.prepare('select ST_Transform($1, {config|db|srs}) as bounds', ['geometry']) res = plpy.execute(plan, [_bbox]) render_context = {{ 'bbox': res[0]['bounds'], 'scale_denominator': scale_denominator }} '''.format(**replacement) if stat['config'].get('debug.context', False): ret += 'plpy.warning(render_context)\n' ret += 'global_data = ' + repr(stat['global_data']) + '\n' ret += '''\ {db_query} {eval_functions} {function_check} db_selects = None {db_selects} counter = {{ 'rendered': 0, 'total': 0 }} {check_chooser} combined_objects = {{}} all_style_elements = _all_style_elements style_element_property = {style_element_property} for style_element in all_style_elements: if not style_element in style_element_property: style_element_property[style_element] = [] '''.format(**replacement) func = "objects_bbox(render_context.get('bbox'), db_selects, {})" if stat['config'].get('debug.profiler', False): ret += "time_qry_start = datetime.datetime.now() # profiling\n" ret += "src = list(" + func + ")\n" ret += "time_qry_stop = datetime.datetime.now() # profiling\n" ret += "plpy.warning('querying db objects took %.2fs' % (time_qry_stop - time_qry_start).total_seconds())\n" else: ret += "src = " + func + "\n" ret += '''\ def ST_Collect(geometries): plan = plpy.prepare('select ST_Collect($1) as r', ['geometry[]']) res = plpy.execute(plan, [geometries]) return res[0]['r'] def convert_srs(geom): plan = plpy.prepare('select ST_Transform($1, $2) as r', ['geometry', 'integer']) res = plpy.execute(plan, [geom, parameters['srs']]) return res[0]['r'] def dict_merge(dicts): ret = {{}} for d in dicts: for k, v in d.items(): if k not in ret: ret[k] = set() ret[k].add(v) for k, vs in ret.items(): ret[k] = ';'.join(vs) return ret while src: for object in src: shown = False counter['total'] += 1 orig_geo_src = object['geo'] orig_geo_out = convert_srs(object['geo']) for result in check(object): if type(result) != tuple or len(result) == 0: plpy.warning('unknown check result: ', result) elif result[0] == 'result': result = result[1] # create a list of all style elements where the current # object/pseudo_element is being shown, with a tuple of # [ ( style_element, index in style_element list, layer, # z-index ), ... ], e.g.: # [ # ( 'line', 2, 0, 5 ), # ( 'line-text', 5, 103, 5 ) # ] style_elements = [ ( style_element, i, to_float(result['properties'][style_element + '-layer'] if style_element + '-layer' in result['properties'] else (result['properties']['layer'] if 'layer' in result['properties'] else 0)), to_float(result['properties'][style_element + '-z-index'] if style_element + '-z-index' in result['properties'] else (result['properties']['z-index'] if 'z-index' in result['properties'] else 0)) ) for i, style_element in enumerate(_all_style_elements) if len({{ k for k in style_element_property[style_element] if k in result['properties'] and result['properties'][k] }}) ] # TODO: maybe not "continue", but better indent yield instead if len(style_elements) == 0: continue shown = True '''.format(**replacement) # now build the return columns if stat['mode'] == 'database-function': ret += ''' yield {{ 'id': result['id'], 'types': result['types'], 'tags': pghstore.dumps(result['tags']), 'pseudo_element': result['pseudo_element'], 'geo': orig_geo_out if result['geo'] == orig_geo_src else convert_srs(result['geo']), 'properties': pghstore.dumps(result['properties']), 'style_elements': [ se[0] for se in style_elements ], 'style_elements_index': [ se[1] for se in style_elements ], 'style_elements_layer': [ se[2] for se in style_elements ], 'style_elements_z_index': [ se[3] for se in style_elements ], }} '''.format(**replacement) elif stat['mode'] == 'standalone': ret += ''' object['geo'] = orig_geo_out yield {{ 'id': result['id'], 'types': result['types'], 'tags': result['tags'], 'pseudo_element': result['pseudo_element'], 'geo': orig_geo_out if result['geo'] == orig_geo_src else convert_srs(result['geo']), 'properties': result['properties'], 'style_elements': [ se[0] for se in style_elements ], 'style_elements_index': [ se[1] for se in style_elements ], 'style_elements_layer': [ se[2] for se in style_elements ], 'style_elements_z_index': [ se[3] for se in style_elements ], 'object': object, }} '''.format(**replacement) ret += ''' elif result[0] == 'combine': shown = True if result[1] not in combined_objects: combined_objects[result[1]] = {{}} if result[2] not in combined_objects[result[1]]: combined_objects[result[1]][result[2]] = [] combined_objects[result[1]][result[2]].append(result[3]) else: plpy.warning('unknown check result: ', result) if shown: counter['rendered'] += 1 '''.format(**replacement) if stat['config'].get('debug.counter', False) == 'verbose': ret += ''' else: plpy.warning('not rendered: ' + object['id'] + ' ' + repr(object['tags'])) '''.format(**replacement) ret += ''' src = None if len(combined_objects): src = [] for combine_type, items in combined_objects.items(): for combine_id, obs in items.items(): src.append({{ 'id': ';'.join([ ob['id'] for ob in obs ]), 'types': [ combine_type ], 'tags': dict_merge([ ob['tags'] for ob in obs ]), 'geo': ST_Collect([ ob['geo'] for ob in obs ]) }}) combined_objects = [] '''.format(**replacement) if stat['config'].get('debug.profiler', False): ret += ''' time_stop = datetime.datetime.now() # profiling plpy.warning('total run of processing (incl. querying db objects) took %.2fs' % (time_stop - time_start).total_seconds()) '''.format(**replacement) if stat['config'].get('debug.counter', False): ret += ''' if counter['total'] == 0: counter['perc'] = 100.0 else: counter['perc'] = counter['rendered'] / counter['total'] * 100.0 plpy.warning('rendered map features: {{rendered}} / {{total}}, {{perc:.2f}}%'.format(**counter)) '''.format(**replacement) if stat['config'].get('debug.rusage', False): ret += ''' import resource plpy.warning('Resource Usage: ' + str(resource.getrusage(resource.RUSAGE_SELF)) + '\\nsee https://docs.python.org/3/library/resource.html') '''.format(**replacement) indent = '' if stat['mode'] == 'standalone': indent = ' ' header = strip_includes(resource_stream(pgmapcss.mode.__name__, stat['mode'] + '/header.inc'), stat) header = header.format(**replacement) footer = strip_includes(resource_stream(pgmapcss.mode.__name__, stat['mode'] + '/footer.inc'), stat) footer = footer.format(**replacement) ret = header + indent + ret.replace('\n', '\n' + indent) + '\n' + footer return ret