More than 6 providers for ProxyProvider, how? - flutter

Until now I used Singleton pattern in my code, but I'm switching to Remi Rousselet’s Provider. And I have a business logic class that depends on 7 others as for now. ProxyProvider allows to use up to 6. How do I implement Provider pattern in this case?
class BlocAuth {
BlocAuth(this.serviceChatFirestore);
ServiceChatFirestore serviceChatFirestore;
var _state = AuthState();
var blocUser = BlocUser();
var user = UserModel();
var blocRouting = BlocRouting();
var blocBrands = BlocBrands();
var blocNotifications = BlocNotifications();
}

ProxyProvider isn't actually fixed to any number of dependency.
ProxyProvider vs ProxyProvider6 is just some syntax sugar. The latter isn't actually needed
For example:
ProxyProvider3<A, B, C, Result>(
builder: (_, a, b, c, previous) {
...
}
)
is strictly equivalent to:
ProxyProvider<A, Result>(
builder: (context, a, previous) {
final b = Provider.of<B>(context);
final c = Provider.of<C>(context);
...
},
)
So you can just do:
ProxyProvider6<A, B, C, D, E, F, Result>(
builder: (context, a, b, c, d, e, f previous) {
final g = Provider.of<G>(context);
...
}
)

Related

How to save operators in Dart

I want to do something like this in dart.
var z = +
and then put it in another var like this
var x = 5 z 5
And when I did this
var z = +
I get an Error
Expected an identifier.
you can not make variable operators in dart though what you can do is to create a custom variable for the same by doing:
void main() {
var operators = {
'+': (a, b) { return a + b; },
'<': (a, b) { return a < b; },
// ...
};
var op = '+';
var x = operators[op]!(10, 20);
print(x);
}

InvalidOperationException in where clause when attempting to create projection with Compile/Invoke

I've got a model and I want to build a simplified query model on top of it using projections.
Here we have 2 related 'derived' classes.
note - in the 2nd class ES_PROGRAMGUIDEDAYSCHEDULE, there are 2 implementations of of the projection, the uncommented explicit one works, the commented one out fails.
class ESP_CHANNEL
{
public string? name { get; set; }
public static Expression<Func<Channel, ESP_CHANNEL>> Projection
{
get
{
return x => new ESP_CHANNEL
{
name = x.LotIdLeafoftreepartNavigation.Leaf
};
}
}
}
class ES_PROGRAMGUIDEDAYSCHEDULE
{
public ESP_CHANNEL? ds_channel { get; set; }
public DateTime? ds_date { get; set; }
public static IQueryable<ES_PROGRAMGUIDEDAYSCHEDULE> Query(ModelContext context)
{
return context.Pgprogramguidedayschedules.Select(ES_PROGRAMGUIDEDAYSCHEDULE.Projection);
}
private static Expression<Func<Pgprogramguidedayschedule, ES_PROGRAMGUIDEDAYSCHEDULE>> Projection
{
get
{
return x => new ES_PROGRAMGUIDEDAYSCHEDULE
{
ds_date = x.PgdsIdDayscheduleNavigation.DsTxdate,
// If I explicitly instantiate an ESP_CHANNEL it works
ds_channel = new ESP_CHANNEL
{
name = x.PgdsIdDayscheduleNavigation.DsIdScheduleNavigation.SchIdChannelNavigation.LotIdLeafoftreepartNavigation.Leaf
}
// note THIS seemingly equivalent implementation via compile/invoke fails
//ds_channel = ESP_CHANNEL.Projection.Compile().Invoke(x.PgdsIdDayscheduleNavigation.DsIdScheduleNavigation.SchIdChannelNavigation)
};
}
}
}
If I then run this query like this.
var x =
(from schedule in ES_PROGRAMGUIDEDAYSCHEDULE.Query(ds)
where schedule.ds_channel.name == channel
&& schedule.ds_date == dt
select schedule).Take(1);
var ys = x.ToArray();
the explicit implementation in ES_PROGRAMGUIDEDAYSCHEDULE.Projection, works
ds_channel = new ESP_CHANNEL
{
name = x.PgdsIdDayscheduleNavigation.DsIdScheduleNavigation.SchIdChannelNavigation.LotIdLeafoftreepartNavigation.Leaf
}
whilst the seemingly equivalent implemention, where the instantiation of the ESP_CHANNEL is held in a the projection expression fails
ds_channel = ESP_CHANNEL.Projection.Compile().Invoke(x.PgdsIdDayscheduleNavigation.DsIdScheduleNavigation.SchIdChannelNavigation)
fails with
An unhandled exception of type 'System.InvalidOperationException' occurred in Microsoft.EntityFrameworkCore.dll
The LINQ expression 'DbSet<Pgprogramguidedayschedule>()
.LeftJoin(
inner: DbSet<Wondayschedule>(),
outerKeySelector: p => EF.Property<decimal?>(p, "PgdsIdDayschedule"),
innerKeySelector: w => EF.Property<decimal?>(w, "Oid"),
resultSelector: (o, i) => new TransparentIdentifier<Pgprogramguidedayschedule, Wondayschedule>(
Outer = o,
Inner = i
))
.LeftJoin(
inner: DbSet<Psischedule>(),
outerKeySelector: p => EF.Property<decimal?>(p.Inner, "DsIdSchedule"),
innerKeySelector: p0 => EF.Property<decimal?>(p0, "Oid"),
resultSelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<Pgprogramguidedayschedule, Wondayschedule>, Psischedule>(
Outer = o,
Inner = i
))
.LeftJoin(
inner: DbSet<Channel>(),
outerKeySelector: p => EF.Property<decimal?>(p.Inner, "SchIdChannel"),
innerKeySelector: c => EF.Property<decimal?>(c, "LotIdLeafoftreepart"),
resultSelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<TransparentIdentifier<Pgprogramguidedayschedule, Wondayschedule>, Psischedule>, Channel>(
Outer = o,
Inner = i
))
.Where(p => __Compile_0.Invoke(p.Inner).name == __channel_1 && p.Outer.Outer.Inner.DsTxdate == __dt_2)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
any ideas?
(the problem appears to be that its the where clause that fails to interpret the invoke correctly).
EDIT 1
note his query DOES execute correctly.
var x =
(from schedule in ES_PROGRAMGUIDEDAYSCHEDULE.Query(ds)
//where schedule.ds_channel.name == channel
//&& schedule.ds_date == dt
select schedule).Take(1);
so it appears that it is the where clause navigating via ds_channel that is causing the issue.
You can use LINQKit to make this query working. It needs just configuring DbContextOptions:
builder
.UseSqlServer(connectionString) // or any other provider
.WithExpressionExpanding(); // enabling LINQKit extension
Then you can inject your projection using LINQKit's Invoke method (but possible your query will be corrected also)
ds_channel = ESP_CHANNEL.Projection.Invoke(x.PgdsIdDayscheduleNavigation.DsIdScheduleNavigation.SchIdChannelNavigation)
Also you may find helpful this answer. It shows how to hide expression magic from end user.

Group and sort map in a predefined order

Here is an extension to group my tasks
/// EXTENSION
Map<K, List<T>> groupBy<T, K>(K key(T e)) {
Map<K, List<T>> map = {};
for (final element in this) {
var list = map.putIfAbsent(key(element as T), () => []);
list.add(element);
}
return map;
}
/// CODE
final List<String> requiredPrioritySortOrder = ['df','sc','de','dd'];
final Map<String, List<Task>> tasksByPriority = _selectedTasks.groupBy<Task, String>((e) => e.priority);
As a result, I have received a map but the sort order change every time after the task update.
How to sort tasksByPriority Map by key in a predefined order (requiredPrioritySortOrder).
Thanks :)
I am already find a solution but maybe there is another way?
_selectedTasks.groupBy<Task, String>((e) => e.priority, order:['sc','df']);
Map<K, List<T>> groupBy<T, K>(K key(T e), {Iterable order = const []}) {
Map<K, List<T>> mapped = {};
Map<K, List<T>> sorted = {};
for (final e in this) {
List list = mapped.putIfAbsent(key(e as T), () => []);
list.add(e);
}
if (order.isNotEmpty) {
order.forEach((e) {
if (mapped[e] != null) {
sorted[e] = mapped[e]!;
}
});
return sorted;
}
return mapped;
}

why I can't run my code where is the problem of this code?

void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (value) => value % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
this kind of error show in my terminal
lib/exercises/18-implement-where-function.dart:3:44: Error: The operator '%' isn't defined for the class 'Object?'.
'Object' is from 'dart:core'.
Try correcting the operator to an existing operator, or defining a '%' operator.
final odd = where(list, (value) => value % 2 == 1);
void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (value) => value! % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
The operator '%' isn't defined for the type 'Object'.
Try defining the operator '%'
Possible Dart analyzer is not able to infer type.
It's better to wait for the answer from the developers.
A workaround as below:
void main() {
const list = [1, 2, 3, 4];
final odd = where(list, (int value) => value % 2 == 1);
print(odd);
}
List<T> where<T>(List<T> items, bool Function(T) f) {
var results = <T>[];
for (var item in items) {
if (f(item)) {
results.add(item);
}
}
return results;
}
P.S.
I also encounter this issue from time to time in Dart.
On the one hand, the type is not explicitly specified (for parameter value) and must be inferred, on the other hand, it is not clear why it is not inferred from another type (aslo T), which is inferred from the value (in our case. list) wuth the same type parameter (T).
I've run your code on https://dartpad.dev/dart, it's working though. I think there is an issue with your import classes.

CombineLatest, but only push for the left

I need to implement a version of CombineLatest (I'll call it WithLatest here) that calls the selector for every item on the left and the latest item on the right. It shouldn't push for items on the right changing only.
I think whether this is built Observable.Create or a combination of existing extensions is not particularly important; I'll be making this a "boxed" extension method either way.
Example
var left = new Subject<int>();
var right = new Subject<int>();
left.WithLatest(right, (l,r) => l + " " + r).Dump();
left.OnNext(1); // <1>
left.OnNext(2); // <2>
right.OnNext(1); // <3>
right.OnNext(2); // <4>
left.OnNext(3); // <5>
should yield
2 1
3 2
Edit: The logic of my example goes:
Left becomes populated with 1. Right is empty, no values pushed.
Left becomes updated with 2 (it forgets the previous value). Right is still empty, so nothing is pushed.
Right becomes populated with 1, so Left = 2 (the latest value), Right = 1 is pushed. Up to this point, there is no difference between WithLatest and CombineLatest
Right is updated -- nothing is pushed. This is what's different
Left is updated with 3, so Left = 3, Right = 2 (the latest value) is pushed.
It's been suggested that I try:
var lr = right.ObserveOn(Scheduler.TaskPool).Latest();
left.Select(l => l + " " + lr.First()).Dump();
but this blocks on the current thread for my test.
You can do this using existing operators.
Func<int, int, string> selector = (l, r) => l + " " + r;
var query = right.Publish(rs => left.Zip(rs.MostRecent(0), selector).SkipUntil(rs));
Publish ensures we only ever subscribe to right once and share the subscription among all subscribers to rs.
MostRecent turns an IObservable<T> into an IEnumerable<T> that always yields the most recently emitted value from the source observable.
Zip between IObservable<T> and IEnumerable<U> emits a value each time the observable emits a value.
SkipUntil skips the pairs (l, r) which occur before right ever emits a value.
I also had the same need for a CombineLatest which "pushes only for the left".
I made the solution an "overload" of Observable.Sample, because that's what the method does:
It samples a source (right) with a sampler (left), with the additional capability of providing a resultSelector (like in CombineLatest).
public static IObservable<TResult> Sample<TSource, TSample, TResult>(
this IObservable<TSource> source,
IObservable<TSample> sampler,
Func<TSource, TSample, TResult> resultSelector)
{
var multiSampler = sampler.Publish().RefCount();
return source.CombineLatest(multiSampler, resultSelector).Sample(multiSampler);
}
Based on the solution picked by the post author I think there's an even simpler solution utilizing DistinctUntilChanged:
public static IObservable<TResult> CombineLatestOnLeft<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource, IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector) {
return leftSource
.Select<TLeft, Tuple<TLeft, int>>(Tuple.Create<TLeft, int>)
.CombineLatest(rightSource,
(l, r) => new { Index = l.Item2, Left = l.Item1, Right = r })
.DistinctUntilChanged(x => x.Index)
.Select(x => selector(x.Left, x.Right));
}
or even
public static IObservable<TResult> CombineLatestOnLeft<TLeft, TRight, TResult>(this IObservable<TLeft> leftSource, IObservable<TRight> rightSource, Func<TLeft, TRight, TResult> selector) {
return leftSource
.CombineLatest(rightSource,
(l, r) => new { Left = l, Right = r })
.DistinctUntilChanged(x => x.Left)
.Select(x => selector(x.Left, x.Right));
}
if you only care about distinct values of leftSource
On latest System.Reactive, we can use WithLatestFrom extension method.
left.WithLatestFrom(right, (l, r) => l + " " + r).Dump();
The result would be below correctly.
3 2
Here's the hacky way using Create - didn't actually build it, mea culpa if it doesn't actually work :)
public static IObservable<TRet> WithLatest<TLeft, TRight, TRet>(
this IObservable<TLeft> lhs,
IObservable<TRight> rhs,
Func<TLeft, TRight, TRet> sel)
{
return Observable.Create<TRet>(subj => {
bool rhsSet = false;
bool deaded = false;
var latestRhs = default(TRight);
Action onDeaded = null;
var rhsDisp = rhs.Subscribe(
x => { latestRhs = x; rhsSet = true; },
ex => { subj.OnError(ex); onDeaded(); });
var lhsDisp = lhs
.Where(_ => deaded == false && rhsSet == true)
.Subscribe(
x => subj.OnNext(sel(x, latestRhs)),
ex => { subj.OnError(ex); onDeaded(); },
() => { subj.OnCompleted(); onDeaded(); });
onDeaded = () => {
deaded = true;
if (lhsDisp != null) {
lhsDisp.Dispose();
lhsDisp = null;
}
if (rhsDisp != null) {
rhsDisp.Dispose();
rhsDisp = null;
}
};
return onDeaded;
});
}
I made a RX operator for project today that does this.
Here's my solutions:
public static IObservable<Tuple<TSource, TTarget>> JoinLeftSoft<TSource, TTarget>(
this IObservable<TSource> source, IObservable<TTarget> right)
{
return source
.Select(x => new Tuple<object, TSource>(new object(), x))
.CombineLatest(right, (l, r) => new Tuple<object, TSource, TTarget>(l.Item1, l.Item2, r))
.DistinctUntilChanged(t => t.Item1)
.Select(t => new Tuple<TSource, TTarget>(t.Item2, t.Item3));
}