hope_cache 0.1.6 copy "hope_cache: ^0.1.6" to clipboard
hope_cache: ^0.1.6 copied to clipboard

Simple and fast caching for Dart/Flutter with TTL support, multiple eviction strategies, and pluggable storage.

example/main.dart

// ignore_for_file: avoid_print
import 'package:hope_cache/cache_manager.dart';
import 'package:hope_cache/cache_store.dart';
import 'package:flutter/material.dart';
import 'package:hope_cache/hope_builder.dart';
import 'package:hope_cache/hope_client.dart';
import 'package:hope_cache/hope_options.dart';
import 'package:hope_cache/mutation_builder.dart';



//basic usage
Future<void> basicUsage() async {
  final cache = await CacheManager.create(
    maxSize: 1024 * 1024,
    defaultTTL: Duration(minutes: 5),
    evictionPolicy: EvictionPolicy.lru,
  );

  // Store individual entries
  await cache.set('user_123', {'name': 'Alice', 'age': 30});
  await cache.set('user_456', {'name': 'Bob', 'age': 25});

  // Store multiple entries at once
  await cache.setMany({
    'product_1': {'name': 'Phone', 'price': 999},
    'product_2': {'name': 'Laptop', 'price': 1999},
  });

  // Read a single entry if present
  final user = await cache.getIfPresent('user_123');
  print(user);

  // Read multiple entries at once
  final products = await cache.getMany([
    'product_1',
    'product_2',
    'product_3', // ignored if not present
  ]);
  print(products);

  // Read with fallback fetcher
  final settings = await cache.get('app_settings', () async {
    return {'theme': 'dark', 'language': 'en'};
  });
  print(settings);

  // Invalidate a single entry
  await cache.invalidate('user_456');

  // Invalidate entries by prefix
  await cache.invalidatePattern('product_');

  // Clear all cached data
  await cache.clear();
}



// Implement CacheStore interface;
class MyCustomStore implements CacheStore {
  final Map<String, String> _storage = {};

  @override
  Future<void> write(String key, String value) async {
    _storage[key] = value;
  }

  @override
  Future<String?> read(String key) async => _storage[key];

  @override
  Future<void> delete(String key) async => _storage.remove(key);

  @override
  Future<void> clear() async => _storage.clear();

  @override
  Future<List<String>> getAllKeys() async => _storage.keys.toList();

  @override
  Future<int> getKeySize(String key) async => _storage[key]?.length ?? 0;

  @override
  Future<int> getTotalSize() async {
    int total = 0;
    for (final value in _storage.values) {
      total += value.length;
    }
    return total;
  }

  @override
  Future<Map<String, String>> getAllEntries() async => Map.from(_storage);
}

//eviction polices
Future<void> evictionPolicies() async {
  // LRU — evicts the least recently accessed entry
  final lruCache = await CacheManager.create(
    maxSize: 200,
    defaultTTL: Duration(hours: 1),
    evictionPolicy: EvictionPolicy.lru,
  );

  // LFU — evicts the least frequently accessed entry
  final lfuCache = await CacheManager.create(
    maxSize: 200,
    defaultTTL: Duration(hours: 1),
    evictionPolicy: EvictionPolicy.lfu,
  );

  // FIFO — evicts the oldest inserted entry
  final fifoCache = await CacheManager.create(
    maxSize: 200,
    defaultTTL: Duration(hours: 1),
    evictionPolicy: EvictionPolicy.fifo,
  );

  // Add entries until eviction is triggered
  await lruCache.set('a', 'A');
  await lruCache.set('b', 'B');
  await lruCache.set('c', 'C');

  // Access one entry to affect eviction order
  await lruCache.getIfPresent('a');

  // Adding another entry may evict a different key
  await lruCache.set('d', 'D');

  print(lruCache.getStats());
}

//map keys

Future<void> mapKey() async {
  final cache = await CacheManager.create(
    maxSize: 1024 * 1024,
    defaultTTL: Duration(minutes: 5),
    evictionPolicy: EvictionPolicy.lru,
  );

  // Store using a Map key
  await cache.set(
    {'resource': 'product', 'id': '123'},
    {'name': 'Laptop'},
  );

  // Same key, different order
  final product = await cache.getIfPresent(
    {'id': '123', 'resource': 'product'},
  );

  print(product); // {name: Laptop}
}


//query data

// ─── 1. Setup ───────────────────────────────────────────────────────────────

void queryData() async {
  WidgetsFlutterBinding.ensureInitialized();

  await HopeClient.init(
    maxSize: 1024 * 1024,
    defaultTTL: Duration(minutes: 5),
    evictionPolicy: EvictionPolicy.lru,
  );

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: UsersScreen());
  }
}

// ─── 2. Basic Query ──────────────────────────────────────────────────────────

class UsersScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HopeBuilder<List<String>>(
      queryKey: ['users'],
      fetcher: (_) async => ['Alice', 'Bob', 'Charlie'],
      builder: (context, state) {
        if (state.isLoading) return CircularProgressIndicator();
        if (state.isError) return Text(state.error.toString());
        return ListView(
          children: state.data!.map((u) => ListTile(title: Text(u))).toList(),
        );
      },
    );
  }
}

// ─── 3. Dependent Query ──────────────────────────────────────────────────────

class UserPostsScreen extends StatelessWidget {
  final String? userId;

  const UserPostsScreen({this.userId});

  @override
  Widget build(BuildContext context) {
    return HopeBuilder<List<String>>(
      queryKey: ['posts', userId],
      fetcher: (_) async => ['Post 1', 'Post 2'],
      options: HopeOptions(enabled: userId != null),
      builder: (context, state) {
        if (state.isIdle) return Text('No user selected');
        if (state.isLoading) return CircularProgressIndicator();
        if (state.isError) return Text(state.error.toString());
        return ListView(
          children: state.data!.map((p) => ListTile(title: Text(p))).toList(),
        );
      },
    );
  }
}

// ─── 4. Infinite Scroll ──────────────────────────────────────────────────────

class ProductsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HopeBuilder<List<String>>(
      queryKey: ['products'],
      fetcher: (pageParam) async {
        final cursor = pageParam ?? 0;
        return List.generate(10, (i) => 'Product ${cursor + i}');
      },
      getNextPageParam: (lastPage) =>
      lastPage.length == 10 ? lastPage.length : null,
      builder: (context, state) {
        if (state.isLoading) return CircularProgressIndicator();
        if (state.isError) return Text(state.error.toString());

        final items = state.pages!.expand((p) => p).toList();

        return ListView.builder(
          itemCount: items.length + (state.hasMore == true ? 1 : 0),
          itemBuilder: (context, index) {
            if (index == items.length) {
              state.fetchMore();
              return CircularProgressIndicator();
            }
            return ListTile(title: Text(items[index]));
          },
        );
      },
    );
  }
}

// ─── 5. Mutation ─────────────────────────────────────────────────────────────

class AddUserScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HopeMutationBuilder<String, String>(
      mutation: (name) async => 'Created: $name',
      onSuccess: (data) {
        HopeClient.instance.invalidate(['users']);
      },
      onError: (error) => debugPrint(error.toString()),
      builder: (context, state, mutate) {
        if (state.isError) return Text(state.error.toString());
        return ElevatedButton(
          onPressed: state.isMutating ? null : () => mutate('Hope'),
          child: state.isMutating
              ? CircularProgressIndicator()
              : Text('Add User'),
        );
      },
    );
  }
}

// ─── 6. Prefetch ─────────────────────────────────────────────────────────────

class HomeScreen extends StatelessWidget {
  void _onHoverUserTab() {
    HopeClient.instance.prefetch(
      queryKey: ['users'],
      fetcher: () async => ['Alice', 'Bob', 'Charlie'],
    );
  }

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: _onHoverUserTab,
      child: Text('Prefetch Users'),
    );
  }
}

// ─── 7. Optimistic Update ────────────────────────────────────────────────────

class OptimisticScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return HopeBuilder<List<String>>(
      queryKey: ['users'],
      fetcher: (_) async => ['Alice', 'Bob'],
      builder: (context, state) {
        if (state.isLoading) return CircularProgressIndicator();
        return HopeMutationBuilder<String, String>(
          mutation: (name) async => name,
          onSuccess: (_) => HopeClient.instance.invalidate(['users']),
          builder: (context, mutationState, mutate) {
            return ElevatedButton(
              onPressed: () async {
                // Update UI instantly before mutation completes
                await HopeClient.instance.prefetch(
                  queryKey: ['users'],
                  fetcher: () async => [...state.data!, 'Hope'],
                );
                await mutate('Hope');
              },
              child: Text('Add Hope Optimistically'),
            );
          },
        );
      },
    );
  }
}


//ttl configuration
Future<void> ttlConfiguration() async {
  final cache = await CacheManager.create(
    maxSize: 1024 * 1024,
    defaultTTL: Duration(minutes: 5), // Default for all keys
    evictionPolicy: EvictionPolicy.lru,
  );

  // Uses default TTL
  await cache.set('session', {'token': 'abc'});

  // Custom TTL
  await cache.set(
    'temp',
    {'value': 'expires soon'},
    ttl: Duration(seconds: 10),
  );

  await Future.delayed(Duration(seconds: 11));
  print('Temp (expired): ${await cache.getIfPresent('temp')}');
  print('Session (valid): ${await cache.getIfPresent('session')}');
}
1
likes
160
points
67
downloads

Documentation

API reference

Publisher

verified publishersupgrow.com

Weekly Downloads

Simple and fast caching for Dart/Flutter with TTL support, multiple eviction strategies, and pluggable storage.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on hope_cache