How to pass Model as an argument in ipcMain.handle - electron

I want to create a reusable function in Electron.js to handle Saving data irrespective of the model(e.g User, Employee, Product),so I passed Model as an argument, then call the specific Model during when the function is called.
but I get this error
Error: Expected handler to be a function, but found type 'object'
This is my code
const User = require( '../database/models/Users.js');
ipcMain.handle('user:create', saveData(User));
async function saveData(_, data,Model) {
try {
const user = await Model.insert(data);
return user;
} catch (e) {
console.log(e.message);
}
}

ipcMain.handle('user:create', saveData(User)); call function saveData(User) after app is started and it returns object. if you want to assign function to 'user:create' then without parameters it's ipcMain.handle('user:create', saveData); but with parameters it's.
ipcMain.handle('user:create', () => saveData(User));
is the same as
ipcMain.handle('user:create', function () {
return saveData(User)
});

Related

How to access a Stimulus JS controller method from inside a nested function?

I have a Stimulus controller inside which I have a setSegments function and then this code in the connect() method:
connect() {
const options = {
overview: {
container: document.getElementById('overview-container'),
waveformColor: 'blue',
},
mediaElement: document.querySelector('audio'),
dataUri: {
arraybuffer: document.getElementById('normal-audio-button').dataset.waveform
},
emitCueEvents: true,
};
Peaks.init(options, function (err, peaks) {
window.instance = peaks;
window.speed = "normal";
setSegments()
instance.on('segments.enter', function (segment) {
const segmentCard = document.getElementById(segment.id)
segmentCard.focus({preventScroll: true})
window.currentSegment = segment
});
});
}
setSegments() {
alert("segment set up)
}
I'm tryng to call setSegments() inside the Peaks.init function but it doesn't work because of the function's scope. I'm just not sure how to get around this. I tried calling this.setSegments() instead but it doesn't help.
What's the correct way of accessing the function in this case?
Thanks
The problem is that this is a bit confusing when working with JavaScript, however a way to think about it that it is the current context.
For example, when your code is running in the browser console or not in another function this is the global window object. When you are directly in the controller's connect method this is the controller's instance.
However, when you pass a function to Peaks.init that function creates it's own new context where this is the function's context and no longer the controller instance.
There are three common workarounds to calling this.setSegments;
1. Set a variable that is outside the function scope
As per your solution, const setSegments = this.setSegments; works because you are creating a reference outside the function scope and functions have access to this.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const setSegments = this setSegments;
Peaks.init(options, function (err, peaks) {
// this is the peaks init handler context
window.instance = peaks;
// this.setSegments(): - will not work
setSegments();
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
});
}
2. Use bind to override the function'sthis
You can pull your function out to a variable and then add .bind(this) to it so that when the function is called it will use the this from the controller instance instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const myFunction = function (err, peaks) {
// this is the BOUND this provided by the bind command and will be the controller's instance
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
};
myFunction.bind(this);
Peaks.init(options, myFunction);
}
3. Use an arrow function (easiest)
You should be able to use an arrow function in modern browsers or if you have a build tool running it may transpiled this for older browsers.
Instead of function() {} you use () => {} and it grabs the this from the parent function context instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
Peaks.init(options, (err, peaks) => {
// this is now the controller's instance and NOT the peak handler context
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually) and is NOT the controller instance as arrow function not used here.
});
});
}
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this for more details
I don't know if it's the best way to do it but adding the following right after the beginning of the connect method did the trick:
let setSegments = this.setSegments

Dart: Function signature for catchError Future

I've got some Future code that looks like this:
return login().then((user) {
print("Logged in user ${user.name}");
return user;
}).catchError(this.displayError);
Where I'm trying to pass a function to the catchError(...) function because it's an error handler I'm reusing across a number of calls. I've tried using this:
Future<void> displayError(Error error) {
return showDialog(context: context, builder: (context) {
return AlertDialog(...);
});
}
But when I run the app I get this error:
Invalid argument (onError): Error handler must accept one Object or one Object and a StackTrace as arguments, and return a a valid result: Closure: (Error) => Future<void> from Function 'displayError':.
If I change my catchError(...) to this:
.catchError((error) {
displayError(error);
})
Everything then works. My question is does anyone know why I've not been successful passing the displayError function to catchError instead of call it within a closure?
Change the signature of the handler – it must be an Object not an Error. There are no promises in Dart that thrown objects are of type Error. They could be anything.
Future<void> displayError(Object error) {
return showDialog(context: context, builder: (context) {
return AlertDialog(...);
});
}

Dart & Mockito. How to call Function() argument in mocked method

I use Mockito for writing tests on Flutter. I have a mocked class and method with arguments that are functions - Function() and this method returns StreamSubscription. I need to pass these arguments to the call of listen() function but can't find a way to do it. (See example)
Could somebody help me, please?
I tried to pass them with argThat(anyNamed('nameOfArgument') like in the example, but tests trows error - The "anyNamed" argument matcher is used outside of method stubbing (via when)
class MockPhotoLibraryService extends Mock implements PhotoLibraryService {}
PhotoLibraryService setupMockPhotoLibraryService() {
final photoLibraryService = MockPhotoLibraryService();
when(
photoLibraryService.getPhotosForPeriod(
onData: anyNamed('onData'),
onDone: anyNamed('onDone'),
onError: anyNamed('onError')),
).thenAnswer((_) => Stream<Photo>.fromFuture(
Future<Photo>.delayed(Duration(milliseconds: 50), () => Photo()))
.listen(argThat(anyNamed('onData')), //need to pass argument named onData
onDone: argThat(anyNamed('onDone')), //need to pass argument named onDone
onError: argThat(anyNamed('onError')), //need to pass argument named onError
cancelOnError: true));
return photoLibraryService;
}
I need these arguments functions to be called by the Future for the correct work of my testable widget.
You can get access to the original call parameters through Invocation object. It is passed as a parameter to the thenAnswer callback function.
when(photoLibraryService.getPhotosForPeriod(
onData: anyNamed('onData'),
onDone: anyNamed('onDone'),
onError: anyNamed('onError'),
)).thenAnswer((Invocation invocation) {
final namedArgs = invocation.namedArguments;
final onData = namedArgs[Symbol('onData')] as Function(Photo);
final onDone = namedArgs[Symbol('onDone')] as Function();
final onError = namedArgs[Symbol('onError')] as Function(dynamic);
return Stream<Photo>.fromFuture(
Future<Photo>.delayed(Duration(milliseconds: 50), () => Photo()),
).listen(onData, onDone: onDone, onError: onError, cancelOnError: true);
});

Can't call onData inside listener

I have very small app:
main() async
{
Stream stream = Stream.fromIterable([1,2,3,4]);
stream.listen(
(d) { print(d); },
onDone: () { print("all done"); }
);
}
I can't understand why I can't call onData in the same manner as onDone like:
onData: (d) { print(d); }
Docs
The onData parameter to listen is a positional parameter, and the onDone parameter is a named parameter. All parameters are one or the other, and it determines how you pass an argument for that parameter.
To pass an argument for a named parameter, you must use the name, so you write onDone: () { ... }.
To pass an argument for a positional parameter, you just write the value. You cannot use the name.
So, to call listen with both, you write:
stream.listen(
(data) { handleData(...); },
onDone: () { handleDone(...); }
);
which passes one positional argument and one named arugment with the name onDone.

How to write tests using the service scope

My app is accessing object from the service scope (package:gcloud/service_scope.dart), like the storageService and additional services that I put inside the scope with ss.register().
Now I want to unit test a function that accesses this scope, and uses mock objects that I want to put in the service scope.
Is the only way to do so, to register them for every test, like this:
var withServiceScope = (callback()) => ss.fork(() {
// Register all services here
return callback();
});
test('the description', () => withServiceScope(() async {
// Call my function that can now access the service scope
}));
Or is there are way that allows me to do that in the setUp() function so I don't need to add this line for each test?
This might make it simpler to write your tests (code not tested)
import 'package:test/test.dart' as t;
import 'package:test/test.dart' show group;
var withServiceScope = (callback()) => ss.fork(() {
// Register all services here
return callback();
});
test(String description, Function testFunction) {
t.test(description, () => withServiceScope(() async {
testFunction();
}));
}
main() {
test('the description', () async {
// Call my function that can now access the service scope
}));
}

Resources