diff options
author | Jochen Topf <jochen@topf.org> | 2013-01-06 13:27:23 +0100 |
---|---|---|
committer | Jochen Topf <jochen@topf.org> | 2013-01-06 13:27:23 +0100 |
commit | 3dc24ee78f73094f44ed89a044c85d7c4338ff97 (patch) | |
tree | 4b276413beef950e549c22c54ba25680ae1b5a45 | |
parent | 94cf8b600b3b59e3bad066b6a4b7bf010007e84e (diff) | |
download | taginfo-3dc24ee78f73094f44ed89a044c85d7c4338ff97.tar taginfo-3dc24ee78f73094f44ed89a044c85d7c4338ff97.tar.gz |
Moved many API calls over to new version 4.
Old versions are marked as deprecated. All new API calls are documented.
-rwxr-xr-x | examples/tapi | 4 | ||||
-rw-r--r-- | web/lib/api/db.rb | 10 | ||||
-rw-r--r-- | web/lib/api/key.rb | 260 | ||||
-rw-r--r-- | web/lib/api/keys.rb | 183 | ||||
-rw-r--r-- | web/lib/api/tag.rb | 159 | ||||
-rw-r--r-- | web/lib/api/tags.rb | 61 | ||||
-rw-r--r-- | web/lib/api/wiki.rb | 19 | ||||
-rw-r--r-- | web/lib/utils.rb | 20 | ||||
-rwxr-xr-x | web/taginfo.rb | 4 | ||||
-rw-r--r-- | web/views/taginfo/apidoc.erb | 4 | ||||
-rw-r--r-- | web/viewsjs/key.js.erb | 10 | ||||
-rw-r--r-- | web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb | 2 | ||||
-rw-r--r-- | web/viewsjs/tag.js.erb | 8 |
13 files changed, 711 insertions, 33 deletions
diff --git a/examples/tapi b/examples/tapi index cb37c03..4495a73 100755 --- a/examples/tapi +++ b/examples/tapi @@ -12,7 +12,7 @@ # You can set the following environment variables (default in brackets): # TAGINFO_API_SERVER [taginfo.openstreetmap.org] # TAGINFO_API_PORT [80] -# TAGINFO_API_VERSION [2] +# TAGINFO_API_VERSION [4] # require 'rubygems' @@ -23,7 +23,7 @@ require 'json' API_SERVER = ENV['TAGINFO_API_SERVER'] || 'taginfo.openstreetmap.org' API_PORT = ENV['TAGINFO_API_PORT'] || 80 -API_VERSION = ENV['TAGINFO_API_VERSION'] || '2' +API_VERSION = ENV['TAGINFO_API_VERSION'] || '4' def api_call(path, params) query = [] diff --git a/web/lib/api/db.rb b/web/lib/api/db.rb index 9c2f5e5..c5bfe01 100644 --- a/web/lib/api/db.rb +++ b/web/lib/api/db.rb @@ -9,6 +9,7 @@ class Taginfo < Sinatra::Base } api(2, 'db/keys', { + :superseded_by => '4/keys/all', :description => 'Get list of keys that are in the database or mentioned in any other source.', :parameters => { :query => 'Only show keys matching this query (substring match, optional).' }, :paging => :optional, @@ -138,6 +139,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/tags', { + :superseded_by => '4/tags/popular', :description => 'Get list of most often used tags.', :parameters => { :query => 'Only show tags matching this query (substring match in key and value, optional).' }, :paging => :optional, @@ -195,6 +197,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/keys/overview', { + :superseded_by => '4/key/stats', :description => 'Show statistics for nodes, ways, relations and total for this key.', :parameters => { :key => 'Tag key (required).' }, :paging => :no, @@ -275,6 +278,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/keys/distribution', { + :superseded_by => '4/key/distribution/nodes', :description => 'Get map with distribution of this key in the database (nodes only).', :parameters => { :key => 'Tag key (required).' }, :result => 'PNG image.', @@ -293,6 +297,7 @@ class Taginfo < Sinatra::Base end api(3, 'db/keys/distribution/nodes', { + :superseded_by => '4/key/distribution/nodes', :description => 'Get map with distribution of this key in the database (nodes only).', :parameters => { :key => 'Tag key (required).' }, :result => 'PNG image.', @@ -311,6 +316,7 @@ class Taginfo < Sinatra::Base end api(3, 'db/keys/distribution/ways', { + :superseded_by => '4/key/distribution/ways', :description => 'Get map with distribution of this key in the database (ways only).', :parameters => { :key => 'Tag key (required).' }, :result => 'PNG image.', @@ -329,6 +335,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/keys/values', { + :superseded_by => '4/key/values', :description => 'Get values used with a given key.', :parameters => { :key => 'Tag key (required).', @@ -409,6 +416,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/keys/keys', { + :superseded_by => '4/key/combinations', :description => 'Find keys that are used together with a given key.', :parameters => { :key => 'Tag key (required).', @@ -511,6 +519,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/tags/overview', { + :superseded_by => '4/tag/stats', :description => 'Show statistics for nodes, ways, relations and total for this tag.', :parameters => { :key => 'Tag key (required).', @@ -590,6 +599,7 @@ class Taginfo < Sinatra::Base end api(2, 'db/tags/combinations', { + :superseded_by => '4/tag/combinations', :description => 'Find keys and tags that are used together with a given tag.', :parameters => { :key => 'Tag key (required).', diff --git a/web/lib/api/key.rb b/web/lib/api/key.rb new file mode 100644 index 0000000..bee71d8 --- /dev/null +++ b/web/lib/api/key.rb @@ -0,0 +1,260 @@ +# web/lib/api/key.rb +class Taginfo < Sinatra::Base + + api(4, 'key/stats', { + :description => 'Show some database statistics for given key.', + :parameters => { :key => 'Tag key (required).' }, + :result => { + :type => :STRING, + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :example => { :key => 'amenity' }, + :ui => '/keys/amenity#overview' + }) do + key = params[:key] + out = [] + + # default values + ['all', 'nodes', 'ways', 'relations'].each_with_index do |type, n| + out[n] = { :type => type, :count => 0, :count_fraction => 0.0, :values => 0 } + end + + @db.select('SELECT * FROM db.keys'). + condition('key = ?', key). + execute() do |row| + ['all', 'nodes', 'ways', 'relations'].each_with_index do |type, n| + out[n] = { + :type => type, + :count => row['count_' + type].to_i, + :count_fraction => (row['count_' + type].to_f / get_total(type)).round_to(4), + :values => row['values_' + type].to_i + } + end + end + + return { + :total => 4, + :data => out + }.to_json + end + + api(4, 'key/distribution/nodes', { + :description => 'Get map with distribution of this key in the database (nodes only).', + :parameters => { :key => 'Tag key (required).' }, + :result => 'PNG image.', + :example => { :key => 'amenity' }, + :ui => '/keys/amenity#map' + }) do + key = params[:key] + content_type :png + @db.select('SELECT png FROM db.key_distributions'). + condition("object_type='n'"). + condition('key = ?', key). + get_first_value() || + @db.select('SELECT png FROM db.key_distributions'). + condition('key IS NULL'). + get_first_value() + end + + api(4, 'key/distribution/ways', { + :description => 'Get map with distribution of this key in the database (ways only).', + :parameters => { :key => 'Tag key (required).' }, + :result => 'PNG image.', + :example => { :key => 'highway' }, + :ui => '/keys/highway#map' + }) do + key = params[:key] + content_type :png + @db.select('SELECT png FROM db.key_distributions'). + condition("object_type='w'"). + condition('key = ?', key). + get_first_value() || + @db.select('SELECT png FROM db.key_distributions'). + condition('key IS NULL'). + get_first_value() + end + + api(4, 'key/values', { + :description => 'Get values used with a given key.', + :parameters => { + :key => 'Tag key (required).', + :lang => "Language for description (optional, default: 'en').", + :query => 'Only show results where the value matches this query (substring match, optional).' + }, + :paging => :optional, + :filter => { + :all => { :doc => 'No filter.' }, + :nodes => { :doc => 'Only values on tags used on nodes.' }, + :ways => { :doc => 'Only values on tags used on ways.' }, + :relations => { :doc => 'Only values on tags used on relations.' } + }, + :sort => %w( value count_all count_nodes count_ways count_relations ), + :result => { + :value => :STRING, + :count => :INT, + :fraction => :FLOAT, + :description => :STRING + }, + :example => { :key => 'highway', :page => 1, :rp => 10, :sortname => 'count_ways', :sortorder => 'desc' }, + :ui => '/keys/highway#values' + }) do + key = params[:key] + lang = params[:lang] || 'en' + filter_type = get_filter() + + if @ap.sortname == 'count' + @ap.sortname = ['count_' + filter_type] + end + + (this_key_count, total) = @db.select("SELECT count_#{filter_type} AS count, values_#{filter_type} AS count_values FROM db.keys"). + condition('key = ?', key). + get_columns(:count, :count_values) + + if params[:query].to_s != '' + total = @db.count('db.tags'). + condition("count_#{filter_type} > 0"). + condition('key = ?', key). + condition_if("value LIKE '%' || ? || '%'", params[:query]). + get_first_value() + end + + res = @db.select('SELECT * FROM db.tags'). + condition("count_#{filter_type} > 0"). + condition('key = ?', key). + condition_if("value LIKE '%' || ? || '%'", params[:query]). + order_by(@ap.sortname, @ap.sortorder) { |o| + o.value + o.count_all + o.count_nodes + o.count_ways + o.count_relations + }. + paging(@ap). + execute() + + # Read description for tag from wikipages, first in English then in the chosen + # language. This way the chosen language description will overwrite the default + # English one. + wikidesc = {} + ['en', lang].uniq.each do |lang| + @db.select('SELECT value, description FROM wiki.wikipages'). + condition('lang = ?', lang). + condition('key = ?', key). + condition("value IN (#{ res.map{ |row| "'" + SQLite3::Database.quote(row['value']) + "'" }.join(',') })"). + execute().each do |row| + wikidesc[row['value']] = row['description'] + end + end + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total.to_i, + :data => res.map{ |row| { + :value => row['value'], + :count => row['count_' + filter_type].to_i, + :fraction => (row['count_' + filter_type].to_f / this_key_count.to_f).round_to(4), + :description => wikidesc[row['value']] + } } + }.to_json + end + + api(4, 'key/combinations', { + :description => 'Find keys that are used together with a given key.', + :parameters => { + :key => 'Tag key (required).', + :query => 'Only show results where the other_key matches this query (substring match, optional).' + }, + :paging => :optional, + :filter => { + :all => { :doc => 'No filter.' }, + :nodes => { :doc => 'Only values on tags used on nodes.' }, + :ways => { :doc => 'Only values on tags used on ways.' }, + :relations => { :doc => 'Only values on tags used on relations.' } + }, + :sort => %w( together_count other_key from_fraction ), + :result => { + :other_key => :STRING, + :together_count => :INT, + :to_fraction => :FLOAT, + :from_fraction => :FLOAT + }, + :example => { :key => 'highway', :page => 1, :rp => 10, :sortname => 'together_count', :sortorder => 'desc' }, + :ui => '/keys/highway#keys' + }) do + key = params[:key] + filter_type = get_filter() + + if @ap.sortname == 'to_count' + @ap.sortname = ['together_count'] + elsif @ap.sortname == 'from_count' + @ap.sortname = ['from_fraction', 'together_count', 'other_key'] + end + + cq = @db.count('db.keypairs') + total = (params[:query].to_s != '' ? cq.condition("(key1 = ? AND key2 LIKE '%' || ? || '%') OR (key2 = ? AND key1 LIKE '%' || ? || '%')", key, params[:query], key, params[:query]) : cq.condition('key1 = ? OR key2 = ?', key, key)). + condition("count_#{filter_type} > 0"). + get_first_value().to_i + + has_this_key = @db.select("SELECT count_#{filter_type} FROM db.keys"). + condition('key = ?', key). + get_first_value() + + res = (params[:query].to_s != '' ? + @db.select("SELECT p.key1 AS other_key, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.keypairs p, db.keys k WHERE p.key1=k.key AND p.key2=? AND (p.key1 LIKE '%' || ? || '%') AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.keypairs p, db.keys k WHERE p.key2=k.key AND p.key1=? AND (p.key2 LIKE '%' || ? || '%') AND p.count_#{filter_type} > 0", key, params[:query], key, params[:query]) : + @db.select("SELECT p.key1 AS other_key, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.keypairs p, db.keys k WHERE p.key1=k.key AND p.key2=? AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.keypairs p, db.keys k WHERE p.key2=k.key AND p.key1=? AND p.count_#{filter_type} > 0", key, key)). + order_by(@ap.sortname, @ap.sortorder) { |o| + o.together_count + o.other_key + o.from_fraction + }. + paging(@ap). + execute() + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total, + :data => res.map{ |row| { + :other_key => row['other_key'], + :together_count => row['together_count'].to_i, + :to_fraction => (row['together_count'].to_f / has_this_key.to_f).round_to(4), + :from_fraction => row['from_fraction'].to_f.round_to(4) + } } + }.to_json + end + + api(4, 'key/wiki_pages', { + :description => 'Get list of wiki pages in different languages describing a key.', + :parameters => { :key => 'Tag key (required)' }, + :paging => :no, + :result => { + :lang => :STRING, + :language => :STRING, + :language_en => :STRING, + :title => :STRING, + :description => :STRING, + :image => :STRING, + :on_node => :BOOL, + :on_way => :BOOL, + :on_area => :BOOL, + :on_relation => :BOOL, + :tags_implies => :ARRAY_OF_STRINGS, + :tags_combination => :ARRAY_OF_STRINGS, + :tags_linked => :ARRAY_OF_STRINGS + }, + :example => { :key => 'highway' }, + :ui => '/keys/highway#wiki' + }) do + key = params[:key] + + res = @db.execute('SELECT * FROM wikipages WHERE value IS NULL AND key = ? ORDER BY lang', key) + + return get_wiki_result(res) + end + +end diff --git a/web/lib/api/keys.rb b/web/lib/api/keys.rb new file mode 100644 index 0000000..13f1ea1 --- /dev/null +++ b/web/lib/api/keys.rb @@ -0,0 +1,183 @@ +# web/lib/api/keys.rb +class Taginfo < Sinatra::Base + + @@filters = { + :characters_space => { :expr => "characters='space'", :doc => 'Only show keys with spaces.' }, + :characters_problematic => { :expr => "characters='problem'", :doc => 'Only show keys with problematic characters.' }, + :in_wiki => { :expr => "in_wiki=1", :doc => 'Only show keys that appear in the wiki.' }, + :not_in_db => { :expr => "count_all=0", :doc => 'Only show keys that do not appear in the database.' } + } + + api(4, 'keys/all', { + :description => 'Get list of all keys.', + :parameters => { :query => 'Only show keys matching this query (substring match, optional).' }, + :paging => :optional, + :filter => @@filters, + :sort => %w( key count_all count_nodes count_ways count_relations values_all users_all in_wiki in_josm in_potlatch length ), + :result => { + :key => :STRING, + :count_all => :INT, + :count_all_fraction => :FLOAT, + :count_nodes => :INT, + :count_nodes_fraction => :FLOAT, + :count_ways => :INT, + :count_ways_fraction => :FLOAT, + :count_relations => :INT, + :count_relations_fraction => :FLOAT, + :values_all => :INT, + :users_all => :INT, + :in_wiki => :BOOL, + :in_josm => :BOOL, + :in_potlatch => :BOOL + }, + :example => { :page => 1, :rp => 10, :filter => 'in_wiki', :sortname => 'key', :sortorder => 'asc' }, + :ui => '/keys' + }) do + + if params[:filters] + filters = params[:filters].split(',').map{ |f| @@filters[f.to_sym][:expr] }.compact + else + filters = [] + end + + include_data = Hash.new + if params[:include] + params[:include].split(',').each{ |inc| include_data[inc.to_sym] = 1 } + end + + total = @db.count('db.keys'). + condition_if("key LIKE '%' || ? || '%'", params[:query]). + conditions(filters). + get_first_value().to_i + + res = @db.select('SELECT * FROM db.keys'). + condition_if("key LIKE '%' || ? || '%'", params[:query]). + conditions(filters). + order_by(@ap.sortname, @ap.sortorder) { |o| + o.key + o.count_all + o.count_nodes + o.count_ways + o.count_relations + o.values_all + o.users_all + o.in_wiki + o.in_josm + o.in_potlatch + o.length 'length(key)' + o.length :key + }. + paging(@ap). + execute() + + if include_data[:wikipages] + reshash = Hash.new + res.each do |row| + reshash[row['key']] = row + row['wikipages'] = Array.new + end + + wikipages = @db.select('SELECT key, lang, title, type FROM wiki.wikipages'). + condition("value IS NULL"). + condition("key IN (#{ res.map{ |row| "'" + SQLite3::Database.quote(row['key']) + "'" }.join(',') })"). + order_by([:key, :lang], 'ASC'). + execute() + + wikipages.each do |wp| + key = wp['key'] + wp.delete_if{ |k,v| k.is_a?(Integer) || k == 'key' } + reshash[key]['wikipages'] << wp + end + end + + if include_data[:prevalent_values] + reshash = Hash.new + res.each do |row| + reshash[row['key']] = row + row['prevalent_values'] = Array.new + end + + prevvalues = @db.select('SELECT key, value, count, fraction FROM db.prevalent_values'). + condition("key IN (#{ res.map{ |row| "'" + SQLite3::Database.quote(row['key']) + "'" }.join(',') })"). + order_by([:count], 'DESC'). + execute() + + prevvalues.each do |pv| + key = pv['key'] + pv.delete_if{ |k,v| k.is_a?(Integer) || k == 'key' } + pv['count'] = pv['count'].to_i + pv['fraction'] = pv['fraction'].to_f + reshash[key]['prevalent_values'] << pv + end + end + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total, + :data => res.map{ |row| h = { + :key => row['key'], + :count_all => row['count_all'].to_i, + :count_all_fraction => (row['count_all'].to_f / @db.stats('objects')).round_to(4), + :count_nodes => row['count_nodes'].to_i, + :count_nodes_fraction => (row['count_nodes'].to_f / @db.stats('nodes_with_tags')).round_to(4), + :count_ways => row['count_ways'].to_i, + :count_ways_fraction => (row['count_ways'].to_f / @db.stats('ways')).round_to(4), + :count_relations => row['count_relations'].to_i, + :count_relations_fraction => (row['count_relations'].to_f / @db.stats('relations')).round_to(4), + :values_all => row['values_all'].to_i, + :users_all => row['users_all'].to_i, + :in_wiki => row['in_wiki'].to_i == 1 ? true : false, + :in_josm => row['in_josm'].to_i == 1 ? true : false, + :in_potlatch => row['in_potlatch'].to_i == 1 ? true : false, + } + h[:wikipages] = row['wikipages'] if row['wikipages'] + h[:prevalent_values] = row['prevalent_values'][0,10] if row['prevalent_values'] + h } + }.to_json + end + + api(4, 'keys/wiki_pages', { + :description => 'Get list of wiki pages in different languages for all keys.', + :parameters => { :query => 'Only show keys matching this query (substring match, optional).' }, + :paging => :optional, + :sort => %w( key ), + :result => { + :key => :STRING, + :lang => "Hash with language codes as keys and values showing what type of wiki page is available" + }, + :example => { :page => 1, :rp => 10, :sortname => 'key', :sortorder => 'asc' }, + :ui => '/reports/language_comparison_table_for_keys_in_the_wiki' + }) do + languages = @db.execute('SELECT language FROM wiki.wiki_languages ORDER by language').map do |row| + row['language'] + end + + total = @db.count('wiki.wikipages_keys'). + condition_if("key LIKE '%' || ? || '%'", params[:query]). + get_first_value().to_i + + res = @db.select('SELECT key, langs FROM wiki.wikipages_keys'). + condition_if("key LIKE '%' || ? || '%'", params[:query]). + order_by(@ap.sortname, @ap.sortorder){ |o| + o.key + }. + paging(@ap). + execute() + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total, + :data => res.map{ |row| + lang_hash = Hash.new + row['langs'].split(',').each{ |l| + (lang, status) = l.split(' ', 2) + lang_hash[lang] = status + } + { :key => row['key'], :lang => lang_hash } + } + }.to_json + end + +end diff --git a/web/lib/api/tag.rb b/web/lib/api/tag.rb new file mode 100644 index 0000000..a4088c1 --- /dev/null +++ b/web/lib/api/tag.rb @@ -0,0 +1,159 @@ +# web/lib/api/tag.rb +class Taginfo < Sinatra::Base + + api(4, 'tag/stats', { + :description => 'Show some database statistics for given tag.', + :parameters => { + :key => 'Tag key (required).', + :value => 'Tag value (required).' + }, + :result => { + :type => :STRING, + :count => :INT, + :count_fraction => :FLOAT, + :values => :INT + }, + :example => { :key => 'amenity', :value => 'school' }, + :ui => '/tags/amenity=school#overview' + }) do + key = params[:key] + value = params[:value] + out = [] + + # default values + ['all', 'nodes', 'ways', 'relations'].each_with_index do |type, n| + out[n] = { :type => type, :count => 0, :count_fraction => 0.0 } + end + + @db.select('SELECT * FROM db.tags'). + condition('key = ?', key). + condition('value = ?', value). + execute() do |row| + ['all', 'nodes', 'ways', 'relations'].each_with_index do |type, n| + out[n] = { + :type => type, + :count => row['count_' + type].to_i, + :count_fraction => (row['count_' + type].to_f / get_total(type)).round_to(4) + } + end + end + + return { + :total => 4, + :data => out + }.to_json + end + + api(4, 'tag/combinations', { + :description => 'Find keys and tags that are used together with a given tag.', + :parameters => { + :key => 'Tag key (required).', + :value => 'Tag value (required).', + :query => 'Only show results where the other_key or other_value matches this query (substring match, optional).' + }, + :paging => :optional, + :filter => { + :all => { :doc => 'No filter.' }, + :nodes => { :doc => 'Only values on tags used on nodes.' }, + :ways => { :doc => 'Only values on tags used on ways.' }, + :relations => { :doc => 'Only values on tags used on relations.' } + }, + :sort => %w( together_count other_tag from_fraction ), + :result => { + :other_key => :STRING, + :other_value => :STRING, + :together_count => :INT, + :to_fraction => :FLOAT, + :from_fraction => :FLOAT + }, + :example => { :key => 'highway', :value => 'residential', :page => 1, :rp => 10, :sortname => 'together_count', :sortorder => 'desc' }, + :ui => '/tags/highway=residential#combinations' + }) do + key = params[:key] + value = params[:value] + filter_type = get_filter() + + if @ap.sortname == 'to_count' + @ap.sortname = ['together_count'] + elsif @ap.sortname == 'from_count' + @ap.sortname = ['from_fraction', 'together_count', 'other_key', 'other_value'] + elsif @ap.sortname == 'other_tag' + @ap.sortname = ['other_key', 'other_value'] + end + + cq = @db.count('db.tagpairs') + total = (params[:query].to_s != '' ? + cq.condition("(key1=? AND value1=? AND (key2 LIKE '%' || ? || '%' OR value2 LIKE '%' || ? || '%')) OR (key2=? AND value2=? AND (key1 LIKE '%' || ? || '%' OR value2 LIKE '%' || ? || '%'))", + key, value, params[:query], params[:query], key, value, params[:query], params[:query]) : + cq.condition('(key1=? AND value1=?) OR (key2=? AND value2=?)', key, value, key, value)). + condition("count_#{filter_type} > 0"). + get_first_value().to_i + + has_this_key = @db.select("SELECT count_#{filter_type} FROM db.tags"). + condition('key = ?', key). + condition('value = ?', value). + get_first_value() + + res = (params[:query].to_s != '' ? + @db.select("SELECT p.key1 AS other_key, p.value1 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.selected_tags k WHERE p.key1=k.skey AND p.value1=k.svalue AND k.svalue != '' AND p.key2=? AND p.value2=? AND ((p.key1 LIKE '%' || ? || '%') OR (p.value1 LIKE '%' || ? || '%')) AND p.count_#{filter_type} > 0 + UNION SELECT p.key1 AS other_key, p.value1 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.keys k WHERE p.key1=k.key AND p.value1='' AND p.key2=? AND p.value2=? AND ((p.key1 LIKE '%' || ? || '%') OR (p.value1 LIKE '%' || ? || '%')) AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, p.value2 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.selected_tags k WHERE p.key2=k.skey AND p.value2=k.svalue AND k.svalue != '' AND p.key1=? AND p.value1=? AND ((p.key2 LIKE '%' || ? || '%') OR (p.value2 LIKE '%' || ? || '%')) AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, p.value2 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.keys k WHERE p.key2=k.key AND p.value2='' AND p.key1=? AND p.value1=? AND ((p.key2 LIKE '%' || ? || '%') OR (p.value2 LIKE '%' || ? || '%')) AND p.count_#{filter_type} > 0", key, value, params[:query], params[:query], key, value, params[:query], params[:query], key, value, params[:query], params[:query], key, value, params[:query], params[:query]) : + @db.select("SELECT p.key1 AS other_key, p.value1 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.selected_tags k WHERE p.key1=k.skey AND p.value1=k.svalue AND k.svalue != '' AND p.key2=? AND p.value2=? AND p.count_#{filter_type} > 0 + UNION SELECT p.key1 AS other_key, '' AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.keys k WHERE p.key1=k.key AND p.value1 = '' AND p.key2=? AND p.value2=? AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, p.value2 AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.selected_tags k WHERE p.key2=k.skey AND p.value2=k.svalue AND k.svalue != '' AND p.key1=? AND p.value1=? AND p.count_#{filter_type} > 0 + UNION SELECT p.key2 AS other_key, '' AS other_value, p.count_#{filter_type} AS together_count, k.count_#{filter_type} AS other_count, CAST(p.count_#{filter_type} AS REAL) / k.count_#{filter_type} AS from_fraction FROM db.tagpairs p, db.keys k WHERE p.key2=k.key AND p.value2 = '' AND p.key1=? AND p.value1=? AND p.count_#{filter_type} > 0", key, value, key, value, key, value, key, value)). + order_by(@ap.sortname, @ap.sortorder) { |o| + o.together_count + o.other_key + o.other_value + o.from_fraction + }. + paging(@ap). + execute() + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total, + :data => res.map{ |row| { + :other_key => row['other_key'], + :other_value => row['other_value'], + :together_count => row['together_count'].to_i, + :to_fraction => (row['together_count'].to_f / has_this_key.to_f).round_to(4), + :from_fraction => row['from_fraction'].to_f.round_to(4) + } } + }.to_json + end + + api(4, 'tag/wiki_pages', { + :description => 'Get list of wiki pages in different languages describing a tag.', + :parameters => { :key => 'Tag key (required)', :value => 'Tag value (required).' }, + :paging => :no, + :result => { + :lang => :STRING, + :language => :STRING, + :language_en => :STRING, + :title => :STRING, + :description => :STRING, + :image => :STRING, + :on_node => :BOOL, + :on_way => :BOOL, + :on_area => :BOOL, + :on_relation => :BOOL, + :tags_implies => :ARRAY_OF_STRINGS, + :tags_combination => :ARRAY_OF_STRINGS, + :tags_linked => :ARRAY_OF_STRINGS + }, + :example => { :key => 'highway', :value => 'residential' }, + :ui => '/tags/highway=residential#wiki' + }) do + key = params[:key] + value = params[:value] + + res = @db.execute('SELECT * FROM wikipages WHERE key = ? AND value = ? ORDER BY lang', key, value) + + return get_wiki_result(res) + end + +end diff --git a/web/lib/api/tags.rb b/web/lib/api/tags.rb new file mode 100644 index 0000000..f9b2432 --- /dev/null +++ b/web/lib/api/tags.rb @@ -0,0 +1,61 @@ +# web/lib/api/tags.rb +class Taginfo < Sinatra::Base + + api(4, 'tags/popular', { + :description => 'Get list of most often used tags.', + :parameters => { :query => 'Only show tags matching this query (substring match in key and value, optional).' }, + :paging => :optional, + :sort => %w( tag count_all count_nodes count_ways count_relations ), + :result => { + :key => :STRING, + :value => :STRING, + :count_all => :INT, + :count_all_fraction => :FLOAT, + :count_nodes => :INT, + :count_nodes_fraction => :FLOAT, + :count_ways => :INT, + :count_ways_fraction => :FLOAT, + :count_relations => :INT, + :count_relations_fraction => :FLOAT, + }, + :example => { :page => 1, :rp => 10, :sortname => 'tag', :sortorder => 'asc' }, + :ui => '/tags' + }) do + + total = @db.count('db.selected_tags'). + condition_if("(skey LIKE '%' || ? || '%') OR (svalue LIKE '%' || ? || '%')", params[:query], params[:query]). + get_first_value().to_i + + res = @db.select('SELECT * FROM db.selected_tags'). + condition_if("(skey LIKE '%' || ? || '%') OR (svalue LIKE '%' || ? || '%')", params[:query], params[:query]). + order_by(@ap.sortname, @ap.sortorder) { |o| + o.tag :skey + o.tag :svalue + o.count_all + o.count_nodes + o.count_ways + o.count_relations + }. + paging(@ap). + execute() + + return { + :page => @ap.page, + :rp => @ap.results_per_page, + :total => total, + :data => res.map{ |row| { + :key => row['skey'], + :value => row['svalue'], + :count_all => row['count_all'].to_i, + :count_all_fraction => (row['count_all'].to_f / @db.stats('objects')).round_to(4), + :count_nodes => row['count_nodes'].to_i, + :count_nodes_fraction => (row['count_nodes'].to_f / @db.stats('nodes_with_tags')).round_to(4), + :count_ways => row['count_ways'].to_i, + :count_ways_fraction => (row['count_ways'].to_f / @db.stats('ways')).round_to(4), + :count_relations => row['count_relations'].to_i, + :count_relations_fraction => (row['count_relations'].to_f / @db.stats('relations')).round_to(4), + } } + }.to_json + end + +end diff --git a/web/lib/api/wiki.rb b/web/lib/api/wiki.rb index 350147a..6245139 100644 --- a/web/lib/api/wiki.rb +++ b/web/lib/api/wiki.rb @@ -1,25 +1,6 @@ # web/lib/api/wiki.rb class Taginfo < Sinatra::Base - def get_wiki_result(res) - return res.map{ |row| { - :lang => h(row['lang']), - :language => h(::Language[row['lang']].native_name), - :language_en => h(::Language[row['lang']].english_name), - :title => h(row['title']), - :description => h(row['description']), - :image => h(row['image']), - :on_node => row['on_node'].to_i == 1 ? true : false, - :on_way => row['on_way'].to_i == 1 ? true : false, - :on_area => row['on_area'].to_i == 1 ? true : false, - :on_relation => row['on_relation'].to_i == 1 ? true : false, - :tags_implies => row['tags_implies' ].split(','), - :tags_combination => row['tags_combination'].split(','), - :tags_linked => row['tags_linked' ].split(',') - } - }.to_json - end - api(2, 'wiki/keys') do key = params[:key] diff --git a/web/lib/utils.rb b/web/lib/utils.rb index 56a5934..c30ff04 100644 --- a/web/lib/utils.rb +++ b/web/lib/utils.rb @@ -176,3 +176,23 @@ def api(version, path, doc=nil, &block) get("/api/#{version}/#{path}", &block) end +# Used in wiki api calls +def get_wiki_result(res) + return res.map{ |row| { + :lang => h(row['lang']), + :language => h(::Language[row['lang']].native_name), + :language_en => h(::Language[row['lang']].english_name), + :title => h(row['title']), + :description => h(row['description']), + :image => h(row['image']), + :on_node => row['on_node'].to_i == 1, + :on_way => row['on_way'].to_i == 1, + :on_area => row['on_area'].to_i == 1, + :on_relation => row['on_relation'].to_i == 1, + :tags_implies => row['tags_implies' ].split(','), + :tags_combination => row['tags_combination'].split(','), + :tags_linked => row['tags_linked' ].split(',') + } + }.to_json +end + diff --git a/web/taginfo.rb b/web/taginfo.rb index 13bcc2f..b0216d2 100755 --- a/web/taginfo.rb +++ b/web/taginfo.rb @@ -196,6 +196,10 @@ class Taginfo < Sinatra::Base # current API (version 4) load 'lib/api/site.rb' + load 'lib/api/key.rb' + load 'lib/api/keys.rb' + load 'lib/api/tag.rb' + load 'lib/api/tags.rb' load 'lib/ui/embed.rb' load 'lib/ui/keys_tags.rb' diff --git a/web/views/taginfo/apidoc.erb b/web/views/taginfo/apidoc.erb index 864dacc..4988d0d 100644 --- a/web/views/taginfo/apidoc.erb +++ b/web/views/taginfo/apidoc.erb @@ -4,14 +4,14 @@ <% if params[:show_deprecated] %> <p><span class="button"><a href="/taginfo/apidoc">Do not show deprecated API calls</a></span></p> +<p style="color: red;">Not all of the older, deprecated API calls are documented!</p> + <% else %> <p><span class="button"><a href="/taginfo/apidoc?show_deprecated=true">Also show deprecated API calls</a></span></p> <% end %> <h2>Table of Contents</h2> -<p style="color: red;">This list of API calls and their descriptions are not complete!</p> - <ul> <% API.paths.keys.sort.each do |version| API.paths[version].keys.sort.each do |path| diff --git a/web/viewsjs/key.js.erb b/web/viewsjs/key.js.erb index 5946cd6..744dde7 100644 --- a/web/viewsjs/key.js.erb +++ b/web/viewsjs/key.js.erb @@ -6,7 +6,7 @@ var create_flexigrid_for = { overview: function(key, filter_type) { create_flexigrid('grid-overview', { - url: '/api/3/db/keys/overview?key=' + encodeURIComponent(key), + url: '/api/4/key/stats?key=' + encodeURIComponent(key), colModel: [ { display: '<%= misc.object_type %>', name: 'type', width: 100, sortable: true }, { display: '<%= page.number_objects %>', name: 'count', width: 260, sortable: true, align: 'center' }, @@ -18,7 +18,7 @@ var create_flexigrid_for = { return { total: 4, page: 1, - rows: jQuery.map(data, function(row, i) { + rows: jQuery.map(data.data, function(row, i) { return { 'cell': [ print_image(row.type) + ' ' + texts.osm[row.type], print_value_with_percent(row.count, row.count_fraction), @@ -31,7 +31,7 @@ var create_flexigrid_for = { }, values: function(key, filter_type, lang) { create_flexigrid('grid-values', { - url: '/api/2/db/keys/values?key=' + encodeURIComponent(key) + '&filter=' + encodeURIComponent(filter_type) + '&lang=' + encodeURIComponent(lang), + url: '/api/4/key/values?key=' + encodeURIComponent(key) + '&filter=' + encodeURIComponent(filter_type) + '&lang=' + encodeURIComponent(lang), colModel: [ { display: '<%= osm.value %>', name: 'value', width: 200, sortable: true }, { display: '<%= misc.count %>', name: 'count', width: 240, sortable: true, align: 'center' }, @@ -57,7 +57,7 @@ var create_flexigrid_for = { }, combinations: function(key, filter_type) { create_flexigrid('grid-keys', { - url: '/api/2/db/keys/keys?key=' + encodeURIComponent(key) + '&filter=' + encodeURIComponent(filter_type), + url: '/api/4/key/combinations?key=' + encodeURIComponent(key) + '&filter=' + encodeURIComponent(filter_type), colModel: [ { display: '<span title="<%= page.other_keys_used.to_count_tooltip %>"><%= misc.count %> →</span>', name: 'to_count', width: 320, sortable: true, align: 'center' }, { display: '<span title="<%= page.other_keys_used.other_key_tooltip %>"><%= page.other_keys_used.other %></span>', name: 'other_key', width: 340, sortable: true }, @@ -82,7 +82,7 @@ var create_flexigrid_for = { }, wiki: function(key, filter_type) { create_flexigrid('grid-wiki', { - url: '/api/2/wiki/keys?key=' + encodeURIComponent(key), + url: '/api/4/key/wiki_pages?key=' + encodeURIComponent(key), colModel: [ { display: '<%= misc.language %>', name: 'lang', width: 150, sortable: false }, { display: '<%= page.wiki_pages.wiki_page %>', name: 'title', width: 160, sortable: false, align: 'right' }, diff --git a/web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb b/web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb index 1ae7e5e..f4f99cd 100644 --- a/web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb +++ b/web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb @@ -18,7 +18,7 @@ function page_init() { var rp = calculate_flexigrid_rp(jQuery('div.box')) - 1; current_grid = 'grid-keys'; grids[current_grid] = jQuery('#grid-keys').flexigrid({ - url: '/api/2/wiki/keys', + url: '/api/4/keys/wiki_pages', method: 'GET', dataType: 'json', colModel: [ diff --git a/web/viewsjs/tag.js.erb b/web/viewsjs/tag.js.erb index 8071944..e0fb9f8 100644 --- a/web/viewsjs/tag.js.erb +++ b/web/viewsjs/tag.js.erb @@ -6,7 +6,7 @@ var create_flexigrid_for = { overview: function(key, value, filter_type) { create_flexigrid('grid-overview', { - url: '/api/3/db/tags/overview?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value), + url: '/api/4/tag/stats?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value), colModel: [ { display: '<%= misc.object_type %>', name: 'type', width: 100, sortable: true }, { display: '<%= page.number_objects %>', name: 'count', width: 260, sortable: true, align: 'center' } @@ -17,7 +17,7 @@ var create_flexigrid_for = { return { total: 4, page: 1, - rows: jQuery.map(data, function(row, i) { + rows: jQuery.map(data.data, function(row, i) { return { 'cell': [ print_image(row.type) + ' ' + texts.osm[row.type], print_value_with_percent(row.count, row.count_fraction) @@ -29,7 +29,7 @@ var create_flexigrid_for = { }, combinations: function(key, value, filter_type) { create_flexigrid('grid-combinations', { - url: '/api/2/db/tags/combinations?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value) + '&filter=' + encodeURIComponent(filter_type), + url: '/api/4/tag/combinations?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value) + '&filter=' + encodeURIComponent(filter_type), colModel: [ { display: '<span title="<%= page.other_tags_used.to_count_tooltip %>"><%= misc.count %> →</span>', name: 'to_count', width: 320, sortable: true, align: 'center' }, { display: '<span title="<%= page.other_tags_used.other_key_tooltip %>"><%= page.other_tags_used.other %></span>', name: 'other_tag', width: 340, sortable: true }, @@ -55,7 +55,7 @@ var create_flexigrid_for = { }, wiki: function(key, value) { create_flexigrid('grid-wiki', { - url: '/api/2/wiki/tags?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value), + url: '/api/4/tag/wiki_pages?key=' + encodeURIComponent(key) + '&value=' + encodeURIComponent(value), colModel: [ { display: '<%= misc.language %>', name: 'lang', width: 150, sortable: false }, { display: '<%= page.wiki_pages.wiki_page %>', name: 'title', width: 200, sortable: false, align: 'right' }, |