Class: PatientHttp::ExternalStorage

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

Overview

Handles external storage of large payloads.

This class provides methods for storing, fetching, and deleting payloads from external storage. It is decoupled from the models being stored (Request, Response, Error).

Examples:

Storing a large payload

external_storage = ExternalStorage.new(config)
data = response.as_json
stored_data = external_storage.store(data)

Fetching and deleting

if ExternalStorage.storage_ref?(data)
  external_storage = ExternalStorage.new(config)
  original_data = external_storage.fetch(data)
  response = Response.load(original_data)
  external_storage.delete(data)
end

Defined Under Namespace

Classes: PayloadNotFoundError, PayloadStoreNotFoundError

Constant Summary collapse

REFERENCE_KEY =

Key used in serialized JSON to indicate an external storage reference

"$ref"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ ExternalStorage

Create a new ExternalStorage instance.

Parameters:



45
46
47
# File 'lib/patient_http/external_storage.rb', line 45

def initialize(config)
  @config = config
end

Instance Attribute Details

#configConfiguration (readonly)

Returns the pool configuration.

Returns:



40
41
42
# File 'lib/patient_http/external_storage.rb', line 40

def config
  @config
end

Class Method Details

.storage_ref?(data) ⇒ Boolean

Check if a hash is a storage reference.

Parameters:

  • data (Hash, Object)

    Data to check

Returns:

  • (Boolean)

    true if this is a reference to external storage



34
35
36
# File 'lib/patient_http/external_storage.rb', line 34

def storage_ref?(data)
  data.is_a?(Hash) && data.key?(REFERENCE_KEY)
end

Instance Method Details

#delete(data) ⇒ void

This method returns an undefined value.

Delete payload from external storage.

This method is idempotent - it’s safe to call on non-reference hashes, already-deleted payloads, or nil values.

Parameters:

  • data (Hash, nil)

    Reference hash (or regular hash, which is ignored)



123
124
125
126
127
128
129
130
131
132
# File 'lib/patient_http/external_storage.rb', line 123

def delete(data)
  return unless data && self.class.storage_ref?(data)

  ref = data[REFERENCE_KEY]
  store_name = ref["store"].to_sym
  key = ref["key"]

  store = config.payload_store(store_name)
  store&.delete(key)
end

#enabled?Boolean

Check if external storage is enabled (i.e. a payload store is configured).

Returns:

  • (Boolean)

    true if external storage is configured



60
61
62
# File 'lib/patient_http/external_storage.rb', line 60

def enabled?
  !!config.payload_store
end

#fetch(data) ⇒ Hash

Fetch a hash from external storage.

Parameters:

  • data (Hash)

    Reference hash containing storage location

Returns:

  • (Hash)

    Original hash from storage

Raises:



100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/patient_http/external_storage.rb', line 100

def fetch(data)
  raise ArgumentError.new("Not a storage reference") unless self.class.storage_ref?(data)

  ref = data[REFERENCE_KEY]
  store_name = ref["store"].to_sym
  key = ref["key"]

  store = config.payload_store(store_name)
  raise PayloadStoreNotFoundError.new("Payload store '#{store_name}' not registered") unless store

  stored_data = store.fetch(key)
  raise PayloadNotFoundError.new("Stored payload not found: #{store_name}/#{key}") unless stored_data

  stored_data
end

#storage_ref?(data) ⇒ Boolean

Check if a hash is a storage reference.

Parameters:

  • data (Hash, Object)

    Data to check

Returns:

  • (Boolean)

    true if this is a reference to external storage



53
54
55
# File 'lib/patient_http/external_storage.rb', line 53

def storage_ref?(data)
  self.class.storage_ref?(data)
end

#store(data, max_size: nil) ⇒ Hash

Store a hash externally if it exceeds the configured threshold.

If no payload store is configured, or if the hash is below the threshold, the original hash is returned unchanged.

Parameters:

  • data (Hash)

    Hash to potentially store

  • max_size (Integer, nil) (defaults to: nil)

    Optional payload size threshold in bytes. The JSON payload will only be stored externally if it exceeds this size. If the JSON payload does not exceed the threshold, the original hash is returned. When nil (the default), the payload is always stored externally.

Returns:

  • (Hash)

    Reference hash if stored, original hash if not

Raises:



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/patient_http/external_storage.rb', line 76

def store(data, max_size: nil)
  store = config.payload_store
  raise PayloadStoreNotFoundError.new("No payload store configured") unless store

  json = JSON.generate(data)
  return data if max_size && json.bytesize <= max_size

  key = store.generate_key
  store.store_json(key, json)

  {
    REFERENCE_KEY => {
      "store" => config.default_payload_store_name.to_s,
      "key" => key
    }
  }
end