I have a local jsonstore linked to a remote sql database through an adapter. I am trying to push local data to the remote database like this :
submit_data = function () {
accessor.getPushRequired().then(function (result) { alert(result.length);
accessor.push();
});
Let us say I only added documents (no replace/remove).
I want my add procedure to look like this:
function addGegegr(document) {
//WL.Logger.warn(document[56]);
return WL.Server.invokeSQLStoredProcedure({
procedure : "DBO.USP_TIM_add_sp",
parameters : [document.key1,document.key2,document.key3,...]
});
}
And same for the replace/remove procedure, they should be calling other stored procedures with the same parameters.
However, I get errors because it seems the variable "document" worklight is passing to the add function after push is called is just a string and not a json object.
So my question is : how do I access the json attributes from the adapter procedure? If not possible, can I pass those attributes to the push function?
P.S.: passing each of the n documents to add as parameter of push() does not work and causes add to be called n*n times instead of n...
Try using JSON.parse to turn the string into a JavaScript object.
function addGegegr(document) {
var doc = JSON.parse(document);
//... use doc as a regular JavaScript object
}
If JSON.parse is not available there, you can add it by including this code in the adapter implementation file.
Related
I'm new to Loopback 4 and I've been trying to execute a native SQL query. I found how to do it, the thing is that don't have any clue of WHERE to put it in my code in order for it to work... here's the documentation I found.
I need to know where should I put this:
const result = await repository.execute('SELECT * FROM Products');
in my Loopback project, which has many files. My goal is to make a REST endpoint like /products/[name] with [name] being a parameter inserted dynamically to the SQL query.
You can do it in your controller class as per loopback docs https://loopback.io/doc/en/lb4/Controller.html. As you will define the REST endpoint in the controller itself you can also do the insertion there using repository.execute() e.g.
#get('/products/{name}')
async doSomething(
#param.path.string('name') name: string,
): Promise<Product> {
const sql = `SELECT * FROM some_table WHERE some_field="${name}"`;
await this.productRepository.execute(sql)
--- other lines of code & return value --
}
Personally, I would implement it as a new Repository method.
Let's say your model is called Product, then you should have src/repositories/product.repository.ts file exporting ProductRepository class already present in your project. (You can run lb4 repository to create it.)
export class Product extends DefaultCrudRepository<
Product,
typeof Product,
Product Relations
> {
constructor(#inject('datasources.db') dataSource: DbDataSource) {
super(Product, dataSource);
}
// your custom method
async selectByName(name: string): Promise<Product[]> {
const rawItems = await repository.execute('SELECT * FROM Products');
// would you like to convert raw data into Product instances?
return rawItems.map(it => new Product(it));
}
}
Then you can call this new custom repository method from your controller in the same way as you would call e.g. repository.find(filter).
I am able to create a worklight adapter, deploy it and invoke it by passing the parameter manually, but i need to create a login page where when the user enters the credentials, the application should get the his/her data from the tables by passing his username in the where clause of the query SELECT * FROM USER_ACC_TABLE WHERE USER = ?
How do I programmatically pass the parameters for a query in worklight adapters?
If you look at the docs, you will see that the invocation process includes a parameters key. In your case, I would use a JSON object as shown.
http://www-01.ibm.com/support/knowledgecenter/SSZH4A_6.2.0/com.ibm.worklight.apiref.doc/html/refjavascript-client/html/WL.Client.html%23invokeProcedure
function invokeAdapter(USERNAME) {
var USERINFO = {username: USERNAME};
var invocationData = {
adapter: "USER_ACCT_TABLE",
procedure: "getUserData",
parameters:[USERINFO]
};
// DEFINE THE CALL BACK FUNCTIONS
var options = {
onSuccess: onSuccess,
onFailure: onFailure
};
WL.Client.invokeProcedure(invocationData, options);
}
In your adapter code, you would have something like the following:
var selectStatement = WL.Server.createSQLStatement("SELECT * FROM USER_ACC_TABLE WHERE USER = ?");
function getUserData(data) {
var USERNAME = data.username;
return WL.Server.invokeSQLStatement({
preparedStatement : selectStatement,
parameters : [USERNAME]
});
}
If I understand you correctly, you'd like to get the values that the user will input in the login form's text fields and use them in your adapter request?
Maybe the answer the following question will help: Passing parameters through HTTP Adapter?
While it explains it for HTTP adapter, the JavaScript part of getting the values should be the same.
Basically, you use the following the get the value from the input field. You could save it in a variable just as well:
parameters : [$('#element-name').val()]
Full example is available in the linked question.
For passing the value to your SQL query in a SQL adapter, the following answer by jnortey should help: IBM Worklight - Error while using variable in a SQL Adapter query, which is basically the same.
That's it. Now the '?' in the SQL query should get the parameter's value.
I have implemented HTTP adapter in IBM Worklight. I want to display the result returned from server. I want to display HTML file. My code is
function getFeeds() {
var input = {
method : 'get',
returnedContentType : 'text',
path : "marketing/partners.html"
};
WL.Logger.debug("sdfsds");
return WL.Server.invokeHttp(input);
}
I want to receive(display) WL.Server.invokeHttp(input). After receiving it I want to parse the data.
Take a look at the Server-side Development Getting Started Modules. Inside the HTTP adapter – Communicating with HTTP back-end systems Module on Slide 15 - 'XSL Transformation Filtering' will show you how to filter data you get back from the backend. Further parsing and showing data has to be done on the client using onSuccess callback for WL.Client.invokeProcedure. There's a module for that too.
Here's an example of getting data and showing to a user:
var invocationData = {
adapter : 'adapter-name',
procedure : 'procedure-name',
parameters : []
};
var options = {};
options.onSuccess = function (response) {
//response is a JavaScript object
$("#id").html(response.invocationResponse.text);
}
options.onFailure = function (response) {
alert('Failed!'); //You probably want something more meaningful here.
}
WL.Client invokeProcedure(invocationData, options);
There are JavaScript libraries you can add to make searching for values inside the JSON response easier, such as: jspath and jquery-jspath. There's also XPath if you're working with XML.
If you retrieve it as plain text, once you got it back to your application, do something like
$("#container-id").html(response.invocationResponse.text);
This will inject the HTML you've retrieved to an element with id container-id.
When javascript is run in the browser there is no need to try and hide function code because it is downloaded and viewable in source.
When run on the server the situation changes. There are use cases such as api where you want to provide users with functions to call without allowing them to view the code that which is run.
On our specific case we want to execute user submitted javascript inside node. We are able to sandbox node.js api however we would like to add our own api to this sandbox without users being able to toString the function to view the code which is run.
Does anyone have a pattern or know of a way of preventing users from outputting a functions code?
Update:
Here is a full solution (i believe) based on the accepted answer below. Please note that although this is demonstrated using client side code. You would not use this client side as someone can see the contents of your hidden function by simply reading the downloaded code (although it may provide some basic slow down to inspect the code if you have used a minify).
This is meant for server side use where you want to allow users to run api code within a sandbox env but not allow them to view what the api's do. The sandbox in this code is only to demonstrate the point. It is not an actual sandbox implementation.
// function which hides another function by returning an anonymous
// function which calls the hidden function (ie. places the hidden
// function in a closure to enable access when the wraped function is passed to the sandbox)
function wrapFunc(funcToHide) {
var shownFunc = function() {
funcToHide();
};
return shownFunc;
}
// function whose contents you want to hide
function secretFunc() {
alert('hello');
}
// api object (will be passed to the sandbox to enable access to
// the hidden function)
var apiFunc = wrapFunc(secretFunc);
var api = {};
api.apiFunc = apiFunc;
// sandbox (not an actual sandbox implementation - just for demo)
(function(api) {
console.log(api);
alert(api.apiFunc.toString());
api.apiFunc();
})(api);
If you wrap a callback in a function, you can use another function in that scope which is actually hidden from the callback scope, thus:
function hideCall(funcToHide) {
var hiddenFunc = funcToHide;
var shownFunc = function() {
hiddenFunc();
};
return shownFunc;
}
Then run thusly
var shtumCallBack = hideCall(secretSquirrelFunc);
userCode.tryUnwindingThis(shtumCallBack);
The userCode scope will not be able to access secretSquirrelFunc except to call it, because the scope it would need is that of the hideCall function which is not available.
I create a JSonStore with a JSON formatted array of objects.
I have verified it is properly formatted.
I then try to use a dojo forEach loop on it but the JSonStore doesn't seem to have any data in it. I can specify the target in my web page URL and it shows the right data. But using console.log(myJsonStore) shows an object but I don't see the data in Firebug. I also don't see any GET for the service providing the data. It's like specifying the target path in a URL in the browser fires the GET but not when I try to trigger it in the postCreate where my foreach is located.
The answer from Ricardo, i believe is a little incorrect, seeing as the JsonRest.query function returns a dojo.Deferred.
You have a REST call being made asynchroniously through store read api - and once it returns values, it will promise to run whats set as the callback.
Try this for your loop iterator instead
storeObj.query( {} ).then(function ( results ) {
dojo.forEach( results, function( obj ) {
console.log( obj );
});
}
you can do this:
var storeObj = new JsonRest({
target: "/some/resource"
});
storeObj.query({}).forEach(function(obj){console.log(obj);});
that should do the trick