diff --git a/README.md b/README.md index 5dbd196b..42dfab4f 100644 --- a/README.md +++ b/README.md @@ -155,23 +155,55 @@ Fully compatible with the tools we know and love: - All methods are now directly on `Adapter`, there is no `Repository`, `RemoteAdapter` or `LocalAdapter`. Any method you are looking for is probably on `Adapter`, for example, `findAll` from `LocalAdapter` is now called `findAllLocal` - For initialization we no longer call the `configure...` method on the Riverpod overrides, we just do `localStorageProvider.overrideWithValue` and pass a `LocalStorage` instance; the actual initialization is done via `initializeFlutterData` which needs an adapter map. An `adapterProvidersMap` is conveniently code-generated and available on `main.data.dart` -## 📚 API +## 📚 Public API + +### Initialization + +First you need to supply a local storage provider, via Riverpod configuration. A popular option for the base directory is using the `path_provider` package. + +```dart +ProviderScope( + overrides: [ + localStorageProvider.overrideWithValue( + LocalStorage( + baseDirFn: () async { + return (await getApplicationSupportDirectory()).path; + }, + busyTimeout: 5000, + clear: LocalStorageClearStrategy.never, + ), + ) + ], + // ... +), +``` + +And initialize like so: + +```dart +return Scaffold( + body: ref.watch(initializeFlutterData(adapterProvidersMap)).when( + data: (_) => child, + error: (e, _) => const Text('Error'), + loading: () => const Center(child: CircularProgressIndicator()), + ), +``` ### Adapters WIP. Method names should be self explanatory. All of these methods have a reasonable default implementation. -#### Public API +#### Local storage -```dart -// local storage +All models are identified by `key`s, that might be associated to an `id` (either self-assigned or fetched from a remote source). +Keys have the format `model#5`. + +```dart List findAllLocal(); List findManyLocal(Iterable keys); -List deserializeFromResult(ResultSet result); - T? findOneLocal(String? key); T? findOneLocalById(Object id); @@ -194,9 +226,11 @@ Future clearLocal({bool notify = true}); int get countLocal; Set get keys; +``` -// remote +##### Remote & watchers +```dart Future> findAll({ bool remote = true, bool background = false, @@ -241,23 +275,6 @@ Future delete( Set> get offlineOperations; -// serialization - -Map serializeLocal(T model, {bool withRelationships = true}); - -T deserializeLocal(Map map, {String? key}); - -Future> serialize(T model, - {bool withRelationships = true}); - -Future> deserialize(Object? data, - {String? key, bool async = true}); - -Future> deserializeAndSave(Object? data, - {String? key, bool notify = true, bool ignoreReturn = false}); - -// watchers - DataState> watchAll({ bool remote = false, Map? params, @@ -296,91 +313,17 @@ DataStateNotifier watchOneNotifier(Object model, final coreNotifierThrottleDurationProvider; ``` -#### Protected API +##### Serialization ```dart -// adapter - -Future onInitialized(); - -Future> initialize({required Ref ref}); - -void dispose(); - -Future runInIsolate(FutureOr fn(Adapter adapter)); - -void log(DataRequestLabel label, String message, {int logLevel = 1}); - -void onModelInitialized(T model) {}; - -// remote - -String get baseUrl; - -FutureOr> get defaultParams; - -FutureOr> get defaultHeaders; - -String urlForFindAll(Map params); - -DataRequestMethod methodForFindAll(Map params); - -String urlForFindOne(id, Map params); - -DataRequestMethod methodForFindOne(id, Map params); - -String urlForSave(id, Map params); - -DataRequestMethod methodForSave(id, Map params); - -String urlForDelete(id, Map params); - -DataRequestMethod methodForDelete(id, Map params); - -bool shouldLoadRemoteAll( - bool remote, - Map params, - Map headers, - ); - -bool shouldLoadRemoteOne( - Object? id, - bool remote, - Map params, - Map headers, - ); - -bool isOfflineError(Object? error); - -http.Client get httpClient; - -Future sendRequest( - final Uri uri, { - DataRequestMethod method = DataRequestMethod.GET, - Map? headers, - Object? body, - _OnSuccessGeneric? onSuccess, - _OnErrorGeneric? onError, - bool omitDefaultParams = false, - bool returnBytes = false, - DataRequestLabel? label, - bool closeClientAfterRequest = true, - }); - -FutureOr onSuccess( - DataResponse response, DataRequestLabel label); - -FutureOr onError( - DataException e, - DataRequestLabel? label, - ); - -// serialization - -Map transformSerialize(Map map, +Future> serialize(T model, {bool withRelationships = true}); -Map transformDeserialize(Map map); +Future> deserialize(Object? data, + {String? key, bool async = true}); + +Future> deserializeAndSave(Object? data, + {String? key, bool notify = true, bool ignoreReturn = false}); ``` ## ➕ Questions and collaborating diff --git a/lib/src/adapter/adapter.dart b/lib/src/adapter/adapter.dart index 8d93c321..5e081ab9 100644 --- a/lib/src/adapter/adapter.dart +++ b/lib/src/adapter/adapter.dart @@ -168,6 +168,11 @@ abstract class _BaseAdapter> with _Lifecycle { return result.first['e'] == 1; } + /// Whether [id] exists in local storage. + bool existsId(Object id) { + return exists(core.getKeyForId(internalType, id)); + } + /// Saves model of type [T] in local storage. /// /// By default notifies this modification to the associated [CoreNotifier]. diff --git a/lib/src/model/relationship/belongs_to.dart b/lib/src/model/relationship/belongs_to.dart index f80b4b66..ec745452 100644 --- a/lib/src/model/relationship/belongs_to.dart +++ b/lib/src/model/relationship/belongs_to.dart @@ -62,6 +62,14 @@ class BelongsTo> extends Relationship { /// Returns the [value]'s `key`. String? get key => super._keys.safeFirst; + Object? get id => key != null ? _adapter.core.getIdForKey(key!) : null; + + Future load() async { + if (value == null && id != null) { + await _adapter.findOne(id!); + } + } + /// Returns a [StateNotifier] which emits the latest [value] of /// this [BelongsTo] relationship. @override diff --git a/lib/src/model/relationship/relationship.dart b/lib/src/model/relationship/relationship.dart index ca806509..a7358a83 100644 --- a/lib/src/model/relationship/relationship.dart +++ b/lib/src/model/relationship/relationship.dart @@ -2,7 +2,8 @@ part of flutter_data; /// A `Set` that models a relationship between one or more [DataModelMixin] objects /// and their a [DataModelMixin] owner. Backed by a [CoreNotifier]. -sealed class Relationship, N> with EquatableMixin { +abstract class Relationship, N> + with EquatableMixin { @protected Relationship(Set? models) : this._(models?.map((m) => m._key!).toSet());