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,102 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
# The dataset describes a table of the Cassandra cluster
|
6
|
+
#
|
7
|
+
# @api private
|
8
|
+
#
|
9
|
+
class Dataset
|
10
|
+
|
11
|
+
include Enumerable
|
12
|
+
include Equalizer.new(:session, :keyspace, :table, :query)
|
13
|
+
|
14
|
+
# @!attribute [r] session
|
15
|
+
#
|
16
|
+
# @return [ROM::Cassandra::Session] The open session to a Cassandra cluster
|
17
|
+
#
|
18
|
+
attr_reader :session
|
19
|
+
|
20
|
+
# @!attribute [r] keyspace
|
21
|
+
#
|
22
|
+
# @return [Symbol] The name of the current keyspace
|
23
|
+
#
|
24
|
+
attr_reader :keyspace
|
25
|
+
|
26
|
+
# @!attribute [r] table
|
27
|
+
#
|
28
|
+
# @return [Symbol] The name of the current table
|
29
|
+
#
|
30
|
+
attr_reader :table
|
31
|
+
|
32
|
+
# @!attribute [r] query
|
33
|
+
#
|
34
|
+
# @return [QueryBuilder::Statement] The lazy query to the current table
|
35
|
+
#
|
36
|
+
attr_reader :query
|
37
|
+
|
38
|
+
# Initializes the dataset for given column family and command options
|
39
|
+
#
|
40
|
+
# @param [ROM::Cassandra::Session] session
|
41
|
+
# @param [#to_sym] keyspace
|
42
|
+
# @param [#to_sym] table
|
43
|
+
# @param [ROM::Cassandra::Query] query
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def initialize(session, keyspace, table, query = nil)
|
48
|
+
@session = session
|
49
|
+
@keyspace = keyspace.to_sym if keyspace
|
50
|
+
@table = table.to_sym if table
|
51
|
+
@query = query || Query.new.keyspace(keyspace).table(table)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns the new dataset carriyng the batch query
|
55
|
+
#
|
56
|
+
# The batch query doesn't restricted by any table or keyspace
|
57
|
+
#
|
58
|
+
# @return [ROM::Relation::Dataset]
|
59
|
+
#
|
60
|
+
def batch
|
61
|
+
reload nil, nil, Query.new.batch
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns new dataset with `select` method applied to the [#query]
|
65
|
+
#
|
66
|
+
# @param [Array, Hash, nil] args
|
67
|
+
#
|
68
|
+
# @return [ROM::Relation::Dataset]
|
69
|
+
#
|
70
|
+
def get(*args)
|
71
|
+
reload keyspace, table, query.select(*args)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Sends the [#query] to Cassandra and iterates through results
|
75
|
+
#
|
76
|
+
# @return [Enumerator]
|
77
|
+
#
|
78
|
+
# @yieldparam [Hash] tuples from the dataset
|
79
|
+
# @yieldreturn [self] itself
|
80
|
+
#
|
81
|
+
def each
|
82
|
+
return to_enum unless block_given?
|
83
|
+
session.call(query).each { |item| yield(item) }
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def reload(*args)
|
89
|
+
self.class.new(session, *args)
|
90
|
+
end
|
91
|
+
|
92
|
+
def method_missing(name, *args)
|
93
|
+
reload keyspace, table, query.public_send(name, *args)
|
94
|
+
end
|
95
|
+
|
96
|
+
def respond_to_missing?(name, *)
|
97
|
+
query.respond_to?(name)
|
98
|
+
end
|
99
|
+
|
100
|
+
end # class Dataset
|
101
|
+
|
102
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
# The gateway to the keyspace of the Cassandra cluster
|
6
|
+
#
|
7
|
+
# @api public
|
8
|
+
#
|
9
|
+
class Gateway < ROM::Gateway
|
10
|
+
|
11
|
+
include Equalizer.new(:options, :datasets)
|
12
|
+
|
13
|
+
# @!attribute [r] session
|
14
|
+
#
|
15
|
+
# @return [ROM::Cassandra::Session] The current session
|
16
|
+
#
|
17
|
+
attr_reader :session
|
18
|
+
|
19
|
+
# @!attribute [r] datasets
|
20
|
+
#
|
21
|
+
# @return [Hash] The list of registered datasets
|
22
|
+
#
|
23
|
+
attr_reader :datasets
|
24
|
+
|
25
|
+
# Initializes the ROM gateway to the Cassandra cluster
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# ROM::Cassandra::Gateway.new(
|
29
|
+
# hosts: ["10.0.1.1", "10.0.1.2"],
|
30
|
+
# port: 9042,
|
31
|
+
# username: "admin",
|
32
|
+
# password: "foo"
|
33
|
+
# )
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# ROM::Cassandra::Gateway.new(
|
37
|
+
# "http://10.0.1.1:9042",
|
38
|
+
# username: "admin",
|
39
|
+
# password: "foo"
|
40
|
+
# )
|
41
|
+
#
|
42
|
+
# @param [Hash] options
|
43
|
+
#
|
44
|
+
def initialize(*options)
|
45
|
+
@session = Session.new(*options)
|
46
|
+
@datasets = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
# The options of the initialized session
|
50
|
+
#
|
51
|
+
# @return [Hash]
|
52
|
+
#
|
53
|
+
def options
|
54
|
+
session.uri
|
55
|
+
end
|
56
|
+
|
57
|
+
# Registers a new dataset
|
58
|
+
#
|
59
|
+
# @example
|
60
|
+
# dataset "foo.bar"
|
61
|
+
#
|
62
|
+
# @param [#to_sym] name The full name of the table
|
63
|
+
#
|
64
|
+
# @return [ROM::Cassandra::Dataset]
|
65
|
+
#
|
66
|
+
def dataset(name)
|
67
|
+
@datasets[name.to_sym] = Dataset.new(session, *split(name))
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the registered dataset
|
71
|
+
#
|
72
|
+
# @param (see #dataset)
|
73
|
+
#
|
74
|
+
# @return (see #dataset)
|
75
|
+
#
|
76
|
+
def [](name)
|
77
|
+
datasets[name.to_sym]
|
78
|
+
end
|
79
|
+
|
80
|
+
# Checks whether the dataset is registered
|
81
|
+
#
|
82
|
+
# @param (see #dataset)
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
#
|
86
|
+
def dataset?(name)
|
87
|
+
self[name] ? true : false
|
88
|
+
end
|
89
|
+
|
90
|
+
# Migrates the Cassandra cluster to given version
|
91
|
+
#
|
92
|
+
# @option (see ROM::Cassandra::Migrations::Migrator#new)
|
93
|
+
# @option options [Integer, nil] :version
|
94
|
+
#
|
95
|
+
# @return [undefined]
|
96
|
+
#
|
97
|
+
def migrate(options = {})
|
98
|
+
settings = options.select { |key| [:path, :logger].include? key }
|
99
|
+
target = options.select { |key| key.equal? :version }
|
100
|
+
|
101
|
+
Migrations::Migrator.new(session, settings).apply(target)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
def split(name)
|
107
|
+
list = name.to_s.split(".")
|
108
|
+
return list if 2.equal? list.count
|
109
|
+
fail ArgumentError.new "'#{name}' is not a valid full name of a table. " \
|
110
|
+
"Use format 'keyspace.table' with both keyspace and table parts."
|
111
|
+
end
|
112
|
+
|
113
|
+
end # class Gateway
|
114
|
+
|
115
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module ROM::Cassandra
|
6
|
+
|
7
|
+
# Migrations features for the Cassandra cluster
|
8
|
+
#
|
9
|
+
module Migrations
|
10
|
+
|
11
|
+
# The procedure that extracts version number from a migration filename
|
12
|
+
GET_VERSION = -> name { File.basename(name, ".rb")[/\d{14}/].to_i }
|
13
|
+
|
14
|
+
# The default path for migrations
|
15
|
+
DEFAULT_PATH = "db/migrate".freeze
|
16
|
+
|
17
|
+
# The biggest possible version for migrations
|
18
|
+
ALL_VERSIONS = ("9" * 14).to_i
|
19
|
+
|
20
|
+
require_relative "migrations/logger"
|
21
|
+
require_relative "migrations/migration"
|
22
|
+
require_relative "migrations/runner"
|
23
|
+
require_relative "migrations/runner_up"
|
24
|
+
require_relative "migrations/runner_down"
|
25
|
+
require_relative "migrations/migrator"
|
26
|
+
require_relative "migrations/generator"
|
27
|
+
|
28
|
+
end # module Migrations
|
29
|
+
|
30
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
module Migrations
|
6
|
+
|
7
|
+
# Generates the migration with given name at the target folder
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# ROM::Cassandra::Migrations::Generator.call "create_users", "/db/migrate"
|
11
|
+
# # => "/db/migrate/20150827133303_create_users.rb"
|
12
|
+
#
|
13
|
+
class Generator
|
14
|
+
|
15
|
+
# Initializes and calls the generator at once
|
16
|
+
#
|
17
|
+
# @param (see #initialize)
|
18
|
+
#
|
19
|
+
# @return (see #call)
|
20
|
+
#
|
21
|
+
def self.call(name, path)
|
22
|
+
new(name, path).call
|
23
|
+
end
|
24
|
+
|
25
|
+
# Initializes the generator with path to target folder and migration name
|
26
|
+
#
|
27
|
+
# @param [String] path
|
28
|
+
# @param [String] name
|
29
|
+
#
|
30
|
+
def initialize(name, path)
|
31
|
+
@path = path
|
32
|
+
@name = Inflecto.underscore(name)
|
33
|
+
@klass = Inflecto.camelize(name)
|
34
|
+
@version = Time.new.strftime "%Y%m%d%H%M%S"
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generates the migration
|
38
|
+
#
|
39
|
+
# @return [String] the full path to the migration
|
40
|
+
#
|
41
|
+
def call
|
42
|
+
FileUtils.mkdir_p path
|
43
|
+
File.write target, content
|
44
|
+
|
45
|
+
target
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
attr_reader :name, :path, :version
|
51
|
+
|
52
|
+
def content
|
53
|
+
ERB.new(File.read source).result(binding)
|
54
|
+
end
|
55
|
+
|
56
|
+
def source
|
57
|
+
File.expand_path("../generator/migration.erb", __FILE__)
|
58
|
+
end
|
59
|
+
|
60
|
+
def target
|
61
|
+
File.join(path, "#{version}_#{name}.rb")
|
62
|
+
end
|
63
|
+
|
64
|
+
end # class Generator
|
65
|
+
|
66
|
+
end # module Migrations
|
67
|
+
|
68
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# ==============================================================================
|
4
|
+
# Define `up` and `down` methods, using `call` and `timestamp` helpers.
|
5
|
+
#
|
6
|
+
# @see http://rom-rb.org/guides/adapters/cassandra#migrations
|
7
|
+
# the example in the Cassandra Adapter Guide
|
8
|
+
# ==============================================================================
|
9
|
+
|
10
|
+
# Adds/discards changes to the Cassandra cluster and registers the migration
|
11
|
+
# at the rom.migrations table of the cluster.
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# migration = <%= @klass %>.new(session)
|
15
|
+
# migration.up
|
16
|
+
# migration.down
|
17
|
+
#
|
18
|
+
class <%= @klass %> < ROM::Cassandra::Migrations::Migration
|
19
|
+
# Adds necessary changes to the Cassandra cluster
|
20
|
+
#
|
21
|
+
# @return [undefined]
|
22
|
+
#
|
23
|
+
def up
|
24
|
+
end
|
25
|
+
|
26
|
+
# Rolls back the changes to the Cassandra cluster
|
27
|
+
#
|
28
|
+
# @return [undefined]
|
29
|
+
#
|
30
|
+
def down
|
31
|
+
end
|
32
|
+
end # class ROM::Cassandra::Migrations::Migration
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module ROM::Cassandra
|
6
|
+
|
7
|
+
module Migrations
|
8
|
+
|
9
|
+
# Default Logger for the migrator
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# logger = Logger.new
|
13
|
+
# logger.info "some text"
|
14
|
+
# # => some text
|
15
|
+
#
|
16
|
+
class Logger < ::Logger
|
17
|
+
|
18
|
+
# @private
|
19
|
+
def initialize
|
20
|
+
super $stdout
|
21
|
+
self.formatter = proc { |_, _, _, message| "#{message}\n" }
|
22
|
+
end
|
23
|
+
|
24
|
+
end # Logger
|
25
|
+
|
26
|
+
end # module Migrations
|
27
|
+
|
28
|
+
end # module ROM::Cassandra
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module ROM::Cassandra
|
4
|
+
|
5
|
+
module Migrations
|
6
|
+
|
7
|
+
# Base class for migrations, responcible for sending queries to the session
|
8
|
+
#
|
9
|
+
# @example Migration can be created in OOP-style
|
10
|
+
# class CreateAuthUsers < ROM::Cassandra::Migration
|
11
|
+
# def up
|
12
|
+
# call keyspace(:auth).create.if_not_exists
|
13
|
+
# call keyspace(:auth)
|
14
|
+
# .table(:users)
|
15
|
+
# .create(:id, :int)
|
16
|
+
# .add(:name, :text)
|
17
|
+
# .primary_key(:id)
|
18
|
+
# .if_not_exists
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# def down
|
22
|
+
# call keyspace(:auth).drop.if_exists
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @example The same migration in CQL style
|
27
|
+
# class CreateAuthUsers < ROM::Cassandra::Migration
|
28
|
+
# def up
|
29
|
+
# call "CREATE KEYSPACE IF NOT EXISTS auth;"
|
30
|
+
# call(
|
31
|
+
# "CREATE TABLE auth.users (id int, name text, PRIMARY KEY (text));"
|
32
|
+
# )
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# def down
|
36
|
+
# call "DROM KEYSPACE IF EXISTS auth;"
|
37
|
+
# end
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
class Migration
|
41
|
+
|
42
|
+
# Makes all helper methods private
|
43
|
+
#
|
44
|
+
# @private
|
45
|
+
#
|
46
|
+
def self.inherited(klass)
|
47
|
+
klass.__send__(:private, :call, :keyspace, :up, :down)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Initializes migration with session to the Cassandra cluster
|
51
|
+
#
|
52
|
+
# @param [ROM::Cassandra::Session] session
|
53
|
+
#
|
54
|
+
def initialize(session)
|
55
|
+
@session = session
|
56
|
+
@builder = Query.new
|
57
|
+
end
|
58
|
+
|
59
|
+
# @!attribute [r] session
|
60
|
+
#
|
61
|
+
# @return [ROM::Cassandra::Session] the session to send queries to
|
62
|
+
#
|
63
|
+
attr_reader :session
|
64
|
+
|
65
|
+
# By default does nothing
|
66
|
+
#
|
67
|
+
# @return [undefined]
|
68
|
+
#
|
69
|
+
# @abstract
|
70
|
+
#
|
71
|
+
def up
|
72
|
+
end
|
73
|
+
|
74
|
+
# By default does nothing
|
75
|
+
#
|
76
|
+
# @return [undefined]
|
77
|
+
#
|
78
|
+
# @abstract
|
79
|
+
#
|
80
|
+
def down
|
81
|
+
end
|
82
|
+
|
83
|
+
# Sends the query to Cassandra cluster
|
84
|
+
#
|
85
|
+
# @param [#to_s] query
|
86
|
+
#
|
87
|
+
# @return [Array]
|
88
|
+
#
|
89
|
+
def call(query)
|
90
|
+
session.call query.to_s
|
91
|
+
end
|
92
|
+
|
93
|
+
# Starts building the CQL query in the context of some keyspace
|
94
|
+
#
|
95
|
+
# @param [#to_s] name
|
96
|
+
#
|
97
|
+
# @return [ROM::Cassandra::Query]
|
98
|
+
#
|
99
|
+
def keyspace(name)
|
100
|
+
@builder.keyspace(name)
|
101
|
+
end
|
102
|
+
|
103
|
+
end # class Migration
|
104
|
+
|
105
|
+
end # module Migrations
|
106
|
+
|
107
|
+
end # module ROM::Cassandra
|