diff --git a/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb b/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb index d5e45f976a3d5f7b3aef2a2593d8091855fadfa3..fd2125bbc185f8a8c5be6382ecd5517973889669 100644 --- a/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb +++ b/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb @@ -1,24 +1,24 @@ class GeocoderMaxmindGeoliteCity < ActiveRecord::Migration def self.up create_table :maxmind_geolite_city_blocks, id: false do |t| - t.column :startIpNum, 'integer unsigned', null: false - t.column :endIpNum, 'integer unsigned', null: false - t.column :locId, 'integer unsigned', null: false + t.column :start_ip_num, :bigint, null: false + t.column :end_ip_num, :bigint, null: false + t.column :loc_id, :bigint, null: false end - add_index :maxmind_geolite_city_blocks, :startIpNum, unique: true + add_index :maxmind_geolite_city_blocks, :start_ip_num, unique: true create_table :maxmind_geolite_city_location, id: false do |t| - t.column :locId, 'integer unsigned', null: false + t.column :loc_id, :bigint, null: false t.string :country, null: false t.string :region, null: false t.string :city - t.string :postalCode, null: false + t.string :postal_code, null: false t.float :latitude t.float :longitude - t.integer :metroCode - t.integer :areaCode + t.integer :metro_code + t.integer :area_code end - add_index :maxmind_geolite_city_location, :locId, unique: true + add_index :maxmind_geolite_city_location, :loc_id, unique: true end def self.down diff --git a/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb b/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb index d47d46b857b31bdf29c6995eac968e330267a071..5b3e1bf36d9526e93a86bc20a80bd16baf156dba 100644 --- a/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb +++ b/lib/generators/geocoder/maxmind/templates/migration/geolite_country.rb @@ -1,14 +1,14 @@ class GeocoderMaxmindGeoliteCountry < ActiveRecord::Migration def self.up create_table :maxmind_geolite_country, id: false do |t| - t.column :startIp, :string - t.column :endIp, :string - t.column :startIpNum, 'integer unsigned', null: false - t.column :endIpNum, 'integer unsigned', null: false + t.column :start_ip, :string + t.column :end_ip, :string + t.column :start_ip_num, :bigint, null: false + t.column :end_ip_num, :bigint, null: false t.column :country_code, :string, null: false t.column :country, :string, null: false end - add_index :maxmind_geolite_country, :startIpNum, unique: true + add_index :maxmind_geolite_country, :start_ip_num, unique: true end def self.down diff --git a/lib/geocoder/lookups/maxmind_local.rb b/lib/geocoder/lookups/maxmind_local.rb index 8a389e3dc58d18c38b57212f3c226bf0abab6765..8fcea68a48604f7f87794ab57f416b3fd997d099 100644 --- a/lib/geocoder/lookups/maxmind_local.rb +++ b/lib/geocoder/lookups/maxmind_local.rb @@ -28,26 +28,30 @@ module Geocoder::Lookup private def results(query) - if !configuration[:file].nil? + if configuration[:file] geoip_class = RUBY_PLATFORM == "java" ? JGeoIP : GeoIP result = geoip_class.new(configuration[:file]).city(query.to_s) result.nil? ? [] : [result.to_hash] elsif configuration[:package] == :city addr = IPAddr.new(query.text).to_i q = "SELECT l.country, l.region, l.city - FROM maxmind_geolite_city_location l JOIN maxmind_geolite_city_blocks b USING (locId) - WHERE b.startIpNum <= #{addr} AND #{addr} <= b.endIpNum" - if r = ActiveRecord::Base.connection.execute(q).first - [Hash[*[:country_name, :region_name, :city_name].zip(r).flatten]] - end + FROM maxmind_geolite_city_location l JOIN maxmind_geolite_city_blocks b USING (loc_id) + WHERE b.start_ip_num <= #{addr} AND #{addr} <= b.end_ip_num" + format_result(q, [:country_name, :region_name, :city_name]) elsif configuration[:package] == :country addr = IPAddr.new(query.text).to_i - q = "SELECT country, country_code - FROM maxmind_geolite_country - WHERE startIpNum <= #{addr} AND #{addr} <= endIpNum" - if r = ActiveRecord::Base.connection.execute(q).first - [Hash[*[:country_name, :country_code].zip(r).flatten]] - end + q = "SELECT country, country_code FROM maxmind_geolite_country + WHERE start_ip_num <= #{addr} AND #{addr} <= end_ip_num" + format_result(q, [:country_name, :country_code]) + end + end + + def format_result(query, attr_names) + if r = ActiveRecord::Base.connection.execute(query).first + r = r.values if r.is_a?(Hash) # some db adapters return Hash, some Array + [Hash[*attr_names.zip(r).flatten]] + else + [] end end end diff --git a/lib/maxmind_database.rb b/lib/maxmind_database.rb index f223b6b445ae59d1315ef40e2f12921719c15f1c..1949e8a6e279210353334a2d49ca730ee90bc1b1 100644 --- a/lib/maxmind_database.rb +++ b/lib/maxmind_database.rb @@ -37,31 +37,31 @@ module Geocoder private # ------------------------------------------------------------- + def table_columns(table_name) + { + maxmind_geolite_city_blocks: %w[start_ip_num end_ip_num loc_id], + maxmind_geolite_city_location: %w[loc_id country region city postal_code latitude longitude metro_code area_code], + maxmind_geolite_country: %w[start_ip end_ip start_ip_num end_ip_num country_code country] + }[table_name.to_sym] + end + def insert_into_table(table, filepath) start_time = Time.now print "Loading data for table #{table}" rows = [] - if table =~ /city/ - headers = nil - else - headers = %w[startIp endIp startIpNum endIpNum country_code country] - end + columns = table_columns(table) CSV.foreach(filepath, encoding: "ISO-8859-1") do |line| - if line.first[0...9] == "Copyright" - next - elsif headers.nil? - headers = line - next - else - rows << line.to_a - if rows.size == 10000 - insert_rows(table, headers, rows) - rows = [] - print "." - end + # Some files have header rows. + # skip if starts with "Copyright" or "locId" or "startIpNum" + next if line.first.match(/[A-z]/) + rows << line.to_a + if rows.size == 10000 + insert_rows(table, columns, rows) + rows = [] + print "." end end - insert_rows(table, headers, rows) if rows.size > 0 + insert_rows(table, columns, rows) if rows.size > 0 puts "done (#{Time.now - start_time} seconds)" end