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,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