From d2c78e6aa2e364ba8f99ae1f453d5fda38ebc573 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 2 May 2023 13:57:11 -0500 Subject: [PATCH] Forgot files --- lib/area_code_repo.rb | 25 +++++++++++++++++++++++++ lib/geo_code.rb | 24 ++++++++++++++++++++++++ lib/geo_code_repo.rb | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 lib/area_code_repo.rb create mode 100644 lib/geo_code.rb create mode 100644 lib/geo_code_repo.rb diff --git a/lib/area_code_repo.rb b/lib/area_code_repo.rb new file mode 100644 index 0000000000000000000000000000000000000000..9239d1b0d274e3f4b58b2015fc158fadbbb47450 --- /dev/null +++ b/lib/area_code_repo.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "json" + +require_relative "geo_code_repo" + +class AreaCodeRepo + def initialize(db: DB, geo_code_repo: GeoCodeRepo.new) + @db = db + @geo_code_repo = geo_code_repo + end + + def find(q, limit: 3) + @geo_code_repo.find(q).then { |geo| + @db.query_defer(<<~SQL, [geo.country, geo.sql_point, limit]) + SELECT area_code FROM area_codes + WHERE country=$1 + ORDER BY location <-> $2 + LIMIT $3 + SQL + }.then { |rows| + rows.map { |row| row["area_code"] } + } + end +end diff --git a/lib/geo_code.rb b/lib/geo_code.rb new file mode 100644 index 0000000000000000000000000000000000000000..d5d8f1798ebc8fe061643dd81ead768d9136e4c4 --- /dev/null +++ b/lib/geo_code.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +require "value_semantics/monkey_patched" + +class GeoCode + def self.for(data) + new(data) + end + + def initialize(data) + @data = data + end + + def country + return "US" unless @data["postal"] + return "US" if @data["postal"] =~ /\A\d+\Z/ + + "CA" + end + + def sql_point + "POINT(#{'%.10f' % @data['longt']} #{'%.10f' % @data['latt']})" + end +end diff --git a/lib/geo_code_repo.rb b/lib/geo_code_repo.rb new file mode 100644 index 0000000000000000000000000000000000000000..35c43a77e60e48865b992c6b3172a00a5b282150 --- /dev/null +++ b/lib/geo_code_repo.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require "cbor" +require "json" + +require_relative "geo_code" + +class GeoCodeRepo + def initialize(memcache: MEMCACHE) + @memcache = memcache + end + + def find(q) + cache(q) { + EM::HttpRequest.new( + "https://geocoder.ca/", + tls: { verify_peer: true } + ).aget(query: { json: 1, locate: q }).then { |res| + JSON.parse(res.response) + } + }.then(&GeoCode.method(:for)) + end + +protected + + def cache(k, &blk) + k = "geocode_#{k.gsub(/ /, '%20')}" + promise = EMPromise.new + @memcache.get(k, &promise.method(:fulfill)) + promise.then { |cbor| + CBOR.decode(cbor) + }.catch(&blk).then { |result| + @memcache.set(k, result.to_cbor) + result + } + end +end