Simple Dart package with build-in code generation. It simplifies and speedup creation of cache mechanism for dart classes.

Related tags

Templates dart flutter
Overview




Test status   stars   pub package   GitHub license  


Cached

Simple Dart package with build-in code generation. It simplifies and speedup creation of cache mechanism for dart classes.

Least Recently Used (LRU) cache algorithm

It is a finite key-value map using the Least Recently Used (LRU) algorithm, where the most recently-used items are "kept alive" while older, less-recently used items are evicted to make room for newer items.

Useful when you want to limit use of memory to only hold commonly-used things or cache some API calls.

Contents

Motivation

There is quite often situation, that you have to cache something in memory for later usage. Common case is cache some API calls and theirs responses. Usually, it is done in some data layer, probably in - let say - RemoteRepository

Oftentimes, the repository code might look like this:

class RemoteRepository implements Repository {
  final SomeApiDataSource _dataSource;
  final SomeResponseType? cachedResponse;

  const RemoteRepository(this._dataSource);

  @override
  Future<SomeResponseType> getSthData() async {
    if (cachedResponse != null) {
      return cachedResponse;
    }

    cachedResponse = await _dataSource.getData();
    return cachedResponse;
  }
}

So, instead of doing it manually we can use library and write our RemoteRepository in that way:

@WithCache()
abstract class RemoteRepository implements Repository, _$RemoteRepository {
  factory RemoteRepository({required SomeApiDataSource dataSource,}) = _RemoteRepository;

  @Cached()
  Future<SomeResponseType> getSthData() {
    return dataSource.getData();
  }
}

Setup

Install package

Run command:

flutter pub add --dev cached
flutter pub add cached_annotation

Or manually add the dependency in the pubspec.yaml

dependencies:
  cached_annotation:

dev_dependencies:
  cached:

That's it! Now, you can write your own cached class 🎉

Run the generator

To run the code generator, execute the following command:

dart run build_runner build

For Flutter projects, you can run:

flutter pub run build_runner build

Note that like most code-generators, [Cached] will need you to both import the annotation ([cached_annotation]) and use the part keyword on the top of your files.

As such, a file that wants to use [Cached] will start with:

import 'package:cached_annotation/cached_annotation.dart';

part 'some_file.cached.dart';

Basics

WithCache

Annotation for Cached package.

Annotating a class with @WithCache will flag it as a needing to be processed by Cached code generator.
It can take one additional boolean parameter useStaticCache. If this parameter is set to true, generator will generate cached class with static cache. It means each instance of this class will have access to the same cache. Default value is set to false

@WithCache(useStaticCache: true)
abstract class Gen implements _$Gen {
  factory Gen() = _Gen;

  ...
}

Cached

Method decorator that flag it as needing to be processed by Cached code generator.

There are 3 possible additional parameters:

  • ttl - time to live. In seconds. Set how long cache will be alive. Default value is set to null, means infinitive ttl.
  • syncWrite - Affects only async methods ( those one that returns Future ) If set to true first method call will be cached, and if following ( the same ) call will occur, all of them will get result from the first call. Default value is set to false;
  • limit - limit how many results for different method call arguments combination will be cached. Default value null, means no limit.
@Cached(
  ttl: 60,
  syncWrite: true,
  limit: 100,
)
Future<int> getInt(String param) {
  return Future.value(1);
}

IgnoreCache

That annotation must be above a field in a method and must be bool, if true the cache will be ignored

Example use:

@cached
Future<int> getInt(String param, {@ignoreCache bool ignoreCache = false}) {
  return Future.value(1);
}

or you can use with useCacheOnError in the annotation and if set true then return the last cached value when an error occurs.

@cached
Future<int> getInt(String param, {@IgnoreCache(useCacheOnError: true) bool ignoreCache = false}) {
  return Future.value(1);
}

Possible reason why the generator gives an error

  • if method has multiple @ignoreCache annotation

Ignore

That annotation must be above a field in a method, arguments with @ignore annotations will be ignored while generating cache key.

Example use:

@cached
Future<int> getInt(@ignore String param) {
  return Future.value(1);
}

CacheKey

That annotation must be above a field in a method and must contain constant function that will return cache key for provided field value

Example use:

@cached
Future<int> getInt(@CacheKey(cacheKeyGenerator: exampleCacheFunction) int test) async {
  await Future.delayed(Duration(milliseconds: 20));
  return test;
}

String exampleCacheFunction(dynamic value) {
  return value.toString();
}

You can also use @iterableCacheKey, which will generate cache key from Iterable values

Example use:

@cached
Future<List<int>> getInt(@iterableCacheKey List<int> test) async {
  await Future.delayed(Duration(milliseconds: 20));
  return test;
}

ClearCached

Method decorator that flag it as needing to be processed by Cached code generator. Method annotated with this annotation can be used to clear result of method annotated with Cached annotation.
Constructor of this annotation can take one possible argument. It is method name, that we want to clear the cache.

Let say there is existing cached method:

@Cached()
Future<SomeResponseType> getUserData() {
  return userDataSource.getData();
}

to generate clearing cache method we can write:

@clearCached
void clearGetUserData();

or

@ClearCached('getUserData')
void clearUserData();

The ClearCached argument or method name has to correspond to cached method name. We can also create a method that returns a bool, and then write our own logic to check if the cache should be cleared or not.

@ClearCached('getUserData')
Future<bool> clearUserData() {
  return userDataSource.isLoggedOut();
};

If the user is logged out, the user cache will be cleared.

Possible reasons why the generator gives an error

  • if method with @cached annotation doesn’t exist
  • if method to pair doesn’t exist
  • if method don’t return bool, Future or not a void

ClearAllCached

This is exactly the same as ClearCached, except you don't pass any arguments and you don't add a clear statement before the method name, all you have to do is add @clearAllCached above the method, this annotation will clear cached values for all methods in the class with the @WithCache.

Here is a simple example:

@clearAllCached
void clearAllData();

or we can also create a method that returns a bool, and then write our own logic to check if cached values for all methods will be cleared

@clearAllCached
Future<bool> clearAllData() {
  return userDataSource.isLoggedOut();
}

If the user is logged out, will clear cached values for all methods

Possible reasons why the generator gives an error

  • if we have too many clearAllCached annotation, only one can be
  • if method don’t return bool, Future or not a void

StreamedCache

Use @StreamedCache annotation to get a stream of cache updates from a cached method. Remember to provide at least the name of the cached class method in the methodName parameter.

Simple example of usage:

cachedStream();">
@cached
int cachedMethod() {
  return 1;
}

@StreamedCache(methodName: "cachedMethod", emitLastValue: true)
Stream<int> cachedStream();

Method annotated with @StreamedCache should have same parameters (except @ignore or @ignoreCache) as method provided in methodName parameter, otherwise InvalidGenerationSourceError will be thrown. Return type of this method should be a Stream - for example for Future the return type will be Stream

Example:

cachedStream(int x);">
@cached
Future<String> cachedMethod(int x, @ignore String y) async {
  await Future.delayed(Duration(miliseconds: 100));
  return x.toString();
}

@StreamedCache(methodName: "cachedMethod", emitLastValue: false)
Stream<String> cachedStream(int x);

CachePeek

Method decorator that flag it as needing to be processed by Cached code generator. Method annotated with this annotation can be used to peek result of method annotated with Cached annotation.

Constructor of this annotation can take one possible argument. It is method name, that we want to peek the cache.

Let say there is existing cached method:

@Cached()
Future<SomeResponseType> getUserData() {
  return userDataSource.getData();
}

to generate peek cache method we can write:

@CachePeek(methodName: "getUserData")
SomeResponseType? peekUserDataCache();

The CachePeek methodName argument has to correspond to cached method name

Possible reasons why the generator gives an error

  • if more then one method is targeting [Cached] method cache
  • if method return type is incorrect
  • if method has different parameters then target function (excluding [Ignore], [IgnoreCache])
  • if method is not abstract

Contribution

We accept any contribution to the project!

Suggestions of a new feature or fix should be created via pull-request or issue.

feature request:

  • Check if feature is already addressed or declined

  • Describe why this is needed

    Just create an issue with label enhancement and descriptive title. Then, provide a description and/or example code. This will help the community to understand the need for it.

  • Write tests for your feature

    The test is the best way to explain how the proposed feature should work. We demand a complete test before any code is merged in order to ensure cohesion with existing codebase.

  • Add it to the README and write documentation for it

    Add a new feature to the existing featrues table and append sample code with usage.

Fix

  • Check if bug was already found

  • Describe what is broken

    The minimum requirement to report a bug fix is a reproduction path. Write steps that should be followed to find a problem in code. Perfect situation is when you give full description why some code doesn’t work and a solution code.

Contributors

Comments
  • Add a way to prevent caching specific results

    Add a way to prevent caching specific results

    It would be useful to have a way inside a cached function to signal that a certain result must not be cached. In particular we are caching results from a server, which can in some situations return data that is explicitly not allowed to be cached. But this can only be known after the data was loaded, not before issuing the call. Thus ignoreCache can not be used to solve the issue here.

    Any thoughts on a nice way to support this? In our case we could for example pass a list of types that must not be cached.

    enhancement good first issue 
    opened by julianscheel 3
  • Use other cache libraries, e.g. `shared_preferences`, `hive`

    Use other cache libraries, e.g. `shared_preferences`, `hive`

    Thank you so much for providing such great package! I'm using it a lot.

    However, in some cases I need to store cache in more persistent place than memory, e.g. shared_preferences or hive. Also, I think on the second/third/etc application boot using saved cache in shared_preferences is better than making call the API during the initialization.

    It seems not possible for now using your package. So, do you have any plans or workarounds to support using not only in-memory cache?

    enhancement 
    opened by akamoroz 2
  • Cache peek

    Cache peek

    It would be nice to have a way to peek at a value in the cache. One possible API design is:

    @Cached()
    Future<Result> getResult(params...) { ... }
    
    @CachePeek(methodName: 'getResult')
    Result? getResultCached(params...);
    

    This method returns either the cached result or null if no result is cached.

    enhancement 
    opened by ryanheise 2
  • Add `@CacheKey()` annotation

    Add `@CacheKey()` annotation

    Add CacheKey annotation which will allow developers to pass function which will generate cache key (by default hashCode is used as a cache key).

    • [x] Create @CacheKey annotation that will take one param with type String Function(dynamic)
    • [x] Validate if @CacheKey is not used with @Ignore or @ignoreCache annotations
    • [x] Create generation logic that will replace hashKey with result of function passed in @CachedKey annotation
    • [x] Write generation tests
    • [x] Write integration tests
    • [x] Write dart doc for @cacheKey
    • [x] Add section in README.md for @cacheKey

    Example usage:

    String getListCacheKeys(Iterable<Object> l) {
      return l.map((e) => e.hashCode).join('')
    }
    
    @withCache
    class Example {
      String doSomething(@CacheKey(getListCacheKeys) List<SomeObject> l) {
        return 'something';
      }
    }
    

    To discus: Maybe we should create also something like @iterableCacheKey which will handle case described in "example usage" as its quite generic.

    enhancement help wanted good first issue 
    opened by Axot017 2
  • modified logo size, removed named arguments from cache_key, cache_pee…

    modified logo size, removed named arguments from cache_key, cache_pee…

    …k, added cached getters

    CacheKey and CachePeek annotations do not have named arguments now: removed_named_arguments

    Changed logo size in readme: changed_logo_size

    Getters can be cached now: added_cached_getters generated_code

    opened by mateuszfilipek2000 1
  • added DeletesCache annotation

    added DeletesCache annotation

    Added @DeletesCache annotation which gives user the ability to specify methods that affect cached methods, and delete the cached data of affected methods.

    If you have class with cache: No ttl cache class

    then cached will generate: generated

    Generated method will delete cached data if the call to super method will return result.

    Generated method will also clear streamed cache, and ttl of cached data if it is available ttl no ttl streamed

    generated ttl no ttl streamed clear

    opened by mateuszfilipek2000 1
  • build(deps): bump dart-lang/setup-dart from 1.0 to 1.3

    build(deps): bump dart-lang/setup-dart from 1.0 to 1.3

    Bumps dart-lang/setup-dart from 1.0 to 1.3.

    Release notes

    Sourced from dart-lang/setup-dart's releases.

    v1.3

    • The install location of the Dart SDK is now available in an environment variable, DART_HOME (#43)

    • Fixed a issue where cached downloads could lead to unzip issues on self hosted runners (#35)

    v1.2

    • Fixes an issue with git dependencies on Windows

    v1.1 release

    • Support build flavors (release, raw, main)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies github_actions 
    opened by dependabot[bot] 0
  • Feature/Persistent storage

    Feature/Persistent storage

    Added optional possibility of persistent storage usage. With that functionality, you'll be able to receive your previously cached data even if an app has been closed.

    opened by lpusz 0
  • doc: Update readme

    doc: Update readme

    • Fix tab in example
    • Fix mismatch between sync and async call in where: example
    • Update table of contents
    • Fix not working @Cached link (duplicated with title)
    opened by kozlowskigrzegorz 0
  • Feature/melos bootstrap

    Feature/melos bootstrap

    Melos Bootstrap is optional, but simplifies local development a lot: we don't have to switch between local dependency (from path) and remember to change them before pub.dev publish.

    Melos Bootstrap -> creates pubspec_overrides.yaml -> dart pub get resolves dependencies using local path

    When push to pub.dev: no changes to paths necessary

    opened by grzegorz-kozlowski 0
Memory Cache is simple, fast and global in-memory cache with CRUD features.

Memory Cache Memory Cache is simple, fast and global in-memory cache. Features Create, read, update, delete and invalidate cache. Expirable Cache Gett

Gökberk Bardakçı 6 Dec 25, 2022
A most easily usable cache management library in Dart. With CacheStorage, you can easily manage cache on your application.

A most easily usable cache management library in Dart! 1. About 1.1. Introduction 1.1.1. Install Library 1.1.2. Import It 1.1.3. Use CacheStorage 1.2.

Kato Shinya 1 Dec 13, 2021
⚡ Cache Manager A tidy utility to handle cache of your flutter app like a Boss.

⚡ Cache Manager A tidy utility to handle cache of your flutter app like a Boss. It provides support for both iOS and Android platforms (offcourse). ??

Abhishek Chavhan 10 Oct 25, 2022
Jannis 0 Jan 29, 2022
Emanuel Braz 27 Dec 22, 2022
This is an opinionated code-generation tool from GraphQL to Dart/Flutter.

GraphQL Codegen This is an opinionated code-generation tool from GraphQL to Dart/Flutter. It'll allow you to generate Dart serializers and client help

United Traders 1 Dec 29, 2021
Automatic source code generation for Dart

Overview source_gen provides utilities for automated source code generation for Dart: A framework for writing Builders that consume and produce Dart c

Dart 418 Dec 30, 2022
Icons Launcher - A command-line tool that simplifies the task of updating your Flutter app's launcher icon.

Icons Launcher - A command-line tool that simplifies the task of updating your Flutter app's launcher icon. Full flexibility allows you to only update the launcher icon for specific platforms as needed.

Mrr Hak 48 Nov 17, 2022
Dart package for Async Data Loading and Caching. Combine local (DB, cache) and network data simply and safely.

Stock is a dart package for loading data from both remote and local sources. It is inspired by the Store Kotlin library.

xmartlabs 59 Dec 24, 2022
Pdf creation module for dart/flutter

Pdf for Dart and Flutter This set of plugins allows Flutter apps to generate and print pdf files to the device printer. This plugin works for iOS and

David PHAM-VAN 954 Jan 3, 2023
A flutter plugin about qr code or bar code scan , it can scan from file、url、memory and camera qr code or bar code .Welcome to feedback your issue.

r_scan A flutter plugin about qr code or bar code scan , it can scan from file、url、memory and camera qr code or bar code .Welcome to feedback your iss

PengHui Li 112 Nov 11, 2022
Code generator for Flutter's theme extension classes.

Welcome to Theme Tailor, a code generator and theming utility for supercharging Flutter ThemeExtension classes introduced in Flutter 3.0! The generato

iteo 35 Jan 2, 2023
A flutter package to cache network image fastly without native dependencies.

Fast Cached Network Image A flutter package to cache network image fastly without native dependencies, with loader, error builder, and smooth fade tra

CHRISTO 3 Sep 22, 2022
A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs when current is overscroll, and set scroll direction and cache extent.

extended_tabs Language: English | 中文简体 A powerful official extension library of Tab/TabBar/TabView, which support to scroll ancestor or child Tabs whe

FlutterCandies 185 Dec 13, 2022
Flutter shareable package of object-oriented classes for local caching of user data in json

json_cache Json Cache is an object-oriented package to serve as a layer on top of local storage packages - packages that persist data locally on the u

Dartoos 10 Dec 19, 2022
A font loader to download, cache and load web fonts in flutter with support for Firebase Cloud Storage.

Dynamic Cached Fonts A simple, easy to use yet customizable font loader to use web fonts. Demo: https://sidrao2006.github.io/dynamic_cached_fonts ?? I

Aneesh Rao 18 Dec 21, 2022
🧾 Flutter widget allowing easy cache-based data display in a ListView featuring pull-to-refresh and error banners.

Often, apps just display data fetched from some server. This package introduces the concept of fetchable streams. They are just like normal Streams, b

Marcel Garus 17 Jan 18, 2022
Nimbostratus is a reactive data-fetching and client-side cache management library built on top of Cloud Firestore.

Nimbostratus ?? Nimbostratus is a reactive data-fetching and client-side cache management library built on top of Cloud Firestore. The Cloud Firestore

Dan Reynolds 13 Dec 15, 2022
A Flutter plugin for fetching Firestore documents with read from cache first then server.

Firestore Cache A Flutter plugin for fetching Firestore documents with read from cache first then server. This plugin is mainly designed for applicati

null 22 Nov 24, 2022