jam-cloud/ruby/lib/jam_ruby/models/geo_ip_locations.rb

151 lines
6.7 KiB
Ruby

module JamRuby
class GeoIpLocations < ActiveRecord::Base
self.table_name = 'geoiplocations'
CITIES_TABLE = 'cities'
REGIONS_TABLE = 'regions'
COUNTRIES_TABLE = 'countries'
def self.lookup(locid)
self.where(locid: locid)
.limit(1)
.first
end
def self.createx(locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode)
c = connection.raw_connection
c.exec_params("insert into #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode, geog) values($1, $2, $3, $4, $5, $6, $7, $8, $9, ST_SetSRID(ST_MakePoint($7, $6), 4326)::geography)",
[locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode])
end
def self.i(s)
return 'NULL' if s.nil? or s.blank?
return s.to_i
end
def self.import_from_max_mind(file)
# File Geo-134
# Format:
# locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode
self.transaction do
self.delete_all
File.open(file, 'r:ISO-8859-1') do |io|
s = io.gets.strip # eat the copyright line. gah, why do they have that in their file??
unless s.eql? 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.'
puts s
puts 'Copyright (c) 2012 MaxMind LLC. All Rights Reserved.'
raise 'file does not start with expected copyright (line 1): Copyright (c) 2012 MaxMind LLC. All Rights Reserved.'
end
s = io.gets.strip # eat the headers line
unless s.eql? 'locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode'
puts s
puts 'locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode'
raise 'file does not start with expected header (line 2): locId,country,region,city,postalCode,latitude,longitude,metroCode,areaCode'
end
saved_level = ActiveRecord::Base.logger ? ActiveRecord::Base.logger.level : 0
count = 0
stmt = "INSERT INTO #{self.table_name} (locid, countrycode, region, city, postalcode, latitude, longitude, metrocode, areacode) VALUES"
vals = ''
sep = ''
i = 0
n = 20
csv = ::CSV.new(io, {encoding: 'ISO-8859-1', headers: false})
csv.each do |row|
raise "file does not have expected number of columns (9): #{row.length}" unless row.length == 9
locid = row[0]
countrycode = row[1]
region = row[2]
city = row[3]
postalcode = row[4]
latitude = row[5]
longitude = row[6]
metrocode = row[7]
areacode = row[8]
vals = vals+sep+"(#{locid}, '#{countrycode}', '#{region}', #{MaxMindIsp.quote_value(city)}, '#{postalcode}', #{latitude}, #{longitude}, #{i(metrocode)}, '#{areacode}')"
sep = ','
i += 1
if count == 0 or i >= n then
self.connection.execute stmt+vals
count += i
vals = ''
sep = ''
i = 0
if ActiveRecord::Base.logger and ActiveRecord::Base.logger.level > 1 then
ActiveRecord::Base.logger.debug "... logging inserts into #{self.table_name} suspended ..."
ActiveRecord::Base.logger.level = 1
end
if ActiveRecord::Base.logger and count%10000 < n then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "... inserted #{count} into #{self.table_name} ..."
ActiveRecord::Base.logger.level = 1
end
end
end
if i > 0 then
self.connection.execute stmt+vals
count += i
end
if ActiveRecord::Base.logger then
ActiveRecord::Base.logger.level = saved_level
ActiveRecord::Base.logger.debug "loaded #{count} records into #{self.table_name}"
end
sts = self.connection.execute "ALTER TABLE #{self.table_name} DROP COLUMN geog;"
ActiveRecord::Base.logger.debug "DROP COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
# sts.check [we don't care]
sts = self.connection.execute "ALTER TABLE #{self.table_name} ADD COLUMN geog geography(point, 4326);"
ActiveRecord::Base.logger.debug "ADD COLUMN geog returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "UPDATE #{self.table_name} SET geog = ST_SetSRID(ST_MakePoint(longitude, latitude), 4326)::geography;"
ActiveRecord::Base.logger.debug "SET geog returned sts #{sts.cmd_tuples}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "CREATE INDEX #{self.table_name}_geog_gix ON #{self.table_name} USING GIST (geog);"
ActiveRecord::Base.logger.debug "CREATE INDEX #{self.table_name}_geog_gix returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{CITIES_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{CITIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{CITIES_TABLE} (city, region, countrycode) SELECT DISTINCT city, region, countrycode FROM #{self.table_name} WHERE length(city) > 0 AND length(countrycode) > 0;"
ActiveRecord::Base.logger.debug "INSERT INTO #{CITIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{REGIONS_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{REGIONS_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{REGIONS_TABLE} (region, regionname, countrycode) SELECT DISTINCT region, region, countrycode FROM #{CITIES_TABLE};"
ActiveRecord::Base.logger.debug "INSERT INTO #{REGIONS_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "DELETE FROM #{COUNTRIES_TABLE};"
ActiveRecord::Base.logger.debug "DELETE FROM #{COUNTRIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
sts = self.connection.execute "INSERT INTO #{COUNTRIES_TABLE} (countrycode, countryname) SELECT DISTINCT countrycode, countrycode FROM #{REGIONS_TABLE};"
ActiveRecord::Base.logger.debug "INSERT INTO #{COUNTRIES_TABLE} returned sts #{sts.cmd_status}" if ActiveRecord::Base.logger
sts.check
end
end
end
end
end