summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJochen Topf <jochen@topf.org>2013-01-06 13:27:23 +0100
committerJochen Topf <jochen@topf.org>2013-01-06 13:27:23 +0100
commit3dc24ee78f73094f44ed89a044c85d7c4338ff97 (patch)
tree4b276413beef950e549c22c54ba25680ae1b5a45
parent94cf8b600b3b59e3bad066b6a4b7bf010007e84e (diff)
downloadtaginfo-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-xexamples/tapi4
-rw-r--r--web/lib/api/db.rb10
-rw-r--r--web/lib/api/key.rb260
-rw-r--r--web/lib/api/keys.rb183
-rw-r--r--web/lib/api/tag.rb159
-rw-r--r--web/lib/api/tags.rb61
-rw-r--r--web/lib/api/wiki.rb19
-rw-r--r--web/lib/utils.rb20
-rwxr-xr-xweb/taginfo.rb4
-rw-r--r--web/views/taginfo/apidoc.erb4
-rw-r--r--web/viewsjs/key.js.erb10
-rw-r--r--web/viewsjs/reports/language_comparison_table_for_keys_in_the_wiki.js.erb2
-rw-r--r--web/viewsjs/tag.js.erb8
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 %> &rarr;</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 %> &rarr;</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' },