Line data Source code
1 : part of flutter_data; 2 : 3 : class DataHelpers { 4 3 : static final uuid = Uuid(); 5 : 6 1 : static String getType<T>([String type]) { 7 1 : if (T == dynamic && type == null) { 8 : return null; 9 : } 10 3 : return (type ?? T.toString()).toLowerCase().pluralize(); 11 : } 12 : 13 1 : static String generateKey<T>([String type]) { 14 1 : type = getType<T>(type); 15 : if (type != null) { 16 4 : return '$type#${uuid.v1().substring(0, 8)}'; 17 : } 18 : return null; 19 : } 20 : } 21 : 22 : // initialization helpers 23 : 24 : typedef InternalLocator<T extends DataModel<T>> = Repository<T> Function( 25 : Provider<Repository<T>>, dynamic); 26 : 27 : /// ONLY FOR FLUTTER DATA INTERNAL USE 28 2 : InternalLocator internalLocatorFn = 29 2 : (provider, owner) => provider.readOwner(owner as ProviderStateOwner); 30 : 31 : class RepositoryInitializer {} 32 : 33 : extension RepositoryInitializerX on RepositoryInitializer { 34 1 : bool get isLoading => this == null; 35 : } 36 : 37 : class RepositoryInitializerArgs { 38 1 : RepositoryInitializerArgs(this.remote, this.verbose); 39 : 40 : final bool remote; 41 : final bool verbose; 42 : 43 1 : @override 44 : bool operator ==(dynamic other) { 45 : return identical(this, other) || 46 1 : (other is RepositoryInitializerArgs && 47 3 : other.remote == remote && 48 3 : other.verbose == verbose); 49 : } 50 : 51 0 : @override 52 0 : int get hashCode => runtimeType.hashCode ^ remote.hashCode ^ verbose.hashCode; 53 : } 54 : 55 : @protected 56 : mixin NothingMixin {} 57 : 58 : typedef FutureFn<R> = FutureOr<R> Function(); 59 : 60 : typedef OnData<R> = FutureOr<R> Function(dynamic); 61 : 62 : // private utilities 63 : 64 : abstract class _Lifecycle<T> { 65 : bool _isInit = false; 66 : 67 : @mustCallSuper 68 : // ignore: missing_return 69 5 : FutureOr<T> initialize() async { 70 5 : _isInit = true; 71 : } 72 : 73 3 : @protected 74 : @visibleForTesting 75 3 : bool get isInitialized => _isInit; 76 : 77 : @mustCallSuper 78 4 : Future<void> dispose() async {} 79 : } 80 : 81 : // misc extensions 82 : 83 : extension IterableX<T> on Iterable<T> { 84 1 : @protected 85 : @visibleForTesting 86 2 : T get safeFirst => (this != null && isNotEmpty) ? first : null; 87 1 : @protected 88 : @visibleForTesting 89 2 : bool containsFirst(T model) => safeFirst == model; 90 1 : @protected 91 : @visibleForTesting 92 : Iterable<T> get filterNulls => 93 2 : this == null ? null : where((elem) => elem != null); 94 1 : @protected 95 : @visibleForTesting 96 1 : List<T> toImmutableList() => this == null ? null : List.unmodifiable(this); 97 : } 98 : 99 : extension StringUtilsX on String { 100 1 : String capitalize() => 101 5 : isEmpty ? '' : '${this[0].toUpperCase()}${substring(1)}'; 102 2 : String pluralize() => inflection.pluralize(this); 103 2 : String singularize() => inflection.singularize(this); 104 2 : Uri get asUri => Uri.parse(this); 105 : } 106 : 107 : extension MapUtilsX<K, V> on Map<K, V> { 108 1 : @protected 109 : @visibleForTesting 110 3 : Map<K, V> operator &(Map<K, V> more) => {...this, ...?more}; 111 : 112 1 : @protected 113 : @visibleForTesting 114 : Map<K, V> get filterNulls => 115 6 : {for (final e in entries) if (e.value != null) e.key: e.value}; 116 : } 117 : 118 : extension UriUtilsX on Uri { 119 1 : Uri operator /(String path) { 120 : if (path == null) return this; 121 4 : return replace(path: path_helper.canonicalize('/${this.path}/$path')); 122 : } 123 : 124 1 : Uri operator &(Map<String, dynamic> params) => params != null && 125 1 : params.isNotEmpty 126 1 : ? replace( 127 3 : queryParameters: queryParameters & _flattenQueryParameters(params)) 128 : : this; 129 : } 130 : 131 1 : Map<String, String> _flattenQueryParameters(Map<String, dynamic> params) { 132 : params ??= const {}; 133 : 134 4 : return params.entries.fold<Map<String, String>>({}, (acc, e) { 135 2 : if (e.value is Map<String, dynamic>) { 136 3 : for (final e2 in (e.value as Map<String, dynamic>).entries) { 137 6 : acc['${e.key}[${e2.key}]'] = e2.value.toString(); 138 : } 139 : } else { 140 4 : acc[e.key] = e.value.toString(); 141 : } 142 : return acc; 143 : }); 144 : } 145 : 146 : // Riverpod type aliases, so we don't have to export it 147 : // (except ProviderStateOwner for now) 148 : 149 : typedef ConfigureRepositoryLocalStorage = Override Function( 150 : {FutureFn<String> baseDirFn, List<int> encryptionKey, bool clear}); 151 : 152 : typedef RepositoryInitializerProvider = FutureProvider<RepositoryInitializer> 153 : Function({bool remote, bool verbose}); 154 : 155 : class RiverpodAlias { 156 1 : static Provider<T> provider<T>(T Function(ProviderReference) create) => 157 1 : Provider<T>(create); 158 0 : static FutureProviderFamily<T, A> futureProviderFamily<T, A>( 159 : Future<T> Function(ProviderReference, A) create) => 160 0 : FutureProvider.family<T, A>(create); 161 : }