cassie 1.0.0.beta.33 → 1.0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cassie +8 -181
- data/lib/cassie/configuration/core.rb +26 -3
- data/lib/cassie/configuration/generator.rb +1 -0
- data/lib/cassie/configuration/loading.rb +5 -2
- data/lib/cassie/configuration.rb +1 -0
- data/lib/cassie/connection.rb +13 -7
- data/lib/cassie/connection_handler/README.md +13 -3
- data/lib/cassie/connection_handler/cluster.rb +11 -0
- data/lib/cassie/connection_handler/sessions.rb +9 -0
- data/lib/cassie/connection_handler.rb +8 -7
- data/lib/cassie/definition.rb +28 -0
- data/lib/cassie/extensions/object/color_methods.rb +21 -0
- data/lib/cassie/instrumentation.rb +4 -0
- data/lib/cassie/modification.rb +29 -0
- data/lib/cassie/query.rb +27 -0
- data/lib/cassie/schema/README.md +306 -0
- data/lib/cassie/schema/apply_command.rb +24 -0
- data/lib/cassie/schema/cassandra_migrations/importer.rb +91 -0
- data/lib/cassie/schema/cassandra_migrations/migration_file.rb +51 -0
- data/lib/cassie/schema/configuration.rb +35 -0
- data/lib/cassie/schema/migration/cassandra_support.rb +34 -0
- data/lib/cassie/schema/migration/dsl/announcing.rb +47 -0
- data/lib/cassie/schema/migration/dsl/column_operations.rb +42 -0
- data/lib/cassie/schema/migration/dsl/table_definition.rb +299 -0
- data/lib/cassie/schema/migration/dsl/table_operations.rb +64 -0
- data/lib/cassie/schema/migration/dsl.rb +17 -0
- data/lib/cassie/schema/migration.rb +12 -0
- data/lib/cassie/schema/migrator.rb +115 -0
- data/lib/cassie/schema/queries/create_keyspace_query.rb +26 -0
- data/lib/cassie/{migration → schema}/queries/create_versions_table_query.rb +6 -6
- data/lib/cassie/schema/queries/delete_version_query.rb +17 -0
- data/lib/cassie/schema/queries/drop_keyspace_query.rb +14 -0
- data/lib/cassie/schema/queries/insert_version_query.rb +22 -0
- data/lib/cassie/schema/queries/select_versions_query.rb +18 -0
- data/lib/cassie/{migration → schema}/queries.rb +4 -2
- data/lib/cassie/schema/rollback_command.rb +24 -0
- data/lib/cassie/schema/structure_dumper.rb +117 -0
- data/lib/cassie/{migration → schema}/structure_loader.rb +3 -3
- data/lib/cassie/schema/version.rb +143 -0
- data/lib/cassie/schema/version_file_loader.rb +34 -0
- data/lib/cassie/schema/version_loader.rb +31 -0
- data/lib/cassie/schema/version_object_loader.rb +19 -0
- data/lib/cassie/schema/version_writer.rb +108 -0
- data/lib/cassie/schema/versioning.rb +162 -0
- data/lib/cassie/schema.rb +24 -0
- data/lib/cassie/statements/README.md +61 -9
- data/lib/cassie/statements/core.rb +16 -5
- data/lib/cassie/statements/execution/results/core.rb +1 -1
- data/lib/cassie/statements/execution/results/modification_result.rb +1 -1
- data/lib/cassie/statements/execution/results/query_result.rb +1 -1
- data/lib/cassie/statements/execution.rb +40 -13
- data/lib/cassie/statements/statement/assignments.rb +33 -3
- data/lib/cassie/statements/statement/conditions.rb +3 -1
- data/lib/cassie/statements/statement/deleting.rb +27 -19
- data/lib/cassie/statements/statement/idempotency.rb +23 -4
- data/lib/cassie/statements/statement/inserting.rb +17 -10
- data/lib/cassie/statements/statement/limiting.rb +5 -2
- data/lib/cassie/statements/statement/mapping.rb +34 -6
- data/lib/cassie/statements/statement/preparation/cache.rb +1 -1
- data/lib/cassie/statements/statement/preparation.rb +37 -7
- data/lib/cassie/statements/statement/relations.rb +29 -8
- data/lib/cassie/statements/statement/selection.rb +51 -15
- data/lib/cassie/statements/statement/type_hinting.rb +12 -4
- data/lib/cassie/statements/statement/updating.rb +22 -8
- data/lib/cassie/statements/statement.rb +39 -14
- data/lib/cassie/statements.rb +12 -0
- data/lib/cassie/support/server_process.rb +117 -0
- data/lib/cassie/support/statement_parser.rb +3 -5
- data/lib/cassie/support/{command_runner.rb → system_command.rb} +22 -13
- data/lib/cassie/support.rb +3 -1
- data/lib/cassie/tasks/configuration/generate.rake +35 -0
- data/lib/cassie/tasks/io.rb +15 -0
- data/lib/cassie/tasks/migration/create.rake +49 -0
- data/lib/cassie/tasks/migration/import.rake +39 -0
- data/lib/cassie/tasks/migration/reset.rake +9 -0
- data/lib/cassie/tasks/restart.rake +5 -0
- data/lib/cassie/tasks/schema/drop.rake +28 -0
- data/lib/cassie/tasks/schema/dump.rake +21 -0
- data/lib/cassie/tasks/schema/history.rake +18 -0
- data/lib/cassie/tasks/schema/import.rake +40 -0
- data/lib/cassie/tasks/schema/init.rake +54 -0
- data/lib/cassie/tasks/schema/load.rake +19 -0
- data/lib/cassie/tasks/schema/migrate.rake +42 -0
- data/lib/cassie/tasks/schema/reset.rake +6 -0
- data/lib/cassie/tasks/schema/status.rake +19 -0
- data/lib/cassie/tasks/schema/version.rake +18 -0
- data/lib/cassie/tasks/schema/version_display.rb +50 -0
- data/lib/cassie/tasks/start.rake +17 -0
- data/lib/cassie/tasks/stop.rake +33 -0
- data/lib/cassie/tasks/tail.rake +14 -0
- data/lib/cassie/tasks/task_runner.rb +49 -0
- data/lib/cassie/tasks.rb +18 -0
- data/lib/cassie/testing/fake/execution_info.rb +1 -1
- data/lib/cassie/testing/fake/result.rb +3 -3
- data/lib/cassie/testing.rb +4 -0
- data/lib/cassie/version.rb +1 -1
- data/lib/cassie.rb +4 -1
- metadata +73 -17
- data/lib/cassie/migration/README.md +0 -141
- data/lib/cassie/migration/configuration.rb +0 -18
- data/lib/cassie/migration/initialization.rb +0 -70
- data/lib/cassie/migration/queries/create_schema_keyspace_query.rb +0 -17
- data/lib/cassie/migration/queries/insert_version_query.rb +0 -23
- data/lib/cassie/migration/queries/select_versions_query.rb +0 -14
- data/lib/cassie/migration/structure_dumper.rb +0 -94
- data/lib/cassie/migration/version.rb +0 -4
- data/lib/cassie/migration.rb +0 -30
@@ -0,0 +1,306 @@
|
|
1
|
+
# Cassie Schema Migrations
|
2
|
+
|
3
|
+
Cassie provides versioned migrations similar to many existing adapters and frameworks.
|
4
|
+
|
5
|
+
Practically speaking, this gives your cluster Schema its own "version" and simplifies upgrading or rolling back the schema.
|
6
|
+
|
7
|
+
As such, Cassie uses semantic versioning, where a defined version describes the keyspace defined in the cluster configuration.
|
8
|
+
|
9
|
+
Major, minor, patch, and build versions are used, however semantic extensions are not recommended (prerelase or metadata, eg: 1.0.0.beta).
|
10
|
+
|
11
|
+
### Schema Migrations
|
12
|
+
|
13
|
+
Schema version and migrations are managed through various `cassie` tasks. See below for basic usage.
|
14
|
+
|
15
|
+
List command descriptions and advanced options:
|
16
|
+
```
|
17
|
+
cassie --help
|
18
|
+
```
|
19
|
+
|
20
|
+
#### Getting Started
|
21
|
+
|
22
|
+
If no schema has been defined yet (e.g. no keyspace, tables, or types), simply initialize Cassie versioning:
|
23
|
+
|
24
|
+
```
|
25
|
+
cassie schema:init
|
26
|
+
```
|
27
|
+
|
28
|
+
```
|
29
|
+
-- Initializing Cassie Versioning
|
30
|
+
-- done
|
31
|
+
-- Initializing 'my_app_development' Keyspace
|
32
|
+
-- done
|
33
|
+
```
|
34
|
+
|
35
|
+
If an existing schema (e.g. keyspace, tables, types) is alredy defined, see below on how to import it.
|
36
|
+
|
37
|
+
#### Coming from `cassandra_migrations`
|
38
|
+
|
39
|
+
Import your existing `cassandra_migrations` migration files with a single task:
|
40
|
+
|
41
|
+
```
|
42
|
+
cassie migrations:import
|
43
|
+
```
|
44
|
+
```bash
|
45
|
+
-- Importing `cassandra_migrations` migration files
|
46
|
+
- Importing db/cassandra_migrate/20161206214301_initial_database.rb
|
47
|
+
> created /db/cassandra/migrations/0000_0000_0000_0001_initial_database.rb
|
48
|
+
> recorded version 0.0.0.1
|
49
|
+
- done
|
50
|
+
- Importing db/cassandra_migrate/20161212210447_add_username_to_users.rb
|
51
|
+
> created /db/cassandra/migrations/0000_0000_0001_0000_add_username_to_users.rb
|
52
|
+
> recorded version 0.0.1.0
|
53
|
+
- done
|
54
|
+
- Importing db/cassandra_migrate/20161213163201_add_reserved_to_users.rb
|
55
|
+
> created /db/cassandra/migrations/0000_0000_0002_0000_add_reserved_to_users.rb
|
56
|
+
> recorded version 0.0.2.0
|
57
|
+
- done
|
58
|
+
-- done
|
59
|
+
```
|
60
|
+
|
61
|
+
> The original `cassandra_migrations` migration files and schema in the physical layer are not changed. Remove the old files when comfortable.
|
62
|
+
|
63
|
+
|
64
|
+
#### Coming from no explicit migration/versioning management
|
65
|
+
|
66
|
+
Import your existing schema held in Cassandra with a single task:
|
67
|
+
|
68
|
+
```
|
69
|
+
cassie schema:import
|
70
|
+
```
|
71
|
+
|
72
|
+
```
|
73
|
+
-- Initializing Cassie Versioning
|
74
|
+
-- done
|
75
|
+
-- Initializing 'my_app_development' Keyspace
|
76
|
+
> 'my_app_development' already exists
|
77
|
+
-- done
|
78
|
+
-- Importing Schema from Cassandra
|
79
|
+
- Creating initial version
|
80
|
+
> created db/cassandra/migrations/0000_0000_0001_0000_import_my_app_development.rb
|
81
|
+
> recorded version 0.0.1.0
|
82
|
+
- done
|
83
|
+
-- done
|
84
|
+
-- Dumping Cassandra schema (version 0.0.1.0)
|
85
|
+
- Writing to db/cassandra/schema.cql
|
86
|
+
- done
|
87
|
+
-- done
|
88
|
+
```
|
89
|
+
|
90
|
+
#### Creating a migration
|
91
|
+
|
92
|
+
```
|
93
|
+
cassie migration:create that killer feature
|
94
|
+
```
|
95
|
+
|
96
|
+
```
|
97
|
+
-- Creating migration file for version 0.0.1.0
|
98
|
+
> created db/cassandra/migrations/0000_0000_0001_0000_that_killer_feature.rb
|
99
|
+
-- done
|
100
|
+
```
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
# db/cassandra/migrations/0000_0000_0001_0000_that_killer_feature.rb
|
104
|
+
class Migration_0_0_1_0 < Cassie::Schema::Migration
|
105
|
+
def up
|
106
|
+
# Code to execute when applying this migration
|
107
|
+
# Supports the excellent `cassandra_migrations` DSL
|
108
|
+
# or call `execute` to call `Cassandra::Session.execute`
|
109
|
+
end
|
110
|
+
|
111
|
+
def down
|
112
|
+
# Code to execute when rolling back this migration
|
113
|
+
# Supports the excellent `cassandra_migrations` DSL
|
114
|
+
# or call `execute` to call `Cassandra::Session.execute`
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
```
|
119
|
+
|
120
|
+
By default, the `patch` version will be bumped. Use the `--major` (`-M`), `--minor` (`-m`), or `--build` (`-b`) switches to bump differently. Or, explicitly set the version with `--version` (`-v`): `cassie migration:create that fixup -v 0.1.3.15`.
|
121
|
+
|
122
|
+
> *Note:* The class name only needs to match the version in the filename. The description suffix can be changed without having to change the classname.
|
123
|
+
|
124
|
+
#### Executing migrations
|
125
|
+
|
126
|
+
##### Roll up to latest version
|
127
|
+
|
128
|
+
```
|
129
|
+
cassie migrate
|
130
|
+
```
|
131
|
+
|
132
|
+
##### Roll up to a specific version
|
133
|
+
|
134
|
+
```
|
135
|
+
cassie migrate 0.2.0
|
136
|
+
```
|
137
|
+
|
138
|
+
##### Rolling back
|
139
|
+
|
140
|
+
Use the same interface to migrate up or down to a specific version.
|
141
|
+
|
142
|
+
```
|
143
|
+
cassie migrate 0.1.9
|
144
|
+
```
|
145
|
+
|
146
|
+
#### Reporting the current version
|
147
|
+
```
|
148
|
+
cassie schema:version
|
149
|
+
```
|
150
|
+
```
|
151
|
+
+-----------+----------------+-------------+---------------------------+
|
152
|
+
| Version | Description | Migrated by | Migrated at |
|
153
|
+
+-----------+----------------+-------------+---------------------------+
|
154
|
+
| * 0.2.0.0 | create users | serverbot | 2016-09-08 10:23:54 -0500 |
|
155
|
+
+-----------+----------------+-------------+---------------------------+
|
156
|
+
```
|
157
|
+
|
158
|
+
#### Reporting the version history
|
159
|
+
```
|
160
|
+
cassie schema:history
|
161
|
+
```
|
162
|
+
```
|
163
|
+
+-----------+----------------+-------------+---------------------------+
|
164
|
+
| Version | Description | Migrated by | Migrated at |
|
165
|
+
+-----------+----------------+-------------+---------------------------+
|
166
|
+
| * 0.2.0.0 | create users | serverbot | 2016-09-08 10:23:54 -0500 |
|
167
|
+
| 0.1.0.0 | initial schema | eprothro | 2016-09-08 09:23:54 -0500 |
|
168
|
+
+-----------+----------------+-------------+---------------------------+
|
169
|
+
```
|
170
|
+
|
171
|
+
#### Reporting the version status
|
172
|
+
```
|
173
|
+
cassie schema:status
|
174
|
+
```
|
175
|
+
```
|
176
|
+
+-----------+----------------+-------------+---------------------------+
|
177
|
+
| Version | Description | Status | Migration File |
|
178
|
+
+-----------+----------------+-------------+---------------------------+
|
179
|
+
| * 0.2.0.0 | create users | serverbot | 2016-09-08 10:23:54 -0500 |
|
180
|
+
| 0.1.0.0 | initial schema | eprothro | 2016-09-08 09:23:54 -0500 |
|
181
|
+
+-----------+----------------+-------------+---------------------------+
|
182
|
+
```
|
183
|
+
|
184
|
+
### Schema Management
|
185
|
+
|
186
|
+
The full schema is stored in `schema.cql`, this is recommended to be checked into source control.
|
187
|
+
It is updated (with a full dump) after each migration, to maintain a truth-store for the schema when used with multiple developers.
|
188
|
+
|
189
|
+
### Dump the schema
|
190
|
+
|
191
|
+
```
|
192
|
+
cassie schema:dump
|
193
|
+
```
|
194
|
+
```
|
195
|
+
-- Dumping Cassandra schema (version 0.2.0.0)
|
196
|
+
- Writing to db/cassandra/schema.cql
|
197
|
+
- done
|
198
|
+
-- done
|
199
|
+
```
|
200
|
+
|
201
|
+
### Drop the schema
|
202
|
+
```
|
203
|
+
cassie schema:drop
|
204
|
+
```
|
205
|
+
```
|
206
|
+
-- Dropping 2 keyspaces
|
207
|
+
- Dropping 'my_app_development'
|
208
|
+
- done
|
209
|
+
- Dropping 'cassie_schema'
|
210
|
+
- done
|
211
|
+
-- done
|
212
|
+
```
|
213
|
+
|
214
|
+
### Load the schema
|
215
|
+
```
|
216
|
+
cassie schema:load
|
217
|
+
```
|
218
|
+
```
|
219
|
+
-- Loading Schema from db/cassandra/schema.cql
|
220
|
+
> Schema is now at version 0.2.0.0
|
221
|
+
-- done
|
222
|
+
```
|
223
|
+
|
224
|
+
### Reset the schema
|
225
|
+
|
226
|
+
```
|
227
|
+
cassie schema:reset
|
228
|
+
```
|
229
|
+
```
|
230
|
+
-- Dropping 2 keyspaces
|
231
|
+
- Dropping 'my_app_development'
|
232
|
+
- done
|
233
|
+
- Dropping 'cassie_schema'
|
234
|
+
- done
|
235
|
+
-- done
|
236
|
+
-- Loading Schema from db/cassandra/schema.cql
|
237
|
+
> Schema is now at version 0.2.0.0
|
238
|
+
-- done
|
239
|
+
```
|
240
|
+
|
241
|
+
### Reset the schema and migrate
|
242
|
+
|
243
|
+
This task reload the schema from the schema file, and then proceeds with incremental migrations up to the latest migration.
|
244
|
+
|
245
|
+
```
|
246
|
+
cassie migrate:reset
|
247
|
+
```
|
248
|
+
```
|
249
|
+
-- Dropping 2 keyspaces
|
250
|
+
- Dropping 'cassie_development'
|
251
|
+
- done
|
252
|
+
- Dropping 'cassie_schema'
|
253
|
+
- done
|
254
|
+
-- done
|
255
|
+
-- Loading Schema from db/cassandra/schema.cql
|
256
|
+
> Schema is now at version 0.2.0.0
|
257
|
+
-- done
|
258
|
+
-- Migrating to version 0.2.1.0
|
259
|
+
- Migragting version 0.2.1.0 UP
|
260
|
+
- done (4.89 ms)
|
261
|
+
-- done
|
262
|
+
-- Dumping Cassandra schema (version 0.2.1.0)
|
263
|
+
- Writing to db/cassandra/schema.cql
|
264
|
+
- done
|
265
|
+
-- done
|
266
|
+
```
|
267
|
+
|
268
|
+
### Architecture (`cassie` developers)
|
269
|
+
|
270
|
+
#### Versions
|
271
|
+
|
272
|
+
A `Version` is a container class for a `migration`. A version may be applied in the current database's schema, or not.
|
273
|
+
|
274
|
+
There are multiple independent, but potentially related/overlapping collections of `versions`.
|
275
|
+
|
276
|
+
One is `Cassie::Schema.applied_versions`, which is the set of versions that have been applied, in the past, to a Cassandra database.
|
277
|
+
|
278
|
+
Another is `Cassie::Schema.local_versions`, which the set of versions represented by migration files found in the `migrations_directory`.
|
279
|
+
|
280
|
+
Versions are migrated up or down, and then recorded or forgotten, respectively, in the database's configurable `<schema_keyspace>.<versions_table>` (`cassie_schema.versions` by default).
|
281
|
+
|
282
|
+
#### Migrations
|
283
|
+
|
284
|
+
Strictly speaking, the *version* is what is being migrated up or down. The `Migration` is the class defining code to execute `up` or `down`. The version object delegates implementation of the migration to the `Migration` object.
|
285
|
+
|
286
|
+
This class embeds the version number in it, but the `Migration` object does not know about the concept of its version. A migration file is used to load a `Version`, which contains the `Migration` object.
|
287
|
+
|
288
|
+
Cassie only expects that the version number emedded in the class name match the one embedded in the file name.
|
289
|
+
|
290
|
+
This means you can change the description embedded in the migration file without having to rename the class.
|
291
|
+
|
292
|
+
#### A Note on rollback
|
293
|
+
|
294
|
+
Migrating down rolls back the state of the schema in the Cassandra database. The in-database schema history keeps track of what migrations have been applied and rolls them back in that order (as opposed to whatever order the files indicate). This ensures the following scenario is supported:
|
295
|
+
|
296
|
+
* Given the following mirgations exist:
|
297
|
+
* 0.1.0.0
|
298
|
+
* 0.1.1.0
|
299
|
+
* And both migrations have been executed.
|
300
|
+
* When a migraiton is created for version `0.1.0.99`
|
301
|
+
* And the schema is migrated with `cassie migrate 0.1.0.0`
|
302
|
+
* Then the `down` method for `0.1.0.99` is NOT executed
|
303
|
+
|
304
|
+
* And then when the schema is migrated with `cassie migrate`, the `up` methods from the following migrations are executed:
|
305
|
+
* 0.1.0.99
|
306
|
+
* 0.1.1.0
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Cassie::Schema
|
2
|
+
class ApplyCommand
|
3
|
+
attr_reader :version
|
4
|
+
|
5
|
+
def initialize(version)
|
6
|
+
@version = version
|
7
|
+
end
|
8
|
+
|
9
|
+
def direction
|
10
|
+
:up
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute
|
14
|
+
version.migration.up
|
15
|
+
apply
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def apply
|
21
|
+
Cassie::Schema.record_version(version)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require_relative 'migration_file'
|
2
|
+
|
3
|
+
module Cassie::Schema
|
4
|
+
module CassandraMigrations
|
5
|
+
class Importer
|
6
|
+
# The source directory containing the +cassandra_migrations+ files.
|
7
|
+
# Defaults to +db/cassandra_migrate+
|
8
|
+
attr_accessor :source
|
9
|
+
# The version the schema will rest at after importing.
|
10
|
+
# Defaults to +0.1.0+ with a description of +Remove cassandra_migrations schema+
|
11
|
+
attr_accessor :final_version
|
12
|
+
# The migration files to be imported
|
13
|
+
attr_accessor :migration_files
|
14
|
+
# A callback fired before importing each migration
|
15
|
+
attr_accessor :before_each
|
16
|
+
# A callback fired after importing each migration
|
17
|
+
attr_accessor :after_each
|
18
|
+
|
19
|
+
def initialize(source_path=nil)
|
20
|
+
@source = source_path || default_source_path
|
21
|
+
@final_version = Cassie::Schema::Version.new("0.0.1.0", "Remove cassandra_migrations schema")
|
22
|
+
@migration_files = find_migration_files
|
23
|
+
@before_each = Proc.new{}
|
24
|
+
@after_each = Proc.new{}
|
25
|
+
end
|
26
|
+
|
27
|
+
def import
|
28
|
+
new_version = initial_version
|
29
|
+
new_version.executor = "cassandra_migrations"
|
30
|
+
new_version.executed_at = Time.now
|
31
|
+
|
32
|
+
migration_files.each do |old_migration_file|
|
33
|
+
before_each.call(old_migration_file)
|
34
|
+
new_version.id = Cassandra::TimeUuid::Generator.new.now
|
35
|
+
new_version.description = old_migration_file.description.humanize
|
36
|
+
writer = VersionWriter.new(new_version)
|
37
|
+
# new_version will automatically find
|
38
|
+
# the new cassie::schema::migration
|
39
|
+
# that is built from the old file
|
40
|
+
writer.migration_contents = old_migration_file.build_migration_class(new_version)
|
41
|
+
|
42
|
+
writer.write
|
43
|
+
|
44
|
+
Cassie::Schema.record_version(new_version, false)
|
45
|
+
after_each.call(new_version)
|
46
|
+
|
47
|
+
new_version = new_version.next
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
def default_source_path
|
54
|
+
"db/cassandra_migrate"
|
55
|
+
end
|
56
|
+
|
57
|
+
def find_migration_files
|
58
|
+
paths = Dir.glob("#{absolute_source}/#{migration_template}")
|
59
|
+
paths = Dir.glob("#{relative_source}/#{migration_template}") if paths.empty?
|
60
|
+
raise_files_not_found if paths.empty?
|
61
|
+
|
62
|
+
paths.map{ |path| MigrationFile.new(path) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def absolute_source
|
66
|
+
source
|
67
|
+
end
|
68
|
+
|
69
|
+
def relative_source
|
70
|
+
File.join(root, source)
|
71
|
+
end
|
72
|
+
|
73
|
+
def root
|
74
|
+
Dir.pwd
|
75
|
+
end
|
76
|
+
|
77
|
+
def migration_template
|
78
|
+
# 20161206214301_initial_database.rb
|
79
|
+
"[0-9]*_*.rb"
|
80
|
+
end
|
81
|
+
|
82
|
+
def raise_files_not_found
|
83
|
+
raise "No Cassandra Migration files were found. Looked in #{absolute_source} and #{relative_source}. Check the path and try again."
|
84
|
+
end
|
85
|
+
|
86
|
+
def initial_version
|
87
|
+
Cassie::Schema::Version.new("0.0.0.1")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Cassie::Schema
|
2
|
+
module CassandraMigrations
|
3
|
+
class MigrationFile
|
4
|
+
|
5
|
+
attr_reader :filename, :source, :description
|
6
|
+
|
7
|
+
def initialize(filename)
|
8
|
+
@filename = filename
|
9
|
+
@description = parse_description
|
10
|
+
end
|
11
|
+
|
12
|
+
# Builds a Cassie::Schema::Migration
|
13
|
+
# from the CassandraMigrations migration file
|
14
|
+
#
|
15
|
+
# @return [String] source string of new migration class
|
16
|
+
def build_migration_class(version)
|
17
|
+
@source = load_source
|
18
|
+
redefine_class(version.migration_class_name)
|
19
|
+
define_new_migration_class
|
20
|
+
version.migration_class_name.constantize
|
21
|
+
@source
|
22
|
+
ensure
|
23
|
+
@source = nil #free for GC
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def parse_description
|
29
|
+
matches = File.basename(filename).match(/[0-9]*_(.*).rb$/).captures
|
30
|
+
matches.first
|
31
|
+
end
|
32
|
+
|
33
|
+
def load_source
|
34
|
+
File.read(filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
def redefine_class(name)
|
38
|
+
class_def = "class #{name} < Cassie::Schema::Migration"
|
39
|
+
# class UserMigration < CassandraMigrations::Migration
|
40
|
+
@source.sub!(/class\s.*<\s*CassandraMigrations::Migration/, class_def)
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_new_migration_class
|
44
|
+
# define class in context of Object
|
45
|
+
# as a migration file does, rather
|
46
|
+
# than in the current context
|
47
|
+
Object.class_eval(@source)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Cassie::Schema
|
4
|
+
# Extend a module/class with Configuration to enable migration management
|
5
|
+
module Configuration
|
6
|
+
|
7
|
+
# The keyspace in which to store Cassie schema data
|
8
|
+
attr_accessor :schema_keyspace
|
9
|
+
# The table in which to store Cassie schema applied versions data
|
10
|
+
attr_accessor :versions_table
|
11
|
+
|
12
|
+
# @!visibility private
|
13
|
+
def self.extended(extender)
|
14
|
+
extender.paths["schema_file"] = "db/cassandra/schema.cql"
|
15
|
+
extender.paths["migrations_directory"] = "db/cassandra/migrations"
|
16
|
+
extender.schema_keyspace = "cassie_schema"
|
17
|
+
extender.versions_table = "versions"
|
18
|
+
end
|
19
|
+
|
20
|
+
# Paths used for configuration loading.
|
21
|
+
#
|
22
|
+
# @return [Hash]
|
23
|
+
# * +:schema_file+ - The .cql file defining the current schema structure
|
24
|
+
# * +:migrations_directory+ - The directory containing the versioned schema migration .rb files
|
25
|
+
def paths
|
26
|
+
@paths ||= {}.with_indifferent_access
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def root
|
32
|
+
Pathname.new(Dir.pwd)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Cassie::Schema
|
2
|
+
class Migration
|
3
|
+
require_relative 'dsl'
|
4
|
+
|
5
|
+
module CassandraSupport
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include Cassie::Connection
|
10
|
+
include DSL
|
11
|
+
end
|
12
|
+
|
13
|
+
def execute(*params)
|
14
|
+
session.execute(*params)
|
15
|
+
end
|
16
|
+
|
17
|
+
# compatibility with casandra_migrations
|
18
|
+
# until import handles this
|
19
|
+
def using_keyspace(val)
|
20
|
+
raise ArgumentError, "block required for using temporary keyspace" unless block_given?
|
21
|
+
orignal = @keyspace if defined?(@keyspace)
|
22
|
+
@keyspace = val
|
23
|
+
|
24
|
+
yield
|
25
|
+
|
26
|
+
if defined?(orignal)
|
27
|
+
@keyspace = original
|
28
|
+
else
|
29
|
+
remove_instance_variable(:@keyspace)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Cassie::Schema::Migration::DSL
|
2
|
+
module Announcing
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
module ClassMethods
|
6
|
+
def announcing_stream
|
7
|
+
return @announcing_stream if defined?(@announcing_stream)
|
8
|
+
$stdout
|
9
|
+
end
|
10
|
+
|
11
|
+
def announcing_stream=(val)
|
12
|
+
@announcing_stream = val
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def announcing_stream
|
17
|
+
self.class.announcing_stream
|
18
|
+
end
|
19
|
+
|
20
|
+
def announce(msg)
|
21
|
+
announcing_stream << msg
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
# Generates output labeled with name of migration and a line that goes up
|
27
|
+
# to 75 characters long in the terminal
|
28
|
+
def announce_migration(message)
|
29
|
+
text = "#{name}: #{message}"
|
30
|
+
length = [0, 75 - text.length].max
|
31
|
+
|
32
|
+
announce("== %s %s" % [text, "=" * length])
|
33
|
+
end
|
34
|
+
|
35
|
+
def announce_operation(message)
|
36
|
+
announce(" " + message)
|
37
|
+
end
|
38
|
+
|
39
|
+
def announce_suboperation(message)
|
40
|
+
announce(" -> " + message)
|
41
|
+
end
|
42
|
+
|
43
|
+
def name
|
44
|
+
version.description || version.number
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative 'table_definition'
|
2
|
+
|
3
|
+
module Cassie::Schema::Migration::DSL
|
4
|
+
# Module grouping methods used in migrations to make table operations like:
|
5
|
+
# - adding/removing columns
|
6
|
+
# - changing column types
|
7
|
+
# - renaming columns
|
8
|
+
module ColumnOperations
|
9
|
+
# Adds a column to a table.
|
10
|
+
#
|
11
|
+
# options: same options you would pass to create a table with that column
|
12
|
+
# (i.e. :limit might be applicable)
|
13
|
+
|
14
|
+
def add_column(table_name, column_name, type, options = {})
|
15
|
+
table_definition = TableDefinition.new
|
16
|
+
|
17
|
+
if !table_definition.respond_to?(type)
|
18
|
+
raise Errors::MigrationDefinitionError("Type '#{type}' is not valid for cassandra migration.")
|
19
|
+
end
|
20
|
+
|
21
|
+
table_definition.send(type, column_name, options)
|
22
|
+
|
23
|
+
announce_operation "add_column(#{column_name}, #{type})"
|
24
|
+
|
25
|
+
cql = "ALTER TABLE #{table_name} ADD "
|
26
|
+
cql << table_definition.to_add_column_cql
|
27
|
+
announce_suboperation cql
|
28
|
+
|
29
|
+
execute cql
|
30
|
+
end
|
31
|
+
|
32
|
+
# Removes a column from the table
|
33
|
+
def remove_column(table_name, column_name)
|
34
|
+
announce_operation "drop_table(#{table_name})"
|
35
|
+
|
36
|
+
cql = "ALTER TABLE #{table_name} DROP #{column_name}"
|
37
|
+
announce_suboperation cql
|
38
|
+
|
39
|
+
execute cql
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|