# try to require home_run in older rubies
unless %r{^1\.9\.[3-9]|^2\.}.match(RUBY_VERSION)
begin
require 'home_run'
rescue LoadError => e
warn "WARNING: DateTime parsing will be slow without home_run gem on Rubies older than 1.9.3"
end
end
# Extension.
require_relative 'swift/adapter'
require_relative 'swift/adapter/sql'
require_relative 'swift/attribute'
require_relative 'swift/header'
require_relative 'swift/record'
require_relative 'swift/type'
# A rational rudimentary object relational mapper.
#
# == Synopsis
# require 'swift'
# require 'swift/migrations'
#
# Swift.trace true # Debugging.
# Swift.setup :default, Swift::DB::Postgres, db: 'swift'
#
# class User < Swift::Record
# store :users
# attribute :id, Swift::Type::Integer, serial: true, key: true
# attribute :name, Swift::Type::String
# attribute :email, Swift::Type::String
# end # User
#
# # Migrate it.
# User.migrate!
#
# # Create
# User.create name: 'Apple Arthurton', email: 'apple@arthurton.local' # => User
#
# # Get by key.
# user = User.get id: 1
#
# # Alter attribute and update in one.
# user.update name: 'Jimmy Arthurton'
#
# # Alter attributes and update.
# user.name = 'Apple Arthurton'
# user.update
#
# # Destroy
# user.delete
#
# == See
# * README.rdoc has more usage examples.
# * API.rdoc is a public API overview.
module Swift
class << self
# Setup a new DB connection.
#
# You almost certainly want to setup a :default named adapter. The :default scope will be used
# for unscoped calls to Swift.db.
#
# @example
# Swift.setup :default, Swift::DB::Postgres, db: 'db1'
# Swift.setup :other, Swift::DB::Postgres, db: 'db2'
#
# @param [Symbol] name Adapter name.
# @param [Swift::Adapter] type Concrete adapter subclass. See Swift::DB
# @param [Hash] options Connection options
# @option options [String] :db Name.
# @option options [String] :user (*nix login user)
# @option options [String] :password ('')
# @option options [String] :host ('localhost')
# @option options [Integer] :port (DB default)
# @return [Swift::Adapter]
#
# @see Swift::DB
# @see Swift::Adapter
def setup name, type, options = {}
unless type.kind_of?(Class) && type < Swift::Adapter
raise TypeError, "Expected +type+ Swift::Adapter subclass but got #{type.inspect}"
end
(@repositories ||= {})[name] = type.new(options)
end
# Fetch or scope a block to a specific DB by name.
#
# @example
# Swift.db :other do |other|
# # Inside this block all these are the same:
# # other
# # Swift.db
# # Swift.db :other
#
# other_users = User.prepare('select * from users where age > ?')
# other_users.execute(32)
# end
#
# @param [Symbol] name Adapter name.
# @param [Proc] block Scope this block to the named adapter instead of :default.
# @return [Swift::Adapter]
#--
# I pilfered the logic from DM but I don't really understand what is/isn't thread safe.
def db name = nil, &block
scopes = (Thread.current[:swift_db] ||= [])
repository = if name || scopes.empty?
@repositories[name || :default] or raise "Unknown db '#{name || :default}', did you forget to #setup?"
else
scopes.last
end
if block_given?
begin
scopes.push(repository)
block.call(repository)
ensure
scopes.pop
end
end
repository
end
# List of known Swift::Schema classes.
#
# Handy if you are brewing stuff like migrations and need a list of defined schema subclasses.
#
# @return [Array]
def schema
@schema ||= []
end
def trace io = $stdout, &block
Swift.db.trace(io, &block)
end
end
end # Swift