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,50 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "cassandra"
|
4
|
+
|
5
|
+
module ROM::Cassandra
|
6
|
+
|
7
|
+
# Wraps the external driver, responsible for sending CQL requests
|
8
|
+
# to the Cassandra cluster
|
9
|
+
#
|
10
|
+
class Session
|
11
|
+
|
12
|
+
# The regexp, describing the format of the allowed address of the cluster
|
13
|
+
FORMAT = /\d{1,3}(\.\d{1,3}){3}(\:\d+)?/
|
14
|
+
|
15
|
+
# @!attribute [r] uri
|
16
|
+
#
|
17
|
+
# @return [Hash] the settings for the session
|
18
|
+
#
|
19
|
+
attr_reader :uri
|
20
|
+
|
21
|
+
# Initializes a session to given cluster
|
22
|
+
#
|
23
|
+
# @param [Hash] options
|
24
|
+
#
|
25
|
+
def initialize(*options)
|
26
|
+
@uri = extract(*options)
|
27
|
+
@conn = ::Cassandra.cluster(uri).connect
|
28
|
+
end
|
29
|
+
|
30
|
+
# Sends the query to the Cassandra syncronously
|
31
|
+
#
|
32
|
+
# @param [#to_s] query
|
33
|
+
#
|
34
|
+
# @return [Array<Hash>]
|
35
|
+
#
|
36
|
+
def call(query)
|
37
|
+
@conn.execute(query.to_s).to_a
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def extract(uri = { hosts: ["127.0.0.1"], port: 9042 }, hash = {})
|
43
|
+
return uri if uri.instance_of? Hash
|
44
|
+
hosts, port = uri[FORMAT].split(":")
|
45
|
+
{ hosts: [hosts], port: port.to_i }.merge hash
|
46
|
+
end
|
47
|
+
|
48
|
+
end # class Session
|
49
|
+
|
50
|
+
end # module ROM::Cassandra
|
data/lib/tasks/db.rake
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
namespace :db do
|
4
|
+
desc "Create a migration (required parameter: NAME)"
|
5
|
+
task :create_migration, [:name, :path] do |_, args|
|
6
|
+
unless (name = args[:name])
|
7
|
+
puts "No NAME specified.\n" \
|
8
|
+
"Usage example: `rake db:create_migration[create_users]`"
|
9
|
+
exit
|
10
|
+
end
|
11
|
+
path = args[:path] || "db/migrate"
|
12
|
+
|
13
|
+
result = ROM::Cassandra::Migrations::Generator.call(name, path)
|
14
|
+
puts "<= Created #{result}"
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "rom/cassandra/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
|
8
|
+
gem.name = "rom-cassandra"
|
9
|
+
gem.version = ROM::Cassandra::VERSION.dup
|
10
|
+
gem.author = ["Andrew Kozin"]
|
11
|
+
gem.email = ["andrew.kozin@gmail.com"]
|
12
|
+
gem.summary = "Cassandra support for Ruby Object Mapper"
|
13
|
+
gem.description = gem.summary
|
14
|
+
gem.homepage = "https://rom-rb.org"
|
15
|
+
gem.license = "MIT"
|
16
|
+
|
17
|
+
gem.files = `git ls-files -z`.split("\x0")
|
18
|
+
gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
20
|
+
gem.extra_rdoc_files = Dir["README.md", "LICENSE"]
|
21
|
+
gem.require_paths = ["lib"]
|
22
|
+
|
23
|
+
gem.required_ruby_version = ">= 1.9.3"
|
24
|
+
|
25
|
+
gem.add_runtime_dependency "cassandra-driver", "~> 2.1"
|
26
|
+
gem.add_runtime_dependency "inflecto", "~> 0.0"
|
27
|
+
gem.add_runtime_dependency "query_builder", "~> 0.0"
|
28
|
+
gem.add_runtime_dependency "rom", "~> 0.9.1"
|
29
|
+
|
30
|
+
gem.add_development_dependency "hexx-rspec", "~> 0.5"
|
31
|
+
gem.add_development_dependency "timecop", "~> 0.8"
|
32
|
+
|
33
|
+
end # Gem::Specification
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "cassandra"
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
|
7
|
+
# Prepares table auth.users using official Datastax ruby driver for Cassandra
|
8
|
+
#
|
9
|
+
# Populates table records [{id: 1, name: "joe"}, {id: 2, name: "jane"}]
|
10
|
+
#
|
11
|
+
def reset_cluster
|
12
|
+
[
|
13
|
+
"DROP KEYSPACE IF EXISTS auth;",
|
14
|
+
"CREATE KEYSPACE auth WITH " \
|
15
|
+
"replication = {'class': 'SimpleStrategy', 'replication_factor': 1};",
|
16
|
+
"CREATE TABLE auth.users (id int, name text, PRIMARY KEY (id));",
|
17
|
+
"INSERT INTO auth.users (id, name) VALUES (1, 'joe');",
|
18
|
+
"INSERT INTO auth.users (id, name) VALUES (2, 'jane');"
|
19
|
+
].each(&::Cassandra.cluster.connect.method(:execute))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Prepares the cluster before the suit
|
23
|
+
reset_cluster
|
24
|
+
|
25
|
+
# Recreates cluster after every example, marked by :reset_cluster tag
|
26
|
+
config.after(:example, :reset_cluster) { reset_cluster }
|
27
|
+
|
28
|
+
end # RSpec.configure
|
data/spec/config/rom.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shared/users"
|
4
|
+
|
5
|
+
module ROM::Cassandra::Test # the namespace for newly created classes
|
6
|
+
|
7
|
+
describe "command 'batch'", :reset_cluster do
|
8
|
+
|
9
|
+
include_context :users
|
10
|
+
|
11
|
+
before do
|
12
|
+
class Batch < ROM::Cassandra::Commands::Batch
|
13
|
+
relation :users
|
14
|
+
register_as :batch
|
15
|
+
|
16
|
+
def execute
|
17
|
+
super do
|
18
|
+
add("DELETE FROM auth.users WHERE id = 1;")
|
19
|
+
.add(keyspace(:auth).table(:users).insert(id: 3, name: "frank"))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
subject { rom.command(:users).batch }
|
26
|
+
|
27
|
+
it "works" do
|
28
|
+
expect { subject.call }
|
29
|
+
.to change { select.to_a }
|
30
|
+
.from([{ "id" => 1, "name" => "joe" }, { "id" => 2, "name" => "jane" }])
|
31
|
+
.to [{ "id" => 2, "name" => "jane" }, { "id" => 3, "name" => "frank" }]
|
32
|
+
end
|
33
|
+
|
34
|
+
end # describe command 'batch'
|
35
|
+
|
36
|
+
end # module ROM::Cassandra::Commands::Batch
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shared/users"
|
4
|
+
|
5
|
+
module ROM::Cassandra::Test # the namespace for newly created classes
|
6
|
+
|
7
|
+
describe "command 'create'", :reset_cluster do
|
8
|
+
|
9
|
+
include_context :users
|
10
|
+
|
11
|
+
before do
|
12
|
+
class CreateUser < ROM::Commands::Create[:cassandra]
|
13
|
+
relation :users
|
14
|
+
register_as :create
|
15
|
+
|
16
|
+
def execute(id, name)
|
17
|
+
super { insert(id: id, name: name) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { rom.command(:users).create }
|
23
|
+
|
24
|
+
it "works" do
|
25
|
+
expect { subject.call(3, "jill") }
|
26
|
+
.to change { select.by_id(3).to_a }
|
27
|
+
.from([])
|
28
|
+
.to [{ "id" => 3, "name" => "jill" }]
|
29
|
+
end
|
30
|
+
|
31
|
+
end # describe command 'create'
|
32
|
+
|
33
|
+
end # module ROM::Cassandra::Test
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shared/users"
|
4
|
+
|
5
|
+
module ROM::Cassandra::Test # the namespace for newly created classes
|
6
|
+
|
7
|
+
describe "command 'delete'", :reset_cluster do
|
8
|
+
|
9
|
+
include_context :users
|
10
|
+
|
11
|
+
before do
|
12
|
+
class DeleteUser < ROM::Commands::Delete[:cassandra]
|
13
|
+
relation :users
|
14
|
+
register_as :delete
|
15
|
+
|
16
|
+
def execute(id)
|
17
|
+
super { where(id: 1) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { rom.command(:users).delete }
|
23
|
+
|
24
|
+
it "works" do
|
25
|
+
expect { subject.call(1) }
|
26
|
+
.to change { select.by_id(1).to_a }
|
27
|
+
.from([{ "id" => 1, "name" => "joe" }])
|
28
|
+
.to []
|
29
|
+
end
|
30
|
+
|
31
|
+
end # describe command 'delete'
|
32
|
+
|
33
|
+
end # module ROM::Cassandra::Test
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class CreateUsers < ROM::Cassandra::Migrations::Migration
|
4
|
+
def up
|
5
|
+
replication = { class: :SimpleStrategy, replication_factor: 1 }
|
6
|
+
|
7
|
+
call keyspace(:logs)
|
8
|
+
.create
|
9
|
+
.if_not_exists
|
10
|
+
.with(replication: replication)
|
11
|
+
|
12
|
+
call keyspace(:logs)
|
13
|
+
.table(:users)
|
14
|
+
.create
|
15
|
+
.if_not_exists
|
16
|
+
.add(:id, :int)
|
17
|
+
.add(:name, :text)
|
18
|
+
.primary_key(:id)
|
19
|
+
end
|
20
|
+
|
21
|
+
def down
|
22
|
+
call keyspace(:logs).drop.if_exists
|
23
|
+
end
|
24
|
+
end # class CreateUsers
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class CreateLogs < ROM::Cassandra::Migrations::Migration
|
4
|
+
def up
|
5
|
+
call keyspace(:logs)
|
6
|
+
.table(:logs)
|
7
|
+
.create
|
8
|
+
.add(:id, :int)
|
9
|
+
.add(:name, :text)
|
10
|
+
.primary_key(:id)
|
11
|
+
.if_not_exists
|
12
|
+
end
|
13
|
+
|
14
|
+
def down
|
15
|
+
call "DROP TABLE IF EXISTS logs.logs;"
|
16
|
+
end
|
17
|
+
end # class CreateUsers
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
describe "migrate" do
|
4
|
+
|
5
|
+
# The helper function to check the db content
|
6
|
+
def check(query)
|
7
|
+
Cassandra.cluster.connect.execute query
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:stdout) { StringIO.new }
|
11
|
+
let(:logger) { Logger.new stdout }
|
12
|
+
let(:path) { File.expand_path("../migrate", __FILE__) }
|
13
|
+
let(:gateway) { ROM.finalize.env.gateways[:default] }
|
14
|
+
|
15
|
+
it "works" do
|
16
|
+
ROM.setup(:cassandra, "127.0.0.1:9042")
|
17
|
+
|
18
|
+
expect { check "SELECT * FROM logs.users;" }.to raise_error StandardError
|
19
|
+
expect { check "SELECT * FROM logs.logs" }.to raise_error StandardError
|
20
|
+
expect(stdout.string).to be_empty
|
21
|
+
|
22
|
+
gateway.migrate logger: logger, path: path, version: 20150825142003
|
23
|
+
|
24
|
+
expect { check "SELECT * FROM logs.users;" }.not_to raise_error
|
25
|
+
expect { check "SELECT * FROM logs.logs" }.to raise_error StandardError
|
26
|
+
expect(stdout.string).to include "Apply migration 20150825142003"
|
27
|
+
expect(stdout.string).not_to include "Apply migration 20150825142024"
|
28
|
+
|
29
|
+
gateway.migrate logger: logger, path: path
|
30
|
+
|
31
|
+
expect { check "SELECT * FROM logs.users;" }.not_to raise_error
|
32
|
+
expect { check "SELECT * FROM logs.logs" }.not_to raise_error
|
33
|
+
expect(stdout.string).to include "Apply migration 20150825142024"
|
34
|
+
expect(stdout.string).not_to include "Roll back"
|
35
|
+
|
36
|
+
gateway.migrate logger: logger, path: path, version: 0
|
37
|
+
|
38
|
+
expect { check "SELECT * FROM logs.users;" }.to raise_error StandardError
|
39
|
+
expect { check "SELECT * FROM logs.logs" }.to raise_error StandardError
|
40
|
+
expect(stdout.string).to include "Roll back migration 20150825142024"
|
41
|
+
expect(stdout.string).to include "Roll back migration 20150825142003"
|
42
|
+
end
|
43
|
+
|
44
|
+
after { check "DROP KEYSPACE IF EXISTS rom;" }
|
45
|
+
after { check "DROP KEYSPACE IF EXISTS logs;" }
|
46
|
+
|
47
|
+
end # describe migrate
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shared/users"
|
4
|
+
|
5
|
+
module ROM::Cassandra::Test # the namespace for newly created classes
|
6
|
+
|
7
|
+
describe "relation" do
|
8
|
+
|
9
|
+
include_context :users
|
10
|
+
|
11
|
+
let(:subject) { rom.relation(:users) }
|
12
|
+
|
13
|
+
it "works" do
|
14
|
+
expect(subject.to_a).to eql [
|
15
|
+
{ "id" => 1, "name" => "joe" },
|
16
|
+
{ "id" => 2, "name" => "jane" }
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "works with modifiers" do
|
21
|
+
expect(subject.by_id(1).to_a)
|
22
|
+
.to eql [{ "id" => 1, "name" => "joe" }]
|
23
|
+
end
|
24
|
+
|
25
|
+
end # describe relation
|
26
|
+
|
27
|
+
end # module ROM::Cassandra::Test
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "shared/users"
|
4
|
+
|
5
|
+
module ROM::Cassandra::Test # the namespace for newly created classes
|
6
|
+
|
7
|
+
describe "command 'update'", :reset_cluster do
|
8
|
+
|
9
|
+
include_context :users
|
10
|
+
|
11
|
+
before do
|
12
|
+
class UpdateUser < ROM::Commands::Update[:cassandra]
|
13
|
+
relation :users
|
14
|
+
register_as :update
|
15
|
+
|
16
|
+
def execute(id, name)
|
17
|
+
super { update(name: name).where(id: 1) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
subject { rom.command(:users).update }
|
23
|
+
|
24
|
+
it "works" do
|
25
|
+
expect { subject.call(1, "frank") }
|
26
|
+
.to change { select.by_id(1).to_a }
|
27
|
+
.from([{ "id" => 1, "name" => "joe" }])
|
28
|
+
.to [{ "id" => 1, "name" => "frank" }]
|
29
|
+
end
|
30
|
+
|
31
|
+
end # describe command 'update'
|
32
|
+
|
33
|
+
end # module ROM::Cassandra::Test
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "fileutils"
|
4
|
+
|
5
|
+
shared_context :fake_migrate_folder do |folder|
|
6
|
+
before { FileUtils.mkdir_p path }
|
7
|
+
before { files.reverse_each(&FileUtils.method(:touch)) }
|
8
|
+
|
9
|
+
let(:root) { File.expand_path "../../sandbox", __FILE__ }
|
10
|
+
let(:path) { File.join(root, folder) }
|
11
|
+
let(:files) do
|
12
|
+
[
|
13
|
+
"20151231235959_create_auth.rb",
|
14
|
+
"20160101000000_create_users.rb",
|
15
|
+
"20160101000001_create_logs.rb",
|
16
|
+
"20160101000002_create_rights.rb"
|
17
|
+
].map { |name| File.join(path, name) }
|
18
|
+
end
|
19
|
+
|
20
|
+
after { FileUtils.rm_rf root }
|
21
|
+
end # shared context
|