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
@@ -14,7 +14,7 @@ module Dynamoid
|
|
14
14
|
module AdapterPlugin
|
15
15
|
# The AwsSdkV3 adapter provides support for the aws-sdk version 2 for ruby.
|
16
16
|
|
17
|
-
#
|
17
|
+
# NOTE: Don't use keyword arguments in public methods as far as method
|
18
18
|
# calls on adapter are delegated to the plugin.
|
19
19
|
#
|
20
20
|
# There are breaking changes in Ruby related to delegating keyword
|
@@ -24,31 +24,6 @@ module Dynamoid
|
|
24
24
|
|
25
25
|
class AwsSdkV3
|
26
26
|
EQ = 'EQ'
|
27
|
-
RANGE_MAP = {
|
28
|
-
range_greater_than: 'GT',
|
29
|
-
range_less_than: 'LT',
|
30
|
-
range_gte: 'GE',
|
31
|
-
range_lte: 'LE',
|
32
|
-
range_begins_with: 'BEGINS_WITH',
|
33
|
-
range_between: 'BETWEEN',
|
34
|
-
range_eq: 'EQ'
|
35
|
-
}.freeze
|
36
|
-
|
37
|
-
FIELD_MAP = {
|
38
|
-
eq: 'EQ',
|
39
|
-
ne: 'NE',
|
40
|
-
gt: 'GT',
|
41
|
-
lt: 'LT',
|
42
|
-
gte: 'GE',
|
43
|
-
lte: 'LE',
|
44
|
-
begins_with: 'BEGINS_WITH',
|
45
|
-
between: 'BETWEEN',
|
46
|
-
in: 'IN',
|
47
|
-
contains: 'CONTAINS',
|
48
|
-
not_contains: 'NOT_CONTAINS',
|
49
|
-
null: 'NULL',
|
50
|
-
not_null: 'NOT_NULL',
|
51
|
-
}.freeze
|
52
27
|
HASH_KEY = 'HASH'
|
53
28
|
RANGE_KEY = 'RANGE'
|
54
29
|
STRING_TYPE = 'S'
|
@@ -70,26 +45,72 @@ module Dynamoid
|
|
70
45
|
|
71
46
|
CONNECTION_CONFIG_OPTIONS = %i[endpoint region http_continue_timeout http_idle_timeout http_open_timeout http_read_timeout].freeze
|
72
47
|
|
73
|
-
|
48
|
+
# See https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html
|
49
|
+
# rubocop:disable Metrics/CollectionLiteralLength
|
50
|
+
RESERVED_WORDS = Set.new(
|
51
|
+
%i[
|
52
|
+
ABORT ABSOLUTE ACTION ADD AFTER AGENT AGGREGATE ALL ALLOCATE ALTER ANALYZE
|
53
|
+
AND ANY ARCHIVE ARE ARRAY AS ASC ASCII ASENSITIVE ASSERTION ASYMMETRIC AT
|
54
|
+
ATOMIC ATTACH ATTRIBUTE AUTH AUTHORIZATION AUTHORIZE AUTO AVG BACK BACKUP
|
55
|
+
BASE BATCH BEFORE BEGIN BETWEEN BIGINT BINARY BIT BLOB BLOCK BOOLEAN BOTH
|
56
|
+
BREADTH BUCKET BULK BY BYTE CALL CALLED CALLING CAPACITY CASCADE CASCADED
|
57
|
+
CASE CAST CATALOG CHAR CHARACTER CHECK CLASS CLOB CLOSE CLUSTER CLUSTERED
|
58
|
+
CLUSTERING CLUSTERS COALESCE COLLATE COLLATION COLLECTION COLUMN COLUMNS
|
59
|
+
COMBINE COMMENT COMMIT COMPACT COMPILE COMPRESS CONDITION CONFLICT CONNECT
|
60
|
+
CONNECTION CONSISTENCY CONSISTENT CONSTRAINT CONSTRAINTS CONSTRUCTOR
|
61
|
+
CONSUMED CONTINUE CONVERT COPY CORRESPONDING COUNT COUNTER CREATE CROSS
|
62
|
+
CUBE CURRENT CURSOR CYCLE DATA DATABASE DATE DATETIME DAY DEALLOCATE DEC
|
63
|
+
DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED DEFINE DEFINED DEFINITION
|
64
|
+
DELETE DELIMITED DEPTH DEREF DESC DESCRIBE DESCRIPTOR DETACH DETERMINISTIC
|
65
|
+
DIAGNOSTICS DIRECTORIES DISABLE DISCONNECT DISTINCT DISTRIBUTE DO DOMAIN
|
66
|
+
DOUBLE DROP DUMP DURATION DYNAMIC EACH ELEMENT ELSE ELSEIF EMPTY ENABLE
|
67
|
+
END EQUAL EQUALS ERROR ESCAPE ESCAPED EVAL EVALUATE EXCEEDED EXCEPT
|
68
|
+
EXCEPTION EXCEPTIONS EXCLUSIVE EXEC EXECUTE EXISTS EXIT EXPLAIN EXPLODE
|
69
|
+
EXPORT EXPRESSION EXTENDED EXTERNAL EXTRACT FAIL FALSE FAMILY FETCH FIELDS
|
70
|
+
FILE FILTER FILTERING FINAL FINISH FIRST FIXED FLATTERN FLOAT FOR FORCE
|
71
|
+
FOREIGN FORMAT FORWARD FOUND FREE FROM FULL FUNCTION FUNCTIONS GENERAL
|
72
|
+
GENERATE GET GLOB GLOBAL GO GOTO GRANT GREATER GROUP GROUPING HANDLER HASH
|
73
|
+
HAVE HAVING HEAP HIDDEN HOLD HOUR IDENTIFIED IDENTITY IF IGNORE IMMEDIATE
|
74
|
+
IMPORT IN INCLUDING INCLUSIVE INCREMENT INCREMENTAL INDEX INDEXED INDEXES
|
75
|
+
INDICATOR INFINITE INITIALLY INLINE INNER INNTER INOUT INPUT INSENSITIVE
|
76
|
+
INSERT INSTEAD INT INTEGER INTERSECT INTERVAL INTO INVALIDATE IS ISOLATION
|
77
|
+
ITEM ITEMS ITERATE JOIN KEY KEYS LAG LANGUAGE LARGE LAST LATERAL LEAD
|
78
|
+
LEADING LEAVE LEFT LENGTH LESS LEVEL LIKE LIMIT LIMITED LINES LIST LOAD
|
79
|
+
LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCATOR LOCK LOCKS LOG LOGED LONG
|
80
|
+
LOOP LOWER MAP MATCH MATERIALIZED MAX MAXLEN MEMBER MERGE METHOD METRICS
|
81
|
+
MIN MINUS MINUTE MISSING MOD MODE MODIFIES MODIFY MODULE MONTH MULTI
|
82
|
+
MULTISET NAME NAMES NATIONAL NATURAL NCHAR NCLOB NEW NEXT NO NONE NOT NULL
|
83
|
+
NULLIF NUMBER NUMERIC OBJECT OF OFFLINE OFFSET OLD ON ONLINE ONLY OPAQUE
|
84
|
+
OPEN OPERATOR OPTION OR ORDER ORDINALITY OTHER OTHERS OUT OUTER OUTPUT
|
85
|
+
OVER OVERLAPS OVERRIDE OWNER PAD PARALLEL PARAMETER PARAMETERS PARTIAL
|
86
|
+
PARTITION PARTITIONED PARTITIONS PATH PERCENT PERCENTILE PERMISSION
|
87
|
+
PERMISSIONS PIPE PIPELINED PLAN POOL POSITION PRECISION PREPARE PRESERVE
|
88
|
+
PRIMARY PRIOR PRIVATE PRIVILEGES PROCEDURE PROCESSED PROJECT PROJECTION
|
89
|
+
PROPERTY PROVISIONING PUBLIC PUT QUERY QUIT QUORUM RAISE RANDOM RANGE RANK
|
90
|
+
RAW READ READS REAL REBUILD RECORD RECURSIVE REDUCE REF REFERENCE
|
91
|
+
REFERENCES REFERENCING REGEXP REGION REINDEX RELATIVE RELEASE REMAINDER
|
92
|
+
RENAME REPEAT REPLACE REQUEST RESET RESIGNAL RESOURCE RESPONSE RESTORE
|
93
|
+
RESTRICT RESULT RETURN RETURNING RETURNS REVERSE REVOKE RIGHT ROLE ROLES
|
94
|
+
ROLLBACK ROLLUP ROUTINE ROW ROWS RULE RULES SAMPLE SATISFIES SAVE SAVEPOINT
|
95
|
+
SCAN SCHEMA SCOPE SCROLL SEARCH SECOND SECTION SEGMENT SEGMENTS SELECT SELF
|
96
|
+
SEMI SENSITIVE SEPARATE SEQUENCE SERIALIZABLE SESSION SET SETS SHARD SHARE
|
97
|
+
SHARED SHORT SHOW SIGNAL SIMILAR SIZE SKEWED SMALLINT SNAPSHOT SOME SOURCE
|
98
|
+
SPACE SPACES SPARSE SPECIFIC SPECIFICTYPE SPLIT SQL SQLCODE SQLERROR
|
99
|
+
SQLEXCEPTION SQLSTATE SQLWARNING START STATE STATIC STATUS STORAGE STORE
|
100
|
+
STORED STREAM STRING STRUCT STYLE SUB SUBMULTISET SUBPARTITION SUBSTRING
|
101
|
+
SUBTYPE SUM SUPER SYMMETRIC SYNONYM SYSTEM TABLE TABLESAMPLE TEMP TEMPORARY
|
102
|
+
TERMINATED TEXT THAN THEN THROUGHPUT TIME TIMESTAMP TIMEZONE TINYINT TO
|
103
|
+
TOKEN TOTAL TOUCH TRAILING TRANSACTION TRANSFORM TRANSLATE TRANSLATION
|
104
|
+
TREAT TRIGGER TRIM TRUE TRUNCATE TTL TUPLE TYPE UNDER UNDO UNION UNIQUE UNIT
|
105
|
+
UNKNOWN UNLOGGED UNNEST UNPROCESSED UNSIGNED UNTIL UPDATE UPPER URL USAGE
|
106
|
+
USE USER USERS USING UUID VACUUM VALUE VALUED VALUES VARCHAR VARIABLE
|
107
|
+
VARIANCE VARINT VARYING VIEW VIEWS VIRTUAL VOID WAIT WHEN WHENEVER WHERE
|
108
|
+
WHILE WINDOW WITH WITHIN WITHOUT WORK WRAPPED WRITE YEAR ZONE
|
109
|
+
]
|
110
|
+
).freeze
|
111
|
+
# rubocop:enable Metrics/CollectionLiteralLength
|
74
112
|
|
75
|
-
|
76
|
-
# Is used in ScanFilter and QueryFilter
|
77
|
-
# https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html
|
78
|
-
# @param [String] operator value of RANGE_MAP or FIELD_MAP hash, e.g. "EQ", "LT" etc
|
79
|
-
# @param [Object] value scalar value or array/set
|
80
|
-
def self.attribute_value_list(operator, value)
|
81
|
-
# For BETWEEN and IN operators we should keep value as is (it should be already an array)
|
82
|
-
# NULL and NOT_NULL require absence of attribute list
|
83
|
-
# For all the other operators we wrap the value with array
|
84
|
-
# https://docs.aws.amazon.com/en_us/amazondynamodb/latest/developerguide/LegacyConditionalParameters.Conditions.html
|
85
|
-
if %w[BETWEEN IN].include?(operator)
|
86
|
-
[value].flatten
|
87
|
-
elsif %w[NULL NOT_NULL].include?(operator)
|
88
|
-
nil
|
89
|
-
else
|
90
|
-
[value]
|
91
|
-
end
|
92
|
-
end
|
113
|
+
attr_reader :table_cache
|
93
114
|
|
94
115
|
# Establish the connection to DynamoDB.
|
95
116
|
#
|
@@ -470,25 +491,32 @@ module Dynamoid
|
|
470
491
|
# only really useful for range queries, since it can only find by one hash key at once. Only provide
|
471
492
|
# one range key to the hash.
|
472
493
|
#
|
494
|
+
# Dynamoid.adapter.query('users', { id: [[:eq, '1']], age: [[:between, [10, 30]]] }, { batch_size: 1000 })
|
495
|
+
#
|
473
496
|
# @param [String] table_name the name of the table
|
474
|
-
# @param [
|
475
|
-
# @
|
476
|
-
# @
|
477
|
-
# @option options [
|
478
|
-
# @option options [
|
479
|
-
# @option options [
|
480
|
-
# @option options [
|
497
|
+
# @param [Array[Array]] key_conditions conditions for the primary key attributes
|
498
|
+
# @param [Array[Array]] non_key_conditions (optional) conditions for non-primary key attributes
|
499
|
+
# @param [Hash] options (optional) the options to query the table with
|
500
|
+
# @option options [Boolean] :consistent_read You can set the ConsistentRead parameter to true and obtain a strongly consistent result
|
501
|
+
# @option options [Boolean] :scan_index_forward Specifies the order for index traversal: If true (default), the traversal is performed in ascending order; if false, the traversal is performed in descending order.
|
502
|
+
# @option options [Symbop] :select The attributes to be returned in the result (one of ALL_ATTRIBUTES, ALL_PROJECTED_ATTRIBUTES, ...)
|
503
|
+
# @option options [Symbol] :index_name The name of an index to query. This index can be any local secondary index or global secondary index on the table.
|
504
|
+
# @option options [Hash] :exclusive_start_key The primary key of the first item that this operation will evaluate.
|
505
|
+
# @option options [Integer] :batch_size The number of items to lazily load one by one
|
506
|
+
# @option options [Integer] :record_limit The maximum number of items to return (not necessarily the number of evaluated items)
|
507
|
+
# @option options [Integer] :scan_limit The maximum number of items to evaluate (not necessarily the number of matching items)
|
508
|
+
# @option options [Array[Symbol]] :project The attributes to retrieve from the table
|
481
509
|
#
|
482
510
|
# @return [Enumerable] matching items
|
483
511
|
#
|
484
512
|
# @since 1.0.0
|
485
513
|
#
|
486
514
|
# @todo Provide support for various other options http://docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#query-instance_method
|
487
|
-
def query(table_name, options = {})
|
515
|
+
def query(table_name, key_conditions, non_key_conditions = {}, options = {})
|
488
516
|
Enumerator.new do |yielder|
|
489
517
|
table = describe_table(table_name)
|
490
518
|
|
491
|
-
Query.new(client, table, options).call.each do |page|
|
519
|
+
Query.new(client, table, key_conditions, non_key_conditions, options).call.each do |page|
|
492
520
|
yielder.yield(
|
493
521
|
page.items.map { |item| item_to_hash(item) },
|
494
522
|
last_evaluated_key: page.last_evaluated_key
|
@@ -497,11 +525,11 @@ module Dynamoid
|
|
497
525
|
end
|
498
526
|
end
|
499
527
|
|
500
|
-
def query_count(table_name,
|
528
|
+
def query_count(table_name, key_conditions, non_key_conditions, options)
|
501
529
|
table = describe_table(table_name)
|
502
530
|
options[:select] = 'COUNT'
|
503
531
|
|
504
|
-
Query.new(client, table, options).call
|
532
|
+
Query.new(client, table, key_conditions, non_key_conditions, options).call
|
505
533
|
.map(&:count)
|
506
534
|
.reduce(:+)
|
507
535
|
end
|
@@ -558,7 +586,7 @@ module Dynamoid
|
|
558
586
|
end
|
559
587
|
|
560
588
|
def count(table_name)
|
561
|
-
describe_table(table_name, true).item_count
|
589
|
+
describe_table(table_name, reload: true).item_count
|
562
590
|
end
|
563
591
|
|
564
592
|
# Run PartiQL query.
|
@@ -605,10 +633,7 @@ module Dynamoid
|
|
605
633
|
conditions.delete(:unless_exists).try(:each) do |col|
|
606
634
|
expected[col.to_s][:exists] = false
|
607
635
|
end
|
608
|
-
|
609
|
-
expected[col.to_s][:exists] = true
|
610
|
-
expected[col.to_s][:value] = val
|
611
|
-
end
|
636
|
+
|
612
637
|
conditions.delete(:if).try(:each) do |col, val|
|
613
638
|
expected[col.to_s][:value] = val
|
614
639
|
end
|
@@ -619,7 +644,7 @@ module Dynamoid
|
|
619
644
|
#
|
620
645
|
# New, semi-arbitrary API to get data on the table
|
621
646
|
#
|
622
|
-
def describe_table(table_name, reload
|
647
|
+
def describe_table(table_name, reload: false)
|
623
648
|
(!reload && table_cache[table_name]) || begin
|
624
649
|
table_cache[table_name] = Table.new(client.describe_table(table_name: table_name).data)
|
625
650
|
end
|
@@ -39,14 +39,14 @@ module Dynamoid
|
|
39
39
|
#
|
40
40
|
# @since 0.2.0
|
41
41
|
def target_association
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
return has_many_key_name if target_class.associations[has_many_key_name][:type] == :has_many
|
42
|
+
name = options[:inverse_of] || source.class.to_s.underscore.pluralize.to_sym
|
43
|
+
if target_class.associations.dig(name, :type) == :has_many
|
44
|
+
return name
|
46
45
|
end
|
47
46
|
|
48
|
-
|
49
|
-
|
47
|
+
name = options[:inverse_of] || source.class.to_s.underscore.to_sym
|
48
|
+
if target_class.associations.dig(name, :type) == :has_one
|
49
|
+
return name # rubocop:disable Style/RedundantReturn
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -265,7 +265,7 @@ module Dynamoid
|
|
265
265
|
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
266
266
|
end
|
267
267
|
|
268
|
-
define_method("#{name}="
|
268
|
+
define_method(:"#{name}=") do |objects|
|
269
269
|
@associations[:"#{name}_ids"] ||= Dynamoid::Associations.const_get(type.to_s.camelcase).new(self, name, options)
|
270
270
|
@associations[:"#{name}_ids"].setter(objects)
|
271
271
|
end
|
@@ -33,21 +33,21 @@ module Dynamoid
|
|
33
33
|
defaults[name] = settings[name] = options[:default]
|
34
34
|
|
35
35
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
36
|
-
def #{name}
|
37
|
-
settings[#{name.inspect}]
|
38
|
-
end
|
36
|
+
def #{name} # def endpoint
|
37
|
+
settings[#{name.inspect}] # settings["endpoint"]
|
38
|
+
end # end
|
39
39
|
|
40
|
-
def #{name}=(value)
|
41
|
-
settings[#{name.inspect}] = value
|
42
|
-
end
|
40
|
+
def #{name}=(value) # def endpoint=(value)
|
41
|
+
settings[#{name.inspect}] = value # settings["endpoint"] = value
|
42
|
+
end # end
|
43
43
|
|
44
|
-
def #{name}?
|
45
|
-
#{name}
|
46
|
-
end
|
44
|
+
def #{name}? # def endpoint?
|
45
|
+
#{name} # endpoint
|
46
|
+
end # end
|
47
47
|
|
48
|
-
def reset_#{name}
|
49
|
-
settings[#{name.inspect}] = defaults[#{name.inspect}]
|
50
|
-
end
|
48
|
+
def reset_#{name} # def reset_endpoint
|
49
|
+
settings[#{name.inspect}] = defaults[#{name.inspect}] # settings["endpoint"] = defaults["endpoint"]
|
50
|
+
end # end
|
51
51
|
RUBY
|
52
52
|
end
|
53
53
|
|
data/lib/dynamoid/config.rb
CHANGED
@@ -59,6 +59,7 @@ module Dynamoid
|
|
59
59
|
option :http_idle_timeout, default: nil # - default: 5
|
60
60
|
option :http_open_timeout, default: nil # - default: 15
|
61
61
|
option :http_read_timeout, default: nil # - default: 60
|
62
|
+
option :create_table_on_save, default: true
|
62
63
|
|
63
64
|
# The default logger for Dynamoid: either the Rails logger or just stdout.
|
64
65
|
#
|