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