Find MAX(date) from HTML5 indexedDB - sql

I'm currently using indexdDB to store offline data of some records in a sales store. The store has columns such as id, shopname, and lastsaledate. I would like some help performing the same operation as the following SQL statement using indexedDB:
SELECT MAX(LastSaleDate) FROM Sales;
Any suggestions?

Ensure you have an index for the lastsaledate property, e.g. when upgrading the database do:
store.createIndex('by_lastsaledate', 'lastsaledate');
When querying, use a reverse cursor ('prev') and null range (i.e. all records):
var store = transaction.objectStore('records');
var index = store.index('by_lastsaledate');
var request = index.openCursor(/*query*/null, /*direction*/'prev');
request.onsuccess = function() {
var cursor = request.result;
if (cursor) {
console.log('max date is: ' + cursor.key);
} else {
console.log('no records!');
}
};

Related

Suitescript: copying sublist data from one record to another

I have a before load user event function on an invoice record that create a button called 'create vendor bill'.
When this button is pressed, a new vendor bill record is opened. The UE script:
/**
*#NApiVersion 2.x
*#NScriptType UserEventScript
*/
define([
"N/url",
"N/record",
"N/runtime",
"N/ui/serverWidget",
"N/redirect",
], function (url, record, runtime, serverWidget, redirect) {
var exports = {};
/**
* #param {UserEventContext.beforeLoad} context
*/
function beforeLoad(context) {
if (
context.type == context.UserEventType.EDIT ||
context.type == context.UserEventType.VIEW
) {
var record = context.newRecord;
var recordId = record.id;
var recordType = record.type;
var customer = record.getValue({ fieldId: "entity" });
log.debug("entity", customer);
var scriptObj = runtime.getCurrentScript();
var customForm = scriptObj.getParameter({
name: "custscript_custom_form_vb",
});
var recordSublist = record.getSublist({ sublistId: "item" });
log.debug("item", recordSublist);
var form = context.form;
log.debug("form", form);
var userVarStr = record;
log.debug("uservarstr", userVarStr);
var userVarURL = url.resolveRecord({
recordType: "vendorbill",
params: {
entity: parseInt(customer),
supportcase: recordId,
cf: parseInt(customForm),
},
});
form.addButton({
id: "custpage_button_test",
label: "Create Vendor Bill",
functionName: "getDetails('" + userVarURL + "')",
});
}
}
exports.beforeLoad = beforeLoad;
return exports;
});
Once the page redirects to the vendor bill form, a client script (deployed on the form), sets the field values on the body of the vendor bill using the parameters passed in the url
This is working as expected.
Where I am getting stuck is trying to work out how to pass the 'item' sublist values to from the invoice to the vendor bill?
Would I pass this as an array?
From what I understand, there is a limit to the number of characters that can be passed via the url.
I can't find anything online or in the Netsuite documentation that deals with passing sublist values between records
For starters I would want to see the Client Script.
One option would be to only pass the Invoice Record ID and Type. Then you can create a Suitelet to be used as a proxy and get the sublist data by a saved search.
Something to keep in mind is that if the sublist is very very long you may reach a execution timeout so you may want to consider triggering a MapReduce script to populate the sublist again you would pass it the recType and ID of the invoice and vendor bill and then use a saved search to get the data.
There are other approaches but I would need to see the client script.

Filter cached sqlJdbs query in Pentaho CE

I use sqlJdbs query as a data provider for my CCC controls. I use geospatial request in my query that's why I cache my results(Cache=True). Otherwise the request made long.
It works fine. However I have to use parameters in my query to filter resulting rows:
SELECT ...
FROM ...
WHERE someField IN (${aoi_param})
Is there some way to cache full set of rows and then apply WHERE to cached results without rebuilding new cache for each set of values in the ${aoi_param}?
What is the best practice?
So, I am not really sure that it is the best practice, but I solved my problem this way:
I included aoi_param to the Listeners and Parameters of my chart control
Then I filtered data set in Post Fetch:
function f(data){
var _aoi_param = this.dashboard.getParameterValue('${p:aoi_param}');
function isInArray(myValue, myArray) {
var arrayLength = myArray.length;
for (var i = 0; i < arrayLength; i++) {
if (myValue == myArray[i]) return true;
}
return false;
}
function getFiltered(cdaData, filterArray) {
var allCdaData = cdaData;
cdaData = {
metadata: allCdaData.metadata,
resultset: allCdaData.resultset.filter(function(row){
// 2nd column is an AOI id in my dataset
return isInArray(row[2], filterArray);
})
};
return cdaData;
}
var dataFiltered = getFiltered(data, _aoi_param);
return dataFiltered;
}
excluded WHERE someField IN (${aoi_param}) from the query of my sql over sqlJdbc component

Why can I not use Continuation when using a proxy class to access MS CRM 2013?

So I have a standard service reference proxy calss for MS CRM 2013 (i.e. right-click add reference etc...) I then found the limitation that CRM data calls limit to 50 results and I wanted to get the full list of results. I found two methods, one looks more correct, but doesn't seem to work. I was wondering why it didn't and/or if there was something I'm doing incorrectly.
Basic setup and process
crmService = new CrmServiceReference.MyContext(new Uri(crmWebServicesUrl));
crmService.Credentials = System.Net.CredentialCache.DefaultCredentials;
var accountAnnotations = crmService.AccountSet.Where(a => a.AccountNumber = accountNumber).Select(a => a.Account_Annotation).FirstOrDefault();
Using Continuation (something I want to work, but looks like it doesn't)
while (accountAnnotations.Continuation != null)
{
accountAnnotations.Load(crmService.Execute<Annotation>(accountAnnotations.Continuation.NextLinkUri));
}
using that method .Continuation is always null and accountAnnotations.Count is always 50 (but there are more than 50 records)
After struggling with .Continutation for a while I've come up with the following alternative method (but it seems "not good")
var accountAnnotationData = accountAnnotations.ToList();
var accountAnnotationFinal = accountAnnotations.ToList();
var index = 1;
while (accountAnnotationData.Count == 50)
{
accountAnnotationData = (from a in crmService.AnnotationSet
where a.ObjectId.Id == accountAnnotationData.First().ObjectId.Id
select a).Skip(50 * index).ToList();
accountAnnotationFinal = accountAnnotationFinal.Union(accountAnnotationData).ToList();
index++;
}
So the second method seems to work, but for any number of reasons it doesn't seem like the best. Is there a reason .Continuation is always null? Is there some setup step I'm missing or some nice way to do this?
The way to get the records from CRM is to use paging here is an example with a query expression but you can also use fetchXML if you want
// Query using the paging cookie.
// Define the paging attributes.
// The number of records per page to retrieve.
int fetchCount = 3;
// Initialize the page number.
int pageNumber = 1;
// Initialize the number of records.
int recordCount = 0;
// Define the condition expression for retrieving records.
ConditionExpression pagecondition = new ConditionExpression();
pagecondition.AttributeName = "address1_stateorprovince";
pagecondition.Operator = ConditionOperator.Equal;
pagecondition.Values.Add("WA");
// Define the order expression to retrieve the records.
OrderExpression order = new OrderExpression();
order.AttributeName = "name";
order.OrderType = OrderType.Ascending;
// Create the query expression and add condition.
QueryExpression pagequery = new QueryExpression();
pagequery.EntityName = "account";
pagequery.Criteria.AddCondition(pagecondition);
pagequery.Orders.Add(order);
pagequery.ColumnSet.AddColumns("name", "address1_stateorprovince", "emailaddress1", "accountid");
// Assign the pageinfo properties to the query expression.
pagequery.PageInfo = new PagingInfo();
pagequery.PageInfo.Count = fetchCount;
pagequery.PageInfo.PageNumber = pageNumber;
// The current paging cookie. When retrieving the first page,
// pagingCookie should be null.
pagequery.PageInfo.PagingCookie = null;
Console.WriteLine("#\tAccount Name\t\t\tEmail Address");while (true)
{
// Retrieve the page.
EntityCollection results = _serviceProxy.RetrieveMultiple(pagequery);
if (results.Entities != null)
{
// Retrieve all records from the result set.
foreach (Account acct in results.Entities)
{
Console.WriteLine("{0}.\t{1}\t\t{2}",
++recordCount,
acct.EMailAddress1,
acct.Name);
}
}
// Check for more records, if it returns true.
if (results.MoreRecords)
{
// Increment the page number to retrieve the next page.
pagequery.PageInfo.PageNumber++;
// Set the paging cookie to the paging cookie returned from current results.
pagequery.PageInfo.PagingCookie = results.PagingCookie;
}
else
{
// If no more records are in the result nodes, exit the loop.
break;
}
}

Speed Up Retrieving View Data?

The database I am trying to pull data from has approximately 50,000 documents. Currently it takes around 90 seconds for an iOS or Android device to query and display the data to the mobile device in a view. My code is posted below. Is there something I could be doing differently to speed this up? Thanks for any tips.
function updateAllPoliciesTable() {
try {
var db = Alloy.Globals.dbPolicyInquiry;
var view = db.getView("AllRecordsByInsured");
var vec = view.getAllEntriesBySQL("Agent like ? OR MasterAgent like ?", [Ti.App.agentNumber, Ti.App.agentNumber], true);
var ve = vec.getFirstEntry();
var data = [];
while (ve) {
var unid = ve.getColumnValue("id");
var row = Ti.UI.createTableViewRow({
unid : unid,
height: '45dp',
rowData: ve.getColumnValue("Insured") + " " + ve.getColumnValue("PolicyNumber")
});
var viewLabel = Ti.UI.createLabel({
color : '#333',
font : {
fontSize : '16dp'
},
text: toTitleCase(ve.getColumnValue("Insured")) + " " + ve.getColumnValue("PolicyNumber"),
left: '10dp'
});
row.add(viewLabel);
data.push(row);
ve = vec.getNextEntry();
}
//Ti.API.log("# of policies= " + data.length);
if(data.length == 0) {
var row = Ti.UI.createTableViewRow({
title : "No policies found"
});
data.push(row);
}
$.AllPoliciesTable.setData(data);
Alloy.Globals.refreshAllPolicies = false;
Alloy.Globals.loading.hide();
} catch (e) {
DTG.exception("updateAllPoliciesTable -> ", e);
}
}
Create an index on the appropriate table, that should speed up things.
The SQLite table for your view should be named "view_AllRecordsByInsured".
Create an index for that table, check SQLite documentation about "CREATE INDEX" for more details.
To execute the appropriate SQL, you could use the DTGDatabase class like
var sqldb = new DTGDatabase(Alloy.Globals.dbPolicyInquiry.localdbname);
sqldb.execute("CREATE INDEX IF NOT EXISTS ON view_AllRecordsByInsured (Agent,MasterAgent)")
If that does give enough speed, look at full text search for SQLite dbs.
Here is some example code regarding full text indexes to give you a starting point:
CREATE VIRTUAL TABLE ft_view__mobile_companies_ USING fts4(id, customername, customercity)
INSERT INTO ft_view__mobile_companies_(id, customername, customercity) SELECT id, customername, customercity FROM view__mobile_companies_
To query the index you need to execute SQL with the MATCH operator (see SQLite documentation). In one app I have well over 100.000 datasets synchronized from a Domino view, and searching using a fulltext search in SQLite works instantly.
Well, unlike big database engines, the SQLite database engine is more limited, and so are the devices that it's run on.
What I would try to do is check the query that pulls the data - are you using indexes in your table? do you use them to query? is there unnecessary joins or pulls?
I you fail to tweet the query you should maybe consider checking out a mobile noSQL solution - I know there are some on the appcelerator marketplace - check if it suits your needs and if it speeds up things.

Dynamic Linq creation

I am re-writing a query which is created in response to user's entry into text fields in order to offer some protection against SQL injection attack.
SELECT DISTINCT (FileNameID) FROM SurNames WHERE Surname IN
('Jones','Smith','Armitage')
AND FileNameID IN ( SELECT DISTINCT (FileNameID) FROM FirstNames WHERE FirstName
IN ('John','William') )
There can be up to 3 other tables involved in this process.
The parameter lists can be up to 50-100 entries so building a parameterized query is tedious and cumbersome.
I am trying to create a Linq query which should take care of the parameterization and offer the protection I need.
This gives me what I need
var surnameValues = new[] { "Jones","Smith","Armitage" };
var firstnameValues = new[] { "John","William" };
var result = (from sn in db.Surnames
from fn in db.FirstNames
where surnameValues.Contains(sn.Surname) &&
firstnameValues.Contains(fn.FirstName)
select fn.FileNameID).Distinct().ToArray();
I now need a way to dynamically create this depending upon whether the user has selected/entered values in the surname or firstname text entry boxes?
Any pointers will be gratefully received
Thanks
Roger
you could combine all the logic into the query;
var surnameValues = new[] { "Jones","Smith","Armitage" };
var firstnameValues = null;
// Set these two variables to handle null values and use an empty array instead
var surnameCheck= surnameValues ?? new string[0];
var firstnameCheck= firstnameValus ?? new string[0];
var result = (from sn in db.Surnames
from fn in db.FirstNames
where
(!surnameCheck.Any() || surnameCheck.Contains(sn.Surname)) &&
(!firstnameCheck.Any() || firstnameCheck.Contains(fn.FirstName))
select fn.FileNameID).Distinct().ToArray();
Your query doesn't seem to have a join condition betwwen the Surnames table and the firstNames table?
You could dynamically build the query (as you appear to be doing I cross join I've used SelectMany)
var query=db.Surnames.SelectMany(sn=>db.FirstNames.Select (fn => new {fn=fn,sn=sn}));
if (surnameValues!=null && surnameValues.Any()) query=query.Where(x=>surnameValues.Contains(x.sn.Surname));
if (firstnameValues !=null && firstnameValues.Any()) query=query.Where(x=>firstnameValues.Contains(x.fn.FirstName));
var result=query.Select(x=>x.fn.FileNameID).Distinct();