I'd like to know how to send several arguments via ipcRenderer on an Electron app.
Should I send an array of arguments or just all the arguments separated by comma?
Thanks,
I would recommend an object for parameter transfer. In consequence, you can also think about implementing a consistent API for your application:
var _myreq = {
state: 0, //0 is no error, 4 is error with message, etc.
message: "", //can include error message (if any)
data: [0,4,6] //application data for request (String, Array, Object)
};
ipc.send('mychannel-functiona', _myreq);
Docs clearly shows that you can pass any number of argument to send.
Send a message to the main process asynchronously via channel, you can
also send arbitrary arguments. Arguments will be serialized in JSON
internally and hence no functions or prototype chain will be included.
From that point on you have no restrictions on how to use those arbitrary arguments. It depends on your needs, your codebase style etc.
We can pass many arguments for the ipcRenderer, you can refer this page: https://electronjs.org/docs/api/ipc-renderer.
Related
I am using a typescript for the back-end app and don't understand quite a simple thing I guess. But searching for articles on Google doesn't bring me confidence at all.
Imagine I am receiving an answer from the API endpoint, the usual schema is something like this:
some_array: [
{ key: value },
{ key: value },
{ key: string || number || nested object }
]
number_key: 12,
string_key: 'string'
As you might see, it's not 100% static, sometimes in the some_array field (which is actually 100% array on success) could be almost any data in object value.
..and with some chance, I could receive an error or something like that.
Well, typescript brings as safety with types, but I don't understand, how it could be safe when I could receive almost any response from endpoint?
For example, what's the difference between:
api as any
//inside async function
const api: any = await fetch('/endpoint');
//I should check responce types manually and to avoid incorrect types
if (!api|| !Array.isArray(api.some_array) || !api.some_array.length) return
for (const document of api.some_array) {
//any function or action
}
and api as predefined interface
interface ApiResp = {
some_array: { [key: string]: any }[]
number_key: number
string_key: string
}
//inside async function
const api: ApiResp = await fetch('/endpoint');
// if (api) ... but should I check only for api, since the interface of api is predefined?
for (const document of api.some_array) {
//any function or action
}
Does in second option, I could no longer check types like if (!api|| !Array.isArray(api.some_array) || !api.some_array.length) return and all incorrect type responces will throw error on receiving (in const api) after compile to js code? So I could just check the existance of api only, like if (api) .... ?
Or, for example, if the actual response from API doesn't suit the interface it will still try to reach to for of loop and throw an error there? (because there is no such field as some_array in endpoint responses with errors like: {error: 404}?
Typescript is not intended for run-time type checking. It's a purely compile-time type system that is meant to reduce coding errors that easily occur when writing in a non statically-type language. So when you say, "I don't see how it can be safe when I can receive almost any response from endpoint" you are mistaking runtime safety and compile time safety.
If you want runtime safety, and the objects you are receiving from the endpoint are highly varying, then you will need to handle those varying types either "manually", with type checks like !Array.isArray(api.some_array), or using some library like io-ts as suggested by zerkms in the comments.
Having determined the type you have received, you may then be able to cast your objects to some static typescript interface so that you can work with them "safely", that is without making type mistakes that won't be picked up until you run the code.
In reality, a good API should guarantee some type of consistent response that you can express in typescript types. If it doesn't, then that is not the type of problem that typescript can solve.
I had a question regarding the return value of a query in hyperledger composer.
For reference my query:
query findCountOfficer {
description: "find count officer asset given name"
statement:
SELECT org.example.CountOfficer
WHERE (name == _$nameParam)
}
My querying:
let countOfficerRecord = await query('findCountOfficer', {nameParam: countOfficerName})
I am trying to retrieve the ID of the count officer from the count officer record parameter.
Does anyone know how to access the identifier or fields of a resource returned from a query?
Or if not that how to have a query return the employeeId? (i.e. select employeeID)
What I've tried:
When I print countOfficerRecord I get Resource {id=org.carm.CountOfficer#1}
I want to access the 1 ID. However if I call countOfficerRecord.id or countOfficerRecord.employeedId (as employeeId is the identifier in the model file) I get undefined.
As this is a Resource I also tried functions from the documentation such as getIdentifier() and isResource() and got an error that these weren't functions for countOfficerRecord.
Thanks!
If you want to get the identifier then try this
console.log( countOfficerRecord.$identifier)
if you want the whole record of countOfficerRecord
then try this
console.log([countOfficerRecord])
It looks like you are invoking the toString() method on the resource object that you have (either explicitly or implicitly via whatever mechanism you use to print the object). The output you see is the result of that toString invocation and not a JSON respresentation of the object, you can interact with the resource object using it's api's, eg
console.log(countOfficerRecord.getIdentifier());
console.log(countOfficerRecord.name)
The above example references $identifier which isn't a recommended approach as this is an internal field name and could change in the future. You should use the api's of a resource object to obtain information.
The api reference for a resource can be found here
https://hyperledger.github.io/composer/latest/api/common-resource
I tried this and it worked.
Queries usually return an array. Therefore, you first reference the array and then get the identifier.
countOfficerRecord[0].$identifier
I'm using openerp and i need to call a python method from a web module using javascript.
this is the method:
def get_data(self, cr, uid, ids, context=None):
_logger.info('ids es %r',ids);
if context is None:
context = {}
data = {}
data['ids'] = context.get('active_ids', [])
data['model'] = context.get('active_model', 'ir.ui.menu')
data['form'] = self.read(cr, uid, ids, ['user_id', 'date_start', 'date_end'], context=context)[0]
_logger.info('data es %r',data);
_logger.info('data[form] es %r',data['form']);
return data;
however i don't know how to call this method from javascript because i don't really know what the ids parameter should be, anyways this is how i call it (i get an error because i'm not sending the ids parameter)
data = reportModel.call('get_data',[],undefined,{});
so my question is, what is the ids parameter, how does it work and what should i send to this function from javascript in order to succeed?
I am not sure you will be able to call this from javascript at all as you will need to pass in a database cursor from the connection pool for the appropriate database and you may need to use the XMLRPC interface.
That said, these methods exist on an ORM model (or transient model) and the ids parameter is the standard OpenERP pattern of passing in the IDS of records in the model this method is on that you want to process. So if this method is on the account invoice model, the IDS would be a list of ids in the account_invoice table that you want to process.
Note that you just have to have the argument, you don't have to have anything in it or use it. For example, most form on_change methods ignore it as those methods have to cater for users keying new records that don't exist in the database.
In JQuery:
initSliders(socket, '!{request}');
request is an object (an HTTP request object in Express.js web app) that has such info as my session. When I pass this in to initSliders() it come in on the other side as the String literal "[object Object]". Why? I don't know. It behaves like an object before it passes in since commands like these execute:
console.log('!{request.session.user}');
console.log('!{request.session.date}');
console.log('!{request.session.city}');
Display things like
Alfred
11/13/2013
Manitoba
How can I keep it's structure when being passed into the function so I can reference it's properties like those above??
The request object is coming in through a render, via an app.js handler like this (which is why I use the single quotes and curly brackets around it, it's the only way I know how to reference this)
exports.dashboard = function(req, res){
res.render('dashboard', {request: req});
}
It prints out [object Object] because req.toString() returns it. res.render('dashboard', { request: JSON.stringify(req) }) also does not make much sense just because request is particularly huge object and you probably do not really want ALL the object properties being passed to render script. However, you can try... So it is highly recommended to pass only what is required as follows:
red.render('dashboard', { parameters : JSON.stringify({ param1 : req..., param2 : req.... and so on })
I have a Breeze web api controller, with methods that accept parameters and do some work, filtering, sorting, etc, on the server.
On the querySucceeded, I'd like to do further querying to data.results. Is there a way to accomplish this? I got this working by exporting/importing data.results to a local manager, and do the projection from there. The projection is needed in order to use the observable collection in a vendor grid control.
var query = datacontext.EntityQuery.from("GetActiveCustomers")
.withParameters({ organizationID: "1" })
.toType("Customer")
.expand("Organization")
.orderBy('name');
var queryProjection = query
.select("customerID, organizationID, name, isActive, organization.name");
return manager.executeQuery(query)
.then(querySucceeded)
.fail(queryFailed);
function querySucceeded(data) {
var exportData = manager.exportEntities(data.results);
var localManager = breeze.EntityManager.importEntities(exportData);
var resultProjection = localManager.executeQueryLocally(queryProjection);
//This is the way I came up with to query data.results (exporting/importing the result entities to a local manager)
//Is there a better way to do this? Querying directly data.results. Example: data.results.where(...).select("customerID, organizationID...)
if (collectionObservable) {
collectionObservable(resultProjection);
}
log('Retrieved Data from remote data source',
data, true);
}
You've taken an interesting approach. Normally a projection returns uncacheable objects, not entities. But you casted this to Customer (with the toType clause) which means you've created PARTIAL Customer entities with missing data.
I must hope you know what you are doing and have no intention of saving changes to these customer entities while they remain partial else calamity may ensue.
Note that when you imported the selected Customers to the "localManager" you did not bring along their related Organization entities. That means an expression such as resultProjection[0].organization will return null. That doesn't seem correct.
I understand that you want to hold on to a subset of the Customer partial entities and that there is no local query that could select that subset from cache because the selection criteria are only fully known on the server.
I think I would handle this need differently.
First, I would bury all of this logic inside the DataContext itself; the purpose of a DataContext is to encapsulate the details of data access so that callers (such as ViewModels) don't have to know internals. The DataContext is an example of the UnitOfWork (UoW) pattern, an abstraction that helps isolate the data access/manipulation concerns from ViewModel concerns.
Then I would store it either in a named array of the DataContext (DC) or of the ViewModel (VM), depending upon whether this subset was of narrow or broad interest in the application.
If only the VM instance cares about this subset, then the DC should return the data.results and let the VM hold them.
I do not understand why you are re-querying a local EntityManager for this set nor for why your local query is ALSO appling a projection ... which would return non-entity data objects to the caller. What is wrong with returning the (partial) Customer entities.
It seems you intend to further filter the subset on the client. Hey ... it's a JavaScript array. You can call stuffArray.filter(filterFunction).
Sure that doesn't give you the Breeze LINQ-like query syntax ... but do you really need that? Why do you need ".select" over that set?
If that REALLY is your need, then I guess I understand why you're dumping the results into a separate EntityManager for local use. In that case, I believe you'll need more code in your query callback method to import the related Organization entities into that local EM so that someCustomer.organization returns a value. The ever-increasing trickiness of this approach makes me uncomfortable but it is your application.
If you continue down this road, I strongly encourage you to encapsulate it either in the DC or in some kind of service class. I wouldn't want my VMs to know about any of these shenanigans.
Best of luck.
Update 3 Oct 2013: Local cache query filtering on unmapped property
After sleeping on it, I have another idea for you that eliminates your need for a second EM in this use case.
You can add an unmapped property to the client-side Customer entity and set that property with a subset marker after querying the "GetActiveCustomers" endpoint on the server; you'd set the marker in the query callback.
Then you can compose a local query that filters on the marker value to ensure you only consider Customer objects from that subset.
Reference the marker value only in local queries. I don't know if a remote query filtering on the marker value will fail or simply ignore that criterion.
You won't need a separate local EntityManager; the Customer entities in your main manager carry the evidence of the server-side filtering. Of course the server will never have to deal with your unmapped property value.
Yes, a breeze local query can target unmapped properties as well as mapped properties.
Here's a small demonstration. Register a custom constructor like this:
function Customer() { /* Custom constructor ... which you register with the metadataStore*/
// Add unmapped 'subset' property to be queried locally.
this.subset = Math.ceil(Math.random() * 3); // simulate values {1..3}
}
Later you query it locally. Here are examples of queries that do and do not reference that property:
// All customers in cache
var x = breeze.EntityQuery.from("Customers").using(manager).executeLocally();
// All customers in cache whose unmapped 'subset' property === 1.
var y = breeze.EntityQuery.from("Customers")
.where("subset", 'eq', 1) // more criteria; knock yourself out
.using(manager).executeLocally();
I trust you'll know how to set the subset property appropriately in your callback to our "GetActiveCustomers" query.
HTH
Once you queried for some data breeze stores those entities on the local memory.
All you have to do is query locally when you need to filter the data some more.
You do this by specifying for the manager to query locally :
manager.executeQueryLocally(query);
Because querying from the database is done asynchronously you have to make sure that you retrieve from the local memory only if there is something there. Follow the promises.