cassandra_migrations 0.0.1.pre3 → 0.0.1.pre4

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.
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module CassandraMigrations
4
+ module Cassandra
5
+ module KeyspaceOperations
6
+
7
+ def create_keyspace!
8
+ begin
9
+ execute(
10
+ "CREATE KEYSPACE #{Config.keyspace} \
11
+ WITH replication = { \
12
+ 'class':'#{Config.replication['class']}', \
13
+ 'replication_factor': #{Config.replication['replication_factor']} \
14
+ }"
15
+ )
16
+ use(Config.keyspace)
17
+ rescue Exception => exception
18
+ drop_keyspace!
19
+ raise exception
20
+ end
21
+ end
22
+
23
+ def drop_keyspace!
24
+ begin
25
+ execute("DROP KEYSPACE #{Config.keyspace}")
26
+ rescue Cql::QueryError
27
+ raise Errors::UnexistingKeyspaceError, keyspace
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module CassandraMigrations
4
+ module Cassandra
5
+ module Queries
6
+
7
+ def write!(table, hash)
8
+ columns = []
9
+ values = []
10
+
11
+ hash.each do |k,v|
12
+ columns << k.to_s
13
+ values << (v.is_a?(String) ? "'#{v.to_s}'" : v.to_s)
14
+ end
15
+
16
+ execute("INSERT INTO #{table} (#{columns.join(', ')}) VALUES (#{values.join(', ')})")
17
+ end
18
+
19
+ def select(table, options={})
20
+ query_string = "SELECT #{options[:projection] || '*'} FROM #{table}"
21
+
22
+ if options[:selection]
23
+ query_string << " WHERE #{options[:selection]}"
24
+ end
25
+
26
+ if options[:order_by]
27
+ query_string << " ORDER BY #{options[:order_by]}"
28
+ end
29
+
30
+ if options[:limit]
31
+ query_string << " LIMIT #{options[:limit]}"
32
+ end
33
+
34
+ execute(query_string)
35
+ end
36
+
37
+ def delete!(table, selection, options={})
38
+ execute("DELETE #{options[:projection]} FROM #{table} WHERE #{selection}")
39
+ end
40
+
41
+ def truncate!(table)
42
+ execute("TRUNCATE #{table}")
43
+ end
44
+
45
+ end
46
+ end
47
+ end
@@ -2,102 +2,63 @@
2
2
 
3
3
  require 'yaml'
4
4
  require 'cql'
5
- require 'cassandra_migrations/cassandra/query'
6
- require 'cassandra_migrations/cassandra/errors'
7
- require 'cassandra_migrations/cassandra/migrator'
5
+ require 'cassandra_migrations/cassandra/queries'
6
+ require 'cassandra_migrations/cassandra/keyspace_operations'
8
7
 
9
- module CassandraMigrations::Cassandra
10
- extend Query
11
-
12
- mattr_accessor :client
13
- mattr_accessor :config
8
+
9
+ module CassandraMigrations
10
+ module Cassandra
11
+ extend Queries
12
+ extend KeyspaceOperations
14
13
 
15
- def self.start!
16
- connect_to_server unless client
14
+ mattr_accessor :client
17
15
 
18
- # setup keyspace use
19
- begin
20
- use(config['keyspace'])
21
- rescue Cql::QueryError # keyspace does not exist
22
- raise Errors::UnexistingKeyspaceError, config['keyspace']
16
+ def self.start!
17
+ # setup keyspace use
18
+ use(Config.keyspace)
23
19
  end
24
- end
25
-
26
- def self.restart!
27
- self.client = nil
28
- self.config = nil
29
- start!
30
- end
31
-
32
- def self.shutdown!
33
- if client
34
- client.close
20
+
21
+ def self.restart!
22
+ raise Errors::ClientNotStartedError unless client
23
+
24
+ client.close if client && client.connected?
35
25
  self.client = nil
26
+ start!
36
27
  end
37
-
38
- self.config = nil
39
- end
40
-
41
- def self.create_keyspace!
42
- connect_to_server unless client
43
28
 
44
- begin
45
- execute(
46
- "CREATE KEYSPACE #{config['keyspace']} \
47
- WITH replication = { \
48
- 'class':'#{config['replication']['class']}', \
49
- 'replication_factor': #{config['replication']['replication_factor']} \
50
- }"
51
- )
52
- use(config['keyspace'])
53
- execute("CREATE TABLE metadata (data_name varchar PRIMARY KEY, data_value varchar)")
54
- write("metadata", {:data_name => 'version', :data_value => '0'})
55
- rescue Exception => exception
56
- drop!
57
- raise exception
29
+ def self.shutdown!
30
+ raise Errors::ClientNotStartedError unless client
31
+
32
+ client.close if client.connected?
33
+ self.client = nil
58
34
  end
59
- end
60
-
61
- def self.drop!
62
- connect_to_server unless client
63
35
 
64
- begin
65
- execute("DROP KEYSPACE #{config['keyspace']}")
66
- rescue Cql::QueryError
67
- raise Errors::UnexistingKeyspaceError, config['keyspace']
36
+ def self.use(keyspace)
37
+ connect_to_server unless client
38
+
39
+ begin
40
+ client.use(keyspace)
41
+ rescue Cql::QueryError # keyspace does not exist
42
+ raise Errors::UnexistingKeyspaceError, keyspace
43
+ end
68
44
  end
69
- end
70
-
71
- def self.use(keyspace)
72
- raise Errors::ClientNotStartedError unless client
73
- client.use(keyspace)
74
- end
75
45
 
76
- def self.execute(cql)
77
- raise Errors::ClientNotStartedError unless client
78
- client.execute(cql)
79
- end
80
-
81
- private
82
-
83
- def self.connect_to_server
84
- load_config
46
+ def self.execute(cql)
47
+ connect_to_server unless client
48
+ client.execute(cql)
49
+ end
85
50
 
86
- Rails.logger.try(:info, "Connecting to Cassandra on #{config['host']}:#{config['port']}")
51
+ private
87
52
 
88
- begin
89
- self.client = Cql::Client.new(:host => config['host'], :port => config['port'])
90
- client.connect
91
- rescue Cql::Io::ConnectionError => e
92
- raise Errors::ConnectionError, e.message
93
- end
94
- end
95
-
96
- def self.load_config
97
- begin
98
- self.config = YAML.load_file(Rails.root.join("config", "cassandra.yml"))[Rails.env]
99
- rescue Errno::ENOENT
100
- raise Errors::MissingConfigurationError
53
+ def self.connect_to_server
54
+ Rails.logger.try(:info, "Connecting to Cassandra on #{Config.host}:#{Config.port}")
55
+
56
+ begin
57
+ self.client = Cql::Client.new(:host => Config.host, :port => Config.port)
58
+ client.connect
59
+ rescue Cql::Io::ConnectionError => e
60
+ raise Errors::ConnectionError, e.message
61
+ end
101
62
  end
102
63
  end
103
- end
64
+ end
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module CassandraMigrations
4
+ module Config
5
+
6
+ mattr_accessor :config
7
+
8
+ def self.method_missing(method_sym, *arguments, &block)
9
+ load_config unless config
10
+ config[method_sym.to_s]
11
+ end
12
+
13
+ private
14
+
15
+ def self.load_config
16
+ begin
17
+ self.config = YAML.load_file(Rails.root.join("config", "cassandra.yml"))[Rails.env]
18
+ rescue Errno::ENOENT
19
+ raise Errors::MissingConfigurationError
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -1,6 +1,6 @@
1
1
  # encoding: utf-8
2
2
 
3
- module CassandraMigrations::Cassandra
3
+ module CassandraMigrations
4
4
  module Errors
5
5
 
6
6
  class CassandraError < StandardError
@@ -39,4 +39,4 @@ module CassandraMigrations::Cassandra
39
39
  end
40
40
 
41
41
  end
42
- end
42
+ end
@@ -1,9 +1,11 @@
1
1
  # encoding: utf-8
2
2
 
3
- module CassandraMigrations::Cassandra
3
+ module CassandraMigrations
4
4
  module Migrator
5
5
 
6
- def self.up_to_latest
6
+ METADATA_TABLE = 'cassandra_migrations_metadata'
7
+
8
+ def self.up_to_latest!
7
9
  current_version = read_current_version
8
10
 
9
11
  new_migrations = get_all_migration_names.sort.select do |migration_name|
@@ -17,7 +19,7 @@ module CassandraMigrations::Cassandra
17
19
  new_migrations.size
18
20
  end
19
21
 
20
- def self.rollback(count=1)
22
+ def self.rollback!(count=1)
21
23
  current_version = read_current_version
22
24
 
23
25
  executed_migrations = get_all_migration_names.sort.reverse.select do |migration_name|
@@ -39,7 +41,13 @@ module CassandraMigrations::Cassandra
39
41
  end
40
42
 
41
43
  def self.read_current_version
42
- CassandraMigrations::Cassandra.select("metadata", :selection => "data_name='version'", :projection => 'data_value').first['data_value'].to_i
44
+ begin
45
+ Cassandra.select(METADATA_TABLE, :selection => "data_name='version'", :projection => 'data_value').first['data_value'].to_i
46
+ rescue Cql::QueryError # table cassandra_migrations_metadata does not exist
47
+ Cassandra.execute("CREATE TABLE #{METADATA_TABLE} (data_name varchar PRIMARY KEY, data_value varchar)")
48
+ Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => '0'})
49
+ return 0
50
+ end
43
51
  end
44
52
 
45
53
  private
@@ -51,7 +59,7 @@ private
51
59
  get_class_from_migration_name(migration_name).up
52
60
 
53
61
  # update version
54
- CassandraMigrations::Cassandra.write("metadata", {:data_name => 'version', :data_value => get_version_from_migration_name(migration_name).to_s})
62
+ Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => get_version_from_migration_name(migration_name).to_s})
55
63
  end
56
64
 
57
65
  def self.down(migration_name, previous_migration_name=nil)
@@ -62,9 +70,9 @@ private
62
70
 
63
71
  # downgrade version
64
72
  if previous_migration_name
65
- CassandraMigrations::Cassandra.write("metadata", {:data_name => 'version', :data_value => get_version_from_migration_name(previous_migration_name).to_s})
73
+ Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => get_version_from_migration_name(previous_migration_name).to_s})
66
74
  else
67
- CassandraMigrations::Cassandra.write("metadata", {:data_name => 'version', :data_value => '0'})
75
+ Cassandra.write!(METADATA_TABLE, {:data_name => 'version', :data_value => '0'})
68
76
  end
69
77
  end
70
78
 
@@ -80,4 +88,4 @@ private
80
88
  migration_name.match(/([0-9]{14})_.+\.rb$/).captures.first.to_i
81
89
  end
82
90
  end
83
- end
91
+ end
@@ -1,17 +1,30 @@
1
1
  # encoding : utf-8
2
2
 
3
- # Em produção (como usamos o Passenger), vários processos ruby são criados através do fork
4
- # do original. No UNIX, quando um fork é realizado, is file descriptors (arquivos, conexões a base de dados,
5
- # sockets, e etc) são copiados em estado aberto para o processo filho. Se não reabrirmos a conexão com o cassandra
6
- # no processo filho, quando ela for ser usada ela estará 'locked' pelo processo pai, o que resultará em deadlock.
3
+ # In production (when Passenger is used with smart spawn), many ruby processes are created
4
+ # by forking the original spawner. Since the child process is a different process, it shares
5
+ # no memory with its father. Because of that we have to connect to cassandra again.
6
+ # It is also common that file descriptors are unintentionally shared when the process forks,
7
+ # that's why we go through the safe path and check if the client exists in order to restart it
8
+ # (production tests have shown that the client is nil when forked)
7
9
 
8
- # Mais explicações em: http://www.modrails.com/documentation/Users%20guide%20Apache.html#spawning_methods_explained
9
- if defined?(PhusionPassenger)
10
- PhusionPassenger.on_event(:starting_worker_process) do |forked|
11
- if forked
12
- CassandraMigrations::Cassandra.restart!
10
+ # More explanations in: http://www.modrails.com/documentation/Users%20guide%20Apache.html#spawning_methods_explained
11
+
12
+ module CassandraMigrations
13
+
14
+ if defined?(PhusionPassenger)
15
+ PhusionPassenger.on_event(:starting_worker_process) do |forked|
16
+ if forked
17
+ if Cassandra.client
18
+ Rails.logger.info "Passenger process forked: reconnecting to Cassandra..."
19
+ Cassandra.restart!
20
+ else
21
+ Rails.logger.info "Passenger process forked: connecting to Cassandra..."
22
+ Cassandra.start!
23
+ end
24
+ end
13
25
  end
26
+ else
27
+ Cassandra.start!
14
28
  end
15
- else
16
- CassandraMigrations::Cassandra.start!
29
+
17
30
  end
@@ -10,26 +10,26 @@ namespace :cassandra do
10
10
  task :create do
11
11
  begin
12
12
  CassandraMigrations::Cassandra.start!
13
- puts "Keyspace #{CassandraMigrations::Cassandra.config['keyspace']} already exists!"
14
- rescue CassandraMigrations::Cassandra::Errors::UnexistingKeyspaceError
13
+ puts "Keyspace #{CassandraMigrations::Config.keyspace} already exists!"
14
+ rescue CassandraMigrations::Errors::UnexistingKeyspaceError
15
15
  CassandraMigrations::Cassandra.create_keyspace!
16
- puts "Created keyspace #{CassandraMigrations::Cassandra.config['keyspace']}"
16
+ puts "Created keyspace #{CassandraMigrations::Config.keyspace}"
17
17
  end
18
18
  end
19
19
 
20
20
  desc 'Drop keyspace in config/cassandra.yml for the current environment'
21
21
  task :drop do
22
22
  begin
23
- CassandraMigrations::Cassandra.drop!
24
- puts "Dropped keyspace #{CassandraMigrations::Cassandra.config['keyspace']}"
25
- rescue CassandraMigrations::Cassandra::Errors::UnexistingKeyspaceError
26
- puts "Keyspace #{CassandraMigrations::Cassandra.config['keyspace']} does not exist already... cannot be dropped"
23
+ CassandraMigrations::Cassandra.drop_keyspace!
24
+ puts "Dropped keyspace #{CassandraMigrations::Config.keyspace}"
25
+ rescue CassandraMigrations::Errors::UnexistingKeyspaceError
26
+ puts "Keyspace #{CassandraMigrations::Config.keyspace} does not exist... cannot be dropped"
27
27
  end
28
28
  end
29
29
 
30
30
  desc 'Migrate the keyspace to the latest version'
31
31
  task :migrate => :start do
32
- migrations_up_count = CassandraMigrations::Cassandra::Migrator.up_to_latest
32
+ migrations_up_count = CassandraMigrations::Migrator.up_to_latest!
33
33
 
34
34
  if migrations_up_count == 0
35
35
  puts "Already up-to-date"
@@ -40,9 +40,9 @@ namespace :cassandra do
40
40
 
41
41
  desc 'Rolls the schema back to the previous version (specify steps w/ STEP=n)'
42
42
  task :rollback => :start do
43
- steps = ENV['STEP'] ? ENV['STEP'].to_i : 1
43
+ steps = (ENV['STEP'] ? ENV['STEP'].to_i : 1)
44
44
 
45
- migrations_down_count = CassandraMigrations::Cassandra::Migrator.rollback(steps)
45
+ migrations_down_count = CassandraMigrations::Migrator.rollback!(steps)
46
46
 
47
47
  if steps == migrations_down_count
48
48
  puts "Rolled back #{steps} version(s)."
@@ -68,7 +68,7 @@ namespace :cassandra do
68
68
 
69
69
  desc 'Retrieves the current schema version number'
70
70
  task :version => :start do
71
- puts "Current version: #{Cassandra::Migrator.read_current_version}"
71
+ puts "Current version: #{CassandraMigrations::Migrator.read_current_version}"
72
72
  end
73
73
 
74
74
  end
@@ -1,6 +1,6 @@
1
-
2
- module CassandraMigrations
3
- end
4
-
1
+ require 'cassandra_migrations/config'
2
+ require 'cassandra_migrations/errors'
5
3
  require 'cassandra_migrations/cassandra'
4
+ require 'cassandra_migrations/migrator'
5
+
6
6
  require 'cassandra_migrations/railtie' if defined?(Rails)
@@ -14,7 +14,7 @@ describe CassandraMigrations::Cassandra do
14
14
  end
15
15
 
16
16
  after do
17
- CassandraMigrations::Cassandra.shutdown!
17
+ CassandraMigrations::Cassandra.shutdown! if CassandraMigrations::Cassandra.client
18
18
  end
19
19
 
20
20
  describe ".start!" do
@@ -45,18 +45,16 @@ describe CassandraMigrations::Cassandra do
45
45
 
46
46
  it "should use host and port configurations to create cassandra client" do
47
47
  cql_client_mock = Cql::Client.new
48
- cql_client_mock.should_receive(:start!)
48
+ cql_client_mock.should_receive(:connect)
49
+ cql_client_mock.stub(:use)
49
50
  Cql::Client.should_receive(:new).with(:host => '127.0.0.1', :port => 9042).and_return(cql_client_mock)
50
51
 
51
- begin
52
- CassandraMigrations::Cassandra.start!
53
- rescue
54
- end
52
+ CassandraMigrations::Cassandra.start!
55
53
  end
56
54
 
57
55
  it "should raise exception if not able to connect to cassandra host" do
58
56
  cql_client_mock = Cql::Client.new
59
- cql_client_mock.stub(:start!).and_raise Cql::Io::ConnectionError
57
+ cql_client_mock.stub(:connect).and_raise Cql::Io::ConnectionError
60
58
  Cql::Client.stub(:new).and_return cql_client_mock
61
59
 
62
60
  expect do
@@ -68,7 +66,9 @@ describe CassandraMigrations::Cassandra do
68
66
  CassandraMigrations::Cassandra.should_receive(:use).with('cassandra_migrations_development')
69
67
  CassandraMigrations::Cassandra.start!
70
68
  end
71
-
69
+ end
70
+
71
+ describe '.use' do
72
72
  it "should raise exception if configured keyspace does not exist" do
73
73
  expect do
74
74
  CassandraMigrations::Cassandra.start!
@@ -85,4 +85,4 @@ describe CassandraMigrations::Cassandra do
85
85
  end
86
86
  end
87
87
 
88
- end
88
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cassandra_migrations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1.pre3
4
+ version: 0.0.1.pre4
5
5
  prerelease: 6
6
6
  platform: ruby
7
7
  authors:
@@ -18,7 +18,7 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 1.0.0.pre5
21
+ version: 1.0.0.pre7
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -26,7 +26,7 @@ dependencies:
26
26
  requirements:
27
27
  - - '='
28
28
  - !ruby/object:Gem::Version
29
- version: 1.0.0.pre5
29
+ version: 1.0.0.pre7
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: rake
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -99,17 +99,20 @@ extensions: []
99
99
  extra_rdoc_files: []
100
100
  files:
101
101
  - lib/cassandra_migrations.rb
102
- - lib/cassandra_migrations/cassandra/migrator.rb
103
- - lib/cassandra_migrations/cassandra/query.rb
104
- - lib/cassandra_migrations/cassandra/errors.rb
105
- - lib/cassandra_migrations/railtie/tasks.rake
106
- - lib/cassandra_migrations/railtie/initializer.rb
102
+ - lib/cassandra_migrations/migrator.rb
107
103
  - lib/cassandra_migrations/cassandra.rb
108
104
  - lib/cassandra_migrations/railtie.rb
109
- - spec/cassandra_migrations/cassandra_spec.rb
105
+ - lib/cassandra_migrations/cassandra/keyspace_operations.rb
106
+ - lib/cassandra_migrations/cassandra/queries.rb
107
+ - lib/cassandra_migrations/config.rb
108
+ - lib/cassandra_migrations/railtie/initializer.rb
109
+ - lib/cassandra_migrations/railtie/tasks.rake
110
+ - lib/cassandra_migrations/errors.rb
110
111
  - spec/cassandra_migrations_spec.rb
112
+ - spec/cassandra_migrations/cassandra_spec.rb
111
113
  homepage: https://github.com/hsgubert/cassandra_migrations
112
- licenses: []
114
+ licenses:
115
+ - MIT
113
116
  post_install_message:
114
117
  rdoc_options: []
115
118
  require_paths:
@@ -133,5 +136,5 @@ signing_key:
133
136
  specification_version: 3
134
137
  summary: Cassandra schema management for a multi-environment developer.
135
138
  test_files:
136
- - spec/cassandra_migrations/cassandra_spec.rb
137
139
  - spec/cassandra_migrations_spec.rb
140
+ - spec/cassandra_migrations/cassandra_spec.rb
@@ -1,44 +0,0 @@
1
- # encoding: utf-8
2
-
3
- module CassandraMigrations::Cassandra
4
- module Query
5
-
6
- def write(table, hash)
7
- columns = []
8
- values = []
9
-
10
- hash.each do |k,v|
11
- columns << k.to_s
12
- values << "'#{v.to_s}'"
13
- end
14
-
15
- execute("INSERT INTO #{table} (#{columns.join(', ')}) VALUES (#{values.join(', ')})")
16
- end
17
-
18
- def select(table, options={})
19
- query_string = "SELECT #{options[:projection] || '*'} FROM #{table}"
20
-
21
- if options[:selection]
22
- query_string << " WHERE #{options[:selection]}"
23
- end
24
-
25
- if options[:order_by]
26
- query_string << " ORDER BY #{options[:order_by]}"
27
- end
28
-
29
- if options[:limit]
30
- query_string << " LIMIT #{options[:limit]}"
31
- end
32
-
33
- execute(query_string)
34
- end
35
-
36
- def delete(table, selection, options={})
37
- execute("DELETE #{options[:projection]} FROM #{table} WHERE #{selection}")
38
- end
39
-
40
- def truncate(table)
41
- execute("TRUNCATE #{table}")
42
- end
43
- end
44
- end