Class: StatelyDB::CoreClient

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

Overview

CoreClient is a low level client for interacting with the Stately Cloud API. This client shouldn’t be used directly in most cases. Instead, use the generated client for your schema.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store_id:, schema:, token_provider: Common::Auth::Auth0TokenProvider.new, endpoint: nil, region: nil) ⇒ CoreClient

Initialize a new StatelyDB CoreClient

Parameters:

  • store_id (Integer)

    the StatelyDB to use for all operations with this client.

  • schema (Module)

    the generated Schema module to use for mapping StatelyDB Items.

  • token_provider (Common::Auth::TokenProvider) (defaults to: Common::Auth::Auth0TokenProvider.new)

    the token provider to use for authentication.

  • endpoint (String) (defaults to: nil)

    the endpoint to connect to.

  • region (String) (defaults to: nil)

    the region to connect to.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/statelydb.rb', line 36

def initialize(store_id:,
               schema:,
               token_provider: Common::Auth::Auth0TokenProvider.new,
               endpoint: nil,
               region: nil)

  endpoint = self.class.make_endpoint(endpoint:, region:)
  channel = Common::Net.new_channel(endpoint:)

  auth_interceptor = Common::Auth::Interceptor.new(token_provider:)
  error_interceptor = Common::ErrorInterceptor.new

  @stub = Stately::Db::DatabaseService::Stub.new(nil, nil, channel_override: channel,
                                                           interceptors: [error_interceptor, auth_interceptor])
  @store_id = store_id.to_i
  @schema = schema
  @allow_stale = false
end

Class Method Details

.make_endpoint(endpoint: nil, region: nil) ⇒ String

Construct the API endpoint from the region and endpoint. If the endpoint is provided, it will be returned as-is. If the region is provided and the endpoint is not, then the region-specific endpoint will be returned. If neither the region nor the endpoint is provided, then the default endpoint will be returned.

Parameters:

  • endpoint (String) (defaults to: nil)

    the endpoint to connect to

  • region (Region) (defaults to: nil)

    the region to connect to

Returns:

  • (String)

    the constructed endpoint



269
270
271
272
273
274
275
276
# File 'lib/statelydb.rb', line 269

def self.make_endpoint(endpoint: nil, region: nil)
  return endpoint unless endpoint.nil?
  return "https://api.stately.cloud" if region.nil?

  region = region.sub("aws-", "") if region.start_with?("aws-")

  "https://#{region}.aws.api.stately.cloud"
end

Instance Method Details

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

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

Examples:

client.data.begin_list("/ItemType-identifier", limit: 10, sort_direction: :ascending)

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:



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/statelydb.rb', line 116

def begin_list(prefix,
               limit: 100,
               sort_property: nil,
               sort_direction: :ascending)
  sort_direction = sort_direction == :ascending ? 0 : 1

  req = Stately::Db::BeginListRequest.new(
    store_id: @store_id,
    key_path_prefix: String(prefix),
    limit:,
    sort_property:,
    sort_direction:,
    allow_stale: @allow_stale,
    schema_version_id: @schema::SCHEMA_VERSION_ID
  )
  resp = @stub.begin_list(req)
  process_list_response(resp)
end

#continue_list(token) ⇒ Array<StatelyDB::Item>, StatelyDB::Token

Continue listing Items from a StatelyDB Store using a token.

Examples:

(items, token) = client.data.begin_list("/ItemType-identifier")
client.data.continue_list(token)

Parameters:

Returns:



143
144
145
146
147
148
149
# File 'lib/statelydb.rb', line 143

def continue_list(token)
  req = Stately::Db::ContinueListRequest.new(
    token_data: token.token_data
  )
  resp = @stub.continue_list(req)
  process_list_response(resp)
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.

Examples:

client.data.delete("/ItemType-identifier", "/ItemType-identifier2")

Parameters:

  • key_paths (String, Array<String>)

    the paths to the items. Max 50 key paths.

Raises:

  • (StatelyDB::Error::InvalidParameters)

    if the parameters are invalid

  • (StatelyDB::Error::NotFound)

    if the item is not found



215
216
217
218
219
220
221
222
223
224
# File 'lib/statelydb.rb', line 215

def delete(*key_paths)
  key_paths = Array(key_paths).flatten
  req = Stately::Db::DeleteRequest.new(
    store_id: @store_id,
    schema_version_id: @schema::SCHEMA_VERSION_ID,
    deletes: key_paths.map { |key_path| Stately::Db::DeleteItem.new(key_path: String(key_path)) }
  )
  @stub.delete(req)
  nil
end

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

Fetch a single Item from a StatelyDB Store at the given key_path.

Examples:

client.get("/ItemType-identifier")

Parameters:

  • key_path (String)

    the path to the item

Returns:

Raises:

  • (StatelyDB::Error)

    if the parameters are invalid or if the item is not found



75
76
77
78
79
80
# File 'lib/statelydb.rb', line 75

def get(key_path)
  resp = get_batch(key_path)

  # Always return a single Item.
  resp.first
end

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

Fetch a batch of up to 100 Items from a StatelyDB Store at the given key_paths.

Examples:

client.data.get_batch("/ItemType-identifier", "/ItemType-identifier2")

Parameters:

  • key_paths (String, Array<String>)

    the paths to the items. Max 100 key paths.

Returns:

Raises:

  • (StatelyDB::Error)

    if the parameters are invalid or if the item is not found



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/statelydb.rb', line 90

def get_batch(*key_paths)
  key_paths = Array(key_paths).flatten
  req = Stately::Db::GetRequest.new(
    store_id: @store_id,
    schema_version_id: @schema::SCHEMA_VERSION_ID,
    gets:
      key_paths.map { |key_path| Stately::Db::GetItem.new(key_path: String(key_path)) },
    allow_stale: @allow_stale
  )

  resp = @stub.get(req)
  resp.items.map do |result|
    @schema.unmarshal_item(stately_item: result)
  end
end

#put(item) ⇒ StatelyDB::Item

Put an Item into a StatelyDB Store at the given key_path.

Examples:

client.data.put(my_item)

Parameters:

Returns:



174
175
176
177
178
179
# File 'lib/statelydb.rb', line 174

def put(item)
  resp = put_batch(item)

  # Always return a single Item.
  resp.first
end

#put_batch(*items) ⇒ Array<StatelyDB::Item>

Put a batch of up to 50 Items into a StatelyDB Store.

Examples:

client.data.put_batch(item1, item2)

Parameters:

Returns:



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/statelydb.rb', line 188

def put_batch(*items)
  items = Array(items).flatten
  req = Stately::Db::PutRequest.new(
    store_id: @store_id,
    schema_version_id: @schema::SCHEMA_VERSION_ID,
    puts: items.map do |item|
      Stately::Db::PutItem.new(
        item: item.send("marshal_stately")
      )
    end
  )
  resp = @stub.put(req)

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

#sync_list(token) ⇒ StatelyDB::SyncResult

Sync a list of Items from a StatelyDB Store.

Examples:

(items, token) = client.data.begin_list("/ItemType-identifier")
client.data.sync_list(token)

Parameters:

Returns:



159
160
161
162
163
164
165
# File 'lib/statelydb.rb', line 159

def sync_list(token)
  req = Stately::Db::SyncListRequest.new(
    token_data: token.token_data
  )
  resp = @stub.sync_list(req)
  process_sync_response(resp)
end

#transactionStatelyDB::Transaction::Transaction::Result

Transaction takes a block and executes the block within a transaction. If the block raises an exception, the transaction is rolled back. If the block completes successfully, the transaction is committed.

Examples:

client.data.transaction do |txn|
  txn.put(item: my_item)
  txn.put(item: another_item)
end

Returns:

Raises:

  • (StatelyDB::Error::InvalidParameters)

    if the parameters are invalid

  • (StatelyDB::Error::NotFound)

    if the item is not found

  • (Exception)

    if any other exception is raised



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
# File 'lib/statelydb.rb', line 240

def transaction
  txn = StatelyDB::Transaction::Transaction.new(stub: @stub, store_id: @store_id, schema: @schema)
  txn.begin
  yield txn
  txn.commit
rescue StatelyDB::Error
  raise
# Handle any other exceptions and abort the transaction. We're rescuing Exception here
# because we want to catch all exceptions, including those that don't inherit from StandardError.
rescue Exception => e
  txn.abort

  # All gRPC errors inherit from GRPC::BadStatus. We wrap these in a StatelyDB::Error.
  raise StatelyDB::Error.from(e) if e.is_a? GRPC::BadStatus

  # Calling raise with no parameters re-raises the original exception
  raise
end

#with_allow_stale(allow_stale) ⇒ self

Set whether to allow stale results for all operations with this client. This produces a new client with the allow_stale flag set.

Examples:

client.with_allow_stale(true).get("/ItemType-identifier")

Parameters:

  • allow_stale (Boolean)

    whether to allow stale results

Returns:

  • (self)

    a new client with the allow_stale flag set



61
62
63
64
65
# File 'lib/statelydb.rb', line 61

def with_allow_stale(allow_stale)
  new_client = clone
  new_client.instance_variable_set(:@allow_stale, allow_stale)
  new_client
end