lib/micro_sql.rb in micro_sql-0.2.0 vs lib/micro_sql.rb in micro_sql-0.3.0

- old
+ new

@@ -1,17 +1,25 @@ require "uri" +require "logger" class MicroSql end require_relative "micro_sql/pg_adapter" require_relative "micro_sql/sqlite_adapter" require_relative "micro_sql/table" -require_relative "micro_sql/settings" +require_relative "micro_sql/key_value_table" class MicroSql + class Error < RuntimeError; end + + (class << self; self; end).class_eval do + attr :logger, true + end + self.logger = Logger.new(STDERR) + (class << self; self; end).class_eval do private :new def create(url) scheme = URI.parse(url).scheme @@ -24,46 +32,136 @@ eval(klass_name).send(:new, url) end end def ask(sql, *args) - r = exec(sql, *args) - return r unless r.is_a?(Array) - - r = r.first - return r unless r.is_a?(Array) - return r unless r.length == 1 - r.first + results = execute :ask, sql, *args + format_results_for_ask(results) end - + def exec!(sql, *args) execute :no_prepare, sql, *args end def exec(sql, *args) execute :prepare, sql, *args end + private + + def format_results_for_ask(results) + return results unless results.is_a?(Array) + + results = results.first + + return results unless results.is_a?(Array) + return results if results.length != 1 + + results.first + end + + public + def transaction(&block) - @impl.transaction(&block) + r = nil + @impl.transaction do + r = yield + end + r + rescue RollbackException + nil end - def settings - @settings ||= MicroSql::SettingsTable.new(self) + def rollback! + raise RollbackException end + public + + def insert(table, *values) + hashes, arrays = values.partition do |value| value.is_a?(Hash) end + + id1 = insert_array_values(table, arrays) + id2 = insert_hash_values(table, hashes) + + id1 || id2 + end + private + def insert_array_values(table, values) + width = values.map(&:length).max + return if width == 0 || width == nil + + sql = insert_sql(table, width, nil) + values.inject(0) do |r, value| + exec sql, *value + end + end + + def insert_hash_values(table, values) + keys = values.map(&:keys).flatten.uniq + return if keys.empty? + + sql = insert_sql(table, keys.length, keys) + values.inject(0) do |r, rec| + exec sql, *rec.values_at(*keys) + end + end + + def insert_sql(table, width, keys = nil) + sql = "INSERT INTO #{table}" + sql += "(#{keys.join(",")})" if keys + sql += " VALUES(" + ([ "?" ] * width).join(",") + ")" + end + + public + + def tables + raise "Implementation missing: #{self.class}#tables" + end + + def table(sql_or_name) + @tables ||= {} + + return table_from_name(sql_or_name) if sql_or_name !~ /\s/ + + table = Table.new(self, sql_or_name) + @tables[table.table_name] = table + end + + private + + def table_from_name(name) + @tables[name] ||= Table.new(self, name) + rescue RuntimeError + end + + public + + def key_value_table(name) + @key_value_tables ||= Hash.new { |hash, key| + hash[key] = MicroSql::KeyValueTable.new(self, key) + } + + @key_value_tables[name] + end + + private + + class RollbackException < RuntimeError; end + def prepared_queries @prepared_queries ||= {} end + def unprepare(key) + @prepared_queries.delete key + end + def prepare(sql) - key = sql.to_uid.to_s - prepared_queries.fetch(key) + key = sql + prepared_queries.fetch(key) rescue KeyError prepared_queries[key] = prepare_query(key, sql) end end - -# url = "pg://sqdb:sqdb@localhost:5433/sqdb" -# MicroSql.create(url)