Class: StatelyDB::Transaction::Transaction

Inherits:
Object
  • Object
show all
Defined in:
lib/transaction/transaction.rb

Overview

Transaction coordinates sending requests and waiting for responses. Consumers should not need to interact with this class directly, but instead use the methods provided by the StatelyDB::Client.

The example below demonstrates using a transaction, which accepts a block. The lines in the block are executed within the context of the transaction. The transaction is committed when the block completes successfully, OR is aborted if an exception is raised.

Examples:

result = client.transaction do |tx|
  key_path = StatelyDB::KeyPath.with('movie', 'The Shining')
  movie = tx.get(key_path:)
  tx.put(item: movie)
end

Defined Under Namespace

Classes: Result

Instance Method Summary collapse

Constructor Details

#initialize(stub:, store_id:, schema:) ⇒ Transaction

Initialize a new Transaction

Parameters:

  • stub (Stately::Db::DatabaseService::Stub)

    a StatelyDB gRPC stub

  • store_id (Integer)

    the StatelyDB Store to transact against

  • schema (StatelyDB::Schema)

    the schema to use for marshalling and unmarshalling Items



48
49
50
51
52
53
54
55
56
# File 'lib/transaction/transaction.rb', line 48

def initialize(stub:, store_id:, schema:)
  @stub = stub
  @store_id = store_id
  @schema = schema
  @is_transaction_open = false

  # A queue of outbound requests
  @outgoing_requests = StatelyDB::Transaction::Queue.new
end

Instance Method Details

#begin_list(prefix, limit: 100, sort_property: nil, sort_direction: :ascending) ⇒ (Array<StatelyDB::Item>, Stately::Db::ListToken)

Begin listing Items from a StatelyDB Store at the given prefix.

Example:

client.data.transaction do |txn|
  (items, token) = txn.begin_list("/ItemType-identifier")
  (items, token) = txn.continue_list(token)
end

Parameters:

  • prefix (String)

    the prefix to list

  • limit (Integer) (defaults to: 100)

    the maximum number of items to return

  • sort_property (String) (defaults to: nil)

    the property to sort by

  • sort_direction (Symbol) (defaults to: :ascending)

    the direction to sort by (:ascending or :descending)

Returns:



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/transaction/transaction.rb', line 313

def begin_list(prefix,
               limit: 100,
               sort_property: nil,
               sort_direction: :ascending)
  sort_direction = case sort_direction
                   when :ascending
                     0
                   else
                     1
                   end
  req = Stately::Db::TransactionRequest.new(
    begin_list: Stately::Db::TransactionBeginList.new(
      key_path_prefix: String(prefix),
      limit:,
      sort_property:,
      sort_direction:
    )
  )
  do_list_request_response(req)
end

#continue_list(token, continue_direction: :forward) ⇒ (Array<StatelyDB::Item>, Stately::Db::ListToken)

Continue listing Items from a StatelyDB Store using a token.

Example:

client.data.transaction do |txn|
  (items, token) = txn.begin_list("/foo")
  (items, token) = txn.continue_list(token)
end

Parameters:

  • token (Stately::Db::ListToken)

    the token to continue from

  • continue_direction (Symbol) (defaults to: :forward)

    the direction to continue by (:forward or :backward)

Returns:



345
346
347
348
349
350
351
352
353
354
355
# File 'lib/transaction/transaction.rb', line 345

def continue_list(token, continue_direction: :forward)
  continue_direction = continue_direction == :forward ? 0 : 1

  req = Stately::Db::TransactionRequest.new(
    continue_list: Stately::Db::TransactionContinueList.new(
      token_data: token.token_data,
      direction: continue_direction
    )
  )
  do_list_request_response(req)
end

#delete(*key_paths) ⇒ void

This method returns an undefined value.

Delete up to 50 Items from a StatelyDB Store at the given key_paths. Results are not returned until the transaction is committed and will be available in the Result object returned by commit.

Example:

client.data.transaction do |txn|
  txn.delete("/ItemType-identifier", "/ItemType-identifier2")
end

Parameters:

  • key_paths (String, Array<String>)

    the paths to the items. Max 50 key paths.



289
290
291
292
293
294
295
296
297
298
# File 'lib/transaction/transaction.rb', line 289

def delete(*key_paths)
  key_paths = Array(key_paths).flatten
  req = Stately::Db::TransactionRequest.new(
    delete_items: Stately::Db::TransactionDelete.new(
      deletes: key_paths.map { |key_path| Stately::Db::DeleteItem.new(key_path: String(key_path)) }
    )
  )
  request_only(req)
  nil
end

#get(key_path) ⇒ StatelyDB::Item, NilClass

Fetch Items from a StatelyDB Store at the given key_path. Note that Items need to exist before being retrieved inside a transaction.

Examples:

client.data.transaction do |txn|
  item = txn.get("/ItemType-identifier")
end

Parameters:

  • key_path (String)

    the path to the item

Returns:

Raises:

  • (StatelyDB::Error::InvalidParameters)

    if the parameters are invalid

  • (StatelyDB::Error::NotFound)

    if the item is not found



185
186
187
188
189
190
# File 'lib/transaction/transaction.rb', line 185

def get(key_path)
  resp = get_batch(key_path)

  # Always return a single Item.
  resp.first
end

#get_batch(*key_paths) ⇒ Array<StatelyDB::Item>

Fetch a batch of up to 100 Items from a StatelyDB Store at the given key_paths. Note that Items need to exist before being retrieved inside a transaction.

key paths. Example:

client.data.transaction do |txn|
  items = txn.get_batch("/foo", "/bar")
end

Parameters:

  • key_paths (String, Array<String>)

    the paths to the items. Max 100

Returns:

Raises:

  • (StatelyDB::Error::InvalidParameters)

    if the parameters are invalid

  • (StatelyDB::Error::NotFound)

    if the item is not found



206
207
208
209
210
211
212
213
214
215
216
217
218
# File 'lib/transaction/transaction.rb', line 206

def get_batch(*key_paths)
  key_paths = Array(key_paths).flatten
  req = Stately::Db::TransactionRequest.new(
    get_items: Stately::Db::TransactionGet.new(
      gets: key_paths.map { |key_path| Stately::Db::GetItem.new(key_path: String(key_path)) }
    )
  )
  resp = request_response(req).get_results

  resp.items.map do |result|
    @schema.unmarshal_item(stately_item: result)
  end
end

#put(item) ⇒ String, Integer

Put a single Item into a StatelyDB store. Results are not returned until the transaction is committed and will be available in the Result object returned by commit. An identifier for the item will be returned while inside the transaction block.

results.puts.each do |result|
  puts result.key_path
end

Examples:

results = client.data.transaction do |txn|
  txn.put(my_item)
end

Parameters:

Returns:

  • (String, Integer)

    the id of the item



234
235
236
237
# File 'lib/transaction/transaction.rb', line 234

def put(item)
  resp = put_batch(item)
  resp.first
end

#put_batch(*items) ⇒ Array<StatelyDB::UUID, String, Integer, nil>

Put a batch of up to 50 Items into a StatelyDB Store. Results are not returned until the transaction is committed and will be available in the Result object returned by commit. A list of identifiers for the items will be returned while inside the transaction block.

results.puts.each do |result|
  puts result.key_path
end

Examples:

results = client.data.transaction do |txn|
  txn.put_batch(item1, item2)
end

Parameters:

Returns:



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'lib/transaction/transaction.rb', line 253

def put_batch(*items)
  items = Array(items).flatten
  req = Stately::Db::TransactionRequest.new(
    put_items: Stately::Db::TransactionPut.new(
      puts: items.map do |item|
        Stately::Db::PutItem.new(
          item: item.send("marshal_stately")
        )
      end
    )
  )

  resp = request_response(req).put_ack
  resp.generated_ids.map do |generated_id|
    case generated_id.value
    when :bytes
      StatelyDB::UUID.valid_uuid?(generated_id.bytes) ? StatelyDB::UUID.parse(generated_id.bytes) : generated_id.bytes
    when :uint
      generated_id.uint
    else # rubocop:disable Style/EmptyElse
      # An empty identifier is sent in the transaction Put response if an initialValue is not set
      nil
    end
  end
end