rom-cassandra 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +9 -0
  4. data/.metrics +9 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +2 -0
  7. data/.travis.yml +26 -0
  8. data/.yardopts +3 -0
  9. data/CHANGELOG.md +3 -0
  10. data/Gemfile +7 -0
  11. data/Guardfile +14 -0
  12. data/LICENSE +21 -0
  13. data/README.md +83 -0
  14. data/Rakefile +34 -0
  15. data/config/metrics/STYLEGUIDE +230 -0
  16. data/config/metrics/cane.yml +5 -0
  17. data/config/metrics/churn.yml +6 -0
  18. data/config/metrics/flay.yml +2 -0
  19. data/config/metrics/metric_fu.yml +14 -0
  20. data/config/metrics/reek.yml +1 -0
  21. data/config/metrics/roodi.yml +24 -0
  22. data/config/metrics/rubocop.yml +84 -0
  23. data/config/metrics/saikuro.yml +3 -0
  24. data/config/metrics/simplecov.yml +6 -0
  25. data/config/metrics/yardstick.yml +37 -0
  26. data/lib/rom-cassandra.rb +3 -0
  27. data/lib/rom/cassandra.rb +33 -0
  28. data/lib/rom/cassandra/commands.rb +53 -0
  29. data/lib/rom/cassandra/commands/batch.rb +54 -0
  30. data/lib/rom/cassandra/commands/create.rb +38 -0
  31. data/lib/rom/cassandra/commands/delete.rb +38 -0
  32. data/lib/rom/cassandra/commands/update.rb +38 -0
  33. data/lib/rom/cassandra/dataset.rb +102 -0
  34. data/lib/rom/cassandra/gateway.rb +115 -0
  35. data/lib/rom/cassandra/migrations.rb +30 -0
  36. data/lib/rom/cassandra/migrations/generator.rb +68 -0
  37. data/lib/rom/cassandra/migrations/generator/migration.erb +32 -0
  38. data/lib/rom/cassandra/migrations/logger.rb +28 -0
  39. data/lib/rom/cassandra/migrations/migration.rb +107 -0
  40. data/lib/rom/cassandra/migrations/migrator.rb +103 -0
  41. data/lib/rom/cassandra/migrations/runner.rb +119 -0
  42. data/lib/rom/cassandra/migrations/runner_down.rb +49 -0
  43. data/lib/rom/cassandra/migrations/runner_up.rb +50 -0
  44. data/lib/rom/cassandra/query.rb +43 -0
  45. data/lib/rom/cassandra/relation.rb +88 -0
  46. data/lib/rom/cassandra/session.rb +50 -0
  47. data/lib/rom/cassandra/tasks.rb +6 -0
  48. data/lib/rom/cassandra/version.rb +15 -0
  49. data/lib/tasks/db.rake +16 -0
  50. data/rom-cassandra.gemspec +33 -0
  51. data/spec/config/reset_cluster.rb +28 -0
  52. data/spec/config/rom.rb +3 -0
  53. data/spec/config/test_module.rb +7 -0
  54. data/spec/integration/batch_spec.rb +36 -0
  55. data/spec/integration/create_spec.rb +33 -0
  56. data/spec/integration/delete_spec.rb +33 -0
  57. data/spec/integration/migrate/20150825142003_create_users.rb +24 -0
  58. data/spec/integration/migrate/20150825142024_create_logs.rb +17 -0
  59. data/spec/integration/migrate_spec.rb +47 -0
  60. data/spec/integration/relation_spec.rb +27 -0
  61. data/spec/integration/update_spec.rb +33 -0
  62. data/spec/shared/fake_migrate_folder.rb +21 -0
  63. data/spec/shared/users.rb +20 -0
  64. data/spec/spec_helper.rb +17 -0
  65. data/spec/unit/commands/batch_spec.rb +86 -0
  66. data/spec/unit/commands/create_spec.rb +77 -0
  67. data/spec/unit/commands/delete_spec.rb +77 -0
  68. data/spec/unit/commands/update_spec.rb +77 -0
  69. data/spec/unit/dataset_spec.rb +130 -0
  70. data/spec/unit/gateway_spec.rb +140 -0
  71. data/spec/unit/migrations/generator_spec.rb +31 -0
  72. data/spec/unit/migrations/logger_spec.rb +21 -0
  73. data/spec/unit/migrations/migration_spec.rb +59 -0
  74. data/spec/unit/migrations/migrator_spec.rb +120 -0
  75. data/spec/unit/migrations/runner_down_spec.rb +65 -0
  76. data/spec/unit/migrations/runner_spec.rb +142 -0
  77. data/spec/unit/migrations/runner_up_spec.rb +67 -0
  78. data/spec/unit/query_spec.rb +21 -0
  79. data/spec/unit/relation_spec.rb +142 -0
  80. data/spec/unit/session_spec.rb +55 -0
  81. data/spec/unit/tasks/create_migration_spec.rb +41 -0
  82. 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