put<T> method

Future<void> put<T>(
  1. String key,
  2. T value, {
  3. Duration? expiry,
  4. Duration? slidingExpiry,
  5. CachePolicy? policy,
  6. Set<String>? tags,
})

Stores a value in the cache with the given key.

The expiry parameter can be used to set an optional expiry time for the data. The slidingExpiry parameter can be used to set an optional sliding expiry time for the data. The policy parameter can be used to set a cache policy for the data. The tags parameter can be used to associate tags with the data for easier retrieval and management.

If both individual parameters (expiry, slidingExpiry) and a policy are provided, the individual parameters will take precedence over the policy.

Throws a CacheException if there is an error storing the data.

Implementation

Future<void> put<T>(
  String key,
  T value, {
  Duration? expiry,
  Duration? slidingExpiry,
  CachePolicy? policy,
  Set<String>? tags,
}) async {
  try {
    final effectivePolicy = policy ?? CachePolicy.defaultPolicy;
    final effectiveExpiry = expiry ?? effectivePolicy.expiry;
    final effectiveSlidingExpiry =
        slidingExpiry ?? effectivePolicy.slidingExpiry;

    // Initialize compression variables
    bool isCompressed = false;
    int? originalSize;
    double? compressionRatio;
    dynamic finalValue = value;

    // Check if compression should be applied
    if (effectivePolicy.compression != CompressionMode.never &&
        _compression != null &&
        value is String) {
      // For auto mode, check if compression is beneficial
      if (effectivePolicy.compression == CompressionMode.auto) {
        if (_compression.shouldCompress(value)) {
          // Compress the value
          originalSize =
              value.length * 2; // Rough estimate: 2 bytes per character
          final compressedValue = _compression.compressString(value);
          compressionRatio = originalSize / (compressedValue.length * 2);

          // Only use compression if it actually reduces the size
          if (compressionRatio > 1.1) {
            // At least 10% reduction
            finalValue = compressedValue;
            isCompressed = true;
            _log.fine(
                'Compressed value for key $key with ratio $compressionRatio');
          }
        }
      } else if (effectivePolicy.compression == CompressionMode.always) {
        // Always compress
        originalSize = value.length * 2;
        final compressedValue = _compression.compressString(value);
        compressionRatio = originalSize / (compressedValue.length * 2);
        finalValue = compressedValue;
        isCompressed = true;
        _log.fine(
            'Compressed value for key $key with ratio $compressionRatio');
      }
    }

    final cacheItem = CacheItem<T>(
      value: finalValue as T,
      expiry: effectiveExpiry != null
          ? DateTime.now().add(effectiveExpiry)
          : null,
      slidingExpiry: effectiveSlidingExpiry,
      priority: effectivePolicy.priority,
      isCompressed: isCompressed,
      originalSize: originalSize,
      compressionRatio: compressionRatio,
      tags: tags,
    );

    // Use the SizeEstimator for more accurate size estimation
    final estimatedSize = SizeEstimator.estimateCacheItemSize(
      finalValue,
      hasExpiry: effectiveExpiry != null,
      hasSlidingExpiry: effectiveSlidingExpiry != null,
      isCompressed: isCompressed,
      originalSize: originalSize,
    );

    // Check if the item exceeds the maximum size (if specified)
    if (effectivePolicy.maxSize != null) {
      if (estimatedSize > effectivePolicy.maxSize!) {
        _log.warning(
            'Item exceeds maximum size: $estimatedSize > ${effectivePolicy.maxSize}');
        throw CacheException(
            'Item exceeds maximum size: $estimatedSize > ${effectivePolicy.maxSize}');
      }
    }

    // Record the put operation in analytics
    _analytics.recordPut(key, estimatedSize);

    await _cacheAdapter.put(key, cacheItem);

    // Check if we need to evict items
    if (_eviction != null) {
      await _eviction.checkAndEvict();
    }
  } on HiveError catch (e) {
    _log.severe('Failed to put data into cache (HiveError): $e');
    throw CacheException('Failed to put data into cache: ${e.message}');
  } catch (e) {
    _log.severe('Failed to put data into cache (Unknown Error): $e');
    throw CacheException('Failed to put data into cache: $e');
  }
}