SQL query with async each - sql

My problem is when I am getting array of users and trying to run async each it start each sqlRequest and not going one by one pushing in array.
It should do sqlRequest 1 by 1, and not do all by each user sqlRequest and the push in an array.
Here is a async each
function getUserFavCat(params, callback) {
var usersArrayCat = [];
async.each(params, function (user, cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else if (result.length == 0) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
usersArrayCat.push(user);
}
cb();
})
}, function() {
callback(null, usersArrayCat)
});
};
Here is the SQL query:
function sqlRequest (sqlQuery, callback) {
var connection = new sql.Connection(sql_conf, function (err) {
if (err){
console.log(err)
} else {
var request = new sql.Request(connection);
request.query(sqlQuery, function(err, result) {
console.log(result)
if(err){
console.error(err)
} else if(!result){
console.error("NO RESPONSE SQL QUERY")
} else {
callback(null, result);
connection.close();
}
})
}
});
connection.on('error', function(err) {
console.log(err);
});
};

use async.eachLimit to limit the no. of request
function getUserFavCat(params, callback) {
var usersArrayCat = [];
console.log(`length of array ${params.length}`)
// 1 here means 1 request at a time
async.eachLimit(params, 1, function (user, cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else if (result.length == 0) {
//console.error("NO FAVOURITE CATEGORY FOR USER " + JSON.stringify(user))
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
usersArrayCat.push(user);
cb();
}
})
}, function (err) {
if (err) return callback(err);
callback(null, usersArrayCat)
});
};

Try this trick by using async.map and push for every callback to an array. Then you can use async.parallel to filter out the callback results for the success user and push it to usersArrayCat arrays
function getUserFavCat(params, callback) {
var usersArrayCat = [], callbackArrays = [];
async.map(params, function (user, cb) {
callbackArrays.push(function (cb) {
sqlRequest("SELECT b_cat.title, b_cat.id FROM dbo.Students st INNER JOIN dbo.SaleView sv ON sv.userId = st.id INNER JOIN dbo.KEY_BrandcategoryToSale b_key ON b_key.saleId = sv.saleId INNER JOIN dbo.BrandCategories b_cat ON b_cat.id = b_key.brandCategoryId WHERE st.id = " + user.id, function (err, result) {
if (!result) {
user.status = '99'; // error status
cb(null, user);
} else if (result.length == 0) {
user.status = '99'; // error status
cb(null, user);
} else {
user.favouriteCat = utils.takeMostRepeatingObj(result);
user.status = '00'; //success status
cb(null, user);
}
});
}, function(err, results) {
// comes here after all individual async calls have completed
// check errors; array of results is in data
cb(null, results)
});
async.parallel(callbackArrays, function (err, results) {
results.forEach (function (elem, ind) {
if (elem.status == '00') {
usersArrayCat.push(elem);
}
});
});
};

Related

Syntax required for conditional variable use to modify SQL query in Node.JS

I've fairly new to NodeJS, and I'm not sure of the best method or syntax to create an MS SQL query with conditional code. Here's what I want to do, with the query greatly simplified, and using some pseudocode:
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query`
SELECT Reference
FROM TABLE
WHERE Status = 'Done' ` +
if(type === 1) {
`AND Station_1 = #station`
} else if(type === 2) {
`AND Station_2 = #station`
} else {
`AND Station_3 = #station`
}
+ `AND Process = 5`
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
Depending on the value of "type" supplied to the function, I want the query to reference a different DB column.
UPDATE:
So I've found that the following works, although arguably the formatting isn't quite as nice.
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let station_column
if(type === 1) {
station_column = 'AND Station_1 = #station'
} else if(type === 2) {
station_column = 'AND Station_2 = #station'
} else {
station_column = 'AND Station_3 = #station'
}
let query = `
SELECT Reference
FROM TABLE
WHERE Status = 'Done'
${station_column}
AND Process = 5`
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query(query)
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
I tried just using the template literal substitutions directly in the query, but that wouldn't work. (Perhaps for reasons stated here: https://github.com/tediousjs/node-mssql#es6-tagged-template-literals )
If I don't get any better answer, I'll post this as the answer; but would like to know if there's a best practice method for doing this.
Seems like this works, and isn't overly complicated:
// #route GET /api/flow/data/references
async function getDataReferences(req, res) {
const { station, type } = req.query
let station_column
if(type === 1) {
station_column = 'AND Station_1 = #station'
} else if(type === 2) {
station_column = 'AND Station_2 = #station'
} else {
station_column = 'AND Station_3 = #station'
}
let query = `
SELECT Reference
FROM TABLE
WHERE Status = 'Done'
${station_column}
AND Process = 5`
let pool
try {
pool = await sql.connect(config)
const { recordset } = await pool
.request()
.input('station', sql.NVarChar(50), station).query(query)
const processedData = recordset.map((item) => item.Reference)
res.json(processedData)
} catch (error) {
console.log(
`ERROR with Station: ${station} with Type: ${type}`,
error.message,
new Date()
)
res.status(500).json({ message: error.message })
} finally {
await pool.close()
}
}
Essentially, create the full query string in advance, including the parameters to bind, and then pull that whole string in as the query.

Management dates on sql server with node.js

the code below performs a select on a sql server database, when the code is executed the following error is generated, i have this error: TypeError: parameter.value.getTime is not a function
Input Parameter:
IdUtente=2
dataInizio=01-07-2018
datafine=02-09-2018
Date:
01-08-2018
01-10-2018
01-11-2018
02-01-2019
02-08-2018
JavaScript:
async function CaricaDataeTotaleOre(IdUtente,dataInizio,datafine) {
console.log("Carica Data e Totale Ore -- IdUtente: "+IdUtente+"\n Data Inizio: "+dataInizio+"\n Data Fine: "+datafine);
var data = [];
var query = "SET LANGUAGE 'Italian' SELECT Distinct CONVERT(varchar(10), DataCreazione, 105) as Data FROM Marcatura inner join Utente on Utente.IdUtente = Marcatura.IdUtente where Utente.IdUtente = #IdUtente and(CONVERT(VARCHAR(10),Marcatura.DataCreazione,103) between #Start and #End) ";
const ret = await new Promise((resolve, reject) => {
new sql.ConnectionPool(DbConfig.config).connect().then(pool => {
return pool.request().input('IdUtente', sql.Int, IdUtente).input('Start', sql.DateTime, dataInizio).input('End', sql.DateTime, datafine).query(query)
}).then(result => {
resolve(result);
sql.close();
}).catch(err => {
ManageError.SendError("Errore CaricaDataeTotaleOre con : " + IdUtente + "\n Errore: " + err);
reject(err)
sql.close();
});
});
for (var i = 0; i < ret.recordset.length; i++) {
data.push({
Data: ret.recordset[i].Data
})
}
return data;
}

Trello API add base64 data image as an attachement

I'd like to send base64 image as an attachment to a trello card through the API
POST /1/cards/[card id or shortlink]/attachments
There's a file field but it does not specify how should look the data there.
Refs: https://developers.trello.com/advanced-reference/card#post-1-cards-card-id-or-shortlink-attachments
Any idea?
Short answer: Trello's API only works to attach binary data via multipart/form-data. Examples below.
Long answer:
The Trello API to add attachments and images is frustratingly under-documented. They do have a coffeescript Client.js for those of us using Javascript to simplify all the basic operations: https://trello.com/1/client.coffee
Using the vanilla Client.js file I have been able to attach links and text files. While the CURL example shows pulling a binary file in from a hard drive, that doesn't work for those of us completely on a server or client where we don't have permissions to create a file.
From a LOT of trial and error, I've determined all binary data (images, documents, etc.) must be attached using multipart/form-data. Here is a jQuery snippet that will take a URL to an item, get it into memory, and then send it to Trello.
var opts = {'key': 'YOUR TRELLO KEY', 'token': 'YOUR TRELLO TOKEN'};
var xhr = new XMLHttpRequest();
xhr.open('get', params); // params is a URL to a file to grab
xhr.responseType = 'blob'; // Use blob to get the file's mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData(); // this is the formdata Trello needs
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
I have submitted a new coffeescript for Trello developer support to consider uploading to replace Client.js. It adds a "Trello.upload(url)" that does this work.
I've also attached here for convenience in JS form.
// Generated by CoffeeScript 1.12.4
(function() {
var opts={"version":1,"apiEndpoint":"https://api.trello.com","authEndpoint":"https://trello.com"};
var deferred, isFunction, isReady, ready, waitUntil, wrapper,
slice = [].slice;
wrapper = function(window, jQuery, opts) {
var $, Trello, apiEndpoint, authEndpoint, authorizeURL, baseURL, collection, fn, fn1, i, intentEndpoint, j, key, len, len1, localStorage, location, parseRestArgs, readStorage, ref, ref1, storagePrefix, token, type, version, writeStorage;
$ = jQuery;
key = opts.key, token = opts.token, apiEndpoint = opts.apiEndpoint, authEndpoint = opts.authEndpoint, intentEndpoint = opts.intentEndpoint, version = opts.version;
baseURL = apiEndpoint + "/" + version + "/";
location = window.location;
Trello = {
version: function() {
return version;
},
key: function() {
return key;
},
setKey: function(newKey) {
key = newKey;
},
token: function() {
return token;
},
setToken: function(newToken) {
token = newToken;
},
rest: function() {
var args, error, method, params, path, ref, success;
method = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
ref = parseRestArgs(args), path = ref[0], params = ref[1], success = ref[2], error = ref[3];
opts = {
url: "" + baseURL + path,
type: method,
data: {},
dataType: "json",
success: success,
error: error
};
if (!$.support.cors) {
opts.dataType = "jsonp";
if (method !== "GET") {
opts.type = "GET";
$.extend(opts.data, {
_method: method
});
}
}
if (key) {
opts.data.key = key;
}
if (token) {
opts.data.token = token;
}
if (params != null) {
$.extend(opts.data, params);
}
if (method === 'UPLOAD' && typeof (params) === "string" && params.length > 5) {
var xhr = new XMLHttpRequest();
xhr.open('get', params);
xhr.responseType = 'blob'; // Use blob to get the mimetype
xhr.onload = function() {
var fileReader = new FileReader();
fileReader.onload = function() {
var filename = (params.split('/').pop().split('#')[0].split('?')[0]) || params || '?'; // Removes # or ? after filename
var file = new File([this.result], filename);
var form = new FormData();
form.append("file", file);
$.each(['key', 'token'], function(iter, item) {
form.append(item, opts.data[item] || 'ERROR! Missing "' + item + '"');
});
$.extend(opts, {
method: "POST",
data: form,
cache: false,
contentType: false,
processData: false
});
return $.ajax(opts);
};
fileReader.readAsArrayBuffer(xhr.response); // Use filereader on blob to get content
};
xhr.send();
} else {
return $.ajax(opts);
}
},
authorized: function() {
return token != null;
},
deauthorize: function() {
token = null;
writeStorage("token", token);
},
authorize: function(userOpts) {
var k, persistToken, ref, regexToken, scope, v;
opts = $.extend(true, {
type: "redirect",
persist: true,
interactive: true,
scope: {
read: true,
write: false,
account: false
},
expiration: "30days"
}, userOpts);
regexToken = /[&#]?token=([0-9a-f]{64})/;
persistToken = function() {
if (opts.persist && (token != null)) {
return writeStorage("token", token);
}
};
if (opts.persist) {
if (token == null) {
token = readStorage("token");
}
}
if (token == null) {
token = (ref = regexToken.exec(location.hash)) != null ? ref[1] : void 0;
}
if (this.authorized()) {
persistToken();
location.hash = location.hash.replace(regexToken, "");
return typeof opts.success === "function" ? opts.success() : void 0;
}
if (!opts.interactive) {
return typeof opts.error === "function" ? opts.error() : void 0;
}
scope = ((function() {
var ref1, results;
ref1 = opts.scope;
results = [];
for (k in ref1) {
v = ref1[k];
if (v) {
results.push(k);
}
}
return results;
})()).join(",");
switch (opts.type) {
case "popup":
(function() {
var authWindow, height, left, origin, receiveMessage, ref1, top, width;
waitUntil("authorized", (function(_this) {
return function(isAuthorized) {
if (isAuthorized) {
persistToken();
return typeof opts.success === "function" ? opts.success() : void 0;
} else {
return typeof opts.error === "function" ? opts.error() : void 0;
}
};
})(this));
width = 420;
height = 470;
left = window.screenX + (window.innerWidth - width) / 2;
top = window.screenY + (window.innerHeight - height) / 2;
origin = (ref1 = /^[a-z]+:\/\/[^\/]*/.exec(location)) != null ? ref1[0] : void 0;
authWindow = window.open(authorizeURL({
return_url: origin,
callback_method: "postMessage",
scope: scope,
expiration: opts.expiration,
name: opts.name
}), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
receiveMessage = function(event) {
var ref2;
if (event.origin !== authEndpoint || event.source !== authWindow) {
return;
}
if ((ref2 = event.source) != null) {
ref2.close();
}
if ((event.data != null) && /[0-9a-f]{64}/.test(event.data)) {
token = event.data;
} else {
token = null;
}
if (typeof window.removeEventListener === "function") {
window.removeEventListener("message", receiveMessage, false);
}
isReady("authorized", Trello.authorized());
};
return typeof window.addEventListener === "function" ? window.addEventListener("message", receiveMessage, false) : void 0;
})();
break;
default:
window.location = authorizeURL({
redirect_uri: location.href,
callback_method: "fragment",
scope: scope,
expiration: opts.expiration,
name: opts.name
});
}
},
addCard: function(options, next) {
var baseArgs, getCard;
baseArgs = {
mode: 'popup',
source: key || window.location.host
};
getCard = function(callback) {
var height, left, returnUrl, top, width;
returnUrl = function(e) {
var data;
window.removeEventListener('message', returnUrl);
try {
data = JSON.parse(e.data);
if (data.success) {
return callback(null, data.card);
} else {
return callback(new Error(data.error));
}
} catch (error1) {}
};
if (typeof window.addEventListener === "function") {
window.addEventListener('message', returnUrl, false);
}
width = 500;
height = 600;
left = window.screenX + (window.outerWidth - width) / 2;
top = window.screenY + (window.outerHeight - height) / 2;
return window.open(intentEndpoint + "/add-card?" + $.param($.extend(baseArgs, options)), "trello", "width=" + width + ",height=" + height + ",left=" + left + ",top=" + top);
};
if (next != null) {
return getCard(next);
} else if (window.Promise) {
return new Promise(function(resolve, reject) {
return getCard(function(err, card) {
if (err) {
return reject(err);
} else {
return resolve(card);
}
});
});
} else {
return getCard(function() {});
}
}
};
ref = ["GET", "PUT", "POST", "DELETE", "UPLOAD"];
fn = function(type) {
return Trello[type.toLowerCase()] = function() {
return this.rest.apply(this, [type].concat(slice.call(arguments)));
};
};
for (i = 0, len = ref.length; i < len; i++) {
type = ref[i];
fn(type);
}
Trello.del = Trello["delete"];
ref1 = ["actions", "cards", "checklists", "boards", "lists", "members", "organizations", "lists"];
fn1 = function(collection) {
return Trello[collection] = {
get: function(id, params, success, error) {
return Trello.get(collection + "/" + id, params, success, error);
}
};
};
for (j = 0, len1 = ref1.length; j < len1; j++) {
collection = ref1[j];
fn1(collection);
}
window.Trello = Trello;
authorizeURL = function(args) {
var baseArgs;
baseArgs = {
response_type: "token",
key: key
};
return authEndpoint + "/" + version + "/authorize?" + $.param($.extend(baseArgs, args));
};
parseRestArgs = function(arg) {
var error, params, path, success;
path = arg[0], params = arg[1], success = arg[2], error = arg[3];
if (isFunction(params)) {
error = success;
success = params;
params = {};
}
path = path.replace(/^\/*/, "");
return [path, params, success, error];
};
localStorage = window.localStorage;
if (localStorage != null) {
storagePrefix = "trello_";
readStorage = function(key) {
return localStorage[storagePrefix + key];
};
writeStorage = function(key, value) {
if (value === null) {
return delete localStorage[storagePrefix + key];
} else {
return localStorage[storagePrefix + key] = value;
}
};
} else {
readStorage = writeStorage = function() {};
}
};
deferred = {};
ready = {};
waitUntil = function(name, fx) {
if (ready[name] != null) {
return fx(ready[name]);
} else {
return (deferred[name] != null ? deferred[name] : deferred[name] = []).push(fx);
}
};
isReady = function(name, value) {
var fx, fxs, i, len;
ready[name] = value;
if (deferred[name]) {
fxs = deferred[name];
delete deferred[name];
for (i = 0, len = fxs.length; i < len; i++) {
fx = fxs[i];
fx(value);
}
}
};
isFunction = function(val) {
return typeof val === "function";
};
wrapper(window, jQuery, opts);
}).call(this);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.2.3/jquery.min.js"></script>

SQL tedious add array as parameter

I'm running this SQL query with tedious.js using parameters:
var query = "select * from table_name where id in (#ids)";
request = new sql.Request(query, function(err, rowCount) {
if (err) {
}
});
request.on('row', function(columns) {
});
var id = [1, 2, 3];
request.addParameters('ids', TYPES.Int, id);
connection.execSql(request);
because I am looking for items that matches the ID provided with where ... in ... clause, I need to pass in an array. However, there is no TYPES.Array. How do I this properly?
for this query, i think you'll just have to manually build the entire sql string. the TYPES enum values are for the datatypes in the database, not in your JavaScript code.
//you can like this:
var userIds = result.map(function (el) {
return el.UserId;
}).join(',');
var params = [{
name: 'userIds',
type: TYPES.VarChar,
value: userIds,
options: null}];
var querySql = ['SELECT COUNT([MomentId]) FROM [T_Moment]',
'WHERE [RecordStatus] = ', sysConst.recordStatus.activation, " AND CHARINDEX(','+RTRIM([UserId])+',' , ','+ #userIds +',')>0 "].join(' ');
dbHelper.count(querySql, params, function (err, result) {
if (err) {
callback('error--');
} else {
callback(null, result);
}
});
Try creating the in clause parameters for query dynamically.
// create connection
let ids = [1, 2, 3];
let inClauseParamters = createInClauseParameters();
let query = `select * from table_name where id in (${inClauseParamters})`;
let request = new Request(query, (err, rowCount) => {
if (err) { /* handle error */ }
});
request.on('row', (columns) => { /* get row */});
request = addRequestParameters(ids, request);
connection.execSql(request);
function createInClauseParameters(values) {
return values.map((val, index) => `#Value${index}`).join(',');
}
function addRequestParameters(values, request) {
values.forEach((val, index) => {
request.addParameter(`Value${index}`, TYPES.VarChar, val);
});
return request;
}

Custom Authentication Azure Mobile Services by Api

I am creating a custom authentication via API on Azure Mobile Service, and picked based on this answer:
Registering and login users in Azure Mobile Services
Then joined with the code of the previous link to create the authentication token.
But I get "internal server error" when I invoke the API. The error happens in here: "...results.length..."
var crypto = require('crypto');
var iterations = 1000;
var bytes = 32;
var aud = "Custom";
var masterKey = "wkeHEoWUaPJSHsSOcWgmVLOZbIpeeg92";
var _request;
var _response;
exports.post = function(request, response) {
var user = request.body.userName;
var pass = request.body.password;
_request = request;
_response = response
validateUserNamePassword(user, pass, function(error, userId, token) {
if (error) {
response.send(401, { error: "Unauthorized" });
} else {
response.send(200, { user: userId, token: token });
}
});
}
function validateUserNamePassword(user, pass, funcao){
var accounts = _request.service.tables.getTable('account');
accounts
.where({ userid : user })
.read({
success: function(results)
{
if (results.length === 0)
{
_response.send(401, { error: "Unauthorized1" });
console.log("Incorrect username or password");
_request.respond(401, "Incorrect username or password");
}
else
_response.send(401, { error: "Unauthorized2" });
var account = results[0];
hash(item.password, account.salt, function(err, h) {
var incoming = h;
if (slowEquals(incoming, account.password)) {
var expiry = new Date().setUTCDate(new Date().getUTCDate() + 30);
var userId = aud + ":" + account.id;
_request.respond(200, {
userId: userId,
token: zumoJwt(expiry, aud, userId, masterKey)
});
}
else {
_request.respond(401, "Incorrect username or password");
}
});
}
}
});
}
function hash(text, salt, callback) {
crypto.pbkdf2(text, salt, iterations, bytes, function(err, derivedKey){
if (err) { callback(err); }
else {
var h = new Buffer(derivedKey).toString('base64');
callback(null, h);
}
});
}
function slowEquals(a, b) {
var diff = a.length ^ b.length;
for (var i = 0; i < a.length && i < b.length; i++) {
diff |= (a[i] ^ b[i]);
}
return diff === 0;
}
function zumoJwt(expiryDate, aud, userId, masterKey) {
var crypto = require('crypto');
function base64(input) {
return new Buffer(input, 'utf8').toString('base64');
}
function urlFriendly(b64) {
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(new RegExp("=", "g"), '');
}
function signature(input) {
var key = crypto.createHash('sha256').update(masterKey + "JWTSig").digest('binary');
var str = crypto.createHmac('sha256', key).update(input).digest('base64');
return urlFriendly(str);
}
var s1 = '{"alg":"HS256","typ":"JWT","kid":0}';
var j2 = {
"exp":expiryDate.valueOf() / 1000,
"iss":"urn:microsoft:windows-azure:zumo",
"ver":1,
"aud":aud,
"uid":userId
};
var s2 = JSON.stringify(j2);
var b1 = urlFriendly(base64(s1));
var b2 = urlFriendly(base64(s2));
var b3 = signature(b1 + "." + b2);
return [b1,b2,b3].join(".");
}
I'm invoking like this:
try
{
var loginInput = new JObject();
loginInput.Add("userName", "breno");
loginInput.Add("password", "test");
var loginResult = await LoginAuthenticationService.InvokeApiAsync("login", loginInput);
LoginAuthenticationService.CurrentUser = new MobileServiceUser((string)loginResult["user"]);
LoginAuthenticationService.CurrentUser.MobileServiceAuthenticationToken = (string)loginResult["token"];
}
catch (MobileServiceInvalidOperationException e)
{
var exception = e;
}
If you're getting this error "Failed to load script file 'login.js': SyntaxError: Unexpected token }" as seen in the comments, there is a syntax issue with your script. You'll need to go through your scripts and figure out where the issue is at.