cequel 1.3.2 → 1.4.0
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 +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +2 -2
- data/lib/cequel/metal/data_set.rb +1 -0
- data/lib/cequel/metal/keyspace.rb +26 -6
- data/lib/cequel/metal/row.rb +1 -0
- data/lib/cequel/record.rb +12 -0
- data/lib/cequel/record/errors.rb +12 -0
- data/lib/cequel/record/persistence.rb +14 -3
- data/lib/cequel/record/schema.rb +2 -0
- data/lib/cequel/schema/keyspace.rb +5 -0
- data/lib/cequel/schema/migration_validator.rb +2 -1
- data/lib/cequel/spec_support.rb +11 -0
- data/lib/cequel/spec_support/preparation.rb +130 -0
- data/lib/cequel/version.rb +1 -1
- data/spec/examples/metal/keyspace_spec.rb +14 -0
- data/spec/examples/record/list_spec.rb +1 -1
- data/spec/examples/record/map_spec.rb +1 -1
- data/spec/examples/record/persistence_spec.rb +39 -2
- data/spec/examples/record/schema_spec.rb +18 -10
- data/spec/examples/record/set_spec.rb +1 -1
- data/spec/examples/spec_support/preparation_spec.rb +81 -0
- data/spec/support/helpers.rb +1 -2
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94c47d58ecd94cbaf5eb664962dc94aad6fcdfc7
|
4
|
+
data.tar.gz: 7a88e130ad1aec7083a9acf7efcd3d71a736472e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 098e9d6b6e4aafb27140892e5911a65b718c9e869fa975a6d81d690720015c65462e0f59ef1190ea34c30dfca7747a9dac41ea8473edfa8c82666ab39b1a0f7a
|
7
|
+
data.tar.gz: ca9f78e81f43253dcf48215320e7743211e260b179d85a3df92280d886cf12a5d1277364374eb45f7739467f7498953b4dea6c28c809c8fd68a887113c5e4c78
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
cequel (1.
|
4
|
+
cequel (1.4.0)
|
5
5
|
activemodel (>= 3.1, < 5.0)
|
6
6
|
cql-rb (>= 1.2, < 3.0)
|
7
7
|
|
@@ -284,7 +284,7 @@ GEM
|
|
284
284
|
thread_safe (0.3.4)
|
285
285
|
thread_safe (0.3.4-java)
|
286
286
|
timecop (0.7.1)
|
287
|
-
tzinfo (1.2.
|
287
|
+
tzinfo (1.2.1)
|
288
288
|
thread_safe (~> 0.1)
|
289
289
|
yard (0.8.7.4)
|
290
290
|
|
@@ -143,7 +143,11 @@ module Cequel
|
|
143
143
|
# @api private
|
144
144
|
#
|
145
145
|
def client
|
146
|
-
synchronize
|
146
|
+
synchronize do
|
147
|
+
@client ||= raw_client.tap do |client|
|
148
|
+
client.use(name) if name
|
149
|
+
end
|
150
|
+
end
|
147
151
|
end
|
148
152
|
|
149
153
|
#
|
@@ -195,6 +199,19 @@ module Cequel
|
|
195
199
|
@default_consistency || :quorum
|
196
200
|
end
|
197
201
|
|
202
|
+
# @return [Boolean] true if the keyspace exists
|
203
|
+
def exists?
|
204
|
+
statement = <<-CQL
|
205
|
+
SELECT keyspace_name
|
206
|
+
FROM system.schema_keyspaces
|
207
|
+
WHERE keyspace_name = ?
|
208
|
+
CQL
|
209
|
+
|
210
|
+
log('CQL', statement, [name]) do
|
211
|
+
raw_client.execute(sanitize(statement, [name])).any?
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
198
215
|
private
|
199
216
|
|
200
217
|
attr_reader :lock
|
@@ -205,12 +222,15 @@ module Cequel
|
|
205
222
|
def_delegator :lock, :synchronize
|
206
223
|
private :lock
|
207
224
|
|
208
|
-
def
|
209
|
-
|
210
|
-
|
225
|
+
def raw_client
|
226
|
+
synchronize do
|
227
|
+
@raw_client ||= Cql::Client.connect(client_options)
|
211
228
|
end
|
212
|
-
|
213
|
-
|
229
|
+
end
|
230
|
+
|
231
|
+
def client_options
|
232
|
+
{hosts: hosts, port: port}.tap do |options|
|
233
|
+
options[:credentials] = credentials if credentials
|
214
234
|
end
|
215
235
|
end
|
216
236
|
|
data/lib/cequel/metal/row.rb
CHANGED
data/lib/cequel/record.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
require 'active_model'
|
3
|
+
require 'weakref'
|
3
4
|
|
4
5
|
require 'cequel'
|
5
6
|
require 'cequel/record/errors'
|
@@ -117,6 +118,17 @@ module Cequel
|
|
117
118
|
def establish_connection(configuration)
|
118
119
|
self.connection = Cequel.connect(configuration)
|
119
120
|
end
|
121
|
+
|
122
|
+
# @return [Array<Class>] All the record classes that are
|
123
|
+
# currently defined.
|
124
|
+
def descendants
|
125
|
+
(@descendants ||= []).select(&:weakref_alive?)
|
126
|
+
end
|
127
|
+
|
128
|
+
# Hook called when new record classes are created.
|
129
|
+
def included(base)
|
130
|
+
@descendants = descendants + [WeakRef.new(base)]
|
131
|
+
end
|
120
132
|
end
|
121
133
|
end
|
122
134
|
end
|
data/lib/cequel/record/errors.rb
CHANGED
@@ -8,6 +8,7 @@ module Cequel
|
|
8
8
|
# @since 1.0.0
|
9
9
|
#
|
10
10
|
MissingAttributeError = Class.new(ArgumentError)
|
11
|
+
|
11
12
|
#
|
12
13
|
# Raised when attempting to read or write an attribute that isn't defined
|
13
14
|
# on the record
|
@@ -15,11 +16,13 @@ module Cequel
|
|
15
16
|
# @since 1.0.0
|
16
17
|
#
|
17
18
|
UnknownAttributeError = Class.new(ArgumentError)
|
19
|
+
|
18
20
|
#
|
19
21
|
# Raised when attempting to load a record by key when that record does not
|
20
22
|
# exist
|
21
23
|
#
|
22
24
|
RecordNotFound = Class.new(StandardError)
|
25
|
+
|
23
26
|
#
|
24
27
|
# Raised when attempting to configure a record in a way that is not
|
25
28
|
# possible
|
@@ -27,10 +30,12 @@ module Cequel
|
|
27
30
|
# @since 1.0.0
|
28
31
|
#
|
29
32
|
InvalidRecordConfiguration = Class.new(StandardError)
|
33
|
+
|
30
34
|
#
|
31
35
|
# Raised when attempting to save a record that is invalid
|
32
36
|
#
|
33
37
|
RecordInvalid = Class.new(StandardError)
|
38
|
+
|
34
39
|
#
|
35
40
|
# Raised when attempting to construct a {RecordSet} that cannot construct
|
36
41
|
# a valid CQL query
|
@@ -38,6 +43,7 @@ module Cequel
|
|
38
43
|
# @since 1.0.0
|
39
44
|
#
|
40
45
|
IllegalQuery = Class.new(StandardError)
|
46
|
+
|
41
47
|
#
|
42
48
|
# Raised when attempting to persist a Cequel::Record without defining all
|
43
49
|
# primary key columns
|
@@ -45,5 +51,11 @@ module Cequel
|
|
45
51
|
# @since 1.0.0
|
46
52
|
#
|
47
53
|
MissingKeyError = Class.new(StandardError)
|
54
|
+
|
55
|
+
#
|
56
|
+
# Raised when attempting to reflect on the schema of a
|
57
|
+
# Cequel::Record without a table name.
|
58
|
+
#
|
59
|
+
MissingTableNameError = Class.new(StandardError)
|
48
60
|
end
|
49
61
|
end
|
@@ -172,12 +172,18 @@ module Cequel
|
|
172
172
|
# @param options [Options] options for save
|
173
173
|
# @option options [Boolean] :validate (true) whether to run validations
|
174
174
|
# before saving
|
175
|
+
# @option options [Symbol] :consistency (:quorum) what consistency with
|
176
|
+
# which to persist the changes
|
177
|
+
# @option options [Integer] :ttl time-to-live of the updated rows in
|
178
|
+
# seconds
|
179
|
+
# @option options [Time] :timestamp the writetime to use for the column
|
180
|
+
# updates
|
175
181
|
# @return [Boolean] true if record saved successfully, false if invalid
|
176
182
|
#
|
177
183
|
# @see Validations#save!
|
178
184
|
#
|
179
185
|
def save(options = {})
|
180
|
-
options.assert_valid_keys(:consistency)
|
186
|
+
options.assert_valid_keys(:consistency, :ttl, :timestamp)
|
181
187
|
if new_record? then create(options)
|
182
188
|
else update(options)
|
183
189
|
end
|
@@ -203,10 +209,15 @@ module Cequel
|
|
203
209
|
#
|
204
210
|
# Remove this record from the database
|
205
211
|
#
|
212
|
+
# @param options [Options] options for deletion
|
213
|
+
# @option options [Symbol] :consistency (:quorum) what consistency with
|
214
|
+
# which to persist the deletion
|
215
|
+
# @option options [Time] :timestamp the writetime to use for the deletion
|
216
|
+
#
|
206
217
|
# @return [Record] self
|
207
218
|
#
|
208
219
|
def destroy(options = {})
|
209
|
-
options.assert_valid_keys(:consistency)
|
220
|
+
options.assert_valid_keys(:consistency, :timestamp)
|
210
221
|
assert_keys_present!
|
211
222
|
metal_scope.delete(options)
|
212
223
|
transient!
|
@@ -271,7 +282,7 @@ module Cequel
|
|
271
282
|
assert_keys_present!
|
272
283
|
connection.batch do
|
273
284
|
updater.execute(options)
|
274
|
-
deleter.execute(options)
|
285
|
+
deleter.execute(options.except(:ttl))
|
275
286
|
@updater, @deleter = nil
|
276
287
|
end
|
277
288
|
end
|
data/lib/cequel/record/schema.rb
CHANGED
@@ -9,6 +9,8 @@ module Cequel
|
|
9
9
|
# {Cequel::Metal::Keyspace} in a future version of Cequel
|
10
10
|
#
|
11
11
|
class Keyspace
|
12
|
+
extend Forwardable
|
13
|
+
|
12
14
|
#
|
13
15
|
# @param keyspace [Keyspace] the keyspace whose schema this object
|
14
16
|
# manipulates
|
@@ -64,6 +66,9 @@ module Cequel
|
|
64
66
|
keyspace.execute("DROP KEYSPACE #{keyspace.name}")
|
65
67
|
end
|
66
68
|
|
69
|
+
# @return [Boolean] true if the keyspace exists
|
70
|
+
def_delegator :keyspace, :exists?
|
71
|
+
|
67
72
|
#
|
68
73
|
# @param name [Symbol] name of the table to read
|
69
74
|
# @return [Table] object representation of the table schema as it
|
@@ -90,7 +90,8 @@ module Cequel
|
|
90
90
|
"Existing clustering columns " \
|
91
91
|
"#{existing.clustering_column_names.join(',')} " \
|
92
92
|
"differ from specified clustering keys " \
|
93
|
-
"#{updated.clustering_column_names.join(',')}"
|
93
|
+
"#{updated.clustering_column_names.join(',')} " \
|
94
|
+
"for #{existing.name}"
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Cequel
|
2
|
+
module SpecSupport
|
3
|
+
# Provide database preparation behavior that is useful for
|
4
|
+
# spec/test suites.
|
5
|
+
#
|
6
|
+
# For Rails apps adding the following code to the bottom of one's
|
7
|
+
# `spec_helper.rb` (below the `RSpec.configure` block) ensures a
|
8
|
+
# clean and fully synced test db before each test run.
|
9
|
+
#
|
10
|
+
# # one time database setup
|
11
|
+
# Cequel::SpecSupport::Preparation.setup_database
|
12
|
+
#
|
13
|
+
# For non-rails apps adding the following code to the bottom of
|
14
|
+
# one's `spec_helper.rb` (below the `RSpec.configure` block)
|
15
|
+
# ensures a clean and fully synced test db before each test run.
|
16
|
+
#
|
17
|
+
# # one time database setup
|
18
|
+
# Cequel::SpecSupport::Preparation
|
19
|
+
# .setup_database(App.root + "lib/models",
|
20
|
+
# App.root + "lib/other-models")
|
21
|
+
class Preparation
|
22
|
+
#
|
23
|
+
# Provision and sync the database for a spec run.
|
24
|
+
#
|
25
|
+
# @param [Array<String,Pathname>] model_dirs directories in
|
26
|
+
# which Cequel record classes reside. All files in these
|
27
|
+
# directories will be loaded before syncing the
|
28
|
+
# schema. Default: `Rails.root + "app/model"` if `Rails` is
|
29
|
+
# defined; otherwise no models will be autoloaded.
|
30
|
+
# @return [void]
|
31
|
+
#
|
32
|
+
def self.setup_database(*model_dirs)
|
33
|
+
options = model_dirs.extract_options!
|
34
|
+
|
35
|
+
model_dirs =
|
36
|
+
if model_dirs.any? then model_dirs.flatten
|
37
|
+
elsif defined? Rails then [Rails.root + "app/models"]
|
38
|
+
else []
|
39
|
+
end
|
40
|
+
|
41
|
+
preparation = new(model_dirs, options)
|
42
|
+
|
43
|
+
preparation.drop_keyspace
|
44
|
+
preparation.create_keyspace
|
45
|
+
preparation.sync_schema
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(model_dirs = [], options = {})
|
49
|
+
@model_dirs, @options = model_dirs, options
|
50
|
+
end
|
51
|
+
|
52
|
+
#
|
53
|
+
# Ensure the current keyspace does not exist.
|
54
|
+
#
|
55
|
+
# @return [Preparation] self
|
56
|
+
#
|
57
|
+
def drop_keyspace
|
58
|
+
keyspace = Cequel::Record.connection.schema
|
59
|
+
|
60
|
+
keyspace.drop! if keyspace.exists?
|
61
|
+
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
# Ensure that the necessary keyspace exists.
|
67
|
+
#
|
68
|
+
# @return [Preparation] self
|
69
|
+
#
|
70
|
+
def create_keyspace
|
71
|
+
keyspace = Cequel::Record.connection.schema
|
72
|
+
|
73
|
+
keyspace.create! unless keyspace.exists?
|
74
|
+
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
#
|
79
|
+
# Ensure that the necessary column families exist and match the
|
80
|
+
# models.
|
81
|
+
#
|
82
|
+
# @return [Preparation] self
|
83
|
+
#
|
84
|
+
def sync_schema
|
85
|
+
record_classes.each do |record_class|
|
86
|
+
begin
|
87
|
+
record_class.synchronize_schema
|
88
|
+
unless options[:quiet]
|
89
|
+
puts "Synchronized schema for #{record_class.name}"
|
90
|
+
end
|
91
|
+
|
92
|
+
rescue Record::MissingTableNameError
|
93
|
+
# It is obviously not a real record class if it doesn't have a
|
94
|
+
# table name.
|
95
|
+
unless options[:quiet]
|
96
|
+
STDERR.puts "Skipping anonymous record class without an " \
|
97
|
+
"explicit table name"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
protected
|
106
|
+
|
107
|
+
attr_reader :model_dirs, :options
|
108
|
+
|
109
|
+
#
|
110
|
+
# @return [Array<Class>] all Cequel record classes
|
111
|
+
#
|
112
|
+
def record_classes
|
113
|
+
load_all_models
|
114
|
+
Cequel::Record.descendants
|
115
|
+
end
|
116
|
+
|
117
|
+
#
|
118
|
+
# Loads all files in the models directory under the assumption
|
119
|
+
# that Cequel record classes live there.
|
120
|
+
#
|
121
|
+
def load_all_models
|
122
|
+
model_dirs.each do |directory|
|
123
|
+
Dir.glob(Pathname(directory).join("**", "*.rb")).each do |file_name|
|
124
|
+
require_dependency(file_name)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
data/lib/cequel/version.rb
CHANGED
@@ -71,4 +71,18 @@ describe Cequel::Metal::Keyspace do
|
|
71
71
|
}.to raise_error(ArgumentError)
|
72
72
|
end
|
73
73
|
end
|
74
|
+
|
75
|
+
describe "#exists?" do
|
76
|
+
it "is true for existent keyspaces" do
|
77
|
+
expect(cequel.exists?).to eq true
|
78
|
+
end
|
79
|
+
|
80
|
+
it "is false for non-existent keyspaces" do
|
81
|
+
nonexistent_keyspace = Cequel.connect host: Cequel::SpecSupport::Helpers.host,
|
82
|
+
port: Cequel::SpecSupport::Helpers.port,
|
83
|
+
keyspace: "totallymadeup"
|
84
|
+
|
85
|
+
expect(nonexistent_keyspace.exists?).to be_false
|
86
|
+
end
|
87
|
+
end
|
74
88
|
end
|
@@ -18,7 +18,7 @@ describe Cequel::Record::Persistence do
|
|
18
18
|
end
|
19
19
|
|
20
20
|
context 'simple keys' do
|
21
|
-
subject { cequel[
|
21
|
+
subject { cequel[Blog.table_name].where(:subdomain => 'cequel').first }
|
22
22
|
|
23
23
|
let!(:blog) do
|
24
24
|
Blog.new do |blog|
|
@@ -57,6 +57,21 @@ describe Cequel::Record::Persistence do
|
|
57
57
|
end.save(consistency: :one)
|
58
58
|
end
|
59
59
|
end
|
60
|
+
|
61
|
+
it 'should save with specified TTL' do
|
62
|
+
Blog.new(subdomain: 'cequel', name: 'Cequel').save(ttl: 10)
|
63
|
+
expect(cequel[Blog.table_name].select_ttl(:name).first.ttl(:name))
|
64
|
+
.to be_within(0.1).of(9.9)
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should save with specified timestamp' do
|
68
|
+
timestamp = 1.minute.from_now
|
69
|
+
Blog.new(subdomain: 'cequel-create-ts', name: 'Cequel')
|
70
|
+
.save(timestamp: timestamp)
|
71
|
+
expect(cequel[Blog.table_name].select_timestamp(:name).first.timestamp(:name))
|
72
|
+
.to eq((timestamp.to_f * 1_000_000).to_i)
|
73
|
+
Blog.connection.schema.truncate_table(Blog.table_name)
|
74
|
+
end
|
60
75
|
end
|
61
76
|
|
62
77
|
context 'on update' do
|
@@ -94,6 +109,22 @@ describe Cequel::Record::Persistence do
|
|
94
109
|
blog.save(consistency: :one)
|
95
110
|
end
|
96
111
|
end
|
112
|
+
|
113
|
+
it 'should save with specified TTL' do
|
114
|
+
blog.name = 'Cequel 1.4'
|
115
|
+
blog.save(ttl: 10)
|
116
|
+
expect(cequel[Blog.table_name].select_ttl(:name).first.ttl(:name)).
|
117
|
+
to be_within(0.1).of(9.9)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should save with specified timestamp' do
|
121
|
+
timestamp = 1.minute.from_now
|
122
|
+
blog.name = 'Cequel 1.4'
|
123
|
+
blog.save(timestamp: timestamp)
|
124
|
+
expect(cequel[Blog.table_name].select_timestamp(:name).first.timestamp(:name))
|
125
|
+
.to eq((timestamp.to_f * 1_000_000).to_i)
|
126
|
+
Blog.connection.schema.truncate_table(Blog.table_name)
|
127
|
+
end
|
97
128
|
end
|
98
129
|
end
|
99
130
|
|
@@ -184,12 +215,18 @@ describe Cequel::Record::Persistence do
|
|
184
215
|
blog.destroy(consistency: :one)
|
185
216
|
end
|
186
217
|
end
|
218
|
+
|
219
|
+
it 'should destroy with specified timestamp' do
|
220
|
+
blog = Blog.create(subdomain: 'big-data', name: 'Big Data')
|
221
|
+
blog.destroy(timestamp: 1.minute.ago)
|
222
|
+
expect(cequel[Blog.table_name].where(subdomain: 'big-data').first).to be
|
223
|
+
end
|
187
224
|
end
|
188
225
|
end
|
189
226
|
|
190
227
|
context 'compound keys' do
|
191
228
|
subject do
|
192
|
-
cequel[
|
229
|
+
cequel[Post.table_name].
|
193
230
|
where(:blog_subdomain => 'cassandra', :permalink => 'cequel').first
|
194
231
|
end
|
195
232
|
|
@@ -3,13 +3,16 @@ require File.expand_path('../spec_helper', __FILE__)
|
|
3
3
|
|
4
4
|
describe Cequel::Record::Schema do
|
5
5
|
context 'CQL3 table' do
|
6
|
-
after { cequel.schema.drop_table(
|
7
|
-
subject { cequel.schema.read_table(
|
6
|
+
after { cequel.schema.drop_table(table_name) }
|
7
|
+
subject { cequel.schema.read_table(table_name) }
|
8
|
+
|
9
|
+
let(:table_name) { 'posts_' + SecureRandom.hex(4) }
|
8
10
|
|
9
11
|
let(:model) do
|
12
|
+
model_table_name = table_name
|
10
13
|
Class.new do
|
11
14
|
include Cequel::Record
|
12
|
-
self.table_name =
|
15
|
+
self.table_name = model_table_name
|
13
16
|
|
14
17
|
key :permalink, :text
|
15
18
|
column :title, :text
|
@@ -47,11 +50,13 @@ describe Cequel::Record::Schema do
|
|
47
50
|
end
|
48
51
|
|
49
52
|
context 'CQL3 table with reversed clustering column' do
|
53
|
+
let(:table_name) { 'posts_' + SecureRandom.hex(4) }
|
50
54
|
|
51
55
|
let(:model) do
|
56
|
+
model_table_name = table_name
|
52
57
|
Class.new do
|
53
58
|
include Cequel::Record
|
54
|
-
self.table_name =
|
59
|
+
self.table_name = model_table_name
|
55
60
|
|
56
61
|
key :blog_id, :uuid
|
57
62
|
key :id, :timeuuid, order: :desc
|
@@ -60,8 +65,8 @@ describe Cequel::Record::Schema do
|
|
60
65
|
end
|
61
66
|
|
62
67
|
before { model.synchronize_schema }
|
63
|
-
after { cequel.schema.drop_table(
|
64
|
-
subject { cequel.schema.read_table(
|
68
|
+
after { cequel.schema.drop_table(table_name) }
|
69
|
+
subject { cequel.schema.read_table(table_name) }
|
65
70
|
|
66
71
|
it 'should order clustering column descending' do
|
67
72
|
subject.clustering_columns.first.clustering_order.should == :desc
|
@@ -69,10 +74,13 @@ describe Cequel::Record::Schema do
|
|
69
74
|
end
|
70
75
|
|
71
76
|
context 'wide-row legacy table' do
|
77
|
+
let(:table_name) { 'legacy_posts_' + SecureRandom.hex(4) }
|
78
|
+
|
72
79
|
let(:legacy_model) do
|
80
|
+
model_table_name = table_name
|
73
81
|
Class.new do
|
74
82
|
include Cequel::Record
|
75
|
-
self.table_name =
|
83
|
+
self.table_name = model_table_name
|
76
84
|
|
77
85
|
key :blog_subdomain, :text
|
78
86
|
key :id, :uuid
|
@@ -81,8 +89,8 @@ describe Cequel::Record::Schema do
|
|
81
89
|
compact_storage
|
82
90
|
end
|
83
91
|
end
|
84
|
-
after { cequel.schema.drop_table(
|
85
|
-
subject { cequel.schema.read_table(
|
92
|
+
after { cequel.schema.drop_table(table_name) }
|
93
|
+
subject { cequel.schema.read_table(table_name) }
|
86
94
|
|
87
95
|
context 'new model' do
|
88
96
|
before { legacy_model.synchronize_schema }
|
@@ -96,7 +104,7 @@ describe Cequel::Record::Schema do
|
|
96
104
|
context 'existing model', thrift: true do
|
97
105
|
before do
|
98
106
|
legacy_connection.execute(<<-CQL2)
|
99
|
-
CREATE COLUMNFAMILY
|
107
|
+
CREATE COLUMNFAMILY #{table_name} (blog_subdomain text PRIMARY KEY)
|
100
108
|
WITH comparator=uuid AND default_validation=text
|
101
109
|
CQL2
|
102
110
|
legacy_model.synchronize_schema
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
require "cequel/spec_support"
|
4
|
+
|
5
|
+
describe Cequel::SpecSupport::Preparation do
|
6
|
+
subject(:prep) { described_class.new([], quiet: true) }
|
7
|
+
let(:keyspace) { cequel }
|
8
|
+
|
9
|
+
it "returns itself from #drop_keyspace" do
|
10
|
+
expect(prep.drop_keyspace).to eq prep
|
11
|
+
end
|
12
|
+
|
13
|
+
it "returns itself from #create_keyspace" do
|
14
|
+
expect(prep.create_keyspace).to eq prep
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns itself from #sync_schema" do
|
18
|
+
expect(prep.sync_schema).to eq prep
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
context "existing keyspace" do
|
23
|
+
it "can be deleted" do
|
24
|
+
prep.drop_keyspace
|
25
|
+
expect(keyspace.exists?).to eq false
|
26
|
+
end
|
27
|
+
|
28
|
+
it "doesn't cause failure upon creation request" do
|
29
|
+
expect{ prep.create_keyspace }.not_to raise_error
|
30
|
+
expect(keyspace.exists?).to eq true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "allows tables to be synced" do
|
34
|
+
3.times do GC.start end # get rid of most of the crufty classes
|
35
|
+
|
36
|
+
table_name = "model_in_nonstandard_place_" + SecureRandom.hex(4)
|
37
|
+
rec_class = Class.new do
|
38
|
+
include Cequel::Record
|
39
|
+
self.table_name = table_name
|
40
|
+
key :sk, :uuid
|
41
|
+
end
|
42
|
+
|
43
|
+
prep.sync_schema
|
44
|
+
expect(keyspace).to contain_table table_name
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "keyspace doesn't exist" do
|
49
|
+
before do
|
50
|
+
Cequel::Record.connection.schema.drop!
|
51
|
+
end
|
52
|
+
|
53
|
+
it "doesn't cause failure upon drop requests" do
|
54
|
+
expect{ prep.drop_keyspace }.not_to raise_error
|
55
|
+
end
|
56
|
+
|
57
|
+
it "allows keyspace can be created" do
|
58
|
+
prep.create_keyspace
|
59
|
+
expect(keyspace).to exist
|
60
|
+
end
|
61
|
+
|
62
|
+
it "causes #sync_schema to fail" do
|
63
|
+
expect{ prep.sync_schema }.to raise_error
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# background
|
68
|
+
|
69
|
+
after { Cequel::Record.connection.schema.create! rescue nil }
|
70
|
+
|
71
|
+
matcher :contain_table do |table_name|
|
72
|
+
match do |keyspace|
|
73
|
+
keyspace.execute(<<-CQL).any?
|
74
|
+
SELECT columnfamily_name
|
75
|
+
FROM System.schema_columnfamilies
|
76
|
+
WHERE keyspace_name='#{keyspace.name}'
|
77
|
+
AND columnfamily_name='#{table_name}'
|
78
|
+
CQL
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/support/helpers.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
module Cequel
|
3
|
-
|
4
3
|
module SpecSupport
|
5
4
|
module Macros
|
6
5
|
def model(class_name, options = {}, &block)
|
@@ -16,7 +15,7 @@ module Cequel
|
|
16
15
|
metadata[:models].each do |name, (options, block)|
|
17
16
|
clazz = Class.new do
|
18
17
|
include Cequel::Record
|
19
|
-
self.table_name = name.to_s.tableize
|
18
|
+
self.table_name = name.to_s.tableize + "_" + SecureRandom.hex(4)
|
20
19
|
class_eval(&block)
|
21
20
|
end
|
22
21
|
Object.module_eval { const_set(name, clazz) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mat Brown
|
@@ -20,7 +20,7 @@ authors:
|
|
20
20
|
autorequire:
|
21
21
|
bindir: bin
|
22
22
|
cert_chain: []
|
23
|
-
date: 2014-06-
|
23
|
+
date: 2014-06-09 00:00:00.000000000 Z
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activemodel
|
@@ -224,6 +224,8 @@ files:
|
|
224
224
|
- lib/cequel/schema/table_updater.rb
|
225
225
|
- lib/cequel/schema/table_writer.rb
|
226
226
|
- lib/cequel/schema/update_table_dsl.rb
|
227
|
+
- lib/cequel/spec_support.rb
|
228
|
+
- lib/cequel/spec_support/preparation.rb
|
227
229
|
- lib/cequel/type.rb
|
228
230
|
- lib/cequel/util.rb
|
229
231
|
- lib/cequel/uuids.rb
|
@@ -254,6 +256,7 @@ files:
|
|
254
256
|
- spec/examples/schema/table_updater_spec.rb
|
255
257
|
- spec/examples/schema/table_writer_spec.rb
|
256
258
|
- spec/examples/spec_helper.rb
|
259
|
+
- spec/examples/spec_support/preparation_spec.rb
|
257
260
|
- spec/examples/type_spec.rb
|
258
261
|
- spec/examples/uuids_spec.rb
|
259
262
|
- spec/shared/readable_dictionary.rb
|
@@ -312,6 +315,7 @@ test_files:
|
|
312
315
|
- spec/examples/schema/table_updater_spec.rb
|
313
316
|
- spec/examples/schema/table_writer_spec.rb
|
314
317
|
- spec/examples/spec_helper.rb
|
318
|
+
- spec/examples/spec_support/preparation_spec.rb
|
315
319
|
- spec/examples/type_spec.rb
|
316
320
|
- spec/examples/uuids_spec.rb
|
317
321
|
has_rdoc: true
|