dynamoid 3.9.0 → 3.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -7
- data/README.md +20 -23
- data/dynamoid.gemspec +1 -2
- data/lib/dynamoid/adapter.rb +18 -12
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb +78 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +19 -1
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/projection_expression_convertor.rb +38 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +46 -61
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +33 -27
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +87 -62
- data/lib/dynamoid/associations/belongs_to.rb +6 -6
- data/lib/dynamoid/associations.rb +1 -1
- data/lib/dynamoid/config/options.rb +12 -12
- data/lib/dynamoid/config.rb +1 -0
- data/lib/dynamoid/criteria/chain.rb +95 -133
- data/lib/dynamoid/criteria/key_fields_detector.rb +6 -7
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +2 -2
- data/lib/dynamoid/criteria/where_conditions.rb +29 -0
- data/lib/dynamoid/dirty.rb +1 -1
- data/lib/dynamoid/document.rb +1 -1
- data/lib/dynamoid/dumping.rb +2 -2
- data/lib/dynamoid/fields/declare.rb +6 -6
- data/lib/dynamoid/fields.rb +6 -8
- data/lib/dynamoid/finders.rb +17 -26
- data/lib/dynamoid/indexes.rb +6 -7
- data/lib/dynamoid/loadable.rb +2 -2
- data/lib/dynamoid/persistence/save.rb +12 -16
- data/lib/dynamoid/persistence/update_fields.rb +2 -2
- data/lib/dynamoid/persistence/update_validations.rb +1 -1
- data/lib/dynamoid/persistence.rb +39 -4
- data/lib/dynamoid/type_casting.rb +15 -14
- data/lib/dynamoid/undumping.rb +1 -1
- data/lib/dynamoid/version.rb +1 -1
- metadata +17 -16
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +0 -41
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +0 -40
@@ -1,29 +1,35 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'key_fields_detector'
|
4
|
-
require_relative 'ignored_conditions_detector'
|
5
|
-
require_relative 'overwritten_conditions_detector'
|
6
4
|
require_relative 'nonexistent_fields_detector'
|
5
|
+
require_relative 'where_conditions'
|
7
6
|
|
8
7
|
module Dynamoid
|
9
8
|
module Criteria
|
10
9
|
# The criteria chain is equivalent to an ActiveRecord relation (and realistically I should change the name from
|
11
10
|
# chain to relation). It is a chainable object that builds up a query and eventually executes it by a Query or Scan.
|
12
11
|
class Chain
|
13
|
-
attr_reader :
|
12
|
+
attr_reader :source, :consistent_read, :key_fields_detector
|
14
13
|
|
15
14
|
include Enumerable
|
15
|
+
|
16
|
+
ALLOWED_FIELD_OPERATORS = Set.new(
|
17
|
+
%w[
|
18
|
+
eq ne gt lt gte lte between begins_with in contains not_contains null not_null
|
19
|
+
]
|
20
|
+
).freeze
|
21
|
+
|
16
22
|
# Create a new criteria chain.
|
17
23
|
#
|
18
24
|
# @param [Class] source the class upon which the ultimate query will be performed.
|
19
25
|
def initialize(source)
|
20
|
-
@
|
26
|
+
@where_conditions = WhereConditions.new
|
21
27
|
@source = source
|
22
28
|
@consistent_read = false
|
23
29
|
@scan_index_forward = true
|
24
30
|
|
25
|
-
# we should re-initialize keys detector every time we change
|
26
|
-
@key_fields_detector = KeyFieldsDetector.new(@
|
31
|
+
# we should re-initialize keys detector every time we change @where_conditions
|
32
|
+
@key_fields_detector = KeyFieldsDetector.new(@where_conditions, @source)
|
27
33
|
end
|
28
34
|
|
29
35
|
# Returns a chain which is a result of filtering current chain with the specified conditions.
|
@@ -92,25 +98,15 @@ module Dynamoid
|
|
92
98
|
# @return [Dynamoid::Criteria::Chain]
|
93
99
|
# @since 0.2.0
|
94
100
|
def where(args)
|
95
|
-
detector = IgnoredConditionsDetector.new(args)
|
96
|
-
if detector.found?
|
97
|
-
Dynamoid.logger.warn(detector.warning_message)
|
98
|
-
end
|
99
|
-
|
100
|
-
detector = OverwrittenConditionsDetector.new(@query, args)
|
101
|
-
if detector.found?
|
102
|
-
Dynamoid.logger.warn(detector.warning_message)
|
103
|
-
end
|
104
|
-
|
105
101
|
detector = NonexistentFieldsDetector.new(args, @source)
|
106
102
|
if detector.found?
|
107
103
|
Dynamoid.logger.warn(detector.warning_message)
|
108
104
|
end
|
109
105
|
|
110
|
-
|
106
|
+
@where_conditions.update(args.symbolize_keys)
|
111
107
|
|
112
|
-
# we should re-initialize keys detector every time we change
|
113
|
-
@key_fields_detector = KeyFieldsDetector.new(@
|
108
|
+
# we should re-initialize keys detector every time we change @where_conditions
|
109
|
+
@key_fields_detector = KeyFieldsDetector.new(@where_conditions, @source, forced_index_name: @forced_index_name)
|
114
110
|
|
115
111
|
self
|
116
112
|
end
|
@@ -187,7 +183,7 @@ module Dynamoid
|
|
187
183
|
def first(*args)
|
188
184
|
n = args.first || 1
|
189
185
|
|
190
|
-
return dup.scan_limit(n).to_a.first(*args) if @
|
186
|
+
return dup.scan_limit(n).to_a.first(*args) if @where_conditions.empty?
|
191
187
|
return super if @key_fields_detector.non_key_present?
|
192
188
|
|
193
189
|
dup.record_limit(n).to_a.first(*args)
|
@@ -230,12 +226,12 @@ module Dynamoid
|
|
230
226
|
ranges = []
|
231
227
|
|
232
228
|
if @key_fields_detector.key_present?
|
233
|
-
Dynamoid.adapter.query(source.table_name,
|
229
|
+
Dynamoid.adapter.query(source.table_name, query_key_conditions, query_non_key_conditions, query_options).flat_map { |i| i }.collect do |hash|
|
234
230
|
ids << hash[source.hash_key.to_sym]
|
235
231
|
ranges << hash[source.range_key.to_sym] if source.range_key
|
236
232
|
end
|
237
233
|
else
|
238
|
-
Dynamoid.adapter.scan(source.table_name,
|
234
|
+
Dynamoid.adapter.scan(source.table_name, scan_conditions, scan_options).flat_map { |i| i }.collect do |hash|
|
239
235
|
ids << hash[source.hash_key.to_sym]
|
240
236
|
ranges << hash[source.range_key.to_sym] if source.range_key
|
241
237
|
end
|
@@ -384,7 +380,7 @@ module Dynamoid
|
|
384
380
|
raise Dynamoid::Errors::InvalidIndex, "Unknown index #{index_name}" unless @source.find_index_by_name(index_name)
|
385
381
|
|
386
382
|
@forced_index_name = index_name
|
387
|
-
@key_fields_detector = KeyFieldsDetector.new(@
|
383
|
+
@key_fields_detector = KeyFieldsDetector.new(@where_conditions, @source, forced_index_name: index_name)
|
388
384
|
self
|
389
385
|
end
|
390
386
|
|
@@ -451,9 +447,9 @@ module Dynamoid
|
|
451
447
|
# It takes one or more field names and returns a collection of models with only
|
452
448
|
# these fields set.
|
453
449
|
#
|
454
|
-
# Post.where('views_count.gt' => 1000).
|
455
|
-
# Post.where('views_count.gt' => 1000).
|
456
|
-
# Post.
|
450
|
+
# Post.where('views_count.gt' => 1000).project(:title)
|
451
|
+
# Post.where('views_count.gt' => 1000).project(:title, :created_at)
|
452
|
+
# Post.project(:id)
|
457
453
|
#
|
458
454
|
# It can be used to avoid loading large field values and to decrease a
|
459
455
|
# memory footprint.
|
@@ -487,6 +483,8 @@ module Dynamoid
|
|
487
483
|
def pluck(*args)
|
488
484
|
fields = args.map(&:to_sym)
|
489
485
|
|
486
|
+
# `project` has a side effect - it sets `@project` instance variable.
|
487
|
+
# So use a duplicate to not pollute original chain.
|
490
488
|
scope = dup
|
491
489
|
scope.project(*fields)
|
492
490
|
|
@@ -535,7 +533,7 @@ module Dynamoid
|
|
535
533
|
if @key_fields_detector.key_present?
|
536
534
|
raw_pages_via_query
|
537
535
|
else
|
538
|
-
issue_scan_warning if Dynamoid::Config.warn_on_scan &&
|
536
|
+
issue_scan_warning if Dynamoid::Config.warn_on_scan && !@where_conditions.empty?
|
539
537
|
raw_pages_via_scan
|
540
538
|
end
|
541
539
|
end
|
@@ -547,7 +545,7 @@ module Dynamoid
|
|
547
545
|
# @since 3.1.0
|
548
546
|
def raw_pages_via_query
|
549
547
|
Enumerator.new do |y|
|
550
|
-
Dynamoid.adapter.query(source.table_name,
|
548
|
+
Dynamoid.adapter.query(source.table_name, query_key_conditions, query_non_key_conditions, query_options).each do |items, metadata|
|
551
549
|
options = metadata.slice(:last_evaluated_key)
|
552
550
|
|
553
551
|
y.yield items, options
|
@@ -562,7 +560,7 @@ module Dynamoid
|
|
562
560
|
# @since 3.1.0
|
563
561
|
def raw_pages_via_scan
|
564
562
|
Enumerator.new do |y|
|
565
|
-
Dynamoid.adapter.scan(source.table_name,
|
563
|
+
Dynamoid.adapter.scan(source.table_name, scan_conditions, scan_options).each do |items, metadata|
|
566
564
|
options = metadata.slice(:last_evaluated_key)
|
567
565
|
|
568
566
|
y.yield items, options
|
@@ -575,121 +573,88 @@ module Dynamoid
|
|
575
573
|
Dynamoid.logger.warn "You can index this query by adding index declaration to #{source.to_s.underscore}.rb:"
|
576
574
|
Dynamoid.logger.warn "* global_secondary_index hash_key: 'some-name', range_key: 'some-another-name'"
|
577
575
|
Dynamoid.logger.warn "* local_secondary_index range_key: 'some-name'"
|
578
|
-
Dynamoid.logger.warn "Not indexed attributes: #{
|
576
|
+
Dynamoid.logger.warn "Not indexed attributes: #{@where_conditions.keys.sort.collect { |name| ":#{name}" }.join(', ')}"
|
579
577
|
end
|
580
578
|
|
581
579
|
def count_via_query
|
582
|
-
Dynamoid.adapter.query_count(source.table_name,
|
580
|
+
Dynamoid.adapter.query_count(source.table_name, query_key_conditions, query_non_key_conditions, query_options)
|
583
581
|
end
|
584
582
|
|
585
583
|
def count_via_scan
|
586
|
-
Dynamoid.adapter.scan_count(source.table_name,
|
587
|
-
end
|
588
|
-
|
589
|
-
def range_hash(key)
|
590
|
-
name, operation = key.to_s.split('.')
|
591
|
-
val = type_cast_condition_parameter(name, query[key])
|
592
|
-
|
593
|
-
case operation
|
594
|
-
when 'gt'
|
595
|
-
{ range_greater_than: val }
|
596
|
-
when 'lt'
|
597
|
-
{ range_less_than: val }
|
598
|
-
when 'gte'
|
599
|
-
{ range_gte: val }
|
600
|
-
when 'lte'
|
601
|
-
{ range_lte: val }
|
602
|
-
when 'between'
|
603
|
-
{ range_between: val }
|
604
|
-
when 'begins_with'
|
605
|
-
{ range_begins_with: val }
|
606
|
-
end
|
584
|
+
Dynamoid.adapter.scan_count(source.table_name, scan_conditions, scan_options)
|
607
585
|
end
|
608
586
|
|
609
|
-
def
|
610
|
-
name,
|
611
|
-
|
612
|
-
|
613
|
-
hash = case operation
|
614
|
-
when 'ne'
|
615
|
-
{ ne: val }
|
616
|
-
when 'gt'
|
617
|
-
{ gt: val }
|
618
|
-
when 'lt'
|
619
|
-
{ lt: val }
|
620
|
-
when 'gte'
|
621
|
-
{ gte: val }
|
622
|
-
when 'lte'
|
623
|
-
{ lte: val }
|
624
|
-
when 'between'
|
625
|
-
{ between: val }
|
626
|
-
when 'begins_with'
|
627
|
-
{ begins_with: val }
|
628
|
-
when 'in'
|
629
|
-
{ in: val }
|
630
|
-
when 'contains'
|
631
|
-
{ contains: val }
|
632
|
-
when 'not_contains'
|
633
|
-
{ not_contains: val }
|
634
|
-
# NULL/NOT_NULL operators don't have parameters
|
635
|
-
# So { null: true } means NULL check and { null: false } means NOT_NULL one
|
636
|
-
# The same logic is used for { not_null: BOOL }
|
637
|
-
when 'null'
|
638
|
-
val ? { null: nil } : { not_null: nil }
|
639
|
-
when 'not_null'
|
640
|
-
val ? { not_null: nil } : { null: nil }
|
641
|
-
end
|
642
|
-
|
643
|
-
{ name.to_sym => hash }
|
644
|
-
end
|
645
|
-
|
646
|
-
def consistent_opts
|
647
|
-
{ consistent_read: consistent_read }
|
648
|
-
end
|
649
|
-
|
650
|
-
def range_query
|
651
|
-
opts = {}
|
652
|
-
query = self.query
|
587
|
+
def field_condition(key, value_before_type_casting)
|
588
|
+
name, operator = key.to_s.split('.')
|
589
|
+
value = type_cast_condition_parameter(name, value_before_type_casting)
|
590
|
+
operator ||= 'eq'
|
653
591
|
|
654
|
-
|
655
|
-
|
656
|
-
@key_fields_detector.hash_key.to_sym != @source.inheritance_field.to_sym
|
657
|
-
query.update(sti_condition)
|
592
|
+
unless operator.in? ALLOWED_FIELD_OPERATORS
|
593
|
+
raise Dynamoid::Errors::Error, "Unsupported operator #{operator} in #{key}"
|
658
594
|
end
|
659
595
|
|
596
|
+
condition =
|
597
|
+
case operator
|
598
|
+
# NULL/NOT_NULL operators don't have parameters
|
599
|
+
# So { null: true } means NULL check and { null: false } means NOT_NULL one
|
600
|
+
# The same logic is used for { not_null: BOOL }
|
601
|
+
when 'null'
|
602
|
+
value ? [:null, nil] : [:not_null, nil]
|
603
|
+
when 'not_null'
|
604
|
+
value ? [:not_null, nil] : [:null, nil]
|
605
|
+
else
|
606
|
+
[operator.to_sym, value]
|
607
|
+
end
|
608
|
+
|
609
|
+
[name.to_sym, condition]
|
610
|
+
end
|
611
|
+
|
612
|
+
def query_key_conditions
|
613
|
+
opts = {}
|
614
|
+
|
660
615
|
# Add hash key
|
661
|
-
|
662
|
-
|
616
|
+
# TODO: always have hash key in @where_conditions?
|
617
|
+
_, condition = field_condition(@key_fields_detector.hash_key, @where_conditions[@key_fields_detector.hash_key])
|
618
|
+
opts[@key_fields_detector.hash_key] = [condition]
|
663
619
|
|
664
620
|
# Add range key
|
665
621
|
if @key_fields_detector.range_key
|
666
|
-
|
667
|
-
|
622
|
+
if @where_conditions[@key_fields_detector.range_key].present?
|
623
|
+
_, condition = field_condition(@key_fields_detector.range_key, @where_conditions[@key_fields_detector.range_key])
|
624
|
+
opts[@key_fields_detector.range_key] = [condition]
|
625
|
+
end
|
668
626
|
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
opts.update(field_hash(key))
|
674
|
-
else
|
675
|
-
value = type_cast_condition_parameter(key, query[key])
|
676
|
-
opts[key] = { eq: value }
|
627
|
+
@where_conditions.keys.select { |k| k.to_s =~ /^#{@key_fields_detector.range_key}\./ }.each do |key|
|
628
|
+
name, condition = field_condition(key, @where_conditions[key])
|
629
|
+
opts[name] ||= []
|
630
|
+
opts[name] << condition
|
677
631
|
end
|
678
632
|
end
|
679
633
|
|
680
|
-
opts
|
634
|
+
opts
|
681
635
|
end
|
682
636
|
|
683
|
-
def
|
684
|
-
opts
|
685
|
-
|
686
|
-
|
687
|
-
|
637
|
+
def query_non_key_conditions
|
638
|
+
opts = {}
|
639
|
+
|
640
|
+
# Honor STI and :type field if it presents
|
641
|
+
if @source.attributes.key?(@source.inheritance_field) &&
|
642
|
+
@key_fields_detector.hash_key.to_sym != @source.inheritance_field.to_sym
|
643
|
+
@where_conditions.update(sti_condition)
|
688
644
|
end
|
689
645
|
|
690
|
-
|
691
|
-
|
646
|
+
# TODO: Separate key conditions and non-key conditions properly:
|
647
|
+
# only =, >, >=, <, <=, between and begins_with
|
648
|
+
# could be used for sort key in KeyConditionExpression
|
649
|
+
keys = (@where_conditions.keys.map(&:to_sym) - [@key_fields_detector.hash_key.to_sym, @key_fields_detector.range_key.try(:to_sym)])
|
650
|
+
.reject { |k, _| k.to_s =~ /^#{@key_fields_detector.range_key}\./ }
|
651
|
+
keys.each do |key|
|
652
|
+
name, condition = field_condition(key, @where_conditions[key])
|
653
|
+
opts[name] ||= []
|
654
|
+
opts[name] << condition
|
692
655
|
end
|
656
|
+
|
657
|
+
opts
|
693
658
|
end
|
694
659
|
|
695
660
|
# TODO: casting should be operator aware
|
@@ -737,7 +702,7 @@ module Dynamoid
|
|
737
702
|
key
|
738
703
|
end
|
739
704
|
|
740
|
-
def
|
705
|
+
def query_options
|
741
706
|
opts = {}
|
742
707
|
# Don't specify select = ALL_ATTRIBUTES option explicitly because it's
|
743
708
|
# already a default value of Select statement. Explicite Select value
|
@@ -749,30 +714,26 @@ module Dynamoid
|
|
749
714
|
opts[:exclusive_start_key] = start_key if @start
|
750
715
|
opts[:scan_index_forward] = @scan_index_forward
|
751
716
|
opts[:project] = @project
|
717
|
+
opts[:consistent_read] = true if @consistent_read
|
752
718
|
opts
|
753
719
|
end
|
754
720
|
|
755
|
-
def
|
756
|
-
query = self.query
|
757
|
-
|
721
|
+
def scan_conditions
|
758
722
|
# Honor STI and :type field if it presents
|
759
723
|
if sti_condition
|
760
|
-
|
724
|
+
@where_conditions.update(sti_condition)
|
761
725
|
end
|
762
726
|
|
763
727
|
{}.tap do |opts|
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
768
|
-
value = type_cast_condition_parameter(key, query[key])
|
769
|
-
opts[key] = { eq: value }
|
770
|
-
end
|
728
|
+
@where_conditions.keys.map(&:to_sym).each do |key|
|
729
|
+
name, condition = field_condition(key, @where_conditions[key])
|
730
|
+
opts[name] ||= []
|
731
|
+
opts[name] << condition
|
771
732
|
end
|
772
733
|
end
|
773
734
|
end
|
774
735
|
|
775
|
-
def
|
736
|
+
def scan_options
|
776
737
|
opts = {}
|
777
738
|
opts[:index_name] = @key_fields_detector.index_name if @key_fields_detector.index_name
|
778
739
|
opts[:record_limit] = @record_limit if @record_limit
|
@@ -784,6 +745,7 @@ module Dynamoid
|
|
784
745
|
opts
|
785
746
|
end
|
786
747
|
|
748
|
+
# TODO: return Array, not String
|
787
749
|
def sti_condition
|
788
750
|
condition = {}
|
789
751
|
type = @source.inheritance_field
|
@@ -5,10 +5,10 @@ module Dynamoid
|
|
5
5
|
# @private
|
6
6
|
class KeyFieldsDetector
|
7
7
|
class Query
|
8
|
-
def initialize(
|
9
|
-
@
|
10
|
-
@fields_with_operator =
|
11
|
-
@fields =
|
8
|
+
def initialize(where_conditions)
|
9
|
+
@where_conditions = where_conditions
|
10
|
+
@fields_with_operator = where_conditions.keys.map(&:to_s)
|
11
|
+
@fields = where_conditions.keys.map(&:to_s).map { |s| s.split('.').first }
|
12
12
|
end
|
13
13
|
|
14
14
|
def contain_only?(field_names)
|
@@ -24,10 +24,9 @@ module Dynamoid
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
-
def initialize(
|
28
|
-
@query = query
|
27
|
+
def initialize(where_conditions, source, forced_index_name: nil)
|
29
28
|
@source = source
|
30
|
-
@query = Query.new(
|
29
|
+
@query = Query.new(where_conditions)
|
31
30
|
@forced_index_name = forced_index_name
|
32
31
|
@result = find_keys_in_query
|
33
32
|
end
|
@@ -20,8 +20,8 @@ module Dynamoid
|
|
20
20
|
fields_list = @nonexistent_fields.map { |s| "`#{s}`" }.join(', ')
|
21
21
|
count = @nonexistent_fields.size
|
22
22
|
|
23
|
-
'where conditions contain nonexistent' \
|
24
|
-
"
|
23
|
+
'where conditions contain nonexistent ' \
|
24
|
+
"field #{'name'.pluralize(count)} #{fields_list}"
|
25
25
|
end
|
26
26
|
|
27
27
|
private
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module Criteria
|
5
|
+
# @private
|
6
|
+
class WhereConditions
|
7
|
+
def initialize
|
8
|
+
@conditions = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def update(hash)
|
12
|
+
@conditions << hash.symbolize_keys
|
13
|
+
end
|
14
|
+
|
15
|
+
def keys
|
16
|
+
@conditions.flat_map(&:keys)
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
@conditions.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def [](key)
|
24
|
+
hash = @conditions.find { |h| h.key?(key) }
|
25
|
+
hash[key] if hash
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/dynamoid/dirty.rb
CHANGED
data/lib/dynamoid/document.rb
CHANGED
data/lib/dynamoid/dumping.rb
CHANGED
@@ -210,7 +210,7 @@ module Dynamoid
|
|
210
210
|
# datetime -> integer/string
|
211
211
|
class DateTimeDumper < Base
|
212
212
|
def process(value)
|
213
|
-
|
213
|
+
value.nil? ? nil : format_datetime(value, @options)
|
214
214
|
end
|
215
215
|
|
216
216
|
private
|
@@ -237,7 +237,7 @@ module Dynamoid
|
|
237
237
|
# date -> integer/string
|
238
238
|
class DateDumper < Base
|
239
239
|
def process(value)
|
240
|
-
|
240
|
+
value.nil? ? nil : format_date(value, @options)
|
241
241
|
end
|
242
242
|
|
243
243
|
private
|
@@ -48,7 +48,7 @@ module Dynamoid
|
|
48
48
|
|
49
49
|
@source.generated_methods.module_eval do
|
50
50
|
define_method(name) { read_attribute(name) }
|
51
|
-
define_method("#{name}?") do
|
51
|
+
define_method(:"#{name}?") do
|
52
52
|
value = read_attribute(name)
|
53
53
|
case value
|
54
54
|
when true then true
|
@@ -57,8 +57,8 @@ module Dynamoid
|
|
57
57
|
!value.nil?
|
58
58
|
end
|
59
59
|
end
|
60
|
-
define_method("#{name}=") { |value| write_attribute(name, value) }
|
61
|
-
define_method("#{name}_before_type_cast") { read_attribute_before_type_cast(name) }
|
60
|
+
define_method(:"#{name}=") { |value| write_attribute(name, value) }
|
61
|
+
define_method(:"#{name}_before_type_cast") { read_attribute_before_type_cast(name) }
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
@@ -70,9 +70,9 @@ module Dynamoid
|
|
70
70
|
|
71
71
|
@source.generated_methods.module_eval do
|
72
72
|
alias_method alias_name, name
|
73
|
-
alias_method "#{alias_name}=", "#{name}="
|
74
|
-
alias_method "#{alias_name}?", "#{name}?"
|
75
|
-
alias_method "#{alias_name}_before_type_cast", "#{name}_before_type_cast"
|
73
|
+
alias_method :"#{alias_name}=", :"#{name}="
|
74
|
+
alias_method :"#{alias_name}?", :"#{name}?"
|
75
|
+
alias_method :"#{alias_name}_before_type_cast", :"#{name}_before_type_cast"
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
data/lib/dynamoid/fields.rb
CHANGED
@@ -164,7 +164,7 @@ module Dynamoid
|
|
164
164
|
#
|
165
165
|
# @param name [Symbol] a range key attribute name
|
166
166
|
# @param type [Symbol] a range key type (optional)
|
167
|
-
# @param options [
|
167
|
+
# @param options [Hash] type options (optional)
|
168
168
|
def range(name, type = :string, options = {})
|
169
169
|
field(name, type, options)
|
170
170
|
self.range_key = name
|
@@ -263,10 +263,8 @@ module Dynamoid
|
|
263
263
|
|
264
264
|
# @private
|
265
265
|
def generated_methods
|
266
|
-
@generated_methods ||=
|
267
|
-
|
268
|
-
include(mod)
|
269
|
-
end
|
266
|
+
@generated_methods ||= Module.new.tap do |mod|
|
267
|
+
include(mod)
|
270
268
|
end
|
271
269
|
end
|
272
270
|
end
|
@@ -362,7 +360,7 @@ module Dynamoid
|
|
362
360
|
seconds = options[:after]
|
363
361
|
|
364
362
|
if self[name].blank?
|
365
|
-
send("#{name}=", Time.now.to_i + seconds)
|
363
|
+
send(:"#{name}=", Time.now.to_i + seconds)
|
366
364
|
end
|
367
365
|
end
|
368
366
|
end
|
@@ -374,12 +372,12 @@ module Dynamoid
|
|
374
372
|
|
375
373
|
type = self.class.inheritance_field
|
376
374
|
if self.class.attributes[type] && send(type).nil?
|
377
|
-
send("#{type}=", self.class.sti_name)
|
375
|
+
send(:"#{type}=", self.class.sti_name)
|
378
376
|
end
|
379
377
|
end
|
380
378
|
|
381
379
|
def attribute_is_present_on_model?(attribute_name)
|
382
|
-
setter = "#{attribute_name}="
|
380
|
+
setter = :"#{attribute_name}="
|
383
381
|
respond_to?(setter)
|
384
382
|
end
|
385
383
|
end
|
data/lib/dynamoid/finders.rb
CHANGED
@@ -6,17 +6,6 @@ module Dynamoid
|
|
6
6
|
module Finders
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
|
-
# @private
|
10
|
-
RANGE_MAP = {
|
11
|
-
'gt' => :range_greater_than,
|
12
|
-
'lt' => :range_less_than,
|
13
|
-
'gte' => :range_gte,
|
14
|
-
'lte' => :range_lte,
|
15
|
-
'begins_with' => :range_begins_with,
|
16
|
-
'between' => :range_between,
|
17
|
-
'eq' => :range_eq
|
18
|
-
}.freeze
|
19
|
-
|
20
9
|
module ClassMethods
|
21
10
|
# Find one or many objects, specified by one id or an array of ids.
|
22
11
|
#
|
@@ -253,7 +242,6 @@ module Dynamoid
|
|
253
242
|
range = options[:range] || {}
|
254
243
|
hash_key_field, hash_key_value = hash.first
|
255
244
|
range_key_field, range_key_value = range.first
|
256
|
-
range_op_mapped = nil
|
257
245
|
|
258
246
|
if range_key_field
|
259
247
|
range_key_field = range_key_field.to_s
|
@@ -261,27 +249,30 @@ module Dynamoid
|
|
261
249
|
if range_key_field.include?('.')
|
262
250
|
range_key_field, range_key_op = range_key_field.split('.', 2)
|
263
251
|
end
|
264
|
-
range_op_mapped = RANGE_MAP.fetch(range_key_op)
|
265
252
|
end
|
266
253
|
|
267
254
|
# Find the index
|
268
255
|
index = find_index(hash_key_field, range_key_field)
|
269
256
|
raise Dynamoid::Errors::MissingIndex, "attempted to find #{[hash_key_field, range_key_field]}" if index.nil?
|
270
257
|
|
271
|
-
#
|
272
|
-
|
273
|
-
|
274
|
-
hash_value: hash_key_value,
|
275
|
-
index_name: index.name
|
276
|
-
}
|
258
|
+
# Query
|
259
|
+
query_key_conditions = {}
|
260
|
+
query_key_conditions[hash_key_field.to_sym] = [[:eq, hash_key_value]]
|
277
261
|
if range_key_field
|
278
|
-
|
279
|
-
opts[range_op_mapped] = range_key_value
|
280
|
-
end
|
281
|
-
dynamo_options = opts.merge(options.reject { |key, _| key == :range })
|
282
|
-
Dynamoid.adapter.query(table_name, dynamo_options).flat_map { |i| i }.map do |item|
|
283
|
-
from_database(item)
|
262
|
+
query_key_conditions[range_key_field.to_sym] = [[range_key_op.to_sym, range_key_value]]
|
284
263
|
end
|
264
|
+
|
265
|
+
query_non_key_conditions = options
|
266
|
+
.except(*Dynamoid::AdapterPlugin::AwsSdkV3::Query::OPTIONS_KEYS)
|
267
|
+
.except(:range)
|
268
|
+
.symbolize_keys
|
269
|
+
|
270
|
+
query_options = options.slice(*Dynamoid::AdapterPlugin::AwsSdkV3::Query::OPTIONS_KEYS)
|
271
|
+
query_options[:index_name] = index.name
|
272
|
+
|
273
|
+
Dynamoid.adapter.query(table_name, query_key_conditions, query_non_key_conditions, query_options)
|
274
|
+
.flat_map { |i| i }
|
275
|
+
.map { |item| from_database(item) }
|
285
276
|
end
|
286
277
|
|
287
278
|
# Find using exciting method_missing finders attributes. Uses criteria
|
@@ -308,7 +299,7 @@ module Dynamoid
|
|
308
299
|
chain = Dynamoid::Criteria::Chain.new(self)
|
309
300
|
chain = chain.where({}.tap { |h| attributes.each_with_index { |attr, index| h[attr.to_sym] = args[index] } })
|
310
301
|
|
311
|
-
if finder
|
302
|
+
if finder.include?('all')
|
312
303
|
chain.all
|
313
304
|
else
|
314
305
|
chain.first
|