Class: BucketStore::KeyStorage

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

Defined Under Namespace

Classes: KeyStreamer

Constant Summary collapse

SUPPORTED_ADAPTERS =
{
  gs: Gcs,
  s3: S3,
  inmemory: InMemory,
  disk: Disk,
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(adapter:, bucket:, key:) ⇒ KeyStorage

Returns a new instance of KeyStorage.



104
105
106
107
108
109
110
111
# File 'lib/bucket_store/key_storage.rb', line 104

def initialize(adapter:, bucket:, key:)
  @adapter_type = adapter.to_sym
  raise "Unknown adapter: #{@adapter_type}" unless SUPPORTED_ADAPTERS.include?(@adapter_type)

  @adapter = SUPPORTED_ADAPTERS.fetch(@adapter_type).build
  @bucket = bucket
  @key = key
end

Instance Attribute Details

#adapter_typeObject (readonly)

Returns the value of attribute adapter_type.



102
103
104
# File 'lib/bucket_store/key_storage.rb', line 102

def adapter_type
  @adapter_type
end

#bucketObject (readonly)

Returns the value of attribute bucket.



102
103
104
# File 'lib/bucket_store/key_storage.rb', line 102

def bucket
  @bucket
end

#keyObject (readonly)

Returns the value of attribute key.



102
103
104
# File 'lib/bucket_store/key_storage.rb', line 102

def key
  @key
end

Instance Method Details

#delete!bool

Deletes the referenced key.

Note that this method will always return true.

Examples:

Delete a file

BucketStore.for("inmemory://bucket/file.txt").delete!

Returns:

  • (bool)


205
206
207
208
209
210
211
212
213
214
215
# File 'lib/bucket_store/key_storage.rb', line 205

def delete!
  BucketStore.logger.info(event: "key_storage.delete_started")

  start = BucketStore::Timing.monotonic_now
  adapter.delete!(bucket: bucket, key: key)

  BucketStore.logger.info(event: "key_storage.delete_finished",
                          duration: BucketStore::Timing.monotonic_now - start)

  true
end

#downloadHash<Symbol, Object>

Downloads the content of the reference key

Examples:

Download a key

BucketStore.for("inmemory://bucket/file.xml").download

Returns:

  • (Hash<Symbol, Object>)

    A hash that includes the download result. The hash keys reference different aspects of the download (e.g. ‘:key` and `:content` will include respectively the original key’s name and the actual download’s content)



126
127
128
129
130
131
132
# File 'lib/bucket_store/key_storage.rb', line 126

def download
  buffer = StringIO.new
  stream.download(file: buffer).tap do |result|
    result.delete(:file)
    result[:content] = buffer.string
  end
end

#exists?bool

Checks if the given key exists.

This will only return true when the ‘key` exactly matches an object within the bucket and conversely it will return false when `key` matches an internal path to an object. For example if the bucket has a key named `prefix/file.txt`, it will only return `true` when `exists?` is called on `prefix/file.txt`. Any other combination (`prefix/`, `prefix/file`) will instead return `false`.

Returns:

  • (bool)

    ‘true` if the given key exists, `false` if not



226
227
228
# File 'lib/bucket_store/key_storage.rb', line 226

def exists?
  list(page_size: 1).first == "#{adapter_type}://#{bucket}/#{key}"
end

#filenameObject



113
114
115
# File 'lib/bucket_store/key_storage.rb', line 113

def filename
  File.basename(key)
end

#list(page_size: 1000) ⇒ Object

Lists all keys for the current adapter that have the reference key as prefix

Internally, this method will paginate through the result set. The default page size for the underlying adapter can be controlled via the ‘page_size` argument.

This will return a enumerator of valid keys in the format of ‘adapter://bucket/key`. The keys in the list will share the reference key as a prefix. Underlying adapters will paginate the result set as the enumerable is consumed. The number of items per page can be controlled by the `page_size` argument.

Parameters:

  • page_size (Integer) (defaults to: 1000)

    the max number of items to fetch for each page of results



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/bucket_store/key_storage.rb', line 167

def list(page_size: 1000)
  BucketStore.logger.info(event: "key_storage.list_started")

  start = BucketStore::Timing.monotonic_now
  pages = adapter.list(
    bucket: bucket,
    key: key,
    page_size: page_size,
  )

  page_count = 0
  Enumerator.new do |yielder|
    pages.each do |page|
      page_count += 1
      keys = page.fetch(:keys, []).map { |key| "#{adapter_type}://#{page[:bucket]}/#{key}" }

      BucketStore.logger.info(
        event: "key_storage.list_page_fetched",
        resource_count: keys.count,
        page: page_count,
        duration: BucketStore::Timing.monotonic_now - start,
      )

      keys.each do |key|
        yielder.yield(key)
      end
    end
  end
end

#streamKeyStreamer

Returns an interface for streaming operations

Returns:

  • (KeyStreamer)

    An interface for streaming operations

Raises:

  • (ArgumentError)


149
150
151
152
153
# File 'lib/bucket_store/key_storage.rb', line 149

def stream
  raise ArgumentError, "Key cannot be empty" if key.empty?

  KeyStreamer.new(adapter: adapter, adapter_type: adapter_type, bucket: bucket, key: key)
end

#upload!(content) ⇒ String

Uploads the given file to the reference key location.

If the ‘key` already exists, its content will be replaced by the one in input.

Examples:

Upload a file

BucketStore.for("inmemory://bucket/file.xml").upload!("hello world")

Parameters:

  • content (String)

    Contents of the file

Returns:

  • (String)

    The final ‘key` where the content has been uploaded



142
143
144
# File 'lib/bucket_store/key_storage.rb', line 142

def upload!(content)
  stream.upload!(file: StringIO.new(content))
end