Save object or array in collection variables to have range of numbers to compare in test - variables

Currently, I encountered a small problem.
I have a goal: to test counter(functionality that calculates numbers) in order to check this counter returns a number that falls under set range of low and high (+-5% deviation)
Now, I have this piece of code:
var allLists = JSON.parse(responseBody);
var min = pm.variables.get("count"); // I separately extract min
var max = pm.variables.get("count1"); // and max, but want to extract one variable with min and max;
var low = parseInt(min)
var high = parseInt(max);
console.log("::MIN_VALIE: " + low + " | " + "::MAX_VALUE: " + high);
pm.test("test count", function () {
const value = allLists.data.count;
console.log(":::::::::=> COUNTER: " + value);
pm.expect(typeof value).to.eql('number');
pm.expect(value > low && value < high).to.eql(true);
});
It works ok, but I believe this code is bulky
In order to compare that value in the range of low and high I have to keep low and high number in collection variable, that out of desired 50 variables makes 100 variables and real mess.
Can I somehow keep one variable for low and high value in collection variables?
UPDATE:
Right after posting came up with it:
var allLists = JSON.parse(responseBody);
var num = pm.variables.get("count").split(',');
var min = parseInt(num[0]);
var max = parseInt(num[1]);
console.log("::MIN_VALIE: " + min + " | " + "::MAX_VALUE: " + max);
pm.test("test count", function () {
const value = allLists.data.count;
console.log(":::::::::=> COUNTER: " + value);
pm.expect(typeof value).to.eql('number');
pm.expect(15 > min && 15 < max).to.eql(true);
});
it's much better, but maybe exists better way

Resolved it with JSON.parse. In collection variable the range is written down as In Collection Varibles:
overall_count:[1,99] format, that I wanted to have.
var allLists = JSON.parse(responseBody);
// Here I parse this variable and make parse int to get integer and hurray, I have 1 variable instead of 2
const num = JSON.parse(pm.variables.get("overall_count")); //resolved it with JSON parsing
var min = parseInt(num[0]);
var max = parseInt(num[1]);
pm.test("test count", function () {
const value = allLists.data.count;
pm.expect(typeof value).to.eql('number');
pm.expect(15 > min && 15 < max).to.eql(true);
});

Related

Locate rows with identical values in a column and email each of those rows in 1 email

I am trying to write an Apps script for my google sheet.
Problem: I have data with the following column headings: Email; ID; Category; $Amount; Comment. There are multiple rows that have the same ID. I need all rows with the same ID to be sent in an email to the email address associated with that line.
So the email for example could (doesn't have to be) a table with the data enclosed
[sample email][2]
Can anyone help me with this?
Here is some code I wrote in Apps Script trying to do this on my own but it doesn't work:
var Send = "Y";
function sendEmails() {
//specify the sheet and definitions
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Sheet1');
var lastrow = sheet.getLastRow();
var startrow = 1; // This is the 1st row of data to process
var numrows = lastrow; //This is the number of rows to process
//This section formats the colums so they appear correctly in the html email below
var column = sheet.getRange("A:A");
column.setNumberFormat("#"); //simple plain text format
var column = sheet.getRange("B:B");
column.setNumberFormat("#"); //simple plain text format
var column = sheet.getRange("D:D");
column.setNumberFormat("#"); //simple plain text format
var column = sheet.getRange("E:E");
column.setNumberFormat("#"); //simple plain text format
var column = sheet.getRange("H:H");
column.setNumberFormat("$0.00"); //simple currency format
var column = sheet.getRange("I:I");
column.setNumberFormat("#"); //simple plain text format
var column = sheet.getRange("J:J");
column.setNumberFormat("#"); //simple plain text format
//This section specifies the actual data we will be working with
var datarange = sheet.getRange(startrow, 1, lastrow, 15) // Fetch the range of cells
var data = datarange.getValues(); // Fetch values for each row in the Range.
//Defining the Column data
for (var i = 0; i < data.length; ++i) {
var col = data[i];
var Name = col[0]; //Column starting at 0 from left to right
var EmailAddress = col[1]; //Column starting at 0 from left to right
var Send = col[2]; //Column starting at 0 from left to right
var LeaseID = col[3]; //Column starting at 0 from left to right
var ExpenseCategory = col[4]; //Column starting at 0 from left to right
var TransactionDate = col[5]; //Column starting at 0 from left to right
var Type = col[6]; //Column starting at 0 from left to right
var Amount = col[7]; //Column starting at 0 from left to right
var PayeeName = col[8]; //Column starting at 0 from left to right
var Comment = col[9]; //Column starting at 0 from left to right
var EmailSent = col[10]; //Column starting at 0 from left to right
var Subject = "xxxxxxx June Payment Detail"; //Suject for the email to be sent
var emailintro = //Introduction part of the email
'Hi' + Name + ',<br /><br />' +
'In order to ensure proper account credit, please see the details from this months payment below: <br /><br />'
var emailtrans = 'List' + ExpenseCategory + Amount + Comment + '<br /><br />'
var emailend = // The end of the email
'Please let us know if you have any questions. You may reach us at xxxxx#xxxxx.com'
var me = Session.getActiveUser().getEmail();
var aliases = GmailApp.getAliases(); //Gets the alias xxxxxx#xxxx.com from account
Logger.log(aliases); //logs the alias
//This section is the one that actually sends the emails
//if (EmailAddress != "" && EmailSent !=""{
if (aliases.length > 0) { // Prevents sending duplicates
GmailApp.sendEmail(EmailAddress, subject, emailintro + emailtrans + emailend, {
'from': aliases[0],
'replyto': 'xxxxxx#xxxxxx.com',
htmlbody: emailintro + emailtrans + emailend
});
sheet.getrange(startrow + i, 392).setVaue(SENT);
SpreadsheetApp.flush(); //Make Sure the cell is updated right away in case the script is interrupted
}
}
}
//}}else {}}}

How to count time in chisel with iotesters?

Is there a way to get the step value in iotesters ?
Currently I'm using a var counter but I'm sure there is a better way :
class MyTest (dut: MyModule) extends PeekPokeTester(dut) {
var timeCounter = 0
for(i <- 0 to 10) {
step(1)
timeCounter = timeCounter + 1
}
println("Step value is " + timeCounter)
Is there a getStepValue() like function to get that ?
You can get this using the (presently undocumented) method t.
There's an internal var simTime that is tracking time. This is automatically incremented on a step (just like how you're doing it). The method t lets you query the query its value.

Merging many spreadsheets into report file exceeds maximum execution time

I am using the following script to add rows of files from a student loop in the Google spreadsheet if credits are less than x. The script was working good but as the data in the spreadsheet is being added daily, now the script is throwing "Exceeded maximum execution time" error (we have more than 2000 files). As I am new to scripting I don't know how to optimize the code.
Could someone help me to optimize the code or any solution so that the execution time take less than 5 min. Every time you compare to an email, it has to be compared to many emails. Please Help!
function updated() {
//Final file data (Combined)
var filecombined = SpreadsheetApp.openById("XXXXXXXXXX");
var sheet2 = filecombined.getSheets();
//Folder with all the files
var parentFolder = DriveApp.getFolderById("YYYYYYYYYYYY");
var files = parentFolder.getFiles();
//Current Date
var fecha = new Date();
//Path for each file in the folder
while (files.hasNext()) {
var idarchivo = files.next().getId();
var sps = SpreadsheetApp.openById(idarchivo);
var sheet = sps.getSheetByName('STUDENT PROFILE');
var data = sheet.getDataRange().getValues();
var credits = data[5][1];
//Flat; bandera:1 (new row), bandera:2 (update row)
var bandera = 1;
//Take data from final file (Combined)
var data2 = sheet2[0].getDataRange().getValues();
//If credits are less than X: write
if (credits < 120) {
var email = data[2][1];
var lastrow = filecombined.getLastRow();
var u = 0;
//comparison loop by email, if found it, update and exit the loop
while (u < lastrow) {
u = u + 1;
if (email == data2[u - 1][1]) {
sheet2[0].getRange(u, 3).setValue(credits);
sheet2[0].getRange(u, 4).setValue(fecha);
u = lastrow;
bandera = 2;
}
}
//if that email does not exist, write a new row
if (bandera == 1) {
var nombre = data[0][1];
sheet2[0].getRange(lastrow + 1, 1).setValue(nombre);
sheet2[0].getRange(lastrow + 1, 2).setValue(email);
sheet2[0].getRange(lastrow + 1, 3).setValue(credits);
sheet2[0].getRange(lastrow + 1, 4).setValue(fecha);
}
}
}
SpreadsheetApp.flush();
}
The questioner's code is taking taking more than 4-6 minutes to run and is getting an error Exceeded maximum execution time.
The following answer is based solely on the code provided by the questioner. We don't have any information about the 'filecombined' spreadsheet, its size and triggers. We are also in the dark about the various student spreadsheets, their size, etc, except that we know that there are 2,000 of these files. We don't know how often this routine is run, nor how many students have credits <120.
getvalues and setvalues statements are very costly; typically 0.2 seconds each. The questioners code includes a variety of such statements - some are unavoidable but others are not.
In looking at optimising this code, I made two major changes.
1 - I moved line 27 var data2 = sheet2[0].getDataRange().getValues();
This line need only be executed once and I relocated it at the top of the code just after the various "filecombined" commands. As it stood, this line was being executed once for every student spreadsheet; this along may have contributed to several minutes of execution time.
2) I converted certain setvalue commands to an array, and then updated the "filecombined" spreadsheet from the array once only, at the end of the processing. Depending on the number of students with low credits and who are not already on the "filecombined" sheet, this may represent a substantial saving.
The code affected was lines 47 to 50.
line47: sheet2[0].getRange(lastrow+1, 1).setValue(nombre);
line48: sheet2[0].getRange(lastrow+1, 2).setValue(email);
line49: sheet2[0].getRange(lastrow+1, 3).setValue(credits);
line50: sheet2[0].getRange(lastrow+1, 4).setValue(fecha);
There are setvalue commands also executed at lines 38 and 39 (if the student is already on the "filecombined" spreadsheet), but I chose to leave these as-is. As noted above, we don't know how many such students there might be, and the cost of these setvalue commands may be minor or not. Until this is clear, and in the light of other time savings, I chose to leave them as-is.
function updated() {
//Final file data (Combined)
var filecombined = SpreadsheetApp.openById("XXXXXXXXXX");
var sheet2 = filecombined.getSheets();
//Take data from final file (Combined)
var data2 = sheet2[0].getDataRange().getValues();
// create some arrays
var Newdataarray = [];
var Masterarray = [];
//Folder with all the files
var parentFolder = DriveApp.getFolderById("YYYYYYYYYYYY");
var files = parentFolder.getFiles();
//Current Date
var fecha = new Date();
//Path for each file in the folder
while (files.hasNext()) {
var idarchivo = files.next().getId();
var sps = SpreadsheetApp.openById(idarchivo);
var sheet = sps.getSheetByName('STUDENT PROFILE');
var data = sheet.getDataRange().getValues();
var credits = data[5][1];
//Flat; bandera:1 (new row), bandera:2 (update row)
var bandera = 1;
//If credits are less than X: write
if (credits < 120){
var email = data[2][1];
var lastrow = filecombined.getLastRow();
var u = 0;
//comparison loop by email, if found it, update and exit the loop
while (u < lastrow) {
u = u + 1;
if (email == data2[u-1][1]){
sheet2[0].getRange(u, 3).setValue(credits);
sheet2[0].getRange(u, 4).setValue(fecha);
u = lastrow;
bandera = 2;
}
}
//if that email does not exist, write a new row
if(bandera == 1){
var nombre = data[0][1];
Newdataarray = [];
Newdataarray.push(nombre);
Newdataarray.push(email);
Newdataarray.push(credits);
Newdataarray.push(fecha);
Masterarray.push(Newdataarray);
}
}
}
// update the target sheet with the contents of the array
// these are all adding new rows
lastrow = filecombined.getLastRow();
sheet2[0].getRange(lastrow+1, 1, Masterarray.length, 4);
sheet2[0].setValues(Masterarray);
SpreadsheetApp.flush();
}
As I mentioned in my comment, the biggest issue you have is that you repeatedly search an array for a value, when you could use a much faster lookup function.
// Create an object that maps an email address to the (last) array
// index of that email in the `data2` array.
const knownEmails = data2.reduce(function (acc, row, index) {
var email = row[1]; // email is the 2nd element of the inner array (Column B on a spreadsheet)
acc[email] = index;
return acc;
}, {});
Then you can determine if an email existed in data2 by trying to obtain the value for it:
// Get this email's index in `data2`:
var index = knownEmails[email];
if (index === undefined) {
// This is a new email we didn't know about before
...
} else {
// This is an email we knew about already.
var u = ++index; // Convert the array index into a worksheet row (assumes `data2` is from a range that started at Row 1)
...
}
To understand how we are constructing knownEmails from data2, you may find the documentation on Array#reduce helpful.

PL/SQL - Aggregate values & Write to table

I am just starting to dabble in PL/SQL so this question may be very straightforward. Here is the scenario:
I have several checkboxes which carry a weighted numeric value. For example:
Checkbox I --> Value '5'
Checkbox II --> Value '10'
Checkbox III --> Value '15'
etc.
The form would have 15 checkboxes in total and the end-user can select anywhere from 0 to all 15. As they select the checkboxes, the total weight would get calculated and a final numeric value would be displayed. For example. checking off 3 Checkbox I & 2 Checkbox III would = 45 points.
Now the total value of 45 would equal to a separate value. Example:
At 0 points, value = 'Okay'
1-15 points, value = 'Error'
16-30 points, value = 'Warning'
31+ points, value = 'Critical'
The form itself is built within Oracle APEX and I can do it using Dynamic Actions but using PL/SQL may be a better solution.
In summary, I'd like the hidden field to first calculate the total from the checked checkboxes and then use that total to figure out the value of either Okay, Error, Warning, or Critical.
Any assistance is much appreciated!
In my experience, it is better if we're going to use javascript on your case since we have to manipulate DOM and events of the checkboxes. If you want to display/change item values and get values at runtime, then javascript is better in doing that than PLSQL unless you want to submit your page every time you check/uncheck a box in your page which is not advisable.
Here is my solution for your question.
First, create a Display Only item on your page. This is where the values "Okay", "Error", "Warning", or "Critical" will appear. And its very important to set it's default value to 0. Then inside your page's "Function and Global Declaration" part, put the following functions:
function getcheck(checkbox_id,displayOnly_id){
var chkboxName = document.getElementById(checkbox_id + "_0").getAttribute("name");
var chks = document.getElementsByName(chkboxName);
var howmanychecks = chks.length;
var currentSum=0;
var v_remarks = "";
for(x=0;x<howmanychecks;x++){
chks[x].setAttribute("onchange","checkIfchecked(this,\'" + displayOnly_id + "\')");
if(chks[x].checked){
currentSum = currentSum + Number(chks[x].value);
}
}
if(currentSum==0){
v_remarks = "Okay";
}
else if(currentSum>0 && currentSum<=15){
v_remarks = "Error";
}
else if(currentSum>15 && currentSum<=30){
v_remarks = "Warning";
}
else{
v_remarks = "Critical";
}
document.getElementById(displayOnly_id).value = currentSum;
document.getElementById(displayOnly_id + "_DISPLAY").innerHTML = currentSum + ": " + v_remarks;
}
function checkIfchecked(p_element, displayOnly_id){
var v_difference;
var v_sum = Number($v(displayOnly_id));
var displayOnly_display = displayOnly_id + "_DISPLAY";
var v_remarks = "";
if(p_element.checked){
v_sum = v_sum + Number(p_element.value);
$("#" + displayOnly_id).val(v_sum);
}
else{
v_difference=Number($("#" + displayOnly_id).val())-Number(p_element.value);
if(v_difference<0){
v_difference=0;
}
$("#" + displayOnly_id).val(v_difference);
}
if($("#" + displayOnly_id).val()==0){
v_remarks = "Okay";
}
else if($("#" + displayOnly_id).val()>0 && $("#" + displayOnly_id).val()<=15){
v_remarks = "Error";
}
else if($("#" + displayOnly_id).val()>15 && $("#" + displayOnly_id).val()<=30){
v_remarks = "Warning";
}
else{
v_remarks = "Critical";
}
document.getElementById(displayOnly_display).innerHTML=$("#" + displayOnly_id).val() + ": " + v_remarks;
}
The above functions will get the sum of the values of those boxes that are checked. A value of a box will be taken out of the current sum if it is unchecked as well. It will also display the remarks for the current checked points whether if it is "Okay", "Error", "Warning", or "Critical".
In your "Execute when Page Loads" part of your page, add the following line:
getcheck(nameofyourcheckboxitem,nameofyourdisplayonlyitem);
where nameofyourcheckboxitem is the name of your Check Box and nameofyourdisplayonlyitem is the name of the Display Only item you have just created.
Here's a sample line on how to use the function that I've given you:
getcheck("P1_MYCHECKBOX","P1_MYDISPLAYONLY");

Exceeded maximum execution time on Google App script with Google Big Query

How can I extend the execution time within my code below. Essentially, I use Google App scripts to query data from our big query data base and export data on to Google spreadsheets.
The following is my code:
function Weekly_Metric(){
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheetName = "Budget";
var sheet = ss.getSheetByName(sheetName);
ss.setActiveSheet(sheet);
var sql = ' bigqueryscript ';
var results = GSReport.runQueryAsync(sql);
var resultsValues = GSReport.parseBigQueryAPIResponse(results);
sheet.clear();
ss.appendRow(["Label1", "Label2", "Label3"]);
for ( var i = 0 ; i < resultsValues.length ; i++ ) {
ss.appendRow(resultsValues[i]);
}
}
Always reduce the number of calls to Google Apps Script services as much as you can.
In this case, the loop containing appendRow() can be replaced with javascript array operations and a single call to setValues().
...
sheet.clear();
var data = [];
data.push(["Label1", "Label2", "Label3"]);
for ( var i = 0 ; i < resultsValues.length ; i++ ) {
data.push(resultsValues[i]);
}
ss.getRange(1,1,data.length,data[0].length).setValues(data);
...
Alternatively, if resultsValues is an array of rows already, you only need to add the labels:
...
sheet.clear();
resultsValues.unshift(["Label1", "Label2", "Label3"]);
ss.getRange(1,1,resultsValues.length,resultsValues[0].length).setValues(resultsValues);
...
If that doesn't do the trick, then you should look at your GSReport object's methods.