Class: TypedCache::CacheRef

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

Overview

A monadic wrapper for cached values that provides safe access with rich error context. All operations return Either[Error, Snapshot] to provide detailed information about cache operations and the source of values.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(store, key) ⇒ CacheRef

: (Store, CacheKey) -> void



18
19
20
21
# File 'lib/typed_cache/cache_ref.rb', line 18

def initialize(store, key)
  @store = store
  @key = key
end

Instance Attribute Details

#keyObject (readonly)

: CacheKey



15
16
17
# File 'lib/typed_cache/cache_ref.rb', line 15

def key
  @key
end

#storeObject (readonly)

: Store



14
15
16
# File 'lib/typed_cache/cache_ref.rb', line 14

def store
  @store
end

Instance Method Details

#compute_if_absent(&block) ⇒ Object

Computes and caches a value if the cache is currently empty Returns existing snapshot if present, computed snapshot if cache miss, error otherwise : () { -> V? } -> either[Error, Snapshot[maybe]]



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/typed_cache/cache_ref.rb', line 96

def compute_if_absent(&block)
  fetch(&block).fold(
    ->(error) {
      Either.left(StoreError.new(
        :compute_if_absent,
        key,
        "Failed to compute value: #{error.message}",
        error,
      ))
    },
    ->(snapshot) { Either.right(snapshot) },
  )
end

#deleteObject

Deletes the value from the cache and returns the deleted value as a snapshot : -> either[Error, maybe]



37
38
39
# File 'lib/typed_cache/cache_ref.rb', line 37

def delete
  store.delete(key)
end

#empty?Boolean

Checks if the cache is empty for this key : -> bool

Returns:

  • (Boolean)


56
57
58
# File 'lib/typed_cache/cache_ref.rb', line 56

def empty?
  store.read(key).left?
end

#fetch(&block) ⇒ Object

Fetches a value from cache, computing and storing it if not found The snapshot indicates whether the value came from cache or was computed : () { -> V? } -> either[Error, Snapshot[maybe]]



44
45
46
# File 'lib/typed_cache/cache_ref.rb', line 44

def fetch(&block)
  store.fetch(key, &block)
end

#inspectObject



126
# File 'lib/typed_cache/cache_ref.rb', line 126

def inspect = "CacheRef(#{key}, #{store.inspect})"

#map(&block) ⇒ Object

Maps over the cached value if it exists, preserving snapshot metadata : [R] () { (V) -> R } -> either[Error, Snapshot]



62
63
64
# File 'lib/typed_cache/cache_ref.rb', line 62

def map(&block)
  read.map { |snapshot| snapshot.map { |mb| mb.map(&block) } }
end

#present?Boolean

Checks if the cache contains a value for this key : -> bool

Returns:

  • (Boolean)


50
51
52
# File 'lib/typed_cache/cache_ref.rb', line 50

def present?
  store.read(key).right?
end

#readObject

Gets a value from the cache as a snapshot : -> either[Error, Snapshot[maybe]]



25
26
27
# File 'lib/typed_cache/cache_ref.rb', line 25

def read
  store.read(key)
end

#to_sObject



123
# File 'lib/typed_cache/cache_ref.rb', line 123

def to_s = "CacheRef(#{key} from #{store.namespace})"

#update(&block) ⇒ Object

Updates the cached value using the provided block Returns the updated value as a snapshot with source=:updated : () { (V) -> V? } -> either[Error, Snapshot[maybe]]



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/typed_cache/cache_ref.rb', line 69

def update(&block)
  read.bind do |snapshot|
    new_value = snapshot.value.bind do |value|
      new_value = yield(value)
      Maybe.wrap(new_value)
    end

    if new_value.some?
      write(new_value.value).map do |snapshot|
        snapshot.map { new_value }
      end
    else
      delete.map { snapshot }
    end
  rescue => e
    Either.left(StoreError.new(
      :update,
      key,
      "Failed to update value: #{e.message}",
      e,
    ))
  end
end

#with(&block) ⇒ Object

Convenience method to work with just the value (losing snapshot context) : [R] () { (V) -> R } -> either[Error, R]



118
119
120
# File 'lib/typed_cache/cache_ref.rb', line 118

def with(&block)
  read.map { |snapshot| yield(snapshot.value) }
end

#with_snapshot(&block) ⇒ Object

Convenience method to work with the snapshot directly : [R] () { (Snapshot) -> R } -> either[Error, R]



112
113
114
# File 'lib/typed_cache/cache_ref.rb', line 112

def with_snapshot(&block)
  read.map(&block)
end

#write(value) ⇒ Object

Sets a value in the cache and returns it as an updated snapshot : (V) -> either[Error, Snapshot]



31
32
33
# File 'lib/typed_cache/cache_ref.rb', line 31

def write(value)
  store.write(key, value)
end