connection_manager 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
 - data/.rspec +1 -0
 - data/Gemfile.lock +8 -3
 - data/README.md +26 -26
 - data/connection_manager.gemspec +2 -0
 - data/lib/connection_manager.rb +1 -0
 - data/lib/connection_manager/connections.rb +34 -25
 - data/lib/connection_manager/replication_builder.rb +11 -12
 - data/lib/connection_manager/version.rb +1 -1
 - data/spec/database.yml +20 -0
 - data/spec/factories.rb +31 -0
 - data/spec/helpers/database_spec_helper.rb +68 -0
 - data/spec/helpers/models_spec_helper.rb +26 -0
 - data/spec/integration/replication_builder_spec.rb +97 -0
 - data/{test_app/spec/connection_manager → spec/lib}/associations_spec.rb +0 -0
 - data/spec/lib/connections_spec.rb +93 -0
 - data/{test_app/spec/connection_manager → spec/lib}/replication_builder_spec.rb +17 -1
 - data/spec/spec_helper.rb +17 -5
 - metadata +49 -60
 - data/test_app/.gitignore +0 -15
 - data/test_app/.rspec +0 -1
 - data/test_app/Gemfile +0 -14
 - data/test_app/Gemfile.lock +0 -140
 - data/test_app/README +0 -261
 - data/test_app/Rakefile +0 -7
 - data/test_app/app/models/.gitkeep +0 -0
 - data/test_app/app/models/basket.rb +0 -4
 - data/test_app/app/models/fruit.rb +0 -6
 - data/test_app/app/models/fruit_basket.rb +0 -4
 - data/test_app/app/models/region.rb +0 -3
 - data/test_app/app/models/type.rb +0 -2
 - data/test_app/config.ru +0 -4
 - data/test_app/config/application.rb +0 -52
 - data/test_app/config/boot.rb +0 -6
 - data/test_app/config/database.yml +0 -42
 - data/test_app/config/environment.rb +0 -5
 - data/test_app/config/environments/development.rb +0 -30
 - data/test_app/config/environments/production.rb +0 -60
 - data/test_app/config/environments/test.rb +0 -39
 - data/test_app/config/initializers/backtrace_silencers.rb +0 -7
 - data/test_app/config/initializers/inflections.rb +0 -10
 - data/test_app/config/initializers/load_connection_manager.rb +0 -6
 - data/test_app/config/initializers/mime_types.rb +0 -5
 - data/test_app/config/initializers/secret_token.rb +0 -7
 - data/test_app/config/initializers/session_store.rb +0 -8
 - data/test_app/config/initializers/wrap_parameters.rb +0 -14
 - data/test_app/config/locales/en.yml +0 -5
 - data/test_app/config/routes.rb +0 -58
 - data/test_app/db/migrate/20111127040654_create_fruits.rb +0 -9
 - data/test_app/db/migrate/20111127040720_create_baskets.rb +0 -9
 - data/test_app/db/migrate/20111127040846_create_fruit_baskets.rb +0 -9
 - data/test_app/db/migrate/20111127040915_create_regions.rb +0 -9
 - data/test_app/db/migrate/20111127060322_create_types.rb +0 -9
 - data/test_app/db/schema.rb +0 -16
 - data/test_app/db/seeds.rb +0 -7
 - data/test_app/log/.gitkeep +0 -0
 - data/test_app/script/rails +0 -6
 - data/test_app/spec/connection_manager/connections_spec.rb +0 -51
 - data/test_app/spec/factories/baskets.rb +0 -7
 - data/test_app/spec/factories/fruit_baskets.rb +0 -8
 - data/test_app/spec/factories/fruits.rb +0 -8
 - data/test_app/spec/factories/regions.rb +0 -7
 - data/test_app/spec/factories/types.rb +0 -7
 - data/test_app/spec/models/type_spec.rb +0 -5
 - data/test_app/spec/spec.opts +0 -4
 - data/test_app/spec/spec_helper.rb +0 -42
 - data/test_app/test_app +0 -0
 
    
        data/.gitignore
    CHANGED
    
    
    
        data/.rspec
    ADDED
    
    | 
         @@ -0,0 +1 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --color
         
     | 
    
        data/Gemfile.lock
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            PATH
         
     | 
| 
       2 
2 
     | 
    
         
             
              remote: .
         
     | 
| 
       3 
3 
     | 
    
         
             
              specs:
         
     | 
| 
       4 
     | 
    
         
            -
                 
     | 
| 
      
 4 
     | 
    
         
            +
                connection_manager (0.1.0)
         
     | 
| 
       5 
5 
     | 
    
         
             
                  activerecord (~> 3.0)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            GEM
         
     | 
| 
         @@ -24,11 +24,13 @@ GEM 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  ZenTest (>= 4.4.1)
         
     | 
| 
       25 
25 
     | 
    
         
             
                builder (3.0.0)
         
     | 
| 
       26 
26 
     | 
    
         
             
                diff-lcs (1.1.3)
         
     | 
| 
      
 27 
     | 
    
         
            +
                factory_girl (2.3.2)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  activesupport
         
     | 
| 
       27 
29 
     | 
    
         
             
                i18n (0.6.0)
         
     | 
| 
       28 
30 
     | 
    
         
             
                metaclass (0.0.1)
         
     | 
| 
       29 
31 
     | 
    
         
             
                mocha (0.10.0)
         
     | 
| 
       30 
32 
     | 
    
         
             
                  metaclass (~> 0.0.1)
         
     | 
| 
       31 
     | 
    
         
            -
                multi_json (1.0. 
     | 
| 
      
 33 
     | 
    
         
            +
                multi_json (1.0.4)
         
     | 
| 
       32 
34 
     | 
    
         
             
                rspec (2.7.0)
         
     | 
| 
       33 
35 
     | 
    
         
             
                  rspec-core (~> 2.7.0)
         
     | 
| 
       34 
36 
     | 
    
         
             
                  rspec-expectations (~> 2.7.0)
         
     | 
| 
         @@ -37,13 +39,16 @@ GEM 
     | 
|
| 
       37 
39 
     | 
    
         
             
                rspec-expectations (2.7.0)
         
     | 
| 
       38 
40 
     | 
    
         
             
                  diff-lcs (~> 1.1.2)
         
     | 
| 
       39 
41 
     | 
    
         
             
                rspec-mocks (2.7.0)
         
     | 
| 
      
 42 
     | 
    
         
            +
                sqlite3 (1.3.4)
         
     | 
| 
       40 
43 
     | 
    
         
             
                tzinfo (0.3.31)
         
     | 
| 
       41 
44 
     | 
    
         | 
| 
       42 
45 
     | 
    
         
             
            PLATFORMS
         
     | 
| 
       43 
46 
     | 
    
         
             
              ruby
         
     | 
| 
       44 
47 
     | 
    
         | 
| 
       45 
48 
     | 
    
         
             
            DEPENDENCIES
         
     | 
| 
       46 
     | 
    
         
            -
              activerecord-connection_manager!
         
     | 
| 
       47 
49 
     | 
    
         
             
              autotest
         
     | 
| 
      
 50 
     | 
    
         
            +
              connection_manager!
         
     | 
| 
      
 51 
     | 
    
         
            +
              factory_girl
         
     | 
| 
       48 
52 
     | 
    
         
             
              mocha
         
     | 
| 
       49 
53 
     | 
    
         
             
              rspec
         
     | 
| 
      
 54 
     | 
    
         
            +
              sqlite3
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,23 +1,23 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            #  
     | 
| 
      
 1 
     | 
    
         
            +
            # ConnectionManager
         
     | 
| 
       2 
2 
     | 
    
         
             
            Replication and Multi-Database ActiveRecord add on.
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
4 
     | 
    
         
             
            ## Goals
         
     | 
| 
       5 
5 
     | 
    
         
             
            * Take the lib I've been using finally make something out of it ;)
         
     | 
| 
       6 
     | 
    
         
            -
            * Use connection classes instead of establish_connection on every model to ensure connection pooling
         
     | 
| 
       7 
     | 
    
         
            -
            *  
     | 
| 
      
 6 
     | 
    
         
            +
            * Use connection classes, instead of establish_connection on every model, to ensure connection pooling
         
     | 
| 
      
 7 
     | 
    
         
            +
            * Use non-adapter specific code.
         
     | 
| 
       8 
8 
     | 
    
         
             
            * Use the default database.yml as single point for all database configurations (no extra .yml files)
         
     | 
| 
       9 
     | 
    
         
            -
            * When slave objects are used in html helpers like link_to and form_for the created urls  
     | 
| 
      
 9 
     | 
    
         
            +
            * When slave objects are used in html helpers like link_to and form_for the created urls match those created using a master object
         
     | 
| 
       10 
10 
     | 
    
         | 
| 
       11 
11 
     | 
    
         
             
            ## Installation
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
      
 13 
     | 
    
         
            +
            ConnectionManager is available through [Rubygems](https://rubygems.org/gems/connection_manager) and can be installed via:
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                $ gem install connection_manager
         
     | 
| 
       16 
16 
     | 
    
         | 
| 
       17 
17 
     | 
    
         
             
            ## Rails 3 setup (Rails 2 untested at this time please let me know if it works for you )
         
     | 
| 
       18 
18 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
       20 
     | 
    
         
            -
            models using the default connection this means the main  
     | 
| 
      
 19 
     | 
    
         
            +
            ConnectionManager assumes the primary connection for the model is the master. For standard
         
     | 
| 
      
 20 
     | 
    
         
            +
            models using the default connection this means the main Rails database connection is the master.
         
     | 
| 
       21 
21 
     | 
    
         | 
| 
       22 
22 
     | 
    
         
             
            Example database.yml
         
     | 
| 
       23 
23 
     | 
    
         | 
| 
         @@ -37,7 +37,7 @@ Example database.yml 
     | 
|
| 
       37 
37 
     | 
    
         | 
| 
       38 
38 
     | 
    
         
             
                slave_1_test_app_development:
         
     | 
| 
       39 
39 
     | 
    
         
             
                  <<: *common
         
     | 
| 
       40 
     | 
    
         
            -
                  database:  
     | 
| 
      
 40 
     | 
    
         
            +
                  database: test_app
         
     | 
| 
       41 
41 
     | 
    
         | 
| 
       42 
42 
     | 
    
         
             
                slave_2_test_app_development:
         
     | 
| 
       43 
43 
     | 
    
         
             
                  <<: *common
         
     | 
| 
         @@ -62,33 +62,32 @@ is the databases name and finally the "development" is the environment. (Of cour 
     | 
|
| 
       62 
62 
     | 
    
         
             
            each slave would have a different connection to is replication :)
         
     | 
| 
       63 
63 
     | 
    
         | 
| 
       64 
64 
     | 
    
         | 
| 
       65 
     | 
    
         
            -
             
     | 
| 
      
 65 
     | 
    
         
            +
            ## Multiple Databases
         
     | 
| 
       66 
66 
     | 
    
         | 
| 
       67 
     | 
    
         
            -
            At startup  
     | 
| 
      
 67 
     | 
    
         
            +
            At startup ConnectionManager builds connection classes  to ConnectionManager::Connections
         
     | 
| 
       68 
68 
     | 
    
         
             
            using the connections described in your database.yml based on the current rails environment.
         
     | 
| 
       69 
69 
     | 
    
         | 
| 
       70 
70 
     | 
    
         
             
            You can use a different master by having the model inherit from one of your ConnectionManager::Connections.
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
       72 
72 
     | 
    
         
             
            To view your ConnectionManager::Connections, at the Rails console type:
         
     | 
| 
       73 
73 
     | 
    
         | 
| 
       74 
     | 
    
         
            -
             
     | 
| 
      
 74 
     | 
    
         
            +
               ConnectionManager::Connections.all => ["TestAppConnection", "Slave1TestAppConnection", "Slave2TestAppConnection"]
         
     | 
| 
       75 
75 
     | 
    
         | 
| 
       76 
76 
     | 
    
         
             
            If your using the example database.yml your array would look like this:
         
     | 
| 
       77 
77 
     | 
    
         
             
                ["TestAppConnection", "Slave1TestAppConnection", "Slave2TestAppConnection", 
         
     | 
| 
       78 
78 
     | 
    
         
             
                "UserDataConnection", "Slave1UserDataConnection", "Slave2UserDataConnection"]
         
     | 
| 
       79 
79 
     | 
    
         | 
| 
       80 
80 
     | 
    
         | 
| 
       81 
     | 
    
         
            -
             
     | 
| 
       82 
81 
     | 
    
         
             
            To use one of your ConnectionManager::Connections for your models default/master database
         
     | 
| 
       83 
     | 
    
         
            -
            setup  
     | 
| 
      
 82 
     | 
    
         
            +
            setup your model like the following
         
     | 
| 
       84 
83 
     | 
    
         | 
| 
       85 
84 
     | 
    
         
             
                class User < ConnectionManager::Connections::UserDataConnection
         
     | 
| 
       86 
85 
     | 
    
         
             
                    # model code ...
         
     | 
| 
       87 
86 
     | 
    
         
             
                end
         
     | 
| 
       88 
87 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
             
     | 
| 
      
 88 
     | 
    
         
            +
            ## Replication
         
     | 
| 
       90 
89 
     | 
    
         | 
| 
       91 
     | 
    
         
            -
             
     | 
| 
      
 90 
     | 
    
         
            +
            Simply add 'replicated' to your model beneath any defined associations
         
     | 
| 
       92 
91 
     | 
    
         | 
| 
       93 
92 
     | 
    
         
             
                class User < ConnectionManager::Connections::UserDataConnection
         
     | 
| 
       94 
93 
     | 
    
         
             
                    has_one :job
         
     | 
| 
         @@ -101,30 +100,31 @@ The replicated method addeds subclass whose names match the replication connecti 
     | 
|
| 
       101 
100 
     | 
    
         
             
            Based on the above example database.yml User class would now have User::Slave1 and User::Slave2. 
         
     | 
| 
       102 
101 
     | 
    
         | 
| 
       103 
102 
     | 
    
         
             
            You can treat your subclass like normal activerecord objects.
         
     | 
| 
       104 
     | 
    
         
            -
                 
     | 
| 
       105 
     | 
    
         
            -
                User:: 
     | 
| 
      
 103 
     | 
    
         
            +
                
         
     | 
| 
      
 104 
     | 
    
         
            +
                User::Slave1.first => returns results from slave_1_user_data_development 
         
     | 
| 
      
 105 
     | 
    
         
            +
                User::Slave2.where(['created_at BETWEEN ? and ?',Time.now - 3.hours, Time.now]).all => returns results from slave_2_user_data_development
         
     | 
| 
       106 
106 
     | 
    
         | 
| 
       107 
     | 
    
         
            -
            For a more elegant implementation,  
     | 
| 
      
 107 
     | 
    
         
            +
            For a more elegant implementation, ConnectionManager also add class methods to your main model following the
         
     | 
| 
       108 
108 
     | 
    
         
             
            same naming standard as the subclass creation.
         
     | 
| 
       109 
     | 
    
         
            -
                 
     | 
| 
       110 
     | 
    
         
            -
                User. 
     | 
| 
      
 109 
     | 
    
         
            +
                
         
     | 
| 
      
 110 
     | 
    
         
            +
                User.slave_1.first  => returns results from slave_1_user_data_development 
         
     | 
| 
      
 111 
     | 
    
         
            +
                User.slave_2.where(['created_at BETWEEN ? and ?',Time.now - 3.hours, Time.now]).all  => returns results from slave_2_user_data_development 
         
     | 
| 
       111 
112 
     | 
    
         | 
| 
       112 
     | 
    
         
            -
            Finally  
     | 
| 
      
 113 
     | 
    
         
            +
            Finally, ConnectionManager creates an addional class method that shifts through your 
         
     | 
| 
       113 
114 
     | 
    
         
             
            available slave connections each time it is called using a different connection on each action.
         
     | 
| 
      
 115 
     | 
    
         
            +
                
         
     | 
| 
       114 
116 
     | 
    
         
             
                User.slave.first  => returns results from slave_1_use_data_development 
         
     | 
| 
       115 
117 
     | 
    
         
             
                User.slave.last =>  => returns results from slave_2_use_data_development 
         
     | 
| 
       116 
     | 
    
         
            -
                User.slave.where(['created_at BETWEEN ? and ?',Time.now - 3.hours, Time.now]).all  => returns results from  
     | 
| 
       117 
     | 
    
         
            -
                User.slave.where(['created_at BETWEEN ? and ?',Time.now - 5.days, Time.now]).all  => returns results from  
     | 
| 
      
 118 
     | 
    
         
            +
                User.slave.where(['created_at BETWEEN ? and ?',Time.now - 3.hours, Time.now]).all  => returns results from slave_1_user_data_development 
         
     | 
| 
      
 119 
     | 
    
         
            +
                User.slave.where(['created_at BETWEEN ? and ?',Time.now - 5.days, Time.now]).all  => returns results from slave_2_user_data_development 
         
     | 
| 
       118 
120 
     | 
    
         | 
| 
       119 
121 
     | 
    
         
             
            ## TODO's
         
     | 
| 
       120 
     | 
    
         
            -
            * add more to readme
         
     | 
| 
       121 
     | 
    
         
            -
            * more specs
         
     | 
| 
       122 
122 
     | 
    
         
             
            * sharding
         
     | 
| 
       123 
123 
     | 
    
         | 
| 
       124 
124 
     | 
    
         
             
            ## Other activerecord Connection gems
         
     | 
| 
       125 
125 
     | 
    
         
             
            * [Octopus](https://github.com/tchandy/octopus)
         
     | 
| 
       126 
126 
     | 
    
         | 
| 
       127 
     | 
    
         
            -
            ## Contributing to  
     | 
| 
      
 127 
     | 
    
         
            +
            ## Contributing to ConnectionManager
         
     | 
| 
       128 
128 
     | 
    
         | 
| 
       129 
129 
     | 
    
         
             
            * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
         
     | 
| 
       130 
130 
     | 
    
         
             
            * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
         
     | 
    
        data/connection_manager.gemspec
    CHANGED
    
    | 
         @@ -18,7 +18,9 @@ Gem::Specification.new do |s| 
     | 
|
| 
       18 
18 
     | 
    
         
             
              s.executables   = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
         
     | 
| 
       19 
19 
     | 
    
         
             
              s.require_paths = ["lib"]
         
     | 
| 
       20 
20 
     | 
    
         
             
              s.add_runtime_dependency 'activerecord', '~> 3.0'
         
     | 
| 
      
 21 
     | 
    
         
            +
              s.add_development_dependency 'sqlite3'
         
     | 
| 
       21 
22 
     | 
    
         
             
              s.add_development_dependency 'rspec'
         
     | 
| 
       22 
23 
     | 
    
         
             
              s.add_development_dependency 'autotest'
         
     | 
| 
       23 
24 
     | 
    
         
             
              s.add_development_dependency 'mocha'
         
     | 
| 
      
 25 
     | 
    
         
            +
              s.add_development_dependency 'factory_girl'
         
     | 
| 
       24 
26 
     | 
    
         
             
            end
         
     | 
    
        data/lib/connection_manager.rb
    CHANGED
    
    
| 
         @@ -40,44 +40,49 @@ module ConnectionManager 
     | 
|
| 
       40 
40 
     | 
    
         | 
| 
       41 
41 
     | 
    
         
             
                  # Returns the database value given a connection key from the database.yml
         
     | 
| 
       42 
42 
     | 
    
         
             
                  def database_name_from_yml(name_from_yml)
         
     | 
| 
       43 
     | 
    
         
            -
                    ActiveRecord::Base.configurations[name_from_yml]['database'] 
     | 
| 
      
 43 
     | 
    
         
            +
                    ActiveRecord::Base.configurations[name_from_yml]['database']
         
     | 
| 
       44 
44 
     | 
    
         
             
                  end
         
     | 
| 
       45 
45 
     | 
    
         | 
| 
      
 46 
     | 
    
         
            +
                  def clean_sqlite_db_name(name)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    new_name = "#{name}".gsub(/(\.sqlite3$)/,'')  
         
     | 
| 
      
 48 
     | 
    
         
            +
                    new_name = new_name.split("/").last 
         
     | 
| 
      
 49 
     | 
    
         
            +
                    new_name.gsub!(Regexp.new("(\_#{env}$)"),'')
         
     | 
| 
      
 50 
     | 
    
         
            +
                    new_name
         
     | 
| 
      
 51 
     | 
    
         
            +
                  end
         
     | 
| 
      
 52 
     | 
    
         
            +
                  
         
     | 
| 
      
 53 
     | 
    
         
            +
                  def clean_bd_name(name)
         
     | 
| 
      
 54 
     | 
    
         
            +
                    new_name = "#{name}".gsub(Regexp.new("#{env}$"),'')
         
     | 
| 
      
 55 
     | 
    
         
            +
                    if new_name.blank?
         
     | 
| 
      
 56 
     | 
    
         
            +
                      new_name = "#{database_name_from_yml(name)}"
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end  
         
     | 
| 
      
 58 
     | 
    
         
            +
                    new_name = clean_sqlite_db_name(new_name)
         
     | 
| 
      
 59 
     | 
    
         
            +
                    new_name.gsub(/\_$/,'')
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
                  
         
     | 
| 
       46 
62 
     | 
    
         
             
                  # Given an connection key name from the database.yml, returns the string 
         
     | 
| 
       47 
63 
     | 
    
         
             
                  # equivelent of the class name for that entry.
         
     | 
| 
       48 
64 
     | 
    
         
             
                  def connection_class_name(name_from_yml)
         
     | 
| 
       49 
     | 
    
         
            -
                     
     | 
| 
       50 
     | 
    
         
            -
                    new_class_name = name_from_yml.gsub(Regexp.new("#{env}$"),'')
         
     | 
| 
       51 
     | 
    
         
            -
                    new_class_name = database_name_from_yml(name_from_yml) if new_class_name.blank?
         
     | 
| 
       52 
     | 
    
         
            -
                  
         
     | 
| 
       53 
     | 
    
         
            -
                    #cleanup sqlite database names
         
     | 
| 
       54 
     | 
    
         
            -
                    if new_class_name.gsub!(/(^db\/)|(\.sqlite3$)/,'')  
         
     | 
| 
       55 
     | 
    
         
            -
                      new_class_name.gsub!(Regexp.new("(\\_#{env}$)"),'')
         
     | 
| 
       56 
     | 
    
         
            -
                    end
         
     | 
| 
       57 
     | 
    
         
            -
                  
         
     | 
| 
      
 65 
     | 
    
         
            +
                    new_class_name = clean_bd_name(name_from_yml)  
         
     | 
| 
       58 
66 
     | 
    
         
             
                    new_class_name = new_class_name.gsub(/\_/,' ').titleize.gsub(/ /,'')
         
     | 
| 
       59 
67 
     | 
    
         
             
                    new_class_name << "Connection"
         
     | 
| 
       60 
68 
     | 
    
         
             
                    new_class_name
         
     | 
| 
       61 
69 
     | 
    
         
             
                  end 
         
     | 
| 
       62 
70 
     | 
    
         | 
| 
       63 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                  def replication_key(name_from_yml)
         
     | 
| 
      
 72 
     | 
    
         
            +
                    rep_name = clean_bd_name(name_from_yml)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    rep_name.gsub!(/(\_)+(\d+)/,'')
         
     | 
| 
      
 74 
     | 
    
         
            +
                    rep_name.to_sym   
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
       64 
76 
     | 
    
         | 
| 
       65 
77 
     | 
    
         
             
                  def add_replication_connection(name_from_yml,new_connection)    
         
     | 
| 
       66 
     | 
    
         
            -
                     
     | 
| 
       67 
     | 
    
         
            -
                     
     | 
| 
       68 
     | 
    
         
            -
                     
     | 
| 
       69 
     | 
    
         
            -
                      db_name.gsub!(Regexp.new("(\\_#{env}$)"),'')
         
     | 
| 
       70 
     | 
    
         
            -
                    end
         
     | 
| 
       71 
     | 
    
         
            -
                    rep_name << "_#{db_name}"
         
     | 
| 
       72 
     | 
    
         
            -
                    rep_name = rep_name.to_sym
         
     | 
| 
       73 
     | 
    
         
            -
                    replication_connections[rep_name] ||= []
         
     | 
| 
       74 
     | 
    
         
            -
                    replication_connections[rep_name] << new_connection
         
     | 
| 
      
 78 
     | 
    
         
            +
                    key = replication_key(name_from_yml)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    replication_connections[key] ||= []
         
     | 
| 
      
 80 
     | 
    
         
            +
                    replication_connections[key] << new_connection
         
     | 
| 
       75 
81 
     | 
    
         
             
                    replication_connections
         
     | 
| 
       76 
82 
     | 
    
         
             
                  end
         
     | 
| 
       77 
83 
     | 
    
         | 
| 
       78 
     | 
    
         
            -
                
         
     | 
| 
       79 
84 
     | 
    
         
             
                  def connections_for_replication(rep_collection_key)
         
     | 
| 
       80 
     | 
    
         
            -
                    replication_connections[rep_collection_key.to_sym]
         
     | 
| 
      
 85 
     | 
    
         
            +
                    replication_connections[(rep_collection_key.gsub(Regexp.new("(\_#{env}$)"),'')).to_sym]
         
     | 
| 
       81 
86 
     | 
    
         
             
                  end
         
     | 
| 
       82 
87 
     | 
    
         | 
| 
       83 
88 
     | 
    
         
             
                  # Sets class instance attributes, then builds connection classes, while populating
         
     | 
| 
         @@ -87,11 +92,15 @@ module ConnectionManager 
     | 
|
| 
       87 
92 
     | 
    
         
             
                      send("#{k.to_s}=",v)
         
     | 
| 
       88 
93 
     | 
    
         
             
                    end     
         
     | 
| 
       89 
94 
     | 
    
         
             
                    connection_keys.each do |connection|
         
     | 
| 
       90 
     | 
    
         
            -
                       
     | 
| 
      
 95 
     | 
    
         
            +
                      #puts ActiveRecord::Base.configurations["test"]
         
     | 
| 
      
 96 
     | 
    
         
            +
                      new_connection = connection_class_name(connection)  
         
     | 
| 
      
 97 
     | 
    
         
            +
                      #puts ActiveRecord::Base.configurations["test"]
         
     | 
| 
       91 
98 
     | 
    
         
             
                      add_replication_connection(connection,new_connection)
         
     | 
| 
       92 
     | 
    
         
            -
                       
     | 
| 
      
 99 
     | 
    
         
            +
                      #puts ActiveRecord::Base.configurations["test"]
         
     | 
| 
      
 100 
     | 
    
         
            +
                      build_connection_class(new_connection,connection) 
         
     | 
| 
      
 101 
     | 
    
         
            +
                      #puts ActiveRecord::Base.configurations["test"]
         
     | 
| 
       93 
102 
     | 
    
         
             
                    end
         
     | 
| 
       94 
     | 
    
         
            -
             
     | 
| 
      
 103 
     | 
    
         
            +
                    all
         
     | 
| 
       95 
104 
     | 
    
         
             
                  end 
         
     | 
| 
       96 
105 
     | 
    
         | 
| 
       97 
106 
     | 
    
         
             
                  # Addes a conneciton subclass to AvailableConnections using the supplied
         
     | 
| 
         @@ -1,11 +1,8 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            module ConnectionManager
         
     | 
| 
       2 
2 
     | 
    
         
             
              module ReplicationBuilder
         
     | 
| 
       3 
3 
     | 
    
         | 
| 
       4 
     | 
    
         
            -
                def database_name 
     | 
| 
       5 
     | 
    
         
            -
                   
     | 
| 
       6 
     | 
    
         
            -
                  db_name.gsub!(/(\.sqlite3$)/,'')
         
     | 
| 
       7 
     | 
    
         
            -
                  db_name = db_name.split("/").last
         
     | 
| 
       8 
     | 
    
         
            -
                  db_name
         
     | 
| 
      
 4 
     | 
    
         
            +
                def database_name
         
     | 
| 
      
 5 
     | 
    
         
            +
                  "#{connection.instance_variable_get(:@config)[:database].to_s}"
         
     | 
| 
       9 
6 
     | 
    
         
             
                end
         
     | 
| 
       10 
7 
     | 
    
         | 
| 
       11 
8 
     | 
    
         
             
                def replication_association_options(method,association,class_name,options={})
         
     | 
| 
         @@ -39,12 +36,14 @@ module ConnectionManager 
     | 
|
| 
       39 
36 
     | 
    
         | 
| 
       40 
37 
     | 
    
         
             
                def replication_connection_classes(options)
         
     | 
| 
       41 
38 
     | 
    
         
             
                  if options[:using] && options[:using].is_a?(Array)
         
     | 
| 
       42 
     | 
    
         
            -
                    connection_classes = options[:using]. 
     | 
| 
      
 39 
     | 
    
         
            +
                    connection_classes = options[:using].collect{|c| Connections.connection_class_name(c)}
         
     | 
| 
       43 
40 
     | 
    
         
             
                  else  
         
     | 
| 
       44 
     | 
    
         
            -
                     
     | 
| 
      
 41 
     | 
    
         
            +
                    rep_name = "#{options[:name].to_s}_#{Connections.clean_sqlite_db_name(database_name)}"
         
     | 
| 
      
 42 
     | 
    
         
            +
                    connection_classes = Connections.connections_for_replication(rep_name) 
         
     | 
| 
       45 
43 
     | 
    
         
             
                  end
         
     | 
| 
       46 
44 
     | 
    
         
             
                  connection_classes
         
     | 
| 
       47 
45 
     | 
    
         
             
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
       48 
47 
     | 
    
         | 
| 
       49 
48 
     | 
    
         
             
                # Adds subclass with the class name of the type provided in the options, which 
         
     | 
| 
       50 
49 
     | 
    
         
             
                # defaults to 'slave' if blank, that uses the connection from a connection class.
         
     | 
| 
         @@ -80,8 +79,8 @@ module ConnectionManager 
     | 
|
| 
       80 
79 
     | 
    
         
             
                # overrides the rails "readonly?" method to ensure saves are prevented. 
         
     | 
| 
       81 
80 
     | 
    
         
             
                # Replication class can be called directly for operaitons.
         
     | 
| 
       82 
81 
     | 
    
         
             
                # Usage: 
         
     | 
| 
       83 
     | 
    
         
            -
                # 
     | 
| 
       84 
     | 
    
         
            -
                # 
     | 
| 
      
 82 
     | 
    
         
            +
                #   User::Slave1.where(:id => 1).first => returns results from slave_1 database
         
     | 
| 
      
 83 
     | 
    
         
            +
                #   User::Slave2.where(:id => 2).first => returns results from slave_1 database
         
     | 
| 
       85 
84 
     | 
    
         
             
                def build_replication_class(class_name,connection_name,options)
         
     | 
| 
       86 
85 
     | 
    
         
             
                  class_eval <<-STR, __FILE__, __LINE__
         
     | 
| 
       87 
86 
     | 
    
         
             
                  class #{class_name} < #{self.name}
         
     | 
| 
         @@ -99,8 +98,8 @@ module ConnectionManager 
     | 
|
| 
       99 
98 
     | 
    
         | 
| 
       100 
99 
     | 
    
         
             
                # Adds as class method to call a specific replication conneciton.
         
     | 
| 
       101 
100 
     | 
    
         
             
                # Usage:
         
     | 
| 
       102 
     | 
    
         
            -
                # 
     | 
| 
       103 
     | 
    
         
            -
                # 
     | 
| 
      
 101 
     | 
    
         
            +
                #   User.slave_1.where(:id => 2).first => returns results from slave_1 database
         
     | 
| 
      
 102 
     | 
    
         
            +
                #   User.slave_2.where(:id => 2).first => returns results from slave_2 database
         
     | 
| 
       104 
103 
     | 
    
         
             
                def build_single_replication_method(method_name,class_name)
         
     | 
| 
       105 
104 
     | 
    
         
             
                  class_eval <<-STR, __FILE__, __LINE__
         
     | 
| 
       106 
105 
     | 
    
         
             
                    class << self
         
     | 
| 
         @@ -114,7 +113,7 @@ module ConnectionManager 
     | 
|
| 
       114 
113 
     | 
    
         
             
                # add a class method that shifts through available connections methods
         
     | 
| 
       115 
114 
     | 
    
         
             
                # on each call.
         
     | 
| 
       116 
115 
     | 
    
         
             
                # Usage:
         
     | 
| 
       117 
     | 
    
         
            -
                # 
     | 
| 
      
 116 
     | 
    
         
            +
                #   User.slave.where(:id => 2).first => can return results from slave_1 or slave_2 
         
     | 
| 
       118 
117 
     | 
    
         
             
                def build_full_replication_method(options,connection_methods)
         
     | 
| 
       119 
118 
     | 
    
         
             
                  class_eval <<-STR, __FILE__, __LINE__
         
     | 
| 
       120 
119 
     | 
    
         
             
                  @connection_methods = #{connection_methods}
         
     | 
    
        data/spec/database.yml
    ADDED
    
    | 
         @@ -0,0 +1,20 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            # Warning: The database defined as "test" will be erased and
         
     | 
| 
      
 2 
     | 
    
         
            +
            # re-generated from your development database when you run "rake".
         
     | 
| 
      
 3 
     | 
    
         
            +
            # Do not set this db to the same as development or production.
         
     | 
| 
      
 4 
     | 
    
         
            +
            test:
         
     | 
| 
      
 5 
     | 
    
         
            +
              adapter: sqlite3
         
     | 
| 
      
 6 
     | 
    
         
            +
              database: spec/cm_test.sqlite3
         
     | 
| 
      
 7 
     | 
    
         
            +
              pool: 5
         
     | 
| 
      
 8 
     | 
    
         
            +
              timeout: 5000
         
     | 
| 
      
 9 
     | 
    
         
            +
              
         
     | 
| 
      
 10 
     | 
    
         
            +
            slave_1_cm_test:
         
     | 
| 
      
 11 
     | 
    
         
            +
              adapter: sqlite3
         
     | 
| 
      
 12 
     | 
    
         
            +
              database: spec/cm_test.sqlite3
         
     | 
| 
      
 13 
     | 
    
         
            +
              pool: 5
         
     | 
| 
      
 14 
     | 
    
         
            +
              timeout: 5000
         
     | 
| 
      
 15 
     | 
    
         
            +
              
         
     | 
| 
      
 16 
     | 
    
         
            +
            slave_2_cm_test:
         
     | 
| 
      
 17 
     | 
    
         
            +
              adapter: sqlite3
         
     | 
| 
      
 18 
     | 
    
         
            +
              database: spec/cm_test.sqlite3
         
     | 
| 
      
 19 
     | 
    
         
            +
              pool: 5
         
     | 
| 
      
 20 
     | 
    
         
            +
              timeout: 5000 
         
     | 
    
        data/spec/factories.rb
    ADDED
    
    | 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            FactoryGirl.define do
         
     | 
| 
      
 2 
     | 
    
         
            +
              factory :basket do
         
     | 
| 
      
 3 
     | 
    
         
            +
                name "MyString"
         
     | 
| 
      
 4 
     | 
    
         
            +
              end
         
     | 
| 
      
 5 
     | 
    
         
            +
            end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            FactoryGirl.define do
         
     | 
| 
      
 8 
     | 
    
         
            +
              factory :fruit_basket do
         
     | 
| 
      
 9 
     | 
    
         
            +
                fruit
         
     | 
| 
      
 10 
     | 
    
         
            +
                basket
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
            end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            FactoryGirl.define do
         
     | 
| 
      
 15 
     | 
    
         
            +
              factory :fruit do
         
     | 
| 
      
 16 
     | 
    
         
            +
                name "MyString"
         
     | 
| 
      
 17 
     | 
    
         
            +
                region
         
     | 
| 
      
 18 
     | 
    
         
            +
              end
         
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            FactoryGirl.define do
         
     | 
| 
      
 22 
     | 
    
         
            +
              factory :region do
         
     | 
| 
      
 23 
     | 
    
         
            +
                name "MyString"
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            FactoryGirl.define do
         
     | 
| 
      
 28 
     | 
    
         
            +
              factory :type do
         
     | 
| 
      
 29 
     | 
    
         
            +
                name "MyString"
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,68 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            class TestDB
         
     | 
| 
      
 2 
     | 
    
         
            +
              def self.connect
         
     | 
| 
      
 3 
     | 
    
         
            +
                ActiveRecord::Base.configurations = YAML::load(File.open(File.join(File.dirname(__FILE__),'..','database.yml')))
         
     | 
| 
      
 4 
     | 
    
         
            +
                ActiveRecord::Base.establish_connection('test') 
         
     | 
| 
      
 5 
     | 
    
         
            +
              end
         
     | 
| 
      
 6 
     | 
    
         
            +
              def self.clean
         
     | 
| 
      
 7 
     | 
    
         
            +
                [:foos,:fruits,:baskets,:fruit_baskets,:regions,:types].each do |t|
         
     | 
| 
      
 8 
     | 
    
         
            +
                  DBSpecManagement.connection.execute("DELETE FROM #{t.to_s}")
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
              end
         
     | 
| 
      
 11 
     | 
    
         
            +
              #Class to clean tables
         
     | 
| 
      
 12 
     | 
    
         
            +
              class DBSpecManagement < ActiveRecord::Base
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
            end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            #Put all the test migrations here
         
     | 
| 
      
 18 
     | 
    
         
            +
            class TestMigrations < ActiveRecord::Migration  
         
     | 
| 
      
 19 
     | 
    
         
            +
              
         
     | 
| 
      
 20 
     | 
    
         
            +
              # all the ups
         
     | 
| 
      
 21 
     | 
    
         
            +
              def self.up  
         
     | 
| 
      
 22 
     | 
    
         
            +
                begin
         
     | 
| 
      
 23 
     | 
    
         
            +
                  create_table :foos do |t|
         
     | 
| 
      
 24 
     | 
    
         
            +
                    t.string :name
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end 
         
     | 
| 
      
 26 
     | 
    
         
            +
                  create_table :fruits do |t|
         
     | 
| 
      
 27 
     | 
    
         
            +
                    t.string :name
         
     | 
| 
      
 28 
     | 
    
         
            +
                    t.integer :region_id
         
     | 
| 
      
 29 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                  create_table :baskets do |t|
         
     | 
| 
      
 32 
     | 
    
         
            +
                    t.string :name
         
     | 
| 
      
 33 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  create_table :fruit_baskets do |t|
         
     | 
| 
      
 36 
     | 
    
         
            +
                    t.integer :fruit_id
         
     | 
| 
      
 37 
     | 
    
         
            +
                    t.integer :basket_id
         
     | 
| 
      
 38 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  create_table :regions do |t|
         
     | 
| 
      
 41 
     | 
    
         
            +
                    t.string :name
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
                  create_table :types do |t|
         
     | 
| 
      
 46 
     | 
    
         
            +
                    t.string :name
         
     | 
| 
      
 47 
     | 
    
         
            +
                    t.timestamps
         
     | 
| 
      
 48 
     | 
    
         
            +
                  end
         
     | 
| 
      
 49 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 50 
     | 
    
         
            +
                  puts "tables failed to create: #{e}"
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
              
         
     | 
| 
      
 53 
     | 
    
         
            +
              end
         
     | 
| 
      
 54 
     | 
    
         
            +
              
         
     | 
| 
      
 55 
     | 
    
         
            +
             
         
     | 
| 
      
 56 
     | 
    
         
            +
              # all the downs
         
     | 
| 
      
 57 
     | 
    
         
            +
              def self.down 
         
     | 
| 
      
 58 
     | 
    
         
            +
                begin
         
     | 
| 
      
 59 
     | 
    
         
            +
                  [:foos,:fruits,:baskets,:fruit_baskets,:regions,:types].each do |t|
         
     | 
| 
      
 60 
     | 
    
         
            +
                    drop_table t 
         
     | 
| 
      
 61 
     | 
    
         
            +
                  end
         
     | 
| 
      
 62 
     | 
    
         
            +
                rescue => e
         
     | 
| 
      
 63 
     | 
    
         
            +
                  puts "tables were not dropped: #{e}"
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end 
         
     | 
| 
      
 66 
     | 
    
         
            +
              
         
     | 
| 
      
 67 
     | 
    
         
            +
              
         
     | 
| 
      
 68 
     | 
    
         
            +
            end 
         
     |