lib/csvsql.rb in csvsql-0.1.5 vs lib/csvsql.rb in csvsql-0.2.0

- old
+ new

@@ -2,24 +2,94 @@ require "csvsql/version" require 'csv' require 'sqlite3' +require 'digest' +require 'fileutils' require 'csvsql/db' require 'csvsql/tracker' +require 'csvsql/command_runner' module Csvsql - def self.execute(sql, csv_data, opts = {}) - encoding = opts.delete(:encoding) - csvdb = Csvsql::Db.new(opts) - csvdb.import(csv_data, encoding: encoding) + extend self + + CACHE_DIR = File.join(Dir.home, '.csvsql_cache') + FileUtils.mkdir_p(CACHE_DIR) unless Dir.exists?(CACHE_DIR) + + def execute(sql, csv_data, opts = {}) + csvdb = init_data(csv_data, opts) pst = Csvsql::Tracker.commit(:execute_query_sql) do csvdb.prepare(sql) end Csvsql::Tracker.commit(:output_format) CSV.generate do |csv| csv << pst.columns.zip(pst.types).map { |c| c.compact.join(':') } pst.each { |line| csv << line } end.tap { Csvsql::Tracker.commit(:output_format) } + end + + def self.clear_cache! + FileUtils.rm_f(Dir.glob(File.join(CACHE_DIR, '*'))) + end + + private + + def init_data(csv_data, opts) + encoding = opts.delete(:encoding) + use_cache = opts.delete(:use_cache) + csvdb = Csvsql::Db.new(opts) + + unless use_cache + csvdb.import(csv_data, encoding: encoding) + return csvdb + end + + case csv_data + when StringIO, IO + # nothing + when Hash + dbs = [] + csv_data.each do |dbname, csv_path| + dbs << [dbname, csvdb.init_db(get_db_cache_path(csv_path) || '')] + csvdb.import(csv_path, encoding: encoding) + end + dbs.each do |dbname, db| + csvdb.execute("ATTACH DATABASE '#{db.filename}' AS #{dbname};") + end + else + csvdb.init_db(get_db_cache_path(csv_data) || '') + csvdb.import(csv_data, encoding: encoding) + end + + csvdb + end + + def get_db_cache_path(csv_path) + csv_path = csv_path || '' + return unless File.exist?(csv_path) + + stat = File.stat(csv_path) + filename = Digest::SHA2.hexdigest(File.absolute_path(csv_path)) + '.cache' + file_stat = [File.absolute_path(csv_path), stat.size, stat.ctime].join("\n") + stat_path = File.join(CACHE_DIR, filename.gsub(/\.cache$/, '.stat')) + cache_path = File.join(CACHE_DIR, filename) + + if File.exist?(stat_path) + if File.read(stat_path) == file_stat + cache_path + else + if update_cb + update_cb.call + else + FileUtils.rm(cache_path) + end + File.write(stat_path, file_stat) + cache_path + end + else + File.write(stat_path, file_stat) + cache_path + end end end