rom-cassandra 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.coveralls.yml +2 -0
- data/.gitignore +9 -0
- data/.metrics +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +26 -0
- data/.yardopts +3 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +7 -0
- data/Guardfile +14 -0
- data/LICENSE +21 -0
- data/README.md +83 -0
- data/Rakefile +34 -0
- data/config/metrics/STYLEGUIDE +230 -0
- data/config/metrics/cane.yml +5 -0
- data/config/metrics/churn.yml +6 -0
- data/config/metrics/flay.yml +2 -0
- data/config/metrics/metric_fu.yml +14 -0
- data/config/metrics/reek.yml +1 -0
- data/config/metrics/roodi.yml +24 -0
- data/config/metrics/rubocop.yml +84 -0
- data/config/metrics/saikuro.yml +3 -0
- data/config/metrics/simplecov.yml +6 -0
- data/config/metrics/yardstick.yml +37 -0
- data/lib/rom-cassandra.rb +3 -0
- data/lib/rom/cassandra.rb +33 -0
- data/lib/rom/cassandra/commands.rb +53 -0
- data/lib/rom/cassandra/commands/batch.rb +54 -0
- data/lib/rom/cassandra/commands/create.rb +38 -0
- data/lib/rom/cassandra/commands/delete.rb +38 -0
- data/lib/rom/cassandra/commands/update.rb +38 -0
- data/lib/rom/cassandra/dataset.rb +102 -0
- data/lib/rom/cassandra/gateway.rb +115 -0
- data/lib/rom/cassandra/migrations.rb +30 -0
- data/lib/rom/cassandra/migrations/generator.rb +68 -0
- data/lib/rom/cassandra/migrations/generator/migration.erb +32 -0
- data/lib/rom/cassandra/migrations/logger.rb +28 -0
- data/lib/rom/cassandra/migrations/migration.rb +107 -0
- data/lib/rom/cassandra/migrations/migrator.rb +103 -0
- data/lib/rom/cassandra/migrations/runner.rb +119 -0
- data/lib/rom/cassandra/migrations/runner_down.rb +49 -0
- data/lib/rom/cassandra/migrations/runner_up.rb +50 -0
- data/lib/rom/cassandra/query.rb +43 -0
- data/lib/rom/cassandra/relation.rb +88 -0
- data/lib/rom/cassandra/session.rb +50 -0
- data/lib/rom/cassandra/tasks.rb +6 -0
- data/lib/rom/cassandra/version.rb +15 -0
- data/lib/tasks/db.rake +16 -0
- data/rom-cassandra.gemspec +33 -0
- data/spec/config/reset_cluster.rb +28 -0
- data/spec/config/rom.rb +3 -0
- data/spec/config/test_module.rb +7 -0
- data/spec/integration/batch_spec.rb +36 -0
- data/spec/integration/create_spec.rb +33 -0
- data/spec/integration/delete_spec.rb +33 -0
- data/spec/integration/migrate/20150825142003_create_users.rb +24 -0
- data/spec/integration/migrate/20150825142024_create_logs.rb +17 -0
- data/spec/integration/migrate_spec.rb +47 -0
- data/spec/integration/relation_spec.rb +27 -0
- data/spec/integration/update_spec.rb +33 -0
- data/spec/shared/fake_migrate_folder.rb +21 -0
- data/spec/shared/users.rb +20 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/unit/commands/batch_spec.rb +86 -0
- data/spec/unit/commands/create_spec.rb +77 -0
- data/spec/unit/commands/delete_spec.rb +77 -0
- data/spec/unit/commands/update_spec.rb +77 -0
- data/spec/unit/dataset_spec.rb +130 -0
- data/spec/unit/gateway_spec.rb +140 -0
- data/spec/unit/migrations/generator_spec.rb +31 -0
- data/spec/unit/migrations/logger_spec.rb +21 -0
- data/spec/unit/migrations/migration_spec.rb +59 -0
- data/spec/unit/migrations/migrator_spec.rb +120 -0
- data/spec/unit/migrations/runner_down_spec.rb +65 -0
- data/spec/unit/migrations/runner_spec.rb +142 -0
- data/spec/unit/migrations/runner_up_spec.rb +67 -0
- data/spec/unit/query_spec.rb +21 -0
- data/spec/unit/relation_spec.rb +142 -0
- data/spec/unit/session_spec.rb +55 -0
- data/spec/unit/tasks/create_migration_spec.rb +41 -0
- metadata +242 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
module Migrations
|
6
|
+
|
7
|
+
# Class Migrator finds the migration files and migrates Cassandra cluster
|
8
|
+
# to the required version using method [#apply].
|
9
|
+
#
|
10
|
+
# The class is responcible for searching files and deciding,
|
11
|
+
# which of them should be runned up and down. Every single migration
|
12
|
+
# is applied or rolled back using `RunnerUp` and `RunnerDown` classes.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# migrator = Migrator.new(hosts: ["127.0.0.1"], port: 9042)
|
16
|
+
#
|
17
|
+
# # Applies all migrations
|
18
|
+
# migrator.apply
|
19
|
+
#
|
20
|
+
# # Rolls back all migrations
|
21
|
+
# migrator.apply version: 0
|
22
|
+
#
|
23
|
+
# # Moves to the required version (before the year 2016)
|
24
|
+
# migrator.apply version: 20151231235959
|
25
|
+
#
|
26
|
+
class Migrator
|
27
|
+
|
28
|
+
# @!attribute [r] session
|
29
|
+
#
|
30
|
+
# @return [ROM::Cassandra::Session] The session to the Cassandra cluster
|
31
|
+
#
|
32
|
+
attr_reader :session
|
33
|
+
|
34
|
+
# @!attribute [r] logger
|
35
|
+
#
|
36
|
+
# @return [::Logger] The logger used by the migrator
|
37
|
+
#
|
38
|
+
attr_reader :logger
|
39
|
+
|
40
|
+
# @!attribute [r] root
|
41
|
+
#
|
42
|
+
# @return [Array<String>] The root path for migrations
|
43
|
+
#
|
44
|
+
attr_reader :root
|
45
|
+
|
46
|
+
# @!attribute [r] paths
|
47
|
+
#
|
48
|
+
# @return [Array<String>] The list of paths to migration files
|
49
|
+
#
|
50
|
+
attr_reader :paths
|
51
|
+
|
52
|
+
# Initializes a migrator with Cassandra uri settings.
|
53
|
+
#
|
54
|
+
# Can specify logger and path as well.
|
55
|
+
#
|
56
|
+
# @param [ROM::Cassandra::Session] session
|
57
|
+
# @option options [::Logger] :logger
|
58
|
+
# @option options [String] :path
|
59
|
+
#
|
60
|
+
# See [ROM::Cassandra::Session] for other avaliable options for URI
|
61
|
+
#
|
62
|
+
def initialize(session, options = {})
|
63
|
+
@session = session
|
64
|
+
@logger = options.fetch(:logger) { Logger.new }
|
65
|
+
@root = options.fetch(:path) { DEFAULT_PATH }
|
66
|
+
@paths = Dir[File.join(root, "*.rb")].sort
|
67
|
+
end
|
68
|
+
|
69
|
+
# Migrates the Cassandra cluster to selected version
|
70
|
+
#
|
71
|
+
# Applies all migrations if a version is skipped.
|
72
|
+
# Rolls all migrations back if a version is set to 0.
|
73
|
+
#
|
74
|
+
# @option options [Integer, nil] :version
|
75
|
+
#
|
76
|
+
# @return [undefined]
|
77
|
+
#
|
78
|
+
def apply(options = {})
|
79
|
+
version = options.fetch(:version) { ALL_VERSIONS }
|
80
|
+
|
81
|
+
migrate_to version
|
82
|
+
rollback_to version
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def migrate_to(version)
|
88
|
+
paths
|
89
|
+
.reject { |path| GET_VERSION[path] > version }
|
90
|
+
.each { |path| RunnerUp.apply(session, logger, path) }
|
91
|
+
end
|
92
|
+
|
93
|
+
def rollback_to(version)
|
94
|
+
paths
|
95
|
+
.select { |path| GET_VERSION[path] > version }
|
96
|
+
.reverse_each { |path| RunnerDown.apply(session, logger, path) }
|
97
|
+
end
|
98
|
+
|
99
|
+
end # class Migrator
|
100
|
+
|
101
|
+
end # module Migrations
|
102
|
+
|
103
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "inflecto"
|
4
|
+
|
5
|
+
module ROM::Cassandra
|
6
|
+
|
7
|
+
module Migrations
|
8
|
+
|
9
|
+
# Base class that loads and runs the migration, registers it in
|
10
|
+
# the Cassandra 'rom.migrations' table, and logs the result.
|
11
|
+
#
|
12
|
+
# As a base class uses the Command pattern to define a sequence of
|
13
|
+
# actions, that should be implemented by the subclasses:
|
14
|
+
# `RunnerUp`, and `RunnderDown`.
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
class Runner
|
19
|
+
|
20
|
+
# @!attribute [r] session
|
21
|
+
#
|
22
|
+
# @return [ROM::Cassandra::Session]
|
23
|
+
# The session for sending requests to Cassandra
|
24
|
+
#
|
25
|
+
attr_reader :session
|
26
|
+
|
27
|
+
# @!attribute [r] logger
|
28
|
+
#
|
29
|
+
# @return [::Logger] The logger to report results
|
30
|
+
#
|
31
|
+
attr_reader :logger
|
32
|
+
|
33
|
+
# @!attribute [r] version
|
34
|
+
#
|
35
|
+
# @return [Integer] The number of migration
|
36
|
+
#
|
37
|
+
attr_reader :version
|
38
|
+
|
39
|
+
# @!attribute [r] path
|
40
|
+
#
|
41
|
+
# @return [String] The path to the migration file
|
42
|
+
#
|
43
|
+
attr_reader :path
|
44
|
+
|
45
|
+
# @!attribute [r] migration
|
46
|
+
#
|
47
|
+
# @return [ROM::Cassandra::Migrations::Migration]
|
48
|
+
# The migration class
|
49
|
+
#
|
50
|
+
attr_reader :migration
|
51
|
+
|
52
|
+
# Applies the runner to session, logger and migration path
|
53
|
+
#
|
54
|
+
# @param (see #initialize)
|
55
|
+
#
|
56
|
+
# @return (see #call)
|
57
|
+
#
|
58
|
+
def self.apply(session, logger, path)
|
59
|
+
new(session, logger, path).call
|
60
|
+
end
|
61
|
+
|
62
|
+
# Initializes the runner for the session, logger and migration path
|
63
|
+
#
|
64
|
+
# @param [ROM::Cassandra::Session] session
|
65
|
+
# @param [Logger] logger
|
66
|
+
# @param [String] path
|
67
|
+
#
|
68
|
+
def initialize(session, logger, path)
|
69
|
+
@session = session
|
70
|
+
@logger = logger
|
71
|
+
@path = path
|
72
|
+
@version = extract_version
|
73
|
+
@migration = extract_migration if migrate? # defined in a subclass
|
74
|
+
end
|
75
|
+
|
76
|
+
# Runs the sequence of commands to provide migration
|
77
|
+
#
|
78
|
+
# @return [undefined]
|
79
|
+
#
|
80
|
+
def call
|
81
|
+
return unless migration
|
82
|
+
apply # defined in a subclass
|
83
|
+
register # defined in a subclass
|
84
|
+
log # defined in a subclass
|
85
|
+
end
|
86
|
+
|
87
|
+
# Prepares the table and selects version
|
88
|
+
#
|
89
|
+
# @return [Array<Hash>] list of rows with the selected version
|
90
|
+
#
|
91
|
+
def select_version
|
92
|
+
session.call "CREATE KEYSPACE IF NOT EXISTS rom WITH" \
|
93
|
+
" REPLICATION = {'class': 'SimpleStrategy', 'replication_factor': 3};"
|
94
|
+
session.call "CREATE TABLE IF NOT EXISTS rom.migrations" \
|
95
|
+
" (version text, PRIMARY KEY (version));"
|
96
|
+
session.call "SELECT * FROM rom.migrations WHERE" \
|
97
|
+
" version = '#{version}';"
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def extract_version
|
103
|
+
version = GET_VERSION[path]
|
104
|
+
return version unless version.equal? 0
|
105
|
+
fail NameError.new "invalid version number: '#{path}'"
|
106
|
+
end
|
107
|
+
|
108
|
+
def extract_migration
|
109
|
+
require path
|
110
|
+
basename = File.basename(path, ".rb")
|
111
|
+
class_name = Inflecto.camelize basename[/_.+/][1..-1]
|
112
|
+
Inflecto.constantize(class_name).new(session)
|
113
|
+
end
|
114
|
+
|
115
|
+
end # class Runner
|
116
|
+
|
117
|
+
end # module Migrations
|
118
|
+
|
119
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
module Migrations
|
6
|
+
|
7
|
+
# Runs migration up, registers it in Cassandra table and logs the change.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
class RunnerDown < Runner
|
12
|
+
|
13
|
+
# Checks if the version hasn't been registered yet
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
def migrate?
|
18
|
+
select_version.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Rolls back the migration
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
def apply
|
26
|
+
migration.down
|
27
|
+
end
|
28
|
+
|
29
|
+
# Removes the version from Cassandra db
|
30
|
+
#
|
31
|
+
# @return [Array] an empty array
|
32
|
+
#
|
33
|
+
def register
|
34
|
+
session.call "DELETE FROM rom.migrations WHERE version = '#{version}';"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Logs the result of the operation
|
38
|
+
#
|
39
|
+
# @return [undefined]
|
40
|
+
#
|
41
|
+
def log
|
42
|
+
logger.info "Roll back migration #{version}\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
end # class RunnerDown
|
46
|
+
|
47
|
+
end # module Migrations
|
48
|
+
|
49
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
module Migrations
|
6
|
+
|
7
|
+
# Runs migration up, registers it in Cassandra table and logs the change.
|
8
|
+
#
|
9
|
+
# @api private
|
10
|
+
#
|
11
|
+
class RunnerUp < Runner
|
12
|
+
|
13
|
+
# Checks if the version has been registered yet
|
14
|
+
#
|
15
|
+
# @return [Boolean]
|
16
|
+
#
|
17
|
+
def migrate?
|
18
|
+
select_version.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Moves the migration forward
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
def apply
|
26
|
+
migration.up
|
27
|
+
end
|
28
|
+
|
29
|
+
# Registers the version in Cassandra db
|
30
|
+
#
|
31
|
+
# @return [Array] an empty array
|
32
|
+
#
|
33
|
+
def register
|
34
|
+
session.call "INSERT INTO rom.migrations (version)" \
|
35
|
+
" VALUES ('#{version}');"
|
36
|
+
end
|
37
|
+
|
38
|
+
# Logs the result of the operation
|
39
|
+
#
|
40
|
+
# @return [undefined]
|
41
|
+
#
|
42
|
+
def log
|
43
|
+
logger.info "Apply migration #{version}\n"
|
44
|
+
end
|
45
|
+
|
46
|
+
end # class RunnerUp
|
47
|
+
|
48
|
+
end # module Migrations
|
49
|
+
|
50
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "query_builder"
|
4
|
+
|
5
|
+
module ROM::Cassandra
|
6
|
+
|
7
|
+
# Wraps the external CQL query builder
|
8
|
+
#
|
9
|
+
class Query
|
10
|
+
|
11
|
+
# Default CQL statements builder
|
12
|
+
DEFAULT_BUILDER = QueryBuilder::CQL
|
13
|
+
|
14
|
+
# Initializes the object carrying the lazy query
|
15
|
+
#
|
16
|
+
# @param [ROM::Cassandra::Query] query
|
17
|
+
#
|
18
|
+
def initialize(query = nil)
|
19
|
+
@query = query || DEFAULT_BUILDER
|
20
|
+
end
|
21
|
+
|
22
|
+
# Builds the Query statement from the wrapped query
|
23
|
+
#
|
24
|
+
# @return [String]
|
25
|
+
#
|
26
|
+
def to_s
|
27
|
+
@query.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def respond_to_missing?(name, *)
|
33
|
+
@query.respond_to? name
|
34
|
+
end
|
35
|
+
|
36
|
+
def method_missing(name, *args)
|
37
|
+
updated_query = @query.public_send(name, *args)
|
38
|
+
self.class.new(updated_query)
|
39
|
+
end
|
40
|
+
|
41
|
+
end # class Query
|
42
|
+
|
43
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
# Relation subclass of Cassandra adapter
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# class Users < ROM::Relation[:cassandra]
|
9
|
+
# def last_ten_admins
|
10
|
+
# select(:id, :name)
|
11
|
+
# .where(role: "admin")
|
12
|
+
# .using(consistency: :quorum)
|
13
|
+
# .order(:name, :desc)
|
14
|
+
# .limit(10)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
#
|
20
|
+
class Relation < ROM::Relation
|
21
|
+
|
22
|
+
adapter :cassandra
|
23
|
+
option :source
|
24
|
+
|
25
|
+
# @!attribute [r] source
|
26
|
+
#
|
27
|
+
# @return [ROM::Cassandra::Dataset]
|
28
|
+
# The source dataset before `get` method has been applied
|
29
|
+
#
|
30
|
+
attr_reader :source
|
31
|
+
|
32
|
+
# @private
|
33
|
+
def initialize(*)
|
34
|
+
super
|
35
|
+
return if (@source = options[:source])
|
36
|
+
@source = dataset
|
37
|
+
@dataset = dataset.get
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the relation whose source is restricted by `#insert` lazy query
|
41
|
+
#
|
42
|
+
# @return [ROM::Cassandra::Relation]
|
43
|
+
#
|
44
|
+
def insert_query
|
45
|
+
reload source.insert
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the relation whose source is restricted by `#update` lazy query
|
49
|
+
#
|
50
|
+
# @return [ROM::Cassandra::Relation]
|
51
|
+
#
|
52
|
+
def update_query
|
53
|
+
reload source.update
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the relation whose source is restricted by `#delete` lazy query
|
57
|
+
#
|
58
|
+
# @return [ROM::Cassandra::Relation]
|
59
|
+
#
|
60
|
+
def delete_query
|
61
|
+
reload source.delete
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the relation whose source is restricted by `#delete` lazy query
|
65
|
+
#
|
66
|
+
# @return [ROM::Cassandra::Relation]
|
67
|
+
#
|
68
|
+
def batch_query
|
69
|
+
reload source.batch
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def respond_to_missing?(name, *)
|
75
|
+
dataset.respond_to? name
|
76
|
+
end
|
77
|
+
|
78
|
+
def method_missing(name, *args)
|
79
|
+
reload dataset.public_send(name, *args)
|
80
|
+
end
|
81
|
+
|
82
|
+
def reload(dataset)
|
83
|
+
Relation.new dataset, source: source
|
84
|
+
end
|
85
|
+
|
86
|
+
end # class Relation
|
87
|
+
|
88
|
+
end # module ROM::Cassandra
|