how do I work with file streams in dart/flutter? - flutter

I am new to dart/flutter programming. I have been trying to analyze the content of a file and return the result but couldn't. The code actually works when in the main function, but as soon as I take it out it doesn't work anymore. I have read the dart tutorial on futures, async, await, and streams as well as watched YouTube videos but still couldn't solve the problem. I believe my problem revolves around those concepts. Here is my code:
Future<String> r(String name) async {
var f = File(name);
var lines = f.readAsLines();
await lines
.then((line) => line.forEach((element) {
if (element.contains(RegExp(r'^hello'))) {
return element;
}
}))
.onError((error, stackTrace) => 'An error occured');
}
I was getting 2 errors:
The function name 'r' was underlined:
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
Try adding either a return or a throw statement at the end.
The variable 'element' was underlined:
The return type 'String' isn't a 'void', as required by the closure's context.
Thanks.

Your first error says that "Whatever happens, You have to return a String"
Your second error says that you are trying to return a String in a void function, As you see List. Foreach is a void function and you can't just return something in it because the return statement matches with the closest Function
So I rewrited you're code as following
Future<String> r(String name) async {
try {
var f = File(name);
var lines = await f.readAsLines();
for (var element in lines)
if (element.contains(RegExp(r'^hello'))) {
return element;
}
return "not found";
} catch (e) {
return 'An error occurred: $e';
}
}
Since you are using File and File.readAsLines I think it would be better to just wrap everything inside a try catch bloc k.

Related

How to write tests for Either<> from dartz package in flutter

I am trying to write unit tests for a flutter app and I can't get this one test case to work correctly.
Here is the function returning Future<Either<WeatherData, DataError>>:
#override
Future<Either<WeatherData, DataError>> fetchWeatherByCity({required String city}) async {
try {
var response = await apiService.fetchWeatherByCity(city: city);
if (response.statusCode == 200) {
return Left(WeatherData.fromJson(jsonDecode(response.body)));
} else {
return Right(DataError(title: "Error", description: "Desc", code: 0, url: "NoUrl"));
}
} catch (error) {
AppException exception = error as AppException;
return Right(DataError(
title: exception.title, description: exception.description, code: exception.code, url: exception.url));
}
}
Here is the code where I am trying to write the unit test:
sut = WeatherRepositoryImpl(apiService: mockWeatherApiService);
test(
"get weather by city DataError 1 - Error 404 ",
() async {
when(mockWeatherApiService.fetchWeatherByCity(city: "city"))
.thenAnswer((_) async => Future.value(weatherRepoMockData.badResponse));
final result = await sut.fetchWeatherByCity(city: "city");
verify(mockWeatherApiService.fetchWeatherByCity(city: "city")).called(1);
expect(result, isInstanceOf<DataError>);
verifyNoMoreInteractions(mockWeatherApiService);
},
);
When I run this specific test, I receive this error:
Expected: <Instance of 'DataError'>
Actual: Right<WeatherData, DataError>:<Right(Instance of 'DataError')>
Which: is not an instance of 'DataError'
What I am not getting here? What should I be expecting from the function for the test to pass successfully?
You are directly using the result which is actually a wrapper and has a type of Either<WeatherData, DataError>.
You need to unwrap the value using the fold method on the result and then expect accordingly, So in your code you can do something like this to make it work:
final result = await sut.fetchWeatherByCity(city: "city");
result.fold(
(left) => fail('test failed'),
(right) {
expect(result, isInstanceOf<DataError>);
});
verifyNoMoreInteractions(mockWeatherApiService);
Hope this helps.
You need to either make the expected value a Right(), or extract the right side of the actual value. Doing either of those will match, but as it is, you're comparing a wrapped value with an unwrapped value.

There is another way to write a inline asyncronous function in dart?

var a = await () async {try{return await ... }}.call();
I was thinking that way to write is not convenient, they are so verbose.
"await () async {...}" is a very ugly style.
What I'm wrong? There is another way to do this?
var a = await () async
{
try {
return await method();
} catch (e) {
return anotherMethod();
}
}.call();
EDIT:
The return inside the try block send the value to a variable "a". Otherwise, I had to: First: declare a variable Then: set the value inside the try-catch block.
This kind of structure can easily drive you to fail, once that you don't have any guarantee that the variable are true set.
By the other hand: with an inline function you have to return any value otherwise the compile alert by the ERROR. And you get a more refactorable code;

Firestore type mismatch : The argument type 'List<Null>' can't be assigned to the parameter type 'List<JobPost>'

In a flutter project, I am trying to make a CollectionGroup query. But messed up with types. Here is my code :
Stream<Either<JobPostFailure, List<JobPost>>> watchAppliedJobPosts({
required String seamanId,
}) async* {
yield* _firestore
.collectionGroup(ConstStrings.applications)
.where(ConstStrings.seamanId, isEqualTo: seamanId)
.snapshots()
.map((querySnapshot) {
return right(querySnapshot.docs.map((docSnapshot) {
final jobPostDocRef = docSnapshot.reference;
jobPostDocRef.snapshots().map((doc) {
final jobPost = JobPostDto.fromFirestore(doc).toDomain();
return jobPost;
});
}).toList());
});
}
I expect to get a List<JobPost>, but getting following error at this line return right(querySnapshot.docs.map((docSnapshot) {...:
The argument type 'List<Null>' can't be assigned to the parameter type
'List<JobPost>'.
Though I am returning List<JobPost>, error says it is List<Null>. Where is the error? How to solve this?
You are missing a return keyword:
return /* <-- */ jobPostDocRef.snapshots().map((doc) {
That said, why are you complicating this function with an Either return type, when there clearly is no other option in your method? It always returns right, so you might as well just remove the Either from the return type.

How to return a non-nullable type from a Function in a function callback?

Future<int> getInt() async { // Error:
final c = Completer<int>();
await foo.bar(
callback1: (i) => c.complete(i),
callback2: (j) => c.complete(j),
error: (e) => throw e,
);
}
The body might complete normally, causing 'null' to be returned, but the return type is a potentially non-nullable type.
As I know one of these callback will work, so how do I tell the analyzer that I've handled all the scenarios?
Note: I know I can simply use Future<int?> but I want to know if there are other ways of handling this case?
Analyzer is right here, you're just not returning anything from getInt().
Add return completer.future at the end of getInt().
Note:
Using Completer here seems rather odd, it's mainly used to bridge between callback-based API and Future-based API.
You need a return statement:
final result = await foo.bar(
callback1: (i) => c.complete(i),
callback2: (j) => c.complete(j),
error: (e) => throw e,
);
return result;
OR
...
return c;

How to handle non explicit errors inside sails.js helpers?

I am trying to figure out how the Error handling in Sails.js works. Unfortunatley the code examples in the docs do not cover this use case.
The problem is I keep getting this error:
UsageError: `.intercept()` handler returned `undefined`, but this should never happen.
Regardless, here is a summary of the original underlying error:
Now all I am trying to do is call a helper and if it fails, then I want to catch the error (any), log it and run some code. If I wouldn't be using Sails but normal promises I would have handled it like this:
await helper().catch((err) => { // run some code }
In Sails I should be able to use .intercept() instead of .catch()
My code looks like this:
// ExportController.js
const csv = await sails.helpers.files.convertToCsv(data)
.intercept((err) => {
sails.log.error(err)
req.addFlash('error_messages', 'Error parsing data to csv!')
return res.redirect(`/`);
})
// convert-to-csv.js
if (!Array.isArray(inputs.data)) {
throw new Error('invalid inputs.data type: ' + typeof inputs.data)
};
Now how can I avoid getting this error?
The code examples show only cases where errors that are explicitly added to the exits object are handled, but not for general error handling.
In the docs it says that if the filter argument is
not provided, ALL errors will be intercepted.
Or is that only true for db queries? Because the .intercept() doc section is in that subcategory.
You could use “throw ‘errorCode’;” for example:
Set the exits:
exits {
errorWithCsvFile: {
responseType: 'badRequest'
}
}
const csv = await sails.helpers.files.convertToCsv(data)
.intercept(‘somethingWrongCode’, ‘errorWithCsvFile’)
... // Other handles
.intercept(err => new Error(err))
Alternative:
try {
...
const csv = await sails.helpers.files.convertToCsv(data)
.intercept((err) => {
sails.log.error(err)
req.addFlash('error_messages', 'Error parsing data to csv!')
throw 'badRequest';
})
...
} catch (err) {
sails.log.err(err);
return res.redirect(`/`);
}