89 lines
2.3 KiB
Ruby
89 lines
2.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "csv"
|
|
require "net/http"
|
|
|
|
require "provider/adapters/adapter"
|
|
|
|
class Provider
|
|
module Adapters
|
|
class ECB < Adapter
|
|
SDMX_URL = "https://data-api.ecb.europa.eu/service/data/EXR/D..EUR.SP00.A"
|
|
class << self
|
|
def backfill_range = 365
|
|
end
|
|
|
|
def fetch(after: nil, upto: nil)
|
|
url = URI(SDMX_URL)
|
|
params = { format: "csvdata" }
|
|
params[:startPeriod] = after.to_s if after
|
|
params[:endPeriod] = upto.to_s if upto
|
|
url.query = URI.encode_www_form(params)
|
|
|
|
dataset = []
|
|
stream_csv(url) do |row|
|
|
record = parse_row(row)
|
|
dataset << record if record
|
|
end
|
|
|
|
dataset
|
|
end
|
|
|
|
def parse(csv)
|
|
CSV.parse(csv, headers: true, liberal_parsing: true).filter_map do |row|
|
|
parse_row(row)
|
|
end
|
|
end
|
|
|
|
private
|
|
|
|
def parse_row(row)
|
|
return unless row["FREQ"] == "D"
|
|
|
|
quote = row["CURRENCY"]
|
|
return unless quote&.match?(/\A[A-Z]{3}\z/)
|
|
|
|
value = row["OBS_VALUE"]
|
|
return unless value
|
|
|
|
rate = Float(value)
|
|
date = Date.parse(row["TIME_PERIOD"])
|
|
|
|
{ date:, base: "EUR", quote:, rate: }
|
|
end
|
|
|
|
def stream_csv(url)
|
|
uri = URI(url)
|
|
Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
|
|
request = Net::HTTP::Get.new(uri)
|
|
http.request(request) do |response|
|
|
headers = nil
|
|
buffer = +""
|
|
|
|
response.read_body do |chunk|
|
|
buffer << chunk
|
|
while (line_end = buffer.index("\n"))
|
|
line = buffer.slice!(0..line_end)
|
|
if headers.nil?
|
|
headers = CSV.parse_line(line, liberal_parsing: true)
|
|
else
|
|
values = CSV.parse_line(line, liberal_parsing: true)
|
|
next unless values
|
|
|
|
row = CSV::Row.new(headers, values)
|
|
yield row
|
|
end
|
|
end
|
|
end
|
|
|
|
# Process remaining buffer
|
|
if headers && !buffer.empty?
|
|
values = CSV.parse_line(buffer, liberal_parsing: true)
|
|
yield CSV::Row.new(headers, values) if values
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|