ar-octopus-master 0.9.2.master → 0.9.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +12 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +46 -0
  5. data/.rubocop_todo.yml +56 -0
  6. data/.travis.yml +25 -0
  7. data/Appraisals +20 -0
  8. data/Gemfile +4 -0
  9. data/README.mkdn +242 -0
  10. data/Rakefile +172 -0
  11. data/TODO.txt +7 -0
  12. data/ar-octopus.gemspec +39 -0
  13. data/gemfiles/rails4.gemfile +7 -0
  14. data/gemfiles/rails41.gemfile +7 -0
  15. data/gemfiles/rails42.gemfile +7 -0
  16. data/gemfiles/rails5.gemfile +7 -0
  17. data/gemfiles/rails51.gemfile +7 -0
  18. data/lib/ar-octopus.rb +1 -0
  19. data/lib/octopus.rb +205 -0
  20. data/lib/octopus/abstract_adapter.rb +33 -0
  21. data/lib/octopus/association.rb +14 -0
  22. data/lib/octopus/association_shard_tracking.rb +74 -0
  23. data/lib/octopus/collection_association.rb +17 -0
  24. data/lib/octopus/collection_proxy.rb +16 -0
  25. data/lib/octopus/exception.rb +4 -0
  26. data/lib/octopus/finder_methods.rb +8 -0
  27. data/lib/octopus/has_and_belongs_to_many_association.rb +9 -0
  28. data/lib/octopus/load_balancing.rb +4 -0
  29. data/lib/octopus/load_balancing/round_robin.rb +20 -0
  30. data/lib/octopus/log_subscriber.rb +26 -0
  31. data/lib/octopus/migration.rb +195 -0
  32. data/lib/octopus/model.rb +223 -0
  33. data/lib/octopus/persistence.rb +45 -0
  34. data/lib/octopus/proxy.rb +346 -0
  35. data/lib/octopus/proxy_config.rb +252 -0
  36. data/lib/octopus/query_cache_for_shards.rb +25 -0
  37. data/lib/octopus/railtie.rb +11 -0
  38. data/lib/octopus/relation_proxy.rb +58 -0
  39. data/lib/octopus/result_patch.rb +19 -0
  40. data/lib/octopus/scope_proxy.rb +68 -0
  41. data/lib/octopus/shard_tracking.rb +46 -0
  42. data/lib/octopus/shard_tracking/attribute.rb +22 -0
  43. data/lib/octopus/shard_tracking/dynamic.rb +11 -0
  44. data/lib/octopus/singular_association.rb +9 -0
  45. data/lib/octopus/slave_group.rb +13 -0
  46. data/lib/octopus/version.rb +3 -0
  47. data/lib/tasks/octopus.rake +16 -0
  48. data/sample_app/.gitignore +4 -0
  49. data/sample_app/.rspec +1 -0
  50. data/sample_app/Gemfile +20 -0
  51. data/sample_app/README +3 -0
  52. data/sample_app/README.rdoc +261 -0
  53. data/sample_app/Rakefile +7 -0
  54. data/sample_app/app/assets/images/rails.png +0 -0
  55. data/sample_app/app/assets/javascripts/application.js +15 -0
  56. data/sample_app/app/assets/stylesheets/application.css +13 -0
  57. data/sample_app/app/controllers/application_controller.rb +4 -0
  58. data/sample_app/app/helpers/application_helper.rb +2 -0
  59. data/sample_app/app/mailers/.gitkeep +0 -0
  60. data/sample_app/app/models/.gitkeep +0 -0
  61. data/sample_app/app/models/item.rb +3 -0
  62. data/sample_app/app/models/user.rb +3 -0
  63. data/sample_app/app/views/layouts/application.html.erb +14 -0
  64. data/sample_app/autotest/discover.rb +2 -0
  65. data/sample_app/config.ru +4 -0
  66. data/sample_app/config/application.rb +62 -0
  67. data/sample_app/config/boot.rb +6 -0
  68. data/sample_app/config/cucumber.yml +8 -0
  69. data/sample_app/config/database.yml +28 -0
  70. data/sample_app/config/environment.rb +5 -0
  71. data/sample_app/config/environments/development.rb +37 -0
  72. data/sample_app/config/environments/production.rb +67 -0
  73. data/sample_app/config/environments/test.rb +37 -0
  74. data/sample_app/config/initializers/backtrace_silencers.rb +7 -0
  75. data/sample_app/config/initializers/inflections.rb +15 -0
  76. data/sample_app/config/initializers/mime_types.rb +5 -0
  77. data/sample_app/config/initializers/secret_token.rb +7 -0
  78. data/sample_app/config/initializers/session_store.rb +8 -0
  79. data/sample_app/config/initializers/wrap_parameters.rb +14 -0
  80. data/sample_app/config/locales/en.yml +5 -0
  81. data/sample_app/config/routes.rb +58 -0
  82. data/sample_app/config/shards.yml +28 -0
  83. data/sample_app/db/migrate/20100720172715_create_users.rb +15 -0
  84. data/sample_app/db/migrate/20100720172730_create_items.rb +16 -0
  85. data/sample_app/db/migrate/20100720210335_create_sample_users.rb +11 -0
  86. data/sample_app/db/schema.rb +29 -0
  87. data/sample_app/db/seeds.rb +16 -0
  88. data/sample_app/doc/README_FOR_APP +2 -0
  89. data/sample_app/features/migrate.feature +45 -0
  90. data/sample_app/features/seed.feature +15 -0
  91. data/sample_app/features/step_definitions/seeds_steps.rb +13 -0
  92. data/sample_app/features/step_definitions/web_steps.rb +218 -0
  93. data/sample_app/features/support/database.rb +13 -0
  94. data/sample_app/features/support/env.rb +57 -0
  95. data/sample_app/features/support/paths.rb +33 -0
  96. data/sample_app/lib/assets/.gitkeep +0 -0
  97. data/sample_app/lib/tasks/.gitkeep +0 -0
  98. data/sample_app/lib/tasks/cucumber.rake +64 -0
  99. data/sample_app/log/.gitkeep +0 -0
  100. data/sample_app/public/404.html +26 -0
  101. data/sample_app/public/422.html +26 -0
  102. data/sample_app/public/500.html +26 -0
  103. data/sample_app/public/favicon.ico +0 -0
  104. data/sample_app/public/images/rails.png +0 -0
  105. data/sample_app/public/index.html +279 -0
  106. data/sample_app/public/javascripts/application.js +2 -0
  107. data/sample_app/public/javascripts/controls.js +965 -0
  108. data/sample_app/public/javascripts/dragdrop.js +974 -0
  109. data/sample_app/public/javascripts/effects.js +1123 -0
  110. data/sample_app/public/javascripts/prototype.js +4874 -0
  111. data/sample_app/public/javascripts/rails.js +118 -0
  112. data/sample_app/public/robots.txt +5 -0
  113. data/sample_app/public/stylesheets/.gitkeep +0 -0
  114. data/sample_app/script/cucumber +10 -0
  115. data/sample_app/script/rails +6 -0
  116. data/sample_app/spec/models/item_spec.rb +5 -0
  117. data/sample_app/spec/models/user_spec.rb +5 -0
  118. data/sample_app/spec/spec_helper.rb +27 -0
  119. data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
  120. data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
  121. data/sample_app/vendor/plugins/.gitkeep +0 -0
  122. data/spec/config/shards.yml +229 -0
  123. data/spec/migrations/10_create_users_using_replication.rb +9 -0
  124. data/spec/migrations/11_add_field_in_all_slaves.rb +11 -0
  125. data/spec/migrations/12_create_users_using_block.rb +23 -0
  126. data/spec/migrations/13_create_users_using_block_and_using.rb +15 -0
  127. data/spec/migrations/14_create_users_on_shards_of_a_group_with_versions.rb +11 -0
  128. data/spec/migrations/15_create_user_on_shards_of_default_group_with_versions.rb +9 -0
  129. data/spec/migrations/1_create_users_on_master.rb +9 -0
  130. data/spec/migrations/2_create_users_on_canada.rb +11 -0
  131. data/spec/migrations/3_create_users_on_both_shards.rb +11 -0
  132. data/spec/migrations/4_create_users_on_shards_of_a_group.rb +11 -0
  133. data/spec/migrations/5_create_users_on_multiples_groups.rb +11 -0
  134. data/spec/migrations/6_raise_exception_with_invalid_shard_name.rb +11 -0
  135. data/spec/migrations/7_raise_exception_with_invalid_multiple_shard_names.rb +11 -0
  136. data/spec/migrations/8_raise_exception_with_invalid_group_name.rb +11 -0
  137. data/spec/migrations/9_raise_exception_with_multiple_invalid_group_names.rb +11 -0
  138. data/spec/octopus/association_shard_tracking_spec.rb +1036 -0
  139. data/spec/octopus/collection_proxy_spec.rb +16 -0
  140. data/spec/octopus/load_balancing/round_robin_spec.rb +15 -0
  141. data/spec/octopus/log_subscriber_spec.rb +19 -0
  142. data/spec/octopus/migration_spec.rb +134 -0
  143. data/spec/octopus/model_spec.rb +754 -0
  144. data/spec/octopus/octopus_spec.rb +123 -0
  145. data/spec/octopus/proxy_spec.rb +303 -0
  146. data/spec/octopus/query_cache_for_shards_spec.rb +17 -0
  147. data/spec/octopus/relation_proxy_spec.rb +124 -0
  148. data/spec/octopus/replicated_slave_grouped_spec.rb +91 -0
  149. data/spec/octopus/replication_spec.rb +196 -0
  150. data/spec/octopus/scope_proxy_spec.rb +97 -0
  151. data/spec/octopus/sharded_replicated_slave_grouped_spec.rb +55 -0
  152. data/spec/octopus/sharded_spec.rb +33 -0
  153. data/spec/spec_helper.rb +18 -0
  154. data/spec/support/active_record/connection_adapters/modify_config_adapter.rb +15 -0
  155. data/spec/support/database_connection.rb +4 -0
  156. data/spec/support/database_models.rb +118 -0
  157. data/spec/support/octopus_helper.rb +54 -0
  158. data/spec/support/query_count.rb +17 -0
  159. data/spec/support/shared_contexts.rb +18 -0
  160. data/spec/tasks/octopus.rake_spec.rb +32 -0
  161. metadata +203 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 90128c0d3c70bd64dd94a0c0504960108bcbbc44ba8ec59e8ee3038365fed47e
4
- data.tar.gz: 3488a3f52cf254d975089ca2d3b2917adda205347465e0725808ece57f815214
3
+ metadata.gz: 2421cdd815a51011a855ac9ee1a72638b4553687f0220ba9c07440de7f8ec60a
4
+ data.tar.gz: ba7c1b67fd42d7e43e90583048cd6192467b6bc3294a8a03c141c992229f14df
5
5
  SHA512:
6
- metadata.gz: 3ca096422e84aace7054a2d92f466ea2727693afcb65e1cfb53bc369e8e3fd2663eb524ed4571e74369e5feeb0360787f565c5be0bfa4c5f7efa41e3a02193be
7
- data.tar.gz: 3f5af63f96283c8ae0e399e5aff245bac1b1b344117aea0749cbc65144e4b7e01f4b5e75879d36b4eb4125b63c1e2c2be1e1cf4926ae3457e51244c514f97550
6
+ metadata.gz: 235e52a3970cb65e936349fe3771fa75e644fbabcc13d18de7dc14dec5111e56834bc0e08deff282d3b42e8ba4351f73a35f6b6f129307bd81188b45e18649a1
7
+ data.tar.gz: 87352848295d5ac01ea82af8e9a78d22aabbf4de56023a6cd6b17475df411ab225549aafbce08c4cca634f768c420fc0171f7d3f86b3170e2717e54827eeb13d
@@ -0,0 +1,12 @@
1
+ *.gem
2
+ *.sqlite3
3
+ .bundle
4
+ .rvmrc
5
+ .ruby-version
6
+ Gemfile.lock
7
+ gemfiles/*.lock
8
+ pkg/*
9
+ *.rbc
10
+ tmp/*
11
+ .*.sw[a-z]
12
+ database.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format=documentation
@@ -0,0 +1,46 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ ActionFilter:
4
+ EnforcedStyle: filter
5
+
6
+ CaseIndentation:
7
+ IndentWhenRelativeTo: end
8
+
9
+ CollectionMethods:
10
+ PreferredMethods:
11
+ find: detect
12
+
13
+ EmptyLineBetweenDefs:
14
+ AllowAdjacentOneLineDefs: true
15
+
16
+ Encoding:
17
+ Enabled: false
18
+
19
+ EndAlignment:
20
+ AlignWith: variable
21
+
22
+ HashSyntax:
23
+ EnforcedStyle: hash_rockets
24
+
25
+ Style/IndentHash:
26
+ EnforcedStyle: consistent
27
+
28
+ Loop:
29
+ Enabled: false
30
+
31
+ PredicateName:
32
+ Enabled: false
33
+
34
+ RegexpLiteral:
35
+ Enabled: false
36
+
37
+ Semicolon:
38
+ AllowAsExpressionSeparator: true
39
+
40
+ Style/TrailingComma:
41
+ EnforcedStyleForMultiline: comma
42
+
43
+ Style/TrivialAccessors:
44
+ AllowDSLWriters: true
45
+ AllowPredicates: true
46
+ ExactNameMatch: true
@@ -0,0 +1,56 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2014-09-25 20:13:18 -0700 using RuboCop version 0.26.1.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 27
9
+ Lint/AmbiguousRegexpLiteral:
10
+ Enabled: false
11
+
12
+ # Offense count: 1
13
+ Lint/HandleExceptions:
14
+ Enabled: false
15
+
16
+ # Offense count: 1
17
+ # Configuration parameters: CountComments.
18
+ Metrics/ClassLength:
19
+ Max: 324
20
+
21
+ # Offense count: 3
22
+ Metrics/CyclomaticComplexity:
23
+ Max: 14
24
+
25
+ # Offense count: 300
26
+ # Configuration parameters: AllowURI, URISchemes.
27
+ Metrics/LineLength:
28
+ Max: 180
29
+
30
+ # Offense count: 10
31
+ # Configuration parameters: CountComments.
32
+ Metrics/MethodLength:
33
+ Max: 52
34
+
35
+ # Offense count: 3
36
+ Metrics/PerceivedComplexity:
37
+ Max: 15
38
+
39
+ # Offense count: 80
40
+ Style/Documentation:
41
+ Enabled: false
42
+
43
+ # Offense count: 1
44
+ # Configuration parameters: Exclude.
45
+ Style/FileName:
46
+ Enabled: false
47
+
48
+ # Offense count: 1
49
+ # Configuration parameters: MinBodyLength.
50
+ Style/GuardClause:
51
+ Enabled: false
52
+
53
+ # Offense count: 2
54
+ # Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles.
55
+ Style/Next:
56
+ Enabled: false
@@ -0,0 +1,25 @@
1
+ language: ruby
2
+ env:
3
+ - CI=true
4
+ before_script:
5
+ - "bundle exec rake db:prepare"
6
+ rvm:
7
+ - 2.2.7
8
+ - 2.3.4
9
+ - 2.4.1
10
+ gemfile:
11
+ - gemfiles/rails4.gemfile
12
+ - gemfiles/rails41.gemfile
13
+ - gemfiles/rails42.gemfile
14
+ - gemfiles/rails5.gemfile
15
+ - gemfiles/rails51.gemfile
16
+ notifications:
17
+ recipients:
18
+ - gabriel.sobrinho@gmail.com
19
+ - thiago.pradi@gmail.com
20
+ matrix:
21
+ exclude:
22
+ - rvm: 2.4.1
23
+ gemfile: gemfiles/rails4.gemfile
24
+ - rvm: 2.4.1
25
+ gemfile: gemfiles/rails41.gemfile
@@ -0,0 +1,20 @@
1
+ appraise "rails4" do
2
+ gem "activerecord", "~> 4.0.0"
3
+ end
4
+
5
+ appraise "rails41" do
6
+ gem "activerecord", "~> 4.1.0"
7
+ end
8
+
9
+ appraise "rails42" do
10
+ gem "activerecord", "~> 4.2.0"
11
+ end
12
+
13
+ appraise "rails5" do
14
+ gem "activerecord", "~> 5.0.0"
15
+ end
16
+
17
+ appraise "rails51" do
18
+ gem "activerecord", "~> 5.1.0"
19
+ end
20
+ # vim: ft=ruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ar-octopus.gemspec
4
+ gemspec
@@ -0,0 +1,242 @@
1
+ # Octopus - Easy Database Sharding for ActiveRecord
2
+
3
+ <a href='http://www.pledgie.com/campaigns/20950'><img alt='Click here to lend your support to: Octopus and make a donation at www.pledgie.com !' src='http://www.pledgie.com/campaigns/20950.png?skin_name=chrome' border='0' /></a> [![Build Status](https://travis-ci.org/thiagopradi/octopus.svg)](https://travis-ci.org/thiagopradi/octopus) [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/thiagopradi/octopus)
4
+
5
+ Octopus is a better way to do Database Sharding in ActiveRecord. Sharding allows multiple databases in the same rails application. While there are several projects that implement Sharding (e.g. DbCharmer, DataFabric, MultiDb), each project has its own limitations. The main goal of octopus project is to provide a better way of doing Database Sharding.
6
+
7
+ ## Feature list:
8
+ The api is designed to be simple as possible. Octopus focuses on the end user, giving the power of multiple databases but with reliable code and flexibility. Octopus is compatible with Rails 4 and Rails 5.
9
+
10
+ Octopus supports:
11
+
12
+ - Sharding (with multiple shards, and grouped shards).
13
+ - Replication (Master/slave support, with multiple slaves).
14
+ - Moving data between shards with migrations.
15
+ - Tools to manage database configurations. (soon)
16
+
17
+ ### Replication
18
+ When using replication, all writes queries will be sent to master, and read queries to slaves. More info could be found at: <a href="http://wiki.github.com/thiagopradi/octopus/replication"> Wiki</a>
19
+
20
+ ### Sharding
21
+ When using sharding, you need to specify which shard to send the query. Octopus supports selecting the shard inside a controller, or manually in each object. More could be found at <a href="http://wiki.github.com/thiagopradi/octopus/sharding"> Wiki</a>
22
+
23
+ ### Replication + Sharding
24
+ When using replication and sharding concurrently, you must specify a shard, and can optionally specify a <a href="https://github.com/thiagopradi/octopus/wiki/Slave-Groups">slave group</a>.
25
+ All write queries will be sent to each shard's master. If the slave group is specified read queries will be sent to slaves in it, or else to shard's master.
26
+ More info could be found at <a href="https://github.com/thiagopradi/octopus/wiki/Slave-Groups"> Wiki</a>
27
+
28
+ ## Install
29
+
30
+ Add this line to Gemfile:
31
+
32
+ ```
33
+ gem 'ar-octopus'
34
+ ```
35
+
36
+ Currently, Octopus doesn't support Rails 2. If you need support for rails 2, please use the version 0.5.0.
37
+
38
+ ## Upgrading
39
+
40
+ ### From < 0.5.0
41
+
42
+ Octopus < 0.5.0 stored schema version information in the master database defined in the database.yml file, and assumed
43
+ that each shard's schema matched the others and the master database. Beginning with Octopus 0.5.0, the schema version
44
+ information for each shard is stored within that shard's database.
45
+
46
+ If you are upgrading from < 0.5.0 run the `copy_schema_versions` rake task to copy the schema version information in the
47
+ master database to each of the shards:
48
+
49
+ ```bash
50
+ rake octopus:copy_schema_versions
51
+ ```
52
+
53
+ Once the task completes migrations will operate normally and schema information will be stored in each shard database
54
+ going forward.
55
+
56
+ ## How to use Octopus?
57
+
58
+ First, you need to create a config file, shards.yml, inside your config/ directory. to see the syntax and how this file should look, please checkout <a href="http://wiki.github.com/thiagopradi/octopus/config-file">this page on wiki</a>.
59
+
60
+ ### Syntax
61
+
62
+ Octopus adds a method to each AR Class and object: the using method is used to select the shard like this:
63
+
64
+ ```ruby
65
+ User.where(:name => "Boba").limit(3).using(:slave_one)
66
+ ```
67
+
68
+ Octopus also supports queries within a block. When you pass a block to the using method, all queries inside the block will be sent to the specified shard.
69
+
70
+ ```ruby
71
+ Octopus.using(:slave_two) do
72
+ User.create(:name => "Thiago")
73
+ end
74
+ ```
75
+
76
+ If you want to use the same code for all shards or all shards in a specific group (for example in `db/seeds.rb`), you can use this syntax.
77
+
78
+ ```ruby
79
+ # This will return a list of the given block's results, per shard.
80
+ Octopus.using_all do
81
+ User.create_from_csv!
82
+ end
83
+
84
+ # This will return a list of the given block's results, per shard in history_shards group.
85
+ Octopus.using_group(:history_shards) do
86
+ HistoryCategory.create_from_csv!
87
+ end
88
+ ```
89
+
90
+ Each model instance knows which shard it came from so this will work automatically:
91
+
92
+ ```ruby
93
+ # This will find the user in the shard1
94
+ @user = User.using(:shard1).find_by_name("Joao")
95
+
96
+ # This will find the user in the master database
97
+ @user2 = User.find_by_name("Jose")
98
+
99
+ #Sets the name
100
+ @user.name = "Mike"
101
+
102
+ # Save the user in the correct shard, shard1.
103
+ @user.save
104
+ ```
105
+
106
+ ### Migrations
107
+
108
+ In migrations, you also have access to the using method. The syntax is basically the same. This migration will run in the brazil and canada shards.
109
+
110
+ ```ruby
111
+ class CreateUsersOnBothShards < ActiveRecord::Migration
112
+ using(:brazil, :canada)
113
+
114
+ def self.up
115
+ User.create!(:name => "Both")
116
+ end
117
+
118
+ def self.down
119
+ User.delete_all
120
+ end
121
+ end
122
+ ```
123
+
124
+ You also could send a migration to a group of shards. This migration will be sent to all shards that belongs to history_shards group, specified in shards.yml:
125
+
126
+ ```ruby
127
+ class CreateUsersOnMultiplesGroups < ActiveRecord::Migration
128
+ using_group(:history_shards)
129
+
130
+ def self.up
131
+ User.create!(:name => "MultipleGroup")
132
+ end
133
+
134
+ def self.down
135
+ User.delete_all
136
+ end
137
+ end
138
+ ```
139
+
140
+ You can specify a `default_migration_group` for migrations, so that modifications to each individual migration file are not needed:
141
+ ```yaml
142
+ octopus:
143
+ default_migration_group: europe_databases
144
+ ```
145
+
146
+ There is no need for a corresponding `default_migration_shard` - simply define that database to be your master. You might want this setting if all of your databases have identical schemas, but are not replicated.
147
+
148
+ You can configure a master shard for the rails application, to connect to when rails is going up. The safest would be to configure this to the shard specified in `database.yml` (some things still use it).
149
+
150
+ ```yaml
151
+ octopus:
152
+ master_shard: <%= ENV['SHARD'] || 'shard1' %>
153
+ ```
154
+
155
+ Then you can use the `SHARD` environment variable to override the `master_shard` specified in `config/shards.yml`, useful for running rake tasks.
156
+
157
+ ```bash
158
+ SHARD=shard1 rake db:setup && SHARD=shard2 rake db:setup
159
+ ```
160
+
161
+ ### Rails Controllers
162
+
163
+ If you want to send a specified action, or all actions from a controller, to a specific shard, use this syntax:
164
+
165
+ ```ruby
166
+ class ApplicationController < ActionController::Base
167
+ around_filter :select_shard
168
+
169
+ def select_shard(&block)
170
+ Octopus.using(:brazil, &block)
171
+ end
172
+ end
173
+ ```
174
+
175
+ To see the complete list of features and syntax, please check out our <a href="http://wiki.github.com/thiagopradi/octopus/"> Wiki</a>
176
+ Want to see sample rails applications using octopus features? please check it out: <a href="http://github.com/thiagopradi/octopus_sharding_example">Sharding Example</a> and <a href="http://github.com/thiagopradi/octopus_replication_example">Replication Example</a>. Also, we have an example that shows how to use Octopus without Rails: <a href="http://github.com/thiagopradi/octopus_sinatra"> Octopus + Sinatra Example</a>.
177
+
178
+ ## Mixing Octopus with the Rails multiple database model
179
+ If you want to set a custom connection to a specific model, use the syntax `octopus_establish_connection` syntax:
180
+
181
+ ```ruby
182
+ #This class sets its own connection
183
+ class CustomConnection < ActiveRecord::Base
184
+ octopus_establish_connection(:adapter => "mysql", :database => "octopus_shard2")
185
+ end
186
+ ```
187
+
188
+ ### allow_shard
189
+ If you'd like to use specific shards with a model that has a Rails-managed connection, you can use `allow_shard`:
190
+
191
+ ```ruby
192
+ class CustomConnectedModel
193
+ octopus_establish_connection(...)
194
+ allow_shard :my_shard
195
+ end
196
+
197
+ #This uses :my_shard
198
+ CustomConnectedModel.using(:my_shard).first
199
+
200
+ #This uses the Rails-managed connection pool (the call to 'using' is ignored)
201
+ CustomConnectedModel.using(:some_other_shard).first
202
+ ```
203
+
204
+ This can be useful if you have a model that lives in a separate database and would like to add sharding or replication to it. For other use cases, you may be better off with <a href="https://github.com/thiagopradi/octopus/wiki/Slave-Groups">slave groups</a>.
205
+
206
+ ## Contributing with Octopus
207
+ Contributors are welcome! To run the test suite, you need mysql, postgresql and sqlite3 installed. This is what you need to setup your Octopus development environment:
208
+
209
+ ```bash
210
+ git clone http://github.com/thiagopradi/octopus.git
211
+ cd octopus
212
+ bundle install
213
+ bundle exec rake db:prepare
214
+ bundle exec rake appraisal:install
215
+ bundle exec rake spec
216
+ ```
217
+
218
+ This command will run the spec suite for all rails versions supported.
219
+ To run our integrations tests inside sample_app, you need to following commands:
220
+
221
+ ```bash
222
+ cd sample_app
223
+ bundle install
224
+ cucumber
225
+ ```
226
+
227
+ If you are having issues running the octopus spec suite, verify your database users and passwords match those inside the config files and your permissions are correct.
228
+
229
+ ## Contributors:
230
+ - <a href="https://github.com/thiagopradi/octopus/contributors">All Contributors</a>
231
+
232
+ ## Mailing List:
233
+ - <a href="http://groups.google.com/group/octopus-activerecord/">Octopus Mailing List</a>
234
+
235
+ ## Thanks
236
+
237
+ This project is sponsored by the <a href="http://www.rubysoc.org">Ruby Summer of Code</a>, Rapid River Software,
238
+ and my mentors <a href="http://github.com/mperham">Mike Perham</a> and <a href="http://github.com/amitagarwal">Amit Agarwal</a>.
239
+
240
+ ## Copyright
241
+
242
+ Copyright (c) Thiago Pradi, released under the MIT license.
@@ -0,0 +1,172 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+ require 'appraisal'
5
+
6
+ RSpec::Core::RakeTask.new
7
+ RuboCop::RakeTask.new
8
+
9
+ task :default => [:spec]
10
+
11
+ namespace :db do
12
+ desc 'Build the databases for tests'
13
+ task :build_databases do
14
+ pg_spec = {
15
+ :adapter => 'postgresql',
16
+ :host => 'localhost',
17
+ :username => (ENV['POSTGRES_USER'] || 'postgres'),
18
+ :encoding => 'utf8',
19
+ }
20
+
21
+ mysql_spec = {
22
+ :adapter => 'mysql2',
23
+ :host => 'localhost',
24
+ :username => (ENV['MYSQL_USER'] || 'root'),
25
+ :encoding => 'utf8',
26
+ }
27
+
28
+ ` rm -f /tmp/database.sqlite3 `
29
+
30
+ require 'active_record'
31
+
32
+ # Connects to PostgreSQL
33
+ ActiveRecord::Base.establish_connection(pg_spec.merge('database' => 'postgres', 'schema_search_path' => 'public'))
34
+ (1..2).map do |i|
35
+ # drop the old database (if it exists)
36
+ ActiveRecord::Base.connection.drop_database("octopus_shard_#{i}")
37
+ # create new database
38
+ ActiveRecord::Base.connection.create_database("octopus_shard_#{i}")
39
+ end
40
+
41
+ # Connect to MYSQL
42
+ ActiveRecord::Base.establish_connection(mysql_spec)
43
+ (1..5).map do |i|
44
+ # drop the old database (if it exists)
45
+ ActiveRecord::Base.connection.drop_database("octopus_shard_#{i}")
46
+ # create new database
47
+ ActiveRecord::Base.connection.create_database("octopus_shard_#{i}")
48
+ end
49
+ end
50
+
51
+ desc 'Create tables on tests databases'
52
+ task :create_tables do
53
+ require 'octopus'
54
+ # Set the octopus variable directory to spec dir, in order to load the config/shards.yml file.
55
+ Octopus.instance_variable_set(:@directory, "#{File.dirname(__FILE__)}/spec/")
56
+
57
+ # Require the database connection
58
+ require "#{File.dirname(__FILE__)}/spec/support/database_connection"
59
+
60
+ shard_symbols = [:master, :brazil, :canada, :russia, :alone_shard, :postgresql_shard, :sqlite_shard]
61
+ shard_symbols << :protocol_shard
62
+ shard_symbols.each do |shard_symbol|
63
+ # Rails 3.1 needs to do some introspection around the base class, which requires
64
+ # the model be a descendent of ActiveRecord::Base.
65
+ class BlankModel < ActiveRecord::Base; end
66
+
67
+ BlankModel.using(shard_symbol).connection.initialize_schema_migrations_table
68
+
69
+ BlankModel.using(shard_symbol).connection.create_table(:users) do |u|
70
+ u.string :name
71
+ u.integer :number
72
+ u.boolean :admin
73
+ u.datetime :created_at
74
+ u.datetime :updated_at
75
+ end
76
+
77
+ BlankModel.using(shard_symbol).connection.create_table(:clients) do |u|
78
+ u.string :country
79
+ u.string :name
80
+ end
81
+
82
+ BlankModel.using(shard_symbol).connection.create_table(:cats) do |u|
83
+ u.string :name
84
+ end
85
+
86
+ BlankModel.using(shard_symbol).connection.create_table(:items) do |u|
87
+ u.string :name
88
+ u.integer :client_id
89
+ end
90
+
91
+ BlankModel.using(shard_symbol).connection.create_table(:computers) do |u|
92
+ u.string :name
93
+ end
94
+
95
+ BlankModel.using(shard_symbol).connection.create_table(:keyboards) do |u|
96
+ u.string :name
97
+ u.integer :computer_id
98
+ end
99
+
100
+ BlankModel.using(shard_symbol).connection.create_table(:roles) do |u|
101
+ u.string :name
102
+ end
103
+
104
+ BlankModel.using(shard_symbol).connection.create_table(:permissions) do |u|
105
+ u.string :name
106
+ end
107
+
108
+ BlankModel.using(shard_symbol).connection.create_table(:permissions_roles, :id => false) do |u|
109
+ u.integer :role_id
110
+ u.integer :permission_id
111
+ end
112
+
113
+ BlankModel.using(shard_symbol).connection.create_table(:assignments) do |u|
114
+ u.integer :programmer_id
115
+ u.integer :project_id
116
+ end
117
+
118
+ BlankModel.using(shard_symbol).connection.create_table(:programmers) do |u|
119
+ u.string :name
120
+ end
121
+
122
+ BlankModel.using(shard_symbol).connection.create_table(:projects) do |u|
123
+ u.string :name
124
+ end
125
+
126
+ BlankModel.using(shard_symbol).connection.create_table(:comments) do |u|
127
+ u.string :name
128
+ u.string :commentable_type
129
+ u.integer :commentable_id
130
+ u.boolean :open, default: false
131
+ end
132
+
133
+ BlankModel.using(shard_symbol).connection.create_table(:parts) do |u|
134
+ u.string :name
135
+ u.integer :item_id
136
+ end
137
+
138
+ BlankModel.using(shard_symbol).connection.create_table(:yummy) do |u|
139
+ u.string :name
140
+ end
141
+
142
+ BlankModel.using(shard_symbol).connection.create_table(:adverts) do |u|
143
+ u.string :name
144
+ end
145
+
146
+ BlankModel.using(shard_symbol).connection.create_table(:custom) do |u|
147
+ u.string :value
148
+ end
149
+
150
+ if shard_symbol == :alone_shard
151
+ BlankModel.using(shard_symbol).connection.create_table(:mmorpg_players) do |u|
152
+ u.string :player_name
153
+ end
154
+
155
+ BlankModel.using(shard_symbol).connection.create_table(:weapons) do |u|
156
+ u.integer :mmorpg_player_id
157
+ u.string :name
158
+ u.string :hand
159
+ end
160
+
161
+ BlankModel.using(shard_symbol).connection.create_table(:skills) do |u|
162
+ u.integer :mmorpg_player_id
163
+ u.integer :weapon_id
164
+ u.string :name
165
+ end
166
+ end
167
+ end
168
+ end
169
+
170
+ desc 'Prepare the test databases'
171
+ task :prepare => [:build_databases, :create_tables]
172
+ end