activerecord-turntable 1.0.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.
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