From 00282062674f2961c39652b3b464b953c3e4e014 Mon Sep 17 00:00:00 2001 From: Alex Reisner <alex@alexreisner.com> Date: Sun, 16 Mar 2014 23:04:11 -0400 Subject: [PATCH] Support DBs other than MySQL (:maxmind_local). --- .../templates/migration/geolite_city.rb | 18 +++++----- .../templates/migration/geolite_country.rb | 10 +++--- lib/geocoder/lookups/maxmind_local.rb | 28 ++++++++------- lib/maxmind_database.rb | 36 +++++++++---------- 4 files changed, 48 insertions(+), 44 deletions(-) diff --git a/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb b/lib/generators/geocoder/maxmind/templates/migration/geolite_city.rb index d5e45f97..fd2125bb 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 d47d46b8..5b3e1bf3 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 8a389e3d..8fcea68a 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 f223b6b4..1949e8a6 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 -- GitLab