Class: Aidp::Database::Repositories::ProviderInfoCacheRepository

Inherits:
Aidp::Database::Repository show all
Defined in:
lib/aidp/database/repositories/provider_info_cache_repository.rb

Overview

Repository for provider info cache Replaces: .aidp/providers/provider_name_info.yml

Stores detailed information about AI providers gathered from CLI introspection

Constant Summary collapse

DEFAULT_TTL =

24 hours in seconds

86400

Instance Attribute Summary

Attributes inherited from Aidp::Database::Repository

#project_dir, #table_name

Instance Method Summary collapse

Constructor Details

#initialize(project_dir: Dir.pwd) ⇒ ProviderInfoCacheRepository

Returns a new instance of ProviderInfoCacheRepository.



15
16
17
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 15

def initialize(project_dir: Dir.pwd)
  super(project_dir: project_dir, table_name: "provider_info_cache")
end

Instance Method Details

#cache(provider_name, info, ttl: DEFAULT_TTL) ⇒ Boolean

Store provider info in cache

Parameters:

  • provider_name (String)

    Provider name (e.g., "claude", "cursor")

  • info (Hash)

    Provider info hash

  • ttl (Integer) (defaults to: DEFAULT_TTL)

    Time to live in seconds

Returns:

  • (Boolean)

    Success status



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 25

def cache(provider_name, info, ttl: DEFAULT_TTL)
  Aidp.log_debug("provider_info_cache_repo", "cache",
    provider: provider_name, ttl: ttl)

  expires_at = Time.now.utc + ttl

  execute(<<~SQL, [project_dir, provider_name, serialize_json(info), current_timestamp, expires_at.strftime("%Y-%m-%d %H:%M:%S")])
    INSERT INTO #{table_name} (project_dir, provider_name, info, cached_at, expires_at)
    VALUES (?, ?, ?, ?, ?)
    ON CONFLICT(project_dir, provider_name) DO UPDATE SET
      info = excluded.info,
      cached_at = excluded.cached_at,
      expires_at = excluded.expires_at
  SQL

  true
rescue => e
  Aidp.log_error("provider_info_cache_repo", "cache_failed",
    provider: provider_name, error: e.message)
  false
end

#cached_providers(include_expired: false) ⇒ Array<String>

List all cached providers

Parameters:

  • include_expired (Boolean) (defaults to: false)

    Include expired entries

Returns:

  • (Array<String>)

    Provider names



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 132

def cached_providers(include_expired: false)
  sql = if include_expired
    <<~SQL
      SELECT provider_name FROM #{table_name}
      WHERE project_dir = ?
      ORDER BY provider_name
    SQL
  else
    <<~SQL
      SELECT provider_name FROM #{table_name}
      WHERE project_dir = ?
        AND (expires_at IS NULL OR datetime(expires_at) > datetime('now'))
      ORDER BY provider_name
    SQL
  end

  query(sql, [project_dir]).map { |row| row["provider_name"] }
end

#cleanup_expiredInteger

Clean up expired entries

Returns:

  • (Integer)

    Number of entries deleted



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 183

def cleanup_expired
  result = query_value(<<~SQL, [project_dir])
    SELECT COUNT(*) FROM #{table_name}
    WHERE project_dir = ?
      AND expires_at IS NOT NULL
      AND datetime(expires_at) <= datetime('now')
  SQL

  execute(<<~SQL, [project_dir])
    DELETE FROM #{table_name}
    WHERE project_dir = ?
      AND expires_at IS NOT NULL
      AND datetime(expires_at) <= datetime('now')
  SQL

  count = result || 0
  if count > 0
    Aidp.log_info("provider_info_cache_repo", "cleanup_expired",
      deleted: count)
  end
  count
end

#get(provider_name) ⇒ Hash?

Get cached provider info if not expired

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Hash, nil)

    Cached info or nil if expired/not found



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 51

def get(provider_name)
  Aidp.log_debug("provider_info_cache_repo", "get", provider: provider_name)

  row = query_one(<<~SQL, [project_dir, provider_name])
    SELECT info, cached_at, expires_at
    FROM #{table_name}
    WHERE project_dir = ? AND provider_name = ?
  SQL

  return nil unless row

  # Check expiration
  if row["expires_at"]
    # Parse as UTC since timestamps are stored in UTC
    expires_at = Time.parse(row["expires_at"] + " UTC")
    if Time.now.utc > expires_at
      Aidp.log_debug("provider_info_cache_repo", "cache_expired",
        provider: provider_name, expires_at: expires_at)
      return nil
    end
  end

  deserialize_json(row["info"])
end

#get_stale(provider_name) ⇒ Hash?

Get cached info, ignoring expiration

Parameters:

  • provider_name (String)

    Provider name

Returns:

  • (Hash, nil)

    Cached info or nil if not found



80
81
82
83
84
85
86
87
88
89
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 80

def get_stale(provider_name)
  row = query_one(<<~SQL, [project_dir, provider_name])
    SELECT info FROM #{table_name}
    WHERE project_dir = ? AND provider_name = ?
  SQL

  return nil unless row

  deserialize_json(row["info"])
end

#invalidate(provider_name) ⇒ Object

Invalidate cache for a specific provider

Parameters:

  • provider_name (String)

    Provider name



112
113
114
115
116
117
118
119
120
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 112

def invalidate(provider_name)
  Aidp.log_debug("provider_info_cache_repo", "invalidate",
    provider: provider_name)

  execute(<<~SQL, [project_dir, provider_name])
    DELETE FROM #{table_name}
    WHERE project_dir = ? AND provider_name = ?
  SQL
end

#invalidate_allObject

Invalidate all cached providers for project



123
124
125
126
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 123

def invalidate_all
  Aidp.log_debug("provider_info_cache_repo", "invalidate_all")
  delete_by_project
end

#stale?(provider_name, max_age: DEFAULT_TTL) ⇒ Boolean

Check if cache is stale for a provider

Parameters:

  • provider_name (String)

    Provider name

  • max_age (Integer) (defaults to: DEFAULT_TTL)

    Maximum age in seconds

Returns:

  • (Boolean)

    True if stale or not found



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 96

def stale?(provider_name, max_age: DEFAULT_TTL)
  row = query_one(<<~SQL, [project_dir, provider_name])
    SELECT cached_at FROM #{table_name}
    WHERE project_dir = ? AND provider_name = ?
  SQL

  return true unless row

  # Parse as UTC since timestamps are stored in UTC
  cached_at = Time.parse(row["cached_at"] + " UTC")
  (Time.now.utc - cached_at) > max_age
end

#statsHash

Get cache statistics

Returns:

  • (Hash)

    Statistics



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/aidp/database/repositories/provider_info_cache_repository.rb', line 154

def stats
  total = query_value(<<~SQL, [project_dir])
    SELECT COUNT(*) FROM #{table_name} WHERE project_dir = ?
  SQL

  valid = query_value(<<~SQL, [project_dir])
    SELECT COUNT(*) FROM #{table_name}
    WHERE project_dir = ?
      AND (expires_at IS NULL OR datetime(expires_at) > datetime('now'))
  SQL

  expired = query_value(<<~SQL, [project_dir])
    SELECT COUNT(*) FROM #{table_name}
    WHERE project_dir = ?
      AND expires_at IS NOT NULL
      AND datetime(expires_at) <= datetime('now')
  SQL

  {
    total_cached: total || 0,
    valid_entries: valid || 0,
    expired_entries: expired || 0,
    providers: cached_providers(include_expired: true)
  }
end