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