cequel 1.3.2 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6143aa040bd563d95f997e29285ec19dc636e2ff
4
- data.tar.gz: 9c91d530af0b021624b83ee1d4bc0081428a5b4d
3
+ metadata.gz: 94c47d58ecd94cbaf5eb664962dc94aad6fcdfc7
4
+ data.tar.gz: 7a88e130ad1aec7083a9acf7efcd3d71a736472e
5
5
  SHA512:
6
- metadata.gz: 0c66344642c23a1551c924c88ccaace992be584a2bb8555a5c61da97e6ce641bd624300e1ce4ba3ae6ce10431d4b4750db01ed531aa524aa153a024bc7fee6d1
7
- data.tar.gz: 6491fc3e289cea01be5125ae4829789266221538799e09d9e221820d487d3026a9c612d892bc80b60b3b63dc51b1bb1766692a4439f06ba9256032243e561a75
6
+ metadata.gz: 098e9d6b6e4aafb27140892e5911a65b718c9e869fa975a6d81d690720015c65462e0f59ef1190ea34c30dfca7747a9dac41ea8473edfa8c82666ab39b1a0f7a
7
+ data.tar.gz: ca9f78e81f43253dcf48215320e7743211e260b179d85a3df92280d886cf12a5d1277364374eb45f7739467f7498953b4dea6c28c809c8fd68a887113c5e4c78
data/CHANGELOG.md CHANGED
@@ -1,3 +1,8 @@
1
+ ## 1.4.0
2
+
3
+ * Support TTL and timestamp options to record persistence methods
4
+ * Convenience methods for test preparation
5
+
1
6
  ## 1.3.2
2
7
 
3
8
  * Cast values passed to primary key filters in record sets
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cequel (1.3.2)
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.0)
287
+ tzinfo (1.2.1)
288
288
  thread_safe (~> 0.1)
289
289
  yard (0.8.7.4)
290
290
 
@@ -471,6 +471,7 @@ module Cequel
471
471
  data_set.writetime_columns.concat(columns.flatten)
472
472
  end
473
473
  end
474
+ alias_method :select_timestamp, :select_writetime
474
475
 
475
476
  #
476
477
  # Select specified columns from this data set, overriding chained scope.
@@ -143,7 +143,11 @@ module Cequel
143
143
  # @api private
144
144
  #
145
145
  def client
146
- synchronize { @client ||= build_client }
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 build_client
209
- client_options = {hosts: hosts, port: port}.tap do |options|
210
- options[:credentials] = credentials if credentials
225
+ def raw_client
226
+ synchronize do
227
+ @raw_client ||= Cql::Client.connect(client_options)
211
228
  end
212
- Cql::Client.connect(client_options).tap do |client|
213
- client.use(name) if name
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
 
@@ -59,6 +59,7 @@ module Cequel
59
59
  def writetime(column)
60
60
  @writetimes[column]
61
61
  end
62
+ alias_method :timestamp, :writetime
62
63
 
63
64
  # @private
64
65
  def set_ttl(column, value)
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
@@ -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
@@ -92,6 +92,8 @@ module Cequel
92
92
  # table in the database
93
93
  #
94
94
  def read_schema
95
+ fail MissingTableNameError unless table_name
96
+
95
97
  connection.schema.read_table(table_name)
96
98
  end
97
99
 
@@ -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,11 @@
1
+ module Cequel
2
+ #
3
+ # A collection of modules providing convenient functionality for running
4
+ # test suites with Cequel
5
+ #
6
+ # @see Preparation
7
+ #
8
+ module SpecSupport
9
+ autoload :Preparation, "cequel/spec_support/preparation"
10
+ end
11
+ end
@@ -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
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
  module Cequel
3
3
  # The current version of the library
4
- VERSION = '1.3.2'
4
+ VERSION = '1.4.0'
5
5
  end
@@ -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
@@ -9,7 +9,7 @@ describe Cequel::Record::List do
9
9
  list :contributor_ids, :int
10
10
  end
11
11
 
12
- let(:scope) { cequel[:posts].where(:permalink => 'cequel') }
12
+ let(:scope) { cequel[Post.table_name].where(:permalink => 'cequel') }
13
13
  subject { scope.first }
14
14
 
15
15
  let! :post do
@@ -8,7 +8,7 @@ describe Cequel::Record::Map do
8
8
  map :likes, :text, :int
9
9
  end
10
10
 
11
- let(:scope) { cequel[:posts].where(:permalink => 'cequel') }
11
+ let(:scope) { cequel[Post.table_name].where(:permalink => 'cequel') }
12
12
  subject { scope.first }
13
13
 
14
14
  let! :post do
@@ -18,7 +18,7 @@ describe Cequel::Record::Persistence do
18
18
  end
19
19
 
20
20
  context 'simple keys' do
21
- subject { cequel[:blogs].where(:subdomain => 'cequel').first }
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[:posts].
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(:posts) }
7
- subject { cequel.schema.read_table(:posts) }
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 = 'posts'
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 = 'posts'
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(:posts) }
64
- subject { cequel.schema.read_table(:posts) }
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 = 'legacy_posts'
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(:legacy_posts) }
85
- subject { cequel.schema.read_table(:legacy_posts) }
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 legacy_posts (blog_subdomain text PRIMARY KEY)
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
@@ -8,7 +8,7 @@ describe Cequel::Record::Set do
8
8
  set :tags, :text
9
9
  end
10
10
 
11
- let(:scope) { cequel[:posts].where(:permalink => 'cequel') }
11
+ let(:scope) { cequel[Post.table_name].where(:permalink => 'cequel') }
12
12
  subject { scope.first }
13
13
 
14
14
  let! :post do
@@ -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
@@ -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.3.2
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-02 00:00:00.000000000 Z
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