rom-cassandra 0.0.1
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.
- 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
|