# This file begins the loading sequence. # # Quick Overview: # * Requires fastthread, support libs, and base. # * Sets the application root and environment for compatibility with frameworks # such as Rails or Merb. # * Checks for the database.yml and loads it if it exists. # * Sets up the database using the config from the Yaml file or from the # environment. # require 'date' require 'pathname' require 'set' require 'time' require 'yaml' require 'rubygems' gem 'addressable', '>=1.0.4' require 'addressable/uri' gem 'extlib', '>=0.9.5' require 'extlib' require "extlib/inflection" begin require 'fastthread' rescue LoadError # fastthread not installed end dir = Pathname(__FILE__).dirname.expand_path / 'dm-core' require dir / 'support' require dir / 'resource' require dir / 'model' require dir / 'dependency_queue' require dir / 'type' require dir / 'type_map' require dir / 'types' require dir / 'hook' require dir / 'associations' require dir / 'auto_migrations' require dir / 'identity_map' require dir / 'logger' require dir / 'migrator' require dir / 'naming_conventions' require dir / 'property_set' require dir / 'query' require dir / 'transaction' require dir / 'repository' require dir / 'scope' require dir / 'property' require dir / 'adapters' require dir / 'collection' require dir / 'is' # == Setup and Configuration # DataMapper uses URIs or a connection hash to connect to your data-store. # URI connections takes the form of: # DataMapper.setup(:default, 'protocol://username:password@localhost:port/path/to/repo') # # Breaking this down, the first argument is the name you wish to give this # connection. If you do not specify one, it will be assigned :default. If you # would like to connect to more than one data-store, simply issue this command # again, but with a different name specified. # # In order to issue ORM commands without specifying the repository context, you # must define the :default database. Otherwise, you'll need to wrap your ORM # calls in repository(:name) { }. # # Second, the URI breaks down into the access protocol, the username, the # server, the password, and whatever path information is needed to properly # address the data-store on the server. # # Here's some examples # DataMapper.setup(:default, "sqlite3://path/to/your/project/db/development.db") # DataMapper.setup(:default, "mysql://localhost/dm_core_test") # # no auth-info # DataMapper.setup(:default, "postgres://root:supahsekret@127.0.0.1/dm_core_test") # # with auth-info # # # Alternatively, you can supply a hash as the second parameter, which would # take the form: # # DataMapper.setup(:default, { # :adapter => 'adapter_name_here', # :database => "path/to/repo", # :username => 'username', # :password => 'password', # :host => 'hostname' # }) # # === Logging # To turn on error logging to STDOUT, issue: # # DataMapper::Logger.new(STDOUT, 0) # # You can pass a file location ("/path/to/log/file.log") in place of STDOUT. # see DataMapper::Logger for more information. # module DataMapper extend Assertions def self.root @root ||= Pathname(__FILE__).dirname.parent.expand_path end ## # Setups up a connection to a data-store # # @param Symbol name a name for the context, defaults to :default # @param [Hash{Symbol => String}, Addressable::URI, String] uri_or_options # connection information # # @return Repository the resulting setup repository # # @raise ArgumentError "+name+ must be a Symbol, but was..." indicates that # an invalid argument was passed for name[Symbol] # @raise [ArgumentError] "+uri_or_options+ must be a Hash, URI or String, # but was..." indicates that connection information could not be gleaned # from the given uri_or_options # # - # @api public def self.setup(name, uri_or_options) assert_kind_of 'name', name, Symbol assert_kind_of 'uri_or_options', uri_or_options, Addressable::URI, Hash, String case uri_or_options when Hash adapter_name = uri_or_options[:adapter].to_s when String, Addressable::URI uri_or_options = Addressable::URI.parse(uri_or_options) if uri_or_options.kind_of?(String) adapter_name = uri_or_options.scheme end class_name = Extlib::Inflection.classify(adapter_name) + 'Adapter' unless Adapters::const_defined?(class_name) lib_name = "#{Extlib::Inflection.underscore(adapter_name)}_adapter" begin require root / 'lib' / 'dm-core' / 'adapters' / lib_name rescue LoadError => e begin require lib_name rescue Exception # library not found, raise the original error raise e end end end Repository.adapters[name] = Adapters::const_get(class_name).new(name, uri_or_options) end ## # Block Syntax # Pushes the named repository onto the context-stack, # yields a new session, and pops the context-stack. # # Non-Block Syntax # Returns the current session, or if there is none, # a new Session. # # @param [Symbol] args the name of a repository to act within or return, :default is default # @yield [Proc] (optional) block to execute within the context of the named repository # @demo spec/integration/repository_spec.rb def self.repository(*args, &block) # :yields: current_context if args.size > 1 raise ArgumentError, "Can only pass in one optional argument, but passed in #{args.size} arguments", caller end if args.any? && !args.first.kind_of?(Symbol) raise ArgumentError, "First optional argument must be a Symbol, but was #{args.first.inspect}", caller end name = args.first current_repository = if name Repository.context.detect { |r| r.name == name } || Repository.new(name) else Repository.context.last || Repository.new(Repository.default_name) end return current_repository unless block_given? current_repository.scope(&block) end # A logger should always be present. Lets be consistent with DO Logger.new(nil, :off) ## # destructively migrates the repository upwards to match model definitions # # @param [Symbol] name repository to act on, :default is the default def self.migrate!(name = Repository.default_name) repository(name).migrate! end ## # drops and recreates the repository upwards to match model definitions # # @param [Symbol] name repository to act on, :default is the default def self.auto_migrate!(repository_name = nil) AutoMigrator.auto_migrate(repository_name) end def self.auto_upgrade!(repository_name = nil) AutoMigrator.auto_upgrade(repository_name) end def self.prepare(*args, &blk) yield repository(*args) end def self.dependency_queue @dependency_queue ||= DependencyQueue.new end end