Class: Dynamoid::AdapterPlugin::AwsSdkV3

Inherits:
Object
  • Object
show all
Defined in:
lib/dynamoid/adapter_plugin/aws_sdk_v3.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/transact.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/batch_get_item.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/execute_statement.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb,
lib/dynamoid/adapter_plugin/aws_sdk_v3/projection_expression_convertor.rb

Overview

NOTE: Don’t use keyword arguments in public methods as far as method calls on adapter are delegated to the plugin.

There are breaking changes in Ruby related to delegating keyword arguments so we have decided just to avoid them when use delegation.

eregon.me/blog/2019/11/10/the-delegation-challenge-of-ruby27.html

Defined Under Namespace

Modules: Middleware Classes: BatchGetItem, CreateTable, ExecuteStatement, FilterExpressionConvertor, ItemUpdater, ProjectionExpressionConvertor, Query, Scan, Table, Transact, UntilPastTableStatus

Constant Summary collapse

EQ =
'EQ'
HASH_KEY =
'HASH'
RANGE_KEY =
'RANGE'
STRING_TYPE =
'S'
NUM_TYPE =
'N'
BINARY_TYPE =
'B'
TABLE_STATUSES =
{
  creating: 'CREATING',
  updating: 'UPDATING',
  deleting: 'DELETING',
  active: 'ACTIVE'
}.freeze
PARSE_TABLE_STATUS =
lambda { |resp, lookup = :table|
  # lookup is table for describe_table API
  # lookup is table_description for create_table API
  #   because Amazon, damnit.
  resp.send(lookup).table_status
}
BATCH_WRITE_ITEM_REQUESTS_LIMIT =
25
CONNECTION_CONFIG_OPTIONS =
%i[endpoint region http_continue_timeout http_idle_timeout http_open_timeout http_read_timeout].freeze
RESERVED_WORDS =

See docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html rubocop:disable Metrics/CollectionLiteralLength

Set.new(
  %i[
    ABORT ABSOLUTE ACTION ADD AFTER AGENT AGGREGATE ALL ALLOCATE ALTER ANALYZE
    AND ANY ARCHIVE ARE ARRAY AS ASC ASCII ASENSITIVE ASSERTION ASYMMETRIC AT
    ATOMIC ATTACH ATTRIBUTE AUTH AUTHORIZATION AUTHORIZE AUTO AVG BACK BACKUP
    BASE BATCH BEFORE BEGIN BETWEEN BIGINT BINARY BIT BLOB BLOCK BOOLEAN BOTH
    BREADTH BUCKET BULK BY BYTE CALL CALLED CALLING CAPACITY CASCADE CASCADED
    CASE CAST CATALOG CHAR CHARACTER CHECK CLASS CLOB CLOSE CLUSTER CLUSTERED
    CLUSTERING CLUSTERS COALESCE COLLATE COLLATION COLLECTION COLUMN COLUMNS
    COMBINE COMMENT COMMIT COMPACT COMPILE COMPRESS CONDITION CONFLICT CONNECT
    CONNECTION CONSISTENCY CONSISTENT CONSTRAINT CONSTRAINTS CONSTRUCTOR
    CONSUMED CONTINUE CONVERT COPY CORRESPONDING COUNT COUNTER CREATE CROSS
    CUBE CURRENT CURSOR CYCLE DATA DATABASE DATE DATETIME DAY DEALLOCATE DEC
    DECIMAL DECLARE DEFAULT DEFERRABLE DEFERRED DEFINE DEFINED DEFINITION
    DELETE DELIMITED DEPTH DEREF DESC DESCRIBE DESCRIPTOR DETACH DETERMINISTIC
    DIAGNOSTICS DIRECTORIES DISABLE DISCONNECT DISTINCT DISTRIBUTE DO DOMAIN
    DOUBLE DROP DUMP DURATION DYNAMIC EACH ELEMENT ELSE ELSEIF EMPTY ENABLE
    END EQUAL EQUALS ERROR ESCAPE ESCAPED EVAL EVALUATE EXCEEDED EXCEPT
    EXCEPTION EXCEPTIONS EXCLUSIVE EXEC EXECUTE EXISTS EXIT EXPLAIN EXPLODE
    EXPORT EXPRESSION EXTENDED EXTERNAL EXTRACT FAIL FALSE FAMILY FETCH FIELDS
    FILE FILTER FILTERING FINAL FINISH FIRST FIXED FLATTERN FLOAT FOR FORCE
    FOREIGN FORMAT FORWARD FOUND FREE FROM FULL FUNCTION FUNCTIONS GENERAL
    GENERATE GET GLOB GLOBAL GO GOTO GRANT GREATER GROUP GROUPING HANDLER HASH
    HAVE HAVING HEAP HIDDEN HOLD HOUR IDENTIFIED IDENTITY IF IGNORE IMMEDIATE
    IMPORT IN INCLUDING INCLUSIVE INCREMENT INCREMENTAL INDEX INDEXED INDEXES
    INDICATOR INFINITE INITIALLY INLINE INNER INNTER INOUT INPUT INSENSITIVE
    INSERT INSTEAD INT INTEGER INTERSECT INTERVAL INTO INVALIDATE IS ISOLATION
    ITEM ITEMS ITERATE JOIN KEY KEYS LAG LANGUAGE LARGE LAST LATERAL LEAD
    LEADING LEAVE LEFT LENGTH LESS LEVEL LIKE LIMIT LIMITED LINES LIST LOAD
    LOCAL LOCALTIME LOCALTIMESTAMP LOCATION LOCATOR LOCK LOCKS LOG LOGED LONG
    LOOP LOWER MAP MATCH MATERIALIZED MAX MAXLEN MEMBER MERGE METHOD METRICS
    MIN MINUS MINUTE MISSING MOD MODE MODIFIES MODIFY MODULE MONTH MULTI
    MULTISET NAME NAMES NATIONAL NATURAL NCHAR NCLOB NEW NEXT NO NONE NOT NULL
    NULLIF NUMBER NUMERIC OBJECT OF OFFLINE OFFSET OLD ON ONLINE ONLY OPAQUE
    OPEN OPERATOR OPTION OR ORDER ORDINALITY OTHER OTHERS OUT OUTER OUTPUT
    OVER OVERLAPS OVERRIDE OWNER PAD PARALLEL PARAMETER PARAMETERS PARTIAL
    PARTITION PARTITIONED PARTITIONS PATH PERCENT PERCENTILE PERMISSION
    PERMISSIONS PIPE PIPELINED PLAN POOL POSITION PRECISION PREPARE PRESERVE
    PRIMARY PRIOR PRIVATE PRIVILEGES PROCEDURE PROCESSED PROJECT PROJECTION
    PROPERTY PROVISIONING PUBLIC PUT QUERY QUIT QUORUM RAISE RANDOM RANGE RANK
    RAW READ READS REAL REBUILD RECORD RECURSIVE REDUCE REF REFERENCE
    REFERENCES REFERENCING REGEXP REGION REINDEX RELATIVE RELEASE REMAINDER
    RENAME REPEAT REPLACE REQUEST RESET RESIGNAL RESOURCE RESPONSE RESTORE
    RESTRICT RESULT RETURN RETURNING RETURNS REVERSE REVOKE RIGHT ROLE ROLES
    ROLLBACK ROLLUP ROUTINE ROW ROWS RULE RULES SAMPLE SATISFIES SAVE SAVEPOINT
    SCAN SCHEMA SCOPE SCROLL SEARCH SECOND SECTION SEGMENT SEGMENTS SELECT SELF
    SEMI SENSITIVE SEPARATE SEQUENCE SERIALIZABLE SESSION SET SETS SHARD SHARE
    SHARED SHORT SHOW SIGNAL SIMILAR SIZE SKEWED SMALLINT SNAPSHOT SOME SOURCE
    SPACE SPACES SPARSE SPECIFIC SPECIFICTYPE SPLIT SQL SQLCODE SQLERROR
    SQLEXCEPTION SQLSTATE SQLWARNING START STATE STATIC STATUS STORAGE STORE
    STORED STREAM STRING STRUCT STYLE SUB SUBMULTISET SUBPARTITION SUBSTRING
    SUBTYPE SUM SUPER SYMMETRIC SYNONYM SYSTEM TABLE TABLESAMPLE TEMP TEMPORARY
    TERMINATED TEXT THAN THEN THROUGHPUT TIME TIMESTAMP TIMEZONE TINYINT TO
    TOKEN TOTAL TOUCH TRAILING TRANSACTION TRANSFORM TRANSLATE TRANSLATION
    TREAT TRIGGER TRIM TRUE TRUNCATE TTL TUPLE TYPE UNDER UNDO UNION UNIQUE UNIT
    UNKNOWN UNLOGGED UNNEST UNPROCESSED UNSIGNED UNTIL UPDATE UPPER URL USAGE
    USE USER USERS USING UUID VACUUM VALUE VALUED VALUES VARCHAR VARIABLE
    VARIANCE VARINT VARYING VIEW VIEWS VIRTUAL VOID WAIT WHEN WHENEVER WHERE
    WHILE WINDOW WITH WITHIN WITHOUT WORK WRAPPED WRITE YEAR ZONE
  ]
).freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#table_cacheObject (readonly)

rubocop:enable Metrics/CollectionLiteralLength



114
115
116
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 114

def table_cache
  @table_cache
end

Instance Method Details

#batch_delete_item(options) ⇒ Object

Delete many items at once from DynamoDB. More efficient than delete each item individually.

or

Dynamoid::AdapterPlugin::AwsSdkV3.batch_delete_item('table1' => [['hk1', 'rk2'], ['hk1', 'rk2']]]))

See:

TODO handle rejections because of internal processing failures

Examples:

Delete IDs 1 and 2 from the table testtable

Dynamoid::AdapterPlugin::AwsSdk.batch_delete_item('table1' => ['1', '2'])

Parameters:

  • options (Hash)

    the hash of tables and IDs to delete



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 267

def batch_delete_item(options)
  requests = []

  options.each_pair do |table_name, ids|
    table = describe_table(table_name)

    ids.each_slice(BATCH_WRITE_ITEM_REQUESTS_LIMIT) do |sliced_ids|
      delete_requests = sliced_ids.map do |id|
        { delete_request: { key: key_stanza(table, *id) } }
      end

      requests << { table_name => delete_requests }
    end
  end

  requests.each do |items|
    client.batch_write_item(
      request_items: items,
      return_consumed_capacity: 'TOTAL',
      return_item_collection_metrics: 'SIZE'
    )
  end
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
  raise Dynamoid::Errors::ConditionalCheckFailedException, e
end

#batch_get_item(table_names_with_ids, options = {}, &block) ⇒ Hash

Get many items at once from DynamoDB. More efficient than getting each item individually.

If optional block is passed ‘nil` will be returned and the block will be called for each read batch of items, meaning once per batch.

Block receives parameters:

  • hash with items like ‘{ table_name: [items]}`

  • and boolean flag is true if there are some unprocessed keys, otherwise false.

@todo: Provide support for passing options to underlying batch_get_item

Examples:

Retrieve IDs 1 and 2 from the table testtable

Dynamoid::AdapterPlugin::AwsSdkV3.batch_get_item('table1' => ['1', '2'])

Pass block to receive each batch

Dynamoid::AdapterPlugin::AwsSdkV3.batch_get_item('table1' => ids) do |hash, bool|
  puts hash['table1']

  if bool
    puts 'there are unprocessed keys'
  end
end

Parameters:

  • table_names_with_ids (Hash)

    the hash of tables and IDs to retrieve

  • options (Hash) (defaults to: {})

    to be passed to underlying BatchGet call

  • block (Proc)

    optional block can be passed to handle each batch of items

Returns:

Since:

  • 1.0.0



246
247
248
249
250
251
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 246

def batch_get_item(table_names_with_ids, options = {}, &block)
  tables_with_ids = table_names_with_ids.transform_keys do |name|
    describe_table(name)
  end
  BatchGetItem.new(client, tables_with_ids, options).call(&block)
end

#batch_write_item(table_name, objects, options = {}) {|true|false| ... } ⇒ Object

Puts multiple items in one table

If optional block is passed it will be called for each written batch of items, meaning once per batch. Block receives boolean flag which is true if there are some unprocessed items, otherwise false.

See:

Examples:

Saves several items to the table testtable

Dynamoid::AdapterPlugin::AwsSdkV3.batch_write_item('table1', [{ id: '1', name: 'a' }, { id: '2', name: 'b'}])

Pass block

Dynamoid::AdapterPlugin::AwsSdkV3.batch_write_item('table1', items) do |bool|
  if bool
    puts 'there are unprocessed items'
  end
end

Parameters:

  • table_name (String)

    the name of the table

  • objects (Array)

    to be processed

  • options (Hash) (defaults to: {})

    additional options

Yields:

  • (true|false)

    invokes an optional block with argument - whether there are unprocessed items



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 186

def batch_write_item(table_name, objects, options = {})
  items = objects.map { |o| sanitize_item(o) }

  while items.present?
    batch = items.shift(BATCH_WRITE_ITEM_REQUESTS_LIMIT)
    requests = batch.map { |item| { put_request: { item: item } } }

    response = client.batch_write_item(
      {
        request_items: {
          table_name => requests
        },
        return_consumed_capacity: 'TOTAL',
        return_item_collection_metrics: 'SIZE'
      }.merge!(options)
    )

    yield(response.unprocessed_items.present?) if block_given?

    if response.unprocessed_items.present?
      items += response.unprocessed_items[table_name].map { |r| r.put_request.item }
    end
  end
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
  raise Dynamoid::Errors::ConditionalCheckFailedException, e
end

#clientObject

Return the client object.

Since:

  • 1.0.0



159
160
161
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 159

def client
  @client
end

#connect!Aws::DynamoDB::Client

Establish the connection to DynamoDB.

Returns:

  • (Aws::DynamoDB::Client)

    the DynamoDB connection



119
120
121
122
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 119

def connect!
  @client = Aws::DynamoDB::Client.new(connection_config)
  @table_cache = {}
end

#connection_configObject



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 124

def connection_config
  @connection_hash = {}

  (Dynamoid::Config.settings.compact.keys & CONNECTION_CONFIG_OPTIONS).each do |option|
    @connection_hash[option] = Dynamoid::Config.send(option)
  end

  # if credentials are passed, they already contain access key & secret key
  if Dynamoid::Config.credentials?
    @connection_hash[:credentials] = Dynamoid::Config.credentials
  else
    # otherwise, pass access key & secret key for credentials creation
    if Dynamoid::Config.access_key?
      @connection_hash[:access_key_id] = Dynamoid::Config.access_key
    end
    if Dynamoid::Config.secret_key?
      @connection_hash[:secret_access_key] = Dynamoid::Config.secret_key
    end
  end

  @connection_hash[:logger] = Dynamoid::Config.logger
  @connection_hash[:log_level] = :debug

  # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/plugins/logging.rb
  # https://github.com/aws/aws-sdk-ruby/blob/master/gems/aws-sdk-core/lib/aws-sdk-core/log/formatter.rb
  if Dynamoid::Config.log_formatter
    @connection_hash[:log_formatter] = Dynamoid::Config.log_formatter
  end

  @connection_hash
end

#count(table_name) ⇒ Object



601
602
603
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 601

def count(table_name)
  describe_table(table_name, reload: true).item_count
end

#create_table(table_name, key = :id, options = {}) ⇒ Object

Create a table on DynamoDB. This usually takes a long time to complete.

Parameters:

  • table_name (String)

    the name of the table to create

  • key (Symbol) (defaults to: :id)

    the table’s primary key (defaults to :id)

  • options (Hash) (defaults to: {})

    provide a range key here if the table has a composite key

Options Hash (options):

Since:

  • 1.0.0



315
316
317
318
319
320
321
322
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 315

def create_table(table_name, key = :id, options = {})
  Dynamoid.logger.info "Creating #{table_name} table. This could take a while."
  CreateTable.new(client, table_name, key, options).call
  true
rescue Aws::DynamoDB::Errors::ResourceInUseException => e
  Dynamoid.logger.error "Table #{table_name} cannot be created as it already exists"
  false
end

#create_table_synchronously(table_name, key = :id, options = {}) ⇒ Object

Create a table on DynamoDB synchronously. This usually takes a long time to complete. CreateTable is normally an asynchronous operation. You can optionally define secondary indexes on the new table,

as part of the CreateTable operation.

If you want to create multiple tables with secondary indexes on them,

you must create the tables sequentially.

Only one table with secondary indexes can be

in the CREATING state at any given time.

See: docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#create_table-instance_method

Parameters:

  • table_name (String)

    the name of the table to create

  • key (Symbol) (defaults to: :id)

    the table’s primary key (defaults to :id)

  • options (Hash) (defaults to: {})

    provide a range key here if the table has a composite key

Options Hash (options):

Since:

  • 1.2.0



354
355
356
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 354

def create_table_synchronously(table_name, key = :id, options = {})
  create_table(table_name, key, options.merge(sync: true))
end

#delete_item(table_name, key, options = {}) ⇒ Object

Removes an item from DynamoDB.

@todo: Provide support for various options docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#delete_item-instance_method

Parameters:

  • table_name (String)

    the name of the table

  • key (String)

    the hash key of the item to delete

  • options (Hash) (defaults to: {})

    provide a range key here if the table has a composite key

Since:

  • 1.0.0



367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 367

def delete_item(table_name, key, options = {})
  options ||= {}
  range_key = options[:range_key]
  conditions = options[:conditions]
  table = describe_table(table_name)
  client.delete_item(
    table_name: table_name,
    key: key_stanza(table, key, range_key),
    expected: expected_stanza(conditions)
  )
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
  raise Dynamoid::Errors::ConditionalCheckFailedException, e
end

#delete_table(table_name, options = {}) ⇒ Object

Deletes an entire table from DynamoDB.

Parameters:

  • table_name (String)

    the name of the table to destroy

  • options (Hash) (defaults to: {})

    a customizable set of options

Options Hash (options):

  • sync (Boolean)

    Wait for table status check to raise ResourceNotFoundException

Since:

  • 1.0.0



387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 387

def delete_table(table_name, options = {})
  resp = client.delete_table(table_name: table_name)

  if options[:sync]
    status = PARSE_TABLE_STATUS.call(resp, :table_description)
    if status == TABLE_STATUSES[:deleting]
      UntilPastTableStatus.new(client, table_name, :deleting).call
    end
  end

  table_cache.delete(table_name)
rescue Aws::DynamoDB::Errors::ResourceInUseException => e
  Dynamoid.logger.error "Table #{table_name} cannot be deleted as it is in use"
  raise e
end

#delete_table_synchronously(table_name, options = {}) ⇒ Object



403
404
405
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 403

def delete_table_synchronously(table_name, options = {})
  delete_table(table_name, options.merge(sync: true))
end

#execute(statement, parameters = [], options = {}) ⇒ [] | Array[Hash] | Enumerator::Lazy[Hash]

Run PartiQL query.

Dynamoid.adapter.execute("SELECT * FROM users WHERE id = ?", ["758"])

Parameters:

  • statement (String)

    PartiQL statement

  • parameters (Array) (defaults to: [])

    a list of bind parameters

  • options (Hash) (defaults to: {})
  • [Boolean] (Hash)

    a customizable set of options

Returns:

  • ([] | Array[Hash] | Enumerator::Lazy[Hash])

    items when used a SELECT statement and empty Array otherwise



615
616
617
618
619
620
621
622
623
624
625
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 615

def execute(statement, parameters = [], options = {})
  items = ExecuteStatement.new(client, statement, parameters, options).call

  if items.is_a?(Array)
    items
  else
    items.lazy.flat_map { |array| array }
  end
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException
  []
end

#get_item(table_name, key, options = {}) ⇒ Hash

Fetches an item from DynamoDB.

Parameters:

  • table_name (String)

    the name of the table

  • key (String)

    the hash key of the item to find

  • options (Hash) (defaults to: {})

    provide a range key here if the table has a composite key

Returns:

  • (Hash)

    a hash representing the raw item in DynamoDB

Since:

  • 1.0.0



420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 420

def get_item(table_name, key, options = {})
  options = options.dup
  options ||= {}

  table = describe_table(table_name)
  range_key = options.delete(:range_key)
  consistent_read = options.delete(:consistent_read)

  item = client.get_item(table_name: table_name,
                         key: key_stanza(table, key, range_key),
                         consistent_read: consistent_read)[:item]
  item ? item_to_hash(item) : nil
end

#list_tablesObject

List all tables on DynamoDB.

Since:

  • 1.0.0



468
469
470
471
472
473
474
475
476
477
478
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 468

def list_tables
  [].tap do |result|
    start_table_name = nil
    loop do
      result_page = client.list_tables exclusive_start_table_name: start_table_name
      start_table_name = result_page.last_evaluated_table_name
      result.concat result_page.table_names
      break unless start_table_name
    end
  end
end

#put_item(table_name, object, options = {}) ⇒ Object

Parameters:

  • table_name (String)

    the name of the table

  • object (Object)

    a hash or Dynamoid object to persist

Since:

  • 1.0.0



488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 488

def put_item(table_name, object, options = {})
  options ||= {}
  item = sanitize_item(object)

  client.put_item(
    {
      table_name: table_name,
      item: item,
      expected: expected_stanza(options)
    }.merge!(options)
  )
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
  raise Dynamoid::Errors::ConditionalCheckFailedException, e
end

#query(table_name, key_conditions, non_key_conditions = [], options = {}) ⇒ Enumerable

Query the DynamoDB table. This employs DynamoDB’s indexes so is generally faster than scanning, but is only really useful for range queries, since it can only find by one hash key at once. Only provide one range key to the hash.

Dynamoid.adapter.query('users', { id: [[:eq, '1']], age: [[:between, [10, 30]]] }, { batch_size: 1000 })

Parameters:

  • table_name (String)

    the name of the table

  • key_conditions (Array[Array])

    conditions for the primary key attributes

  • non_key_conditions (Array[Array]) (defaults to: [])

    (optional) conditions for non-primary key attributes

  • options (Hash) (defaults to: {})

    (optional) the options to query the table with

Options Hash (options):

  • :consistent_read (Boolean)

    You can set the ConsistentRead parameter to true and obtain a strongly consistent result

  • :scan_index_forward (Boolean)

    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.

  • :select (Symbop)

    The attributes to be returned in the result (one of ALL_ATTRIBUTES, ALL_PROJECTED_ATTRIBUTES, …)

  • :index_name (Symbol)

    The name of an index to query. This index can be any local secondary index or global secondary index on the table.

  • :exclusive_start_key (Hash)

    The primary key of the first item that this operation will evaluate.

  • :batch_size (Integer)

    The number of items to lazily load one by one

  • :record_limit (Integer)

    The maximum number of items to return (not necessarily the number of evaluated items)

  • :scan_limit (Integer)

    The maximum number of items to evaluate (not necessarily the number of matching items)

  • :project (Array[Symbol])

    The attributes to retrieve from the table

Returns:

  • (Enumerable)

    matching items

Since:

  • 1.0.0



528
529
530
531
532
533
534
535
536
537
538
539
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 528

def query(table_name, key_conditions, non_key_conditions = [], options = {})
  Enumerator.new do |yielder|
    table = describe_table(table_name)

    Query.new(client, table, key_conditions, non_key_conditions, options).call.each do |page|
      yielder.yield(
        page.items.map { |item| item_to_hash(item) },
        last_evaluated_key: page.last_evaluated_key
      )
    end
  end
end

#query_count(table_name, key_conditions, non_key_conditions, options) ⇒ Object



541
542
543
544
545
546
547
548
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 541

def query_count(table_name, key_conditions, non_key_conditions, options)
  table = describe_table(table_name)
  options[:select] = 'COUNT'

  Query.new(client, table, key_conditions, non_key_conditions, options).call
    .map(&:count)
    .reduce(:+)
end

#scan(table_name, conditions = [], options = {}) ⇒ Enumerable

Scan the DynamoDB table. This is usually a very slow operation as it naively filters all data on the DynamoDB servers.

@todo: Provide support for various options docs.aws.amazon.com/sdkforruby/api/Aws/DynamoDB/Client.html#scan-instance_method

Parameters:

  • table_name (String)

    the name of the table

  • conditions (Hash) (defaults to: [])

    a hash of attributes: matching records will be returned by the scan

Returns:

  • (Enumerable)

    matching items

Since:

  • 1.0.0



561
562
563
564
565
566
567
568
569
570
571
572
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 561

def scan(table_name, conditions = [], options = {})
  Enumerator.new do |yielder|
    table = describe_table(table_name)

    Scan.new(client, table, conditions, options).call.each do |page|
      yielder.yield(
        page.items.map { |item| item_to_hash(item) },
        last_evaluated_key: page.last_evaluated_key
      )
    end
  end
end

#scan_count(table_name, conditions = [], options = {}) ⇒ Object



574
575
576
577
578
579
580
581
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 574

def scan_count(table_name, conditions = [], options = {})
  table = describe_table(table_name)
  options[:select] = 'COUNT'

  Scan.new(client, table, conditions, options).call
    .map(&:count)
    .reduce(:+)
end

#transact_read_items(items) ⇒ Object



297
298
299
300
301
302
303
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 297

def transact_read_items(items)
  request = {
    transact_items: items,
    return_consumed_capacity: 'TOTAL',
  }
  client.transact_get_items(request)
end

#transact_write_items(items) ⇒ Object



293
294
295
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 293

def transact_write_items(items)
  Transact.new(client).transact_write_items(items)
end

#truncate(table_name) ⇒ Object

Truncates all records in the given table

Parameters:

  • table_name (String)

    the name of the table

Since:

  • 1.0.0



589
590
591
592
593
594
595
596
597
598
599
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 589

def truncate(table_name)
  table = describe_table(table_name)
  hk    = table.hash_key
  rk    = table.range_key

  ids = scan(table_name, {}, {}).flat_map { |i| i }.map do |attributes|
    rk ? [attributes[hk], attributes[rk.to_sym]] : attributes[hk]
  end

  batch_delete_item(table_name => ids)
end

#update_item(table_name, key, options = {}) ⇒ Object

Edits an existing item’s attributes, or adds a new item to the table if it does not already exist. You can put, delete, or add attribute values

Parameters:

  • table_name (String)

    the name of the table

  • key (String)

    the hash key of the item to find

  • options (Hash) (defaults to: {})

    provide a range key here if the table has a composite key

Returns:

  • new attributes for the record



443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 443

def update_item(table_name, key, options = {})
  options = options.dup

  range_key = options.delete(:range_key)
  conditions = options.delete(:conditions)
  table = describe_table(table_name)

  item_updater = ItemUpdater.new(table, key, range_key)
  yield(item_updater)

  raise "non-empty options: #{options}" unless options.empty?

  result = client.update_item(table_name: table_name,
                              key: key_stanza(table, key, range_key),
                              attribute_updates: item_updater.attribute_updates,
                              expected: expected_stanza(conditions),
                              return_values: 'ALL_NEW')
  item_to_hash(result[:attributes])
rescue Aws::DynamoDB::Errors::ConditionalCheckFailedException => e
  raise Dynamoid::Errors::ConditionalCheckFailedException, e
end

#update_time_to_live(table_name, attribute) ⇒ Object



324
325
326
327
328
329
330
331
332
333
334
# File 'lib/dynamoid/adapter_plugin/aws_sdk_v3.rb', line 324

def update_time_to_live(table_name, attribute)
  request = {
    table_name: table_name,
    time_to_live_specification: {
      attribute_name: attribute,
      enabled: true,
    }
  }

  client.update_time_to_live(request)
end