datastax_rails 2.0.18 → 2.1.23
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/config/solrconfig.xml.erb +7 -7
- data/lib/datastax_rails/associations/collection_association.rb +4 -4
- data/lib/datastax_rails/associations/has_many_association.rb +1 -1
- data/lib/datastax_rails/attribute_methods/dirty.rb +6 -0
- data/lib/datastax_rails/attribute_methods/primary_key.rb +9 -1
- data/lib/datastax_rails/attribute_methods/read.rb +2 -2
- data/lib/datastax_rails/attribute_methods/typecasting.rb +4 -7
- data/lib/datastax_rails/attribute_methods.rb +25 -0
- data/lib/datastax_rails/autosave_association.rb +3 -3
- data/lib/datastax_rails/base.rb +33 -11
- data/lib/datastax_rails/column.rb +25 -15
- data/lib/datastax_rails/connection.rb +1 -1
- data/lib/datastax_rails/cql/base.rb +31 -19
- data/lib/datastax_rails/cql/select.rb +2 -2
- data/lib/datastax_rails/dynamic_model.rb +1 -1
- data/lib/datastax_rails/errors.rb +3 -0
- data/lib/datastax_rails/instrumentation/controller_runtime.rb +52 -0
- data/lib/datastax_rails/instrumentation/log_subscriber.rb +92 -0
- data/lib/datastax_rails/instrumentation.rb +4 -0
- data/lib/datastax_rails/persistence.rb +49 -17
- data/lib/datastax_rails/railtie.rb +7 -0
- data/lib/datastax_rails/reflection.rb +16 -12
- data/lib/datastax_rails/relation/batches.rb +1 -1
- data/lib/datastax_rails/relation/finder_methods.rb +5 -5
- data/lib/datastax_rails/relation/modification_methods.rb +11 -26
- data/lib/datastax_rails/relation/search_methods.rb +10 -11
- data/lib/datastax_rails/relation.rb +81 -50
- data/lib/datastax_rails/scoping.rb +1 -1
- data/lib/datastax_rails/serialization.rb +10 -6
- data/lib/datastax_rails/serializers/xml_serializer.rb +3 -1
- data/lib/datastax_rails/tasks/ds.rake +25 -26
- data/lib/datastax_rails/timestamps.rb +1 -1
- data/lib/datastax_rails/types/dynamic_set.rb +4 -0
- data/lib/datastax_rails/version.rb +1 -1
- data/lib/datastax_rails/wide_storage_model.rb +3 -1
- data/lib/datastax_rails.rb +1 -0
- data/spec/datastax_rails/attribute_methods/read_spec.rb +33 -0
- data/spec/datastax_rails/attribute_methods/typecasting_spec.rb +25 -0
- data/spec/datastax_rails/base_spec.rb +1 -1
- data/spec/datastax_rails/callbacks_spec.rb +6 -0
- data/spec/datastax_rails/column_spec.rb +20 -0
- data/spec/datastax_rails/cql/base_spec.rb +1 -1
- data/spec/datastax_rails/cql/select_spec.rb +7 -1
- data/spec/datastax_rails/persistence_spec.rb +22 -3
- data/spec/datastax_rails/relation/finder_methods_spec.rb +13 -0
- data/spec/datastax_rails/relation/search_methods_spec.rb +37 -12
- data/spec/datastax_rails/serialization_spec.rb +17 -0
- data/spec/dummy/log/development.log +0 -24195
- data/spec/dummy/log/test.log +20 -15610
- data/spec/factories/hobbies.rb +1 -0
- data/spec/factories/jobs.rb +7 -0
- data/spec/factories/people.rb +1 -0
- data/spec/factories/person_roles.rb +7 -0
- data/spec/factories/roles.rb +6 -0
- data/spec/factories/uuid_keys.rb +6 -0
- data/spec/feature/associations_spec.rb +26 -0
- data/spec/support/models.rb +82 -0
- metadata +19 -4
- data/spec/dummy/log/production.log +0 -2
@@ -3,7 +3,7 @@ require 'pp' if ENV['DEBUG_SOLR'] == 'true'
|
|
3
3
|
# TODO: Move functionality into modules
|
4
4
|
module DatastaxRails
|
5
5
|
# = DatastaxRails Relation
|
6
|
-
class Relation # rubocop:disable
|
6
|
+
class Relation # rubocop:disable Metrics/ClassLength
|
7
7
|
MULTI_VALUE_METHODS = %i(order where where_not fulltext greater_than less_than select stats field_facet
|
8
8
|
range_facet slow_order)
|
9
9
|
SINGLE_VALUE_METHODS = %i(page per_page reverse_order query_parser consistency ttl use_solr escape group
|
@@ -263,7 +263,8 @@ module DatastaxRails
|
|
263
263
|
return :solr unless page_value == 1
|
264
264
|
@where_values.each do |wv|
|
265
265
|
wv.each do |k, _v|
|
266
|
-
|
266
|
+
col = klass.column_for_attribute(k)
|
267
|
+
next if col && (col.options[:cql_index] || col.primary)
|
267
268
|
return :solr
|
268
269
|
end
|
269
270
|
end
|
@@ -290,7 +291,18 @@ module DatastaxRails
|
|
290
291
|
cql = @cql.select(['count(*)'])
|
291
292
|
cql.using(@consistency_value) if @consistency_value
|
292
293
|
@where_values.each do |wv|
|
293
|
-
|
294
|
+
wv.each do |k, v|
|
295
|
+
attr = (k.to_s == 'id' ? @klass.primary_key : k)
|
296
|
+
col = klass.column_for_attribute(attr)
|
297
|
+
if col.primary
|
298
|
+
v.compact! if v.respond_to?(:compact)
|
299
|
+
return 0 if v.blank?
|
300
|
+
end
|
301
|
+
values = Array(v).map do |val|
|
302
|
+
col.type_cast_for_cql3(val)
|
303
|
+
end
|
304
|
+
cql.conditions(attr => values)
|
305
|
+
end
|
294
306
|
end
|
295
307
|
cql.allow_filtering if @allow_filtering_value
|
296
308
|
cql.execute.first['count']
|
@@ -305,7 +317,18 @@ module DatastaxRails
|
|
305
317
|
cql = @cql.select((select_columns + [@klass.primary_key]).uniq)
|
306
318
|
cql.using(@consistency_value) if @consistency_value
|
307
319
|
@where_values.each do |wv|
|
308
|
-
|
320
|
+
wv.each do |k, v|
|
321
|
+
attr = (k.to_s == 'id' ? @klass.primary_key : k)
|
322
|
+
col = klass.column_for_attribute(attr)
|
323
|
+
if col.primary
|
324
|
+
v.compact! if v.respond_to?(:compact!)
|
325
|
+
return [] if v.blank?
|
326
|
+
end
|
327
|
+
values = Array(v).map do |val|
|
328
|
+
col.type_cast_for_cql3(val)
|
329
|
+
end
|
330
|
+
cql.conditions(attr => values)
|
331
|
+
end
|
309
332
|
end
|
310
333
|
@greater_than_values.each do |gtv|
|
311
334
|
gtv.each do |k, v|
|
@@ -322,9 +345,7 @@ module DatastaxRails
|
|
322
345
|
end
|
323
346
|
rescue ::Cql::CqlError => e # TODO: Break out the various exception types
|
324
347
|
# If we get an exception about an empty key, ignore it. We'll return an empty set.
|
325
|
-
|
326
|
-
# No-Op
|
327
|
-
else
|
348
|
+
unless e.message =~ /Key may not be empty/
|
328
349
|
raise
|
329
350
|
end
|
330
351
|
end
|
@@ -394,27 +415,35 @@ module DatastaxRails
|
|
394
415
|
orders = []
|
395
416
|
@where_values.each do |wv|
|
396
417
|
wv.each do |k, v|
|
397
|
-
# If v is blank, check that there is no value for the field in the document
|
398
|
-
|
418
|
+
# If v is blank but not false, check that there is no value for the field in the document
|
419
|
+
if v.blank? && v != false
|
420
|
+
filter_queries << "-#{k}:#{full_solr_range(k)}"
|
421
|
+
else
|
422
|
+
filter_queries << "#{k}:(#{solr_format(k, v)})"
|
423
|
+
end
|
399
424
|
end
|
400
425
|
end
|
401
426
|
|
402
427
|
@where_not_values.each do |wnv|
|
403
428
|
wnv.each do |k, v|
|
404
|
-
# If v is blank, check for any value
|
405
|
-
|
429
|
+
# If v is blank but not false, check for any value in the field in the document
|
430
|
+
if v.blank? && v != false
|
431
|
+
filter_queries << "#{k}:#{full_solr_range(k)}"
|
432
|
+
else
|
433
|
+
filter_queries << "-#{k}:(#{solr_format(k, v)})"
|
434
|
+
end
|
406
435
|
end
|
407
436
|
end
|
408
437
|
|
409
438
|
@greater_than_values.each do |gtv|
|
410
439
|
gtv.each do |k, v|
|
411
|
-
filter_queries << "#{k}:[#{v} TO *]"
|
440
|
+
filter_queries << "#{k}:[#{solr_format(k, v)} TO *]"
|
412
441
|
end
|
413
442
|
end
|
414
443
|
|
415
444
|
@less_than_values.each do |ltv|
|
416
445
|
ltv.each do |k, v|
|
417
|
-
filter_queries << "#{k}:[* TO #{v}]"
|
446
|
+
filter_queries << "#{k}:[* TO #{solr_format(k, v)}]"
|
418
447
|
end
|
419
448
|
end
|
420
449
|
|
@@ -497,43 +526,47 @@ module DatastaxRails
|
|
497
526
|
params['stats.facet'] = @group_value
|
498
527
|
end
|
499
528
|
solr_response = nil
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
529
|
+
ActiveSupport::Notifications.instrument(
|
530
|
+
'solr.datastax_rails',
|
531
|
+
name: 'Search',
|
532
|
+
klass: @klass.name,
|
533
|
+
search: params) do
|
534
|
+
if @group_value
|
535
|
+
results = DatastaxRails::GroupedCollection.new
|
536
|
+
params[:group] = 'true'
|
537
|
+
params[:rows] = 10_000
|
538
|
+
params['group.field'] = @group_value
|
539
|
+
params['group.limit'] = @per_page_value
|
540
|
+
params['group.offset'] = (@page_value - 1) * @per_page_value
|
541
|
+
params['group.ngroups'] = 'false' # must be false due to issues with solr sharding
|
542
|
+
solr_response = rsolr.post('select', data: params)
|
543
|
+
response = solr_response['grouped'][@group_value.to_s]
|
544
|
+
results.total_groups = response['groups'].size
|
545
|
+
results.total_for_all = response['matches'].to_i
|
546
|
+
results.total_entries = 0
|
547
|
+
response['groups'].each do |group|
|
548
|
+
results[group['groupValue']] = parse_docs(group['doclist'], select_columns)
|
549
|
+
if results[group['groupValue']].total_entries > results.total_entries
|
550
|
+
results.total_entries = results[group['groupValue']].total_entries
|
551
|
+
end
|
517
552
|
end
|
553
|
+
else
|
554
|
+
solr_response = rsolr.paginate(@page_value, @per_page_value, 'select', data: params, method: :post)
|
555
|
+
response = solr_response['response']
|
556
|
+
results = parse_docs(response, select_columns)
|
557
|
+
results.highlights = solr_response['highlighting']
|
518
558
|
end
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
# Apply Facets if they exist
|
530
|
-
if solr_response['facet_counts']
|
531
|
-
results.facets = {}
|
532
|
-
results.facets = results.facets.merge(solr_response['facet_counts']['facet_fields'].to_h)
|
533
|
-
results.facets = results.facets.merge(solr_response['facet_counts']['facet_ranges'].to_h)
|
559
|
+
if solr_response['stats']
|
560
|
+
@stats = solr_response['stats']['stats_fields'].with_indifferent_access
|
561
|
+
end
|
562
|
+
# Apply Facets if they exist
|
563
|
+
if solr_response['facet_counts']
|
564
|
+
results.facets = {}
|
565
|
+
results.facets = results.facets.merge(solr_response['facet_counts']['facet_fields'].to_h)
|
566
|
+
results.facets = results.facets.merge(solr_response['facet_counts']['facet_ranges'].to_h)
|
567
|
+
end
|
568
|
+
results
|
534
569
|
end
|
535
|
-
pp params if ENV['DEBUG_SOLR'] == 'true'
|
536
|
-
results
|
537
570
|
end
|
538
571
|
|
539
572
|
# Parse out a set of documents and return the results
|
@@ -610,9 +643,7 @@ module DatastaxRails
|
|
610
643
|
value.split(/\bAND\b/).map do |a|
|
611
644
|
a.split(/\bOR\b/).map do |o|
|
612
645
|
o.split(/\bNOT\b/).map do |n|
|
613
|
-
n.split(/\bTO\b/).map
|
614
|
-
t.downcase
|
615
|
-
end.join('TO')
|
646
|
+
n.split(/\bTO\b/).map(&:downcase).join('TO')
|
616
647
|
end.join('NOT')
|
617
648
|
end.join('OR')
|
618
649
|
end.join('AND').gsub(SOLR_DATE_REGEX) { Regexp.last_match[1].upcase }
|
@@ -57,7 +57,7 @@ module DatastaxRails
|
|
57
57
|
# end
|
58
58
|
#
|
59
59
|
# *Note*: the +:find+ scope also has effect on update and deletion methods, like +update_all+ and +delete_all+.
|
60
|
-
def with_scope(scope = {}, action = :merge, &_block) # rubocop:disable
|
60
|
+
def with_scope(scope = {}, action = :merge, &_block) # rubocop:disable Metrics/CyclomaticComplexity
|
61
61
|
# If another DatastaxRails class has been passed in, get its current scope
|
62
62
|
scope = scope.current_scope if !scope.is_a?(Relation) && scope.respond_to?(:current_scope)
|
63
63
|
previous_scope = current_scope
|
@@ -7,7 +7,7 @@ module DatastaxRails
|
|
7
7
|
def serializable_hash(options = nil)
|
8
8
|
options = options.try(:clone) || {}
|
9
9
|
|
10
|
-
options[:except] = Array.wrap(options[:except]).map
|
10
|
+
options[:except] = Array.wrap(options[:except]).map(&:to_s)
|
11
11
|
|
12
12
|
hash = super(options)
|
13
13
|
|
@@ -19,16 +19,20 @@ module DatastaxRails
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
hash
|
23
|
-
end
|
22
|
+
serializable_convert_uuids(hash)
|
24
23
|
|
25
|
-
|
26
|
-
json = super(options)
|
27
|
-
json.each { |k, v| json[k] = v.to_s if v.is_a?(::Cql::Uuid) }
|
24
|
+
hash
|
28
25
|
end
|
29
26
|
|
30
27
|
private
|
31
28
|
|
29
|
+
def serializable_convert_uuids(hash)
|
30
|
+
hash.each do |k, v|
|
31
|
+
serializable_convert_uuids(v) if v.is_a?(Hash)
|
32
|
+
hash[k] = v.to_s if v.is_a?(::Cql::Uuid)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
32
36
|
# Add associations specified via the <tt>:include</tt> option.
|
33
37
|
#
|
34
38
|
# Expects a block that takes as arguments:
|
@@ -1,6 +1,6 @@
|
|
1
1
|
namespace :ds do
|
2
|
-
task :
|
3
|
-
datastax_config = ERB.new(Rails.root.join('config',
|
2
|
+
task configure: :environment do
|
3
|
+
datastax_config = ERB.new(Rails.root.join('config', 'datastax.yml').read).result(binding)
|
4
4
|
@configs = YAML.load(datastax_config)
|
5
5
|
@config = @configs[Rails.env || 'development']
|
6
6
|
@migrator = DatastaxRails::Schema::Migrator.new(@config['keyspace'])
|
@@ -8,72 +8,71 @@ namespace :ds do
|
|
8
8
|
|
9
9
|
desc 'Create the keyspace in config/datastax.yml for the current environment'
|
10
10
|
task :create do
|
11
|
-
datastax_config = ERB.new(Rails.root.join('config',
|
11
|
+
datastax_config = ERB.new(Rails.root.join('config', 'datastax.yml').read).result(binding)
|
12
12
|
@configs = YAML.load(datastax_config)
|
13
13
|
@config = @configs[Rails.env || 'development']
|
14
|
-
DatastaxRails::Base.establish_connection(@config.with_indifferent_access.merge(:
|
14
|
+
DatastaxRails::Base.establish_connection(@config.with_indifferent_access.merge(keyspace: 'system'))
|
15
15
|
DatastaxRails::Schema::Migrator.new('system').create_keyspace(@config['keyspace'], @config)
|
16
16
|
end
|
17
17
|
|
18
18
|
desc 'Drop keyspace in config/datastax.yml for the current environment'
|
19
|
-
task :
|
19
|
+
task drop: :configure do
|
20
20
|
@migrator.drop_keyspace
|
21
21
|
end
|
22
22
|
|
23
23
|
desc 'Migrate keyspace to latest version -- pass in model name to force an upload of just that one (all force-uploads everything).'
|
24
|
-
task :migrate, [:force_cf] => :configure do |
|
24
|
+
task :migrate, [:force_cf] => :configure do |_t, args|
|
25
25
|
if args[:force_cf].blank?
|
26
26
|
@migrator.migrate_all
|
27
27
|
else
|
28
28
|
args[:force_cf] == 'all' ? @migrator.migrate_all(true) : @migrator.migrate_one(args[:force_cf].constantize, true)
|
29
29
|
end
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
desc 'Alias for ds:migrate to maintain backwards-compatibility'
|
33
33
|
task :schema, [:force_cf] => :migrate
|
34
|
-
|
34
|
+
|
35
35
|
desc 'Rebuild SOLR Index -- pass in a model name (all rebuilds everything)'
|
36
|
-
task :reindex, [:model] => :configure do |
|
36
|
+
task :reindex, [:model] => :configure do |_t, args|
|
37
37
|
if args[:model].blank?
|
38
38
|
puts "\nUSAGE: rake ds:reindex[Model]"
|
39
39
|
else
|
40
40
|
@migrator.reindex_solr(args[:model].constantize)
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
desc 'Create SOLR Core (Normally not needed) -- pass in a model name (all creates everything)'
|
45
|
-
task :create_core, [:model] => :configure do |
|
45
|
+
task :create_core, [:model] => :configure do |_t, args|
|
46
46
|
if args[:model].blank?
|
47
47
|
puts "\nUSAGE: rake ds:create_core[Model]"
|
48
48
|
else
|
49
49
|
@migrator.create_solr_core(args[:model].constantize)
|
50
50
|
end
|
51
51
|
end
|
52
|
-
|
52
|
+
|
53
53
|
desc 'Load the seed data from ks/seeds.rb'
|
54
|
-
task :
|
55
|
-
seed_file = Rails.root.join(
|
54
|
+
task seed: :environment do
|
55
|
+
seed_file = Rails.root.join('ks', 'seeds.rb')
|
56
56
|
load(seed_file) if seed_file.exist?
|
57
57
|
end
|
58
|
-
|
59
|
-
if
|
58
|
+
|
59
|
+
if defined?(ParallelTests)
|
60
60
|
namespace :parallel do
|
61
|
-
desc
|
62
|
-
task :create, :count do |
|
61
|
+
desc 'create test keyspaces via ds:create --> ds:parallel:create[num_cpus]'
|
62
|
+
task :create, :count do |_t, args|
|
63
63
|
ParallelTests::Tasks.run_in_parallel("rake ds:create RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
|
64
64
|
end
|
65
|
-
|
66
|
-
desc
|
67
|
-
task :drop, :count do |
|
65
|
+
|
66
|
+
desc 'drop test keyspaces via ds:drop --> ds:parallel:drop[num_cpus]'
|
67
|
+
task :drop, :count do |_t, args|
|
68
68
|
ParallelTests::Tasks.run_in_parallel("rake ds:drop RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
|
69
69
|
end
|
70
|
-
|
71
|
-
desc
|
72
|
-
task :migrate, :count do |
|
73
|
-
args = args.to_hash.merge(:
|
70
|
+
|
71
|
+
desc 'update test keyspaces via ds:migrate --> ds:parallel:migrate[num_cpus]'
|
72
|
+
task :migrate, :count do |_t, args|
|
73
|
+
args = args.to_hash.merge(non_parallel: true)
|
74
74
|
ParallelTests::Tasks.run_in_parallel("rake ds:migrate RAILS_ENV=#{ParallelTests::Tasks.rails_env}", args)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
78
78
|
end
|
79
|
-
|
@@ -27,7 +27,9 @@ module DatastaxRails
|
|
27
27
|
|
28
28
|
# Returns a primary key hash for updates that includes the cluster key
|
29
29
|
def id_for_update
|
30
|
-
|
30
|
+
cc = self.class.column_for_attribute(self.class.cluster_by)
|
31
|
+
{ self.class.primary_key.to_s => __id,
|
32
|
+
self.class.cluster_by.to_s => cc.type_cast_for_cql3(read_attribute(self.class.cluster_by.to_s)) }
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
data/lib/datastax_rails.rb
CHANGED
@@ -99,6 +99,7 @@ end
|
|
99
99
|
|
100
100
|
require 'datastax_rails/railtie' if defined?(Rails)
|
101
101
|
require 'datastax_rails/errors'
|
102
|
+
require 'datastax_rails/instrumentation' if defined?(Rails)
|
102
103
|
require 'cql-rb_extensions'
|
103
104
|
|
104
105
|
ActiveSupport.run_load_hooks(:datastax_rails, DatastaxRails::Base)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DatastaxRails::Base do
|
4
|
+
context 'attribute methods' do
|
5
|
+
context 'read' do
|
6
|
+
context 'overrides' do
|
7
|
+
subject { CollectionOverride.new }
|
8
|
+
|
9
|
+
context 'lists' do
|
10
|
+
before do
|
11
|
+
subject.list1 = ['foo']
|
12
|
+
subject.list2 = ['bar']
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'returns the correct values before a save' do
|
16
|
+
expect(subject.read_attribute(:list1)).to eq(['foo'])
|
17
|
+
expect(subject.read_attribute(:list2)).to eq(['bar'])
|
18
|
+
expect(subject.list1).to eq(['FOO'])
|
19
|
+
expect(subject.list2).to eq(['BAR'])
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns the correct values after a save' do
|
23
|
+
subject.save
|
24
|
+
expect(subject.read_attribute(:list1)).to eq(['FOO'])
|
25
|
+
expect(subject.read_attribute(:list2)).to eq(['bar'])
|
26
|
+
expect(subject.list1).to eq(['FOO'])
|
27
|
+
expect(subject.list2).to eq(['BAR'])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -9,10 +9,21 @@ describe DatastaxRails::Base do
|
|
9
9
|
its(:bool) { is_expected.to be(true) }
|
10
10
|
its(:bool2) { is_expected.to be(false) }
|
11
11
|
its(:bool3) { is_expected.to be_nil }
|
12
|
+
its(:version) { is_expected.to be(1) }
|
13
|
+
its(:complexity) { is_expected.to be(0.0) }
|
14
|
+
its(:previous_id) { is_expected.to eq('00000000-0000-0000-0000-000000000000') }
|
15
|
+
its(:epoch) { is_expected.to eq(Date.parse('1970-01-01')) }
|
16
|
+
its(:epoch2) { is_expected.to eq(Time.parse('1970-01-01 00:00:00')) }
|
17
|
+
|
12
18
|
its(:changed_attributes) { is_expected.to include('str') }
|
13
19
|
its(:changed_attributes) { is_expected.to include('bool') }
|
14
20
|
its(:changed_attributes) { is_expected.to include('bool2') }
|
15
21
|
its(:changed_attributes) { is_expected.not_to include('bool3') }
|
22
|
+
its(:changed_attributes) { is_expected.to include('version') }
|
23
|
+
its(:changed_attributes) { is_expected.to include('complexity') }
|
24
|
+
its(:changed_attributes) { is_expected.to include('previous_id') }
|
25
|
+
its(:changed_attributes) { is_expected.to include('epoch') }
|
26
|
+
its(:changed_attributes) { is_expected.to include('epoch2') }
|
16
27
|
|
17
28
|
context 'setting the attribute to the default' do
|
18
29
|
before { subject.bool = true }
|
@@ -20,6 +31,20 @@ describe DatastaxRails::Base do
|
|
20
31
|
its(:bool) { is_expected.to be(true) }
|
21
32
|
its(:changed_attributes) { is_expected.to include('bool') }
|
22
33
|
end
|
34
|
+
|
35
|
+
context 'collections' do
|
36
|
+
context 'when not specified' do
|
37
|
+
its(:m) { is_expected.to eq({}) }
|
38
|
+
its(:s) { is_expected.to eq(Set.new) }
|
39
|
+
its(:l) { is_expected.to eq([]) }
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'when specified' do
|
43
|
+
its(:m2) { is_expected.to eq('m2test' => 'string') }
|
44
|
+
its(:s2) { is_expected.to eq(Set.new(['unique string'])) }
|
45
|
+
its(:l2) { is_expected.to eq(['ordered string']) }
|
46
|
+
end
|
47
|
+
end
|
23
48
|
end
|
24
49
|
end
|
25
50
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe DatastaxRails::Base do
|
4
4
|
it 'should raise RecordNotFound when finding a bogus ID' do
|
5
|
-
expect { Person.find(
|
5
|
+
expect { Person.find(::Cql::TimeUuid::Generator.new.next) }.to raise_exception(DatastaxRails::RecordNotFound)
|
6
6
|
end
|
7
7
|
|
8
8
|
describe 'equality' do
|
@@ -33,6 +33,12 @@ describe DatastaxRails::Base do
|
|
33
33
|
expect(subject).to receive(callback + '_callback')
|
34
34
|
subject.destroy
|
35
35
|
end
|
36
|
+
|
37
|
+
it 'provides a method to run without callbacks' do
|
38
|
+
subject.save
|
39
|
+
expect(subject).not_to receive(callback + '_callback')
|
40
|
+
subject.destroy_without_callbacks
|
41
|
+
end
|
36
42
|
end
|
37
43
|
|
38
44
|
it 'runs after_find' do
|
@@ -212,6 +212,10 @@ describe DatastaxRails::Column do
|
|
212
212
|
expect(c.type_cast({ 'field_key' => '7' }, record)).to be_a(DatastaxRails::Types::DynamicMap)
|
213
213
|
end
|
214
214
|
|
215
|
+
it 'casts nil to an empty hash' do
|
216
|
+
expect(c.type_cast(nil, record)).to eq({})
|
217
|
+
end
|
218
|
+
|
215
219
|
describe 'to cql' do
|
216
220
|
it 'casts map values to the appropriate type' do
|
217
221
|
date = Date.parse('1980-10-19')
|
@@ -231,6 +235,14 @@ describe DatastaxRails::Column do
|
|
231
235
|
it 'wraps list values in a DynamicList' do
|
232
236
|
expect(c.type_cast([1, '2', 6.minutes], record)).to be_a(DatastaxRails::Types::DynamicList)
|
233
237
|
end
|
238
|
+
|
239
|
+
it 'casts nil to an empty array' do
|
240
|
+
expect(c.type_cast(nil, record)).to eq([])
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'casts a scalar value to a list' do
|
244
|
+
expect(c.type_cast(1, record)).to eq([1])
|
245
|
+
end
|
234
246
|
end
|
235
247
|
|
236
248
|
describe 'set' do
|
@@ -243,6 +255,14 @@ describe DatastaxRails::Column do
|
|
243
255
|
it 'wraps list values in a DynamicSet' do
|
244
256
|
expect(c.type_cast([1, '2', 6.minutes, 2], record)).to be_a(DatastaxRails::Types::DynamicSet)
|
245
257
|
end
|
258
|
+
|
259
|
+
it 'casts nil to an empty set' do
|
260
|
+
expect(c.type_cast(nil, record)).to eq(Set.new)
|
261
|
+
end
|
262
|
+
|
263
|
+
it 'casts a scalar value to a set' do
|
264
|
+
expect(c.type_cast(1, record)).to eq(Set.new([1]))
|
265
|
+
end
|
246
266
|
end
|
247
267
|
end
|
248
268
|
end
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe DatastaxRails::Cql::Base do
|
4
4
|
it 'caches prepared statements' do
|
5
|
-
expect(DatastaxRails::Base.connection).to receive(:prepare).once.and_return(double('statement', execute: true))
|
5
|
+
expect(DatastaxRails::Base.connection).to receive(:prepare).once.and_return(double('statement', execute: [true]))
|
6
6
|
cql = DatastaxRails::Cql::ColumnFamily.new(Person)
|
7
7
|
cql.select(['*']).conditions(name: 'John').execute
|
8
8
|
cql.select(['*']).conditions(name: 'John').execute
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe DatastaxRails::Cql::Select do
|
4
|
-
let(:model_class) { double('Model Class', column_family: 'users', default_consistency: DatastaxRails::Cql::Consistency::QUORUM) }
|
4
|
+
let(:model_class) { double('Model Class', column_family: 'users', primary_key: 'id', default_consistency: DatastaxRails::Cql::Consistency::QUORUM) }
|
5
5
|
|
6
6
|
it 'should generate valid CQL' do
|
7
7
|
cql = DatastaxRails::Cql::Select.new(model_class, ['*'])
|
@@ -9,5 +9,11 @@ describe DatastaxRails::Cql::Select do
|
|
9
9
|
expect(cql.to_cql).to eq("SELECT * FROM users WHERE \"key\" = ? LIMIT 1 ")
|
10
10
|
end
|
11
11
|
|
12
|
+
it 'ignores multiple values for non-primary-key' do
|
13
|
+
cql = DatastaxRails::Cql::Select.new(model_class, ['*'])
|
14
|
+
cql.using(DatastaxRails::Cql::Consistency::QUORUM).conditions(key: %w(12345 67890)).limit(1)
|
15
|
+
expect(cql.to_cql).to eq("SELECT * FROM users WHERE \"key\" = ? LIMIT 1 ")
|
16
|
+
end
|
17
|
+
|
12
18
|
it_has_behavior 'default_consistency'
|
13
19
|
end
|
@@ -72,14 +72,24 @@ describe 'DatastaxRails::Base' do
|
|
72
72
|
end
|
73
73
|
|
74
74
|
it 'should successfully remove columns that are set to nil' do
|
75
|
-
skip
|
76
75
|
Person.create!(name: 'Steven', birthdate: Date.today)
|
77
76
|
Person.commit_solr
|
78
|
-
p = Person.
|
77
|
+
p = Person.find_by(name: 'Steven')
|
79
78
|
p.birthdate = nil
|
80
79
|
p.save
|
81
80
|
Person.commit_solr
|
82
|
-
Person.
|
81
|
+
expect(Person.find_by(name: 'Steven').birthdate).to be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'keeps existing attributes from being deleted' do
|
85
|
+
p = Person.create!(name: 'Jacob', birthdate: Date.today)
|
86
|
+
p.nickname = 'Jake'
|
87
|
+
p.save
|
88
|
+
Person.commit_solr
|
89
|
+
p2 = Person.find_by(name: 'Jacob')
|
90
|
+
expect(p2.name).to eql('Jacob')
|
91
|
+
expect(p2.nickname).to eql('Jake')
|
92
|
+
expect(p2.birthdate).to eql(Date.today)
|
83
93
|
end
|
84
94
|
end
|
85
95
|
end
|
@@ -106,5 +116,14 @@ describe 'DatastaxRails::Base' do
|
|
106
116
|
expect(CarPayload.find('limo').payload).to eq(smallfile)
|
107
117
|
end
|
108
118
|
end
|
119
|
+
|
120
|
+
describe '#write_attribute' do
|
121
|
+
let(:person) { create(:person) }
|
122
|
+
|
123
|
+
it 'writes an attribute directly to the database' do
|
124
|
+
Person.write_attribute(person, birthdate: Date.today)
|
125
|
+
expect(Person.find(person.id).birthdate).to eq(Date.today)
|
126
|
+
end
|
127
|
+
end
|
109
128
|
end
|
110
129
|
end
|
@@ -116,5 +116,18 @@ describe DatastaxRails::Relation do
|
|
116
116
|
Boat.commit_solr
|
117
117
|
expect(Boat.find_by(name: 'Dumb: Name')).not_to be_nil
|
118
118
|
end
|
119
|
+
|
120
|
+
it 'does not interpret wildcards' do
|
121
|
+
Boat.create(name: 'Water Lily')
|
122
|
+
Boat.commit_solr
|
123
|
+
expect(Boat.find_by(name: 'Wat*')).to be_nil
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'finds a record by an attribute with a wildcard in it' do
|
127
|
+
Boat.create(name: 'L*ly')
|
128
|
+
Boat.commit_solr
|
129
|
+
Boat.commit_solr
|
130
|
+
expect(Boat.find_by(name: 'L*ly')).not_to be_nil
|
131
|
+
end
|
119
132
|
end
|
120
133
|
end
|