activerecord-turntable 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/.document +5 -0
  2. data/.gitignore +25 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +25 -0
  5. data/Guardfile +9 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.rdoc +290 -0
  8. data/Rakefile +101 -0
  9. data/activerecord-turntable.gemspec +47 -0
  10. data/lib/active_record/turntable.rb +58 -0
  11. data/lib/active_record/turntable/active_record_ext.rb +26 -0
  12. data/lib/active_record/turntable/active_record_ext/.gitkeep +0 -0
  13. data/lib/active_record/turntable/active_record_ext/abstract_adapter.rb +50 -0
  14. data/lib/active_record/turntable/active_record_ext/clever_load.rb +90 -0
  15. data/lib/active_record/turntable/active_record_ext/fixtures.rb +131 -0
  16. data/lib/active_record/turntable/active_record_ext/log_subscriber.rb +64 -0
  17. data/lib/active_record/turntable/active_record_ext/persistence.rb +95 -0
  18. data/lib/active_record/turntable/active_record_ext/schema_dumper.rb +107 -0
  19. data/lib/active_record/turntable/active_record_ext/sequencer.rb +28 -0
  20. data/lib/active_record/turntable/active_record_ext/transactions.rb +33 -0
  21. data/lib/active_record/turntable/algorithm.rb +7 -0
  22. data/lib/active_record/turntable/algorithm/.gitkeep +0 -0
  23. data/lib/active_record/turntable/algorithm/base.rb +11 -0
  24. data/lib/active_record/turntable/algorithm/range_algorithm.rb +37 -0
  25. data/lib/active_record/turntable/algorithm/range_bsearch_algorithm.rb +41 -0
  26. data/lib/active_record/turntable/base.rb +130 -0
  27. data/lib/active_record/turntable/cluster.rb +70 -0
  28. data/lib/active_record/turntable/compatible.rb +19 -0
  29. data/lib/active_record/turntable/config.rb +24 -0
  30. data/lib/active_record/turntable/connection_proxy.rb +218 -0
  31. data/lib/active_record/turntable/connection_proxy/mixable.rb +39 -0
  32. data/lib/active_record/turntable/error.rb +8 -0
  33. data/lib/active_record/turntable/helpers.rb +5 -0
  34. data/lib/active_record/turntable/helpers/test_helper.rb +25 -0
  35. data/lib/active_record/turntable/master_shard.rb +28 -0
  36. data/lib/active_record/turntable/migration.rb +132 -0
  37. data/lib/active_record/turntable/mixer.rb +203 -0
  38. data/lib/active_record/turntable/mixer/fader.rb +34 -0
  39. data/lib/active_record/turntable/mixer/fader/calculate_shards_sum_result.rb +15 -0
  40. data/lib/active_record/turntable/mixer/fader/insert_shards_merge_result.rb +24 -0
  41. data/lib/active_record/turntable/mixer/fader/select_shards_merge_result.rb +22 -0
  42. data/lib/active_record/turntable/mixer/fader/specified_shard.rb +12 -0
  43. data/lib/active_record/turntable/mixer/fader/update_shards_merge_result.rb +17 -0
  44. data/lib/active_record/turntable/pool_proxy.rb +56 -0
  45. data/lib/active_record/turntable/rack.rb +5 -0
  46. data/lib/active_record/turntable/rack/connection_management.rb +18 -0
  47. data/lib/active_record/turntable/railtie.rb +14 -0
  48. data/lib/active_record/turntable/railties/databases.rake +205 -0
  49. data/lib/active_record/turntable/seq_shard.rb +14 -0
  50. data/lib/active_record/turntable/sequencer.rb +46 -0
  51. data/lib/active_record/turntable/sequencer/api.rb +36 -0
  52. data/lib/active_record/turntable/sequencer/mysql.rb +32 -0
  53. data/lib/active_record/turntable/shard.rb +48 -0
  54. data/lib/active_record/turntable/sql_tree_patch.rb +199 -0
  55. data/lib/active_record/turntable/version.rb +5 -0
  56. data/lib/activerecord-turntable.rb +2 -0
  57. data/lib/generators/active_record/turntable/install_generator.rb +14 -0
  58. data/lib/generators/templates/turntable.yml +40 -0
  59. data/sample_app/.gitignore +16 -0
  60. data/sample_app/Gemfile +41 -0
  61. data/sample_app/README.rdoc +261 -0
  62. data/sample_app/Rakefile +7 -0
  63. data/sample_app/app/assets/images/rails.png +0 -0
  64. data/sample_app/app/assets/javascripts/application.js +15 -0
  65. data/sample_app/app/assets/stylesheets/application.css +13 -0
  66. data/sample_app/app/controllers/application_controller.rb +3 -0
  67. data/sample_app/app/helpers/application_helper.rb +2 -0
  68. data/sample_app/app/mailers/.gitkeep +0 -0
  69. data/sample_app/app/models/.gitkeep +0 -0
  70. data/sample_app/app/models/user.rb +4 -0
  71. data/sample_app/app/views/layouts/application.html.erb +14 -0
  72. data/sample_app/config.ru +4 -0
  73. data/sample_app/config/application.rb +65 -0
  74. data/sample_app/config/boot.rb +6 -0
  75. data/sample_app/config/database.yml +70 -0
  76. data/sample_app/config/environment.rb +5 -0
  77. data/sample_app/config/environments/development.rb +37 -0
  78. data/sample_app/config/environments/production.rb +67 -0
  79. data/sample_app/config/environments/test.rb +37 -0
  80. data/sample_app/config/initializers/backtrace_silencers.rb +7 -0
  81. data/sample_app/config/initializers/inflections.rb +15 -0
  82. data/sample_app/config/initializers/mime_types.rb +5 -0
  83. data/sample_app/config/initializers/secret_token.rb +7 -0
  84. data/sample_app/config/initializers/session_store.rb +8 -0
  85. data/sample_app/config/initializers/wrap_parameters.rb +14 -0
  86. data/sample_app/config/locales/en.yml +5 -0
  87. data/sample_app/config/routes.rb +58 -0
  88. data/sample_app/config/turntable.yml +64 -0
  89. data/sample_app/db/migrate/20120316073058_create_users.rb +11 -0
  90. data/sample_app/db/seeds.rb +7 -0
  91. data/sample_app/lib/assets/.gitkeep +0 -0
  92. data/sample_app/lib/tasks/.gitkeep +0 -0
  93. data/sample_app/log/.gitkeep +0 -0
  94. data/sample_app/public/404.html +26 -0
  95. data/sample_app/public/422.html +26 -0
  96. data/sample_app/public/500.html +25 -0
  97. data/sample_app/public/favicon.ico +0 -0
  98. data/sample_app/public/index.html +241 -0
  99. data/sample_app/public/robots.txt +5 -0
  100. data/sample_app/script/rails +6 -0
  101. data/sample_app/vendor/assets/javascripts/.gitkeep +0 -0
  102. data/sample_app/vendor/assets/stylesheets/.gitkeep +0 -0
  103. data/sample_app/vendor/plugins/.gitkeep +0 -0
  104. data/script/performance/algorithm +32 -0
  105. data/spec/active_record/turntable/active_record_ext/clever_load_spec.rb +81 -0
  106. data/spec/active_record/turntable/active_record_ext/persistence_spec.rb +151 -0
  107. data/spec/active_record/turntable/algorithm/range_algorithm_spec.rb +35 -0
  108. data/spec/active_record/turntable/algorithm_spec.rb +69 -0
  109. data/spec/active_record/turntable/base_spec.rb +13 -0
  110. data/spec/active_record/turntable/cluster_spec.rb +18 -0
  111. data/spec/active_record/turntable/config_spec.rb +17 -0
  112. data/spec/active_record/turntable/connection_proxy_spec.rb +186 -0
  113. data/spec/active_record/turntable/finder_spec.rb +27 -0
  114. data/spec/active_record/turntable/mixer/fader_spec.rb +4 -0
  115. data/spec/active_record/turntable/mixer_spec.rb +114 -0
  116. data/spec/active_record/turntable/shard_spec.rb +21 -0
  117. data/spec/active_record/turntable_spec.rb +30 -0
  118. data/spec/config/database.yml +45 -0
  119. data/spec/config/turntable.yml +17 -0
  120. data/spec/fabricators/.gitkeep +0 -0
  121. data/spec/fabricators/turntable_fabricator.rb +14 -0
  122. data/spec/migrations/.gitkeep +0 -0
  123. data/spec/migrations/001_create_users.rb +16 -0
  124. data/spec/migrations/002_create_user_statuses.rb +16 -0
  125. data/spec/migrations/003_create_cards.rb +14 -0
  126. data/spec/migrations/004_create_cards_users.rb +15 -0
  127. data/spec/spec_helper.rb +23 -0
  128. data/spec/test_models.rb +27 -0
  129. data/spec/turntable_helper.rb +29 -0
  130. metadata +367 -0
@@ -0,0 +1,17 @@
1
+ module ActiveRecord::Turntable
2
+ class Mixer
3
+ class Fader
4
+ class UpdateShardsMergeResult < Fader
5
+ def execute
6
+ @proxy.shards_transaction(@shards_query_hash.keys) do
7
+ @shards_query_hash.map do |shard, query|
8
+ args = @args.dup
9
+ args[1] = args[1].dup if args[1].present?
10
+ shard.connection.send(@called_method, query, *@args, &@block)
11
+ end.inject(&:+)
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ module ActiveRecord::Turntable
2
+ module ActiveRecordConnectionMethods
3
+ def self.included(base)
4
+ base.alias_method_chain :reload, :master
5
+ end
6
+
7
+ def reload_with_master(*args, &block)
8
+ connection.with_master { reload_without_master }
9
+ end
10
+ end
11
+
12
+ class PoolProxy
13
+ def initialize(proxy)
14
+ @proxy = proxy
15
+ end
16
+
17
+ def connection
18
+ @proxy
19
+ end
20
+
21
+ def spec
22
+ @proxy.spec
23
+ end
24
+
25
+
26
+ def with_connection
27
+ yield @proxy
28
+ end
29
+
30
+ def connected?
31
+ @proxy.connected?
32
+ end
33
+
34
+ if ActiveRecord::VERSION::STRING > '3.1'
35
+ %w(columns_hash column_defaults primary_keys).each do |name|
36
+ define_method(name.to_sym) do
37
+ @proxy.send(name.to_sym)
38
+ end
39
+ end
40
+
41
+ %w(table_exists? columns).each do |name|
42
+ define_method(name.to_sym) do |*args|
43
+ @proxy.send(name.to_sym, *args)
44
+ end
45
+ end
46
+ end
47
+
48
+ %w(disconnect! release_connection clear_all_connections! clear_reloadable_connections! clear_stale_cached_connections! verify_active_connections!).each do |name|
49
+ define_method(name.to_sym) do
50
+ @proxy.shards.values.each do |pool|
51
+ pool.connection_pool.send(name.to_sym)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ module ActiveRecord::Turntable
2
+ module Rack
3
+ autoload :ConnectionManagement, 'active_record/turntable/rack/connection_management'
4
+ end
5
+ end
@@ -0,0 +1,18 @@
1
+ module ActiveRecord::Turntable
2
+ module Rack
3
+ class ConnectionManagement
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ @app.call(env)
10
+ ensure
11
+ unless env.key?("rack.test")
12
+ ActiveRecord::Base.connection_handler.clear_all_connections!
13
+ ActiveRecord::Base.clear_all_connections!
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,14 @@
1
+ module ActiveRecord::Turntable
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load "active_record/turntable/railties/databases.rake"
5
+ end
6
+
7
+ # rails loading hook
8
+ ActiveSupport.on_load(:before_initialize) do
9
+ ActiveSupport.on_load(:active_record) do
10
+ ActiveRecord::Base.send(:include, ActiveRecord::Turntable)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,205 @@
1
+ require 'active_record/turntable'
2
+ ActiveRecord::SchemaDumper.send(:include, ActiveRecord::Turntable::ActiveRecordExt::SchemaDumper)
3
+
4
+ db_namespace = namespace :db do
5
+ task :create do
6
+ if Rails.env.development? && ActiveRecord::Base.configurations['test'] && ActiveRecord::Base.configurations["test"]["shards"]
7
+ dbs = ActiveRecord::Base.configurations["test"]["shards"].values
8
+ dbs += ActiveRecord::Base.configurations["test"]["seq"].values if ActiveRecord::Base.configurations["test"]["seq"]
9
+ dbs.each do |shard_config|
10
+ create_database(shard_config)
11
+ end
12
+ end
13
+ if shard_configs = ActiveRecord::Base.configurations[Rails.env || 'development']["shards"]
14
+ dbs = shard_configs.values
15
+ dbs += ActiveRecord::Base.configurations[Rails.env || 'development']["seq"].values if ActiveRecord::Base.configurations[Rails.env || 'development']["seq"]
16
+ dbs.each do |shard_config|
17
+ create_database(shard_config)
18
+ end
19
+ end
20
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
21
+ ActiveRecord::Base.establish_connection(config)
22
+ end
23
+
24
+ task :drop do
25
+ config = ActiveRecord::Base.configurations[Rails.env || 'development']
26
+ shard_configs = config["shards"]
27
+ if shard_configs
28
+ dbs = shard_configs.values
29
+ dbs += ActiveRecord::Base.configurations[Rails.env || 'development']["seq"].values if ActiveRecord::Base.configurations[Rails.env || 'development']["seq"]
30
+ dbs.each do |shard_config|
31
+ begin
32
+ drop_database(shard_config)
33
+ rescue Exception => e
34
+ $stderr.puts "Couldn't drop #{ config['database']} : #{e.inspect}"
35
+ end
36
+ end
37
+ end
38
+ ActiveRecord::Base.establish_connection(config)
39
+ end
40
+
41
+ namespace :schema do
42
+ task :dump do
43
+ require 'active_record/schema_dumper'
44
+ config = ActiveRecord::Base.configurations[Rails.env]
45
+ shard_configs = config["shards"]
46
+ shard_configs.merge!(config["seq"]) if config["seq"]
47
+ if shard_configs
48
+ shard_configs.each do |name, config|
49
+ filename = ENV['SCHEMA'] || "#{Rails.root}/db/schema-#{name}.rb"
50
+ File.open(filename, "w:utf-8") do |file|
51
+ ActiveRecord::Base.establish_connection(config)
52
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
53
+ end
54
+ end
55
+ end
56
+ ActiveRecord::Base.establish_connection(config)
57
+ db_namespace['schema:dump'].reenable
58
+ end
59
+
60
+ desc 'Load a schema.rb file into the database'
61
+ task :load => :environment do
62
+ config = ActiveRecord::Base.configurations[Rails.env]
63
+ shard_configs = config["shards"]
64
+ shard_configs.merge!(config["seq"]) if config["seq"]
65
+ if shard_configs
66
+ shard_configs.each do |name, config|
67
+ ActiveRecord::Base.establish_connection(config)
68
+ file = ENV['SCHEMA'] || "#{Rails.root}/db/schema-#{name}.rb"
69
+ if File.exists?(file)
70
+ load(file)
71
+ else
72
+ abort %{#{file} doesn't exist yet. Run "rake db:migrate" to create it then try again. If you do not intend to use a database, you should instead alter #{Rails.root}/config/application.rb to limit the frameworks that will be loaded'}
73
+ end
74
+ end
75
+ end
76
+ ActiveRecord::Base.establish_connection(config)
77
+ end
78
+ end
79
+
80
+ namespace :structure do
81
+ desc 'Dump the database structure to an SQL file'
82
+ task :dump => :environment do
83
+ config = ActiveRecord::Base.configurations[Rails.env]
84
+ shard_configs = config["shards"]
85
+ shard_configs.merge!(config["seq"]) if config["seq"]
86
+ if shard_configs
87
+ shard_configs.each do |name, config|
88
+ case config['adapter']
89
+ when /mysql/, 'oci', 'oracle'
90
+ ActiveRecord::Base.establish_connection(config)
91
+ File.open("#{Rails.root}/db/#{Rails.env}_#{name}_structure.sql", "w+") { |f| f << ActiveRecord::Base.connection.structure_dump }
92
+ when /postgresql/
93
+ ENV['PGHOST'] = config['host'] if config['host']
94
+ ENV['PGPORT'] = config["port"].to_s if config['port']
95
+ ENV['PGPASSWORD'] = config['password'].to_s if config['password']
96
+ search_path = config['schema_search_path']
97
+ unless search_path.blank?
98
+ search_path = search_path.split(",").map{|search_path| "--schema=#{search_path.strip}" }.join(" ")
99
+ end
100
+ `pg_dump -i -U "#{config['username']}" -s -x -O -f db/#{Rails.env}_#{name}_structure.sql #{search_path} #{config['database']}`
101
+ raise 'Error dumping database' if $?.exitstatus == 1
102
+ when /sqlite/
103
+ dbfile = config['database'] || config['dbfile']
104
+ `sqlite3 #{dbfile} .schema > db/#{Rails.env}_#{name}_structure.sql`
105
+ when 'sqlserver'
106
+ `smoscript -s #{config['host']} -d #{config['database']} -u #{config['username']} -p #{config['password']} -f db\\#{Rails.env}_#{name}_structure.sql -A -U`
107
+ when "firebird"
108
+ set_firebird_env(config)
109
+ db_string = firebird_db_string(config)
110
+ sh "isql -a #{db_string} > #{Rails.root}/db/#{Rails.env}_#{name}_structure.sql"
111
+ else
112
+ raise "Task not supported by '#{config["adapter"]}'"
113
+ end
114
+
115
+ if ActiveRecord::Base.connection.supports_migrations?
116
+ File.open("#{Rails.root}/db/#{Rails.env}_#{name}_structure.sql", "a") { |f| f << ActiveRecord::Base.connection.dump_schema_information }
117
+ end
118
+ end
119
+ end
120
+ ActiveRecord::Base.establish_connection(config)
121
+ end
122
+ end
123
+
124
+
125
+ namespace :test do
126
+ # desc "Recreate the test databases from the development structure"
127
+ task :clone_structure do
128
+ config = ActiveRecord::Base.configurations[Rails.env]
129
+ shard_configs = config["shards"]
130
+ shard_configs.merge!(config["seq"]) if config["seq"]
131
+ if shard_configs
132
+ shard_configs.each do |name, config|
133
+ case config['adapter']
134
+ when /mysql/
135
+ ActiveRecord::Base.establish_connection(config)
136
+ ActiveRecord::Base.connection.execute('SET foreign_key_checks = 0')
137
+ IO.readlines("#{Rails.root}/db/#{Rails.env}_#{name}_structure.sql").join.split("\n\n").each do |table|
138
+ ActiveRecord::Base.connection.execute(table)
139
+ end
140
+ when /postgresql/
141
+ ENV['PGHOST'] = config['host'] if config['host']
142
+ ENV['PGPORT'] = config['port'].to_s if config['port']
143
+ ENV['PGPASSWORD'] = config['password'].to_s if config['password']
144
+ `psql -U "#{config['username']}" -f "#{Rails.root}/db/#{Rails.env}#{name}_structure.sql" #{config['database']} #{config['template']}`
145
+ when /sqlite/
146
+ dbfile = config['database'] || config['dbfile']
147
+ `sqlite3 #{dbfile} < "#{Rails.root}/db/#{Rails.env}#{name}_structure.sql"`
148
+ when 'sqlserver'
149
+ `sqlcmd -S #{config['host']} -d #{config['database']} -U #{config['username']} -P #{config['password']} -i db\\#{Rails.env}#{name}_structure.sql`
150
+ when 'oci', 'oracle'
151
+ ActiveRecord::Base.establish_connection(config)
152
+ IO.readlines("#{Rails.root}/db/#{Rails.env}#{name}_structure.sql").join.split(";\n\n").each do |ddl|
153
+ ActiveRecord::Base.connection.execute(ddl)
154
+ end
155
+ when 'firebird'
156
+ set_firebird_env(config)
157
+ db_string = firebird_db_string(config)
158
+ sh "isql -i #{Rails.root}/db/#{Rails.env}#{name}_structure.sql #{db_string}"
159
+ else
160
+ raise "Task not supported by '#{config['adapter']}'"
161
+ end
162
+ end
163
+ end
164
+ ActiveRecord::Base.establish_connection(config)
165
+ end
166
+
167
+ # desc "Empty the test database"
168
+ task :purge => :environment do
169
+ config = ActiveRecord::Base.configurations[Rails.env]
170
+ shard_configs = config["shards"]
171
+ shard_configs.merge!(config["seq"]) if config["seq"]
172
+ if shard_configs
173
+ shard_configs.each do |name, config|
174
+ case config['adapter']
175
+ when /mysql/
176
+ ActiveRecord::Base.establish_connection(config)
177
+ ActiveRecord::Base.connection.recreate_database(config['database'], mysql_creation_options(config))
178
+ when /postgresql/
179
+ ActiveRecord::Base.clear_active_connections!
180
+ drop_database(config)
181
+ create_database(config)
182
+ when /sqlite/
183
+ dbfile = config['database'] || config['dbfile']
184
+ File.delete(dbfile) if File.exist?(dbfile)
185
+ when 'sqlserver'
186
+ # TODO
187
+ when "oci", "oracle"
188
+ ActiveRecord::Base.establish_connection(config)
189
+ ActiveRecord::Base.connection.structure_drop.split(";\n\n").each do |ddl|
190
+ ActiveRecord::Base.connection.execute(ddl)
191
+ end
192
+ when 'firebird'
193
+ ActiveRecord::Base.establish_connection(config)
194
+ ActiveRecord::Base.connection.recreate_database!
195
+ else
196
+ raise "Task not supported by '#{config['adapter']}'"
197
+ end
198
+ end
199
+ end
200
+ ActiveRecord::Base.establish_connection(config)
201
+ end
202
+ end
203
+
204
+ end
205
+
@@ -0,0 +1,14 @@
1
+ module ActiveRecord::Turntable
2
+ class SeqShard < Shard
3
+ private
4
+ def retrieve_connection_pool
5
+ ActiveRecord::Base.turntable_connections[name] ||=
6
+ begin
7
+ config = ActiveRecord::Base.configurations[Rails.env]["seq"][name]
8
+ raise ArgumentError, "Unknown database config: #{name}, have #{ActiveRecord::Base.configurations.inspect}" unless config
9
+ ActiveRecord::ConnectionAdapters::ConnectionPool.new(spec_for(config))
10
+ end
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # 採番
4
+ #
5
+
6
+ module ActiveRecord::Turntable
7
+ class Sequencer
8
+ autoload :Api, "active_record/turntable/sequencer/api"
9
+ autoload :Mysql, "active_record/turntable/sequencer/mysql"
10
+ @@sequence_types = {
11
+ :api => Api,
12
+ :mysql => Mysql
13
+ }
14
+
15
+ @@sequences = {}
16
+ @@tables = {}
17
+ cattr_reader :sequences, :tables
18
+
19
+ def self.build(klass)
20
+ seq_config_name = ActiveRecord::Base.turntable_config["clusters"][klass.turntable_cluster_name.to_s]["seq"]["connection"]
21
+ seq_config = ActiveRecord::Base.configurations[Rails.env]["seq"][seq_config_name]
22
+ seq_type = (seq_config["seq_type"] ? seq_config["seq_type"].to_sym : :mysql)
23
+ @@tables[klass.table_name] ||= (@@sequences[sequence_name(klass.table_name, klass.primary_key)] ||= @@sequence_types[seq_type].new(klass, seq_config))
24
+ end
25
+
26
+ def self.has_sequencer?(table_name)
27
+ !!@@tables[table_name]
28
+ end
29
+
30
+ def self.sequence_name(table_name, pk)
31
+ "#{ table_name}_#{pk || 'id'}_seq"
32
+ end
33
+
34
+ def self.table_name(seq_name)
35
+ seq_name.split('_').first
36
+ end
37
+
38
+ def next_sequence_value
39
+ raise ActiveRecord::Turntable::NotImplementedError
40
+ end
41
+
42
+ def current_sequence_value
43
+ raise ActiveRecord::Turntable::NotImplementedError
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,36 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # APIサーバを利用しての採番
4
+ #
5
+ require 'httpclient'
6
+
7
+ module ActiveRecord::Turntable
8
+ class Sequencer
9
+ class Api < Sequencer
10
+ API_ENDPOINT = '/sequences/'
11
+ NEXT_VALUE_ENDPOINT = '/new'
12
+
13
+ def initialize(klass, options = {})
14
+ @klass = klass
15
+ @options = options
16
+ @host = @options["api_host"]
17
+ @port = @options["api_port"]
18
+ @client = HTTPClient.new
19
+ end
20
+
21
+ def next_sequence_value(sequence_name)
22
+ res = @client.get_content("http://#{@host}:#{@port}#{API_ENDPOINT}#{sequence_name}#{NEXT_VALUE_ENDPOINT}")
23
+ new_id = res.to_i
24
+ raise SequenceNotFoundError if new_id.zero?
25
+ return new_id
26
+ end
27
+
28
+ def current_sequence_value(sequence_name)
29
+ res = @client.get_content("http://#{@host}:#{@port}#{API_ENDPOINT}#{sequence_name}")
30
+ current_id = res.to_i
31
+ raise SequenceNotFoundError if current_id.zero?
32
+ return current_id
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ # -*- coding: utf-8 -*-
2
+ #
3
+ # 採番
4
+ #
5
+
6
+ module ActiveRecord::Turntable
7
+ class Sequencer
8
+ class Mysql < Sequencer
9
+ def initialize(klass, options = {})
10
+ @klass = klass
11
+ @options = options
12
+ end
13
+
14
+ def next_sequence_value(sequence_name)
15
+ conn = @klass.connection.seq.connection
16
+ conn.execute "BEGIN"
17
+ conn.execute "UPDATE #{@klass.connection.quote_table_name(sequence_name)} SET id=LAST_INSERT_ID(id+1)"
18
+ conn.execute "COMMIT"
19
+ res = conn.execute("SELECT LAST_INSERT_ID()")
20
+ new_id = res.first.first.to_i
21
+ raise SequenceNotFoundError if new_id.zero?
22
+ return new_id
23
+ end
24
+
25
+ def current_sequence_value(sequence_name)
26
+ res = @klass.connection.seq.connection.execute("SELECT id FROM #{@klass.connection.quote_table_name(sequence_name)} LIMIT 1")
27
+ current_id = res.first.first.to_i
28
+ return current_id
29
+ end
30
+ end
31
+ end
32
+ end