How do you compare versions in InstallScript? - installscript

It looks like there is a builtin function, VerCompare, but it requires strings that have all four components, e.g. 1.2.3.4. I haven't tried to do string manipulation in InstallScript and was hoping someone already had the code to take a version string and add .0's as necessary.

Needs some error checking, but here's the general idea:
prototype NUMBER CompareVersions(STRING, STRING);
prototype STRING FormatVersion(STRING);
function NUMBER CompareVersions(leftVersion, rightVersion)
STRING formattedLeftVersion, formattedRightVersion;
begin
formattedLeftVersion = FormatVersion(leftVersion);
formattedRightVersion = FormatVersion(rightVersion);
return VerCompare(formattedLeftVersion, formattedRightVersion, VERSION);
end;
function STRING FormatVersion(version)
STRING formattedVersion;
LIST tokens;
NUMBER count;
begin
tokens = ListCreate(STRINGLIST);
StrGetTokens(tokens, version, ".");
count = ListCount(tokens);
ListSetIndex(tokens, LISTLAST);
while (count < 4)
ListAddString(tokens, "0", AFTER);
count = count + 1;
endwhile;
StrPutTokens(tokens, formattedVersion, ".", FALSE);
ListDestroy(tokens);
return formattedVersion;
end;

Related

LINQ to Entities does not recognize the method call within it

I completely understand that this is because LINQ query requires the whole expression to be translated to a server , and therefore I cant call an outside method in it. but as I have looked at other answers there is not relative solution to this. the only approach that I thought about is to loop through all the items in the model and than passing them to the query one by one but even though this approach would not help so I am seeking help in here for anyone to help me to figure out how to call a method or a way of calling a method appendstr that initializes a.PostedDate before checking its actual equivalent value in the giving LINQ Query.
[HttpGet]
public ActionResult SearchResult(int? page, string searchTitle = null, string searchLocation = null, string last24 = "")
{
ViewBag.searchTitle = searchTitle;
ViewBag.searchLocation = searchLocation;
ViewBag.page = page;
ViewBag.last24 = last24;
setUpApi(searchTitle, searchLocation);
var result = new List<AllJobModel>().AsQueryable();
if (!string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.last24))
{
setUpApi(searchTitle, searchLocation);
DateTime now = DateTime.Now;
result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation) &&
appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")));
}
else
{
result = from app in db.AllJobModel select app;
}
return View(result.ToList().ToPagedList(page ?? 1, 5));
}
The second method that gets called in the LINQ Query
public string appendstr(string str)
{
var x = str.Split(' ');
return 01 + "-" + x[1] + "-" + x[2];
}
I think you already understand that the .NET code you write in the Where clause is actually an expression that is parsed and converted to SQL. So if you have a funky string manipulation method, you can't use it directly.
The brute force option, as you seem to already understand, it to materialize the query first and then run the C# code over the results. You can do this with ToList() or AsEnumerable().
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
)
.AsEnumerable()
.Where
(
a => appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")))
);
However in your specific case you can try a trick. You are attempting a date comparison, which SQL is perfectly capable of doing... you just need to convert that funky PostedDate to a SQL DateTime so that you can compare it directly. The gimmick for that is to use SqlFunctions.DateAdd to add null interval (e.g. 0 days). This implicitly converts the string to DateTime, where you can now query on the SQL side:
var targetDate = DateTime.Now.AddHours(-24);
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
&& SqlFunctions.DateAdd("DAY", 0, a.PostedDate) == targetDate
);
Credit goes to this post for the workaround.

Passing javascript string variable into nlapiSearchRecord filter

I'm working on a Suitelet to apply landed costs (through a .csv file) to item receipts. This code below is iterating through an array of PO numbers to build out a formula(number) to pass into nlapiSearchRecord().
I'm having trouble getting the search to fire when passing part of the search filter in from a variable. I've tried passing various sizes of string with and without double or single quotes (see commented out sections for an idea) and now I'm simply passing one variable, testNumber, into the search string. It's still failing giving me this error:
SSS_INVALID_SRCH_FILTER_EXPR_OBJ_TYPEMalformed search filter expression: Unrecognized object type.
The complete line is supposed to be
["formulanumeric: case when {number} = 'PO476' or {number} = '294' then 1 else 2 end","equalto","1"],
for(var i = 0; i<poNumbers.length; i++) {
if(i < (poNumbers.length - 1)) {
poFormula += "{number} = '"+poNumbers[i]+"' or ";
}
else {
poFormula += "{number} = '"+poNumbers[i]+"'";
}
}
//poFormula(string) --> {number} = 'PO481' or {number} = 'PO476' or {number} = '294' or {number} = 'PO440' or {number} = 'PO441'
//var searchFormulaStart = "formulanumeric: case when "+poFormula+" then 1 else 2 end";
//var sfMiddle = "equalto";
//var sfEnd = "1";
var testNumber = "'PO476'";
var purchaseorderSearch = nlapiSearchRecord("purchaseorder",null,
[
["mainline","is","T"],
"AND",
["type","anyof","PurchOrd"],
"AND",
["formulanumeric: case when {number} = "+testNumber+" then 1 else 2 end","equalto","1"],
//[searchFormulaStart,sfMiddle,sfEnd],
"AND",
["type","anyof","PurchOrd"]
],
[
new nlobjSearchColumn("internalid",null,null)
]
);
The idea is that I need to return all the POs included in the .csv so I can get their internal ids. Later in the code, I will pass these ids into another search against item receipts, finding all receipts created from those POs. Once I have those, I can apply freight costs to those receipts.
var itemreceiptSearch = nlapiSearchRecord("itemreceipt",null,
[
["type","anyof","ItemRcpt"],
"AND",
["mainline","is","T"],
"AND",
["createdfrom","anyof", poInternalIds]
],
[
new nlobjSearchColumn("tranid",null,null)
]
);
Can anyone confirm if there's some undocumented bug or something with passing part of a search string in from a variable like this? Alternatively, given PO numbers and freight costs, is there a better way to apply landed costs to item receipts?
Thanks!
I found a solution with help from some folks on Slack. Rather than trying to concatenate variables into the filter string, I'm now creating the entire filter array in a forEach() loop as shown below.
I'm still not sure why the Netsuite API didn't like my search formatted with a concatenation, but this is a much cleaner solution anyway.
for(var i = 0; i<freightCosts.length; i++) {
poNumbers.push(freightCosts[i].PO);
}
poNumbers.forEach(function(tranid){
filters.push(["tranid", "is", tranid]);
filters.push("or");
});
// remove the last "or"
filters.pop();
var purchaseorderSearch = nlapiSearchRecord("purchaseorder",null,
[
["mainline","is","T"],
"AND",
["type","anyof","PurchOrd"],
"AND",
[filters]
],
[
new nlobjSearchColumn("internalid",null,null)
]
);
Weirdly enough, I ran into this exact issue just last week. It appears to be a bug in the Rhino Javascript engine that Netsuite uses. The workaround to get it to work is to wrap your concatenation in a String():
[String("formulanumeric: case when {number} = "+ testNumber + " then 1 else 2 end"), "equalto", "1"]

Problems with migration from swift2 to swift3 with ranges

I have strings and determine the ranges of indexes. I will need later for instance .last .count for these ranges. How should I initialise the range for string to be able to get functionality .last .count for these ranges (that is obvious in swift2 but not in swift3) ?
For example, I am often using the .count for range of string in my code in swift2, like this
var str = "Hello, playground"
let myRange = str.rangeOfString("Hello")
let myCountOfRange = myRange.count
Now it is not possible to do this in swift3
var str = "Hello, playground"
let myRange = str.range(of: "Hello")
let myCountOfRange = myRange.count // type index does not conform to protocol strideable
In Swift3, to find the size of a range you can do:
var str = "Hello, playground"
let myRange = str.range(of: "Hello")
let myCountOfRange = str[myRange!].characters.count
I don't know if this is the best way, but it works.
Alternatively:
let myCountOfRange = str.distance(from: myRange!.lowerBound, to: myRange!.upperBound)
Both require access to the original collection (ie. string), and that apparently is a limitation of Swift 3. The new model for collections and indices is discussed here.
If you want to store the ranges in an array and call .count and .last on them, you can convert the Range<Index> to a CountableRange<Int> while you still have access to the collection:
var str = "Hello, playground"
let myRange = str.range(of: "Hello")!
let lb = str.distance(from: str.startIndex, to: myRange.lowerBound) as Int
let ub = str.distance(from: str.startIndex, to: myRange.upperBound) as Int
let newRange = lb..<ub
newRange.count // 5
newRange.last // 4

How to get the last two sections of a URL

When the URL is: http://www.example.com/services/product/Software.aspx , I need: "product/Software.aspx",
So far I just tried the below code :
string[] SplitUrls = Request.RawURL.Split('/');
string CategorynQuery = SplitUrls[SplitUrls.Length - 2]
+ SplitUrls[SplitUrls.Length - 1];
However, is there some other way to do this using functions IndexOf(), LastIndexOf() etc.. or any other Function? Or any possibility using Substring method ?
Please note that the above URL is just an example, there are around 100 such URls and I need the Last 2 sections for each.
Try this, using the LastIndexOf, and Substring.
string str = "http://www.example.com/services/product/Software.aspx";
int lastIndexOfBackSlash = str.LastIndexOf('/');
int secondLastIndex = lastIndexOfBackSlash > 0 ? str.LastIndexOf('/', lastIndexOfBackSlash - 1) : -1;
string result = str.Substring(secondLastIndex, str.Length - secondLastIndex);
I am also checking the presence when getting the second last index - obviously you can alter this depending on your requirements :)
You can use Uri class:
Uri uri = new Uri("http://myUrl/%2E%2E/%2E%2E");
uri.AbsoluteUri;
uri.PathAndQuery;
Not too efficient but a little more elegant:
string url = "http://www.example.com/services/product/Software.aspx";
var splitted = url.Split('/').Reverse().Take(2).Reverse().ToList();
var str = string.Format("{0}/{1}", splitted[0], splitted[1]);

EXC_BAD_ACCESS on inserting

I'm using FMDatabase to operate on an sqlite3 database. Here's my code:
NSString *dbFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#"temp_info.db"]];
FMDatabase *fmdb = [FMDatabase databaseWithPath:dbFilePath];
if (![fmdb open]) {
NSLog(#"......");
} else {
NSString *sql = #"CREATE TABLE IF NOT EXISTS test1(id INTEGER, name TEXT, create_time TEXT)";
if (![fmdb executeUpdate:sql]) {
NSLog(#"......");
}
for (int i = 0; i < 3; i++) {
BOOL result = [fmdb executeUpdate:#"INSERT INTO test1(id, name, create_time) values(?,?,?)", i+1, #"test", #"12-09-10 12:10"];
NSLog(#"%d", result);
}
// EXC_BAD_ACCESS
}
When I run the line:
BOOL result = [fmdb executeUpdate:#"INSERT INTO test1(id, name, create_time) values(?,?,?)", i+1, #"test", #"12-09-10 12:10"];
I get an EXC_BAD_ACCESS error. Why?
question has been solved!
*1.*All arguments provided to the -executeUpdate: method(or any of the variants that accept a va_list as a parameter) must be objects.The following will be not work (and will result in a crash):
[db executeUpdate:#"INSERT INTO mytable VALUES (?)", 66];
The proper way to insert a number is to box it in an NSNumber object:
[db executeUpdate:#"INSERT INTO mytable VALUES (?)", [NSNumber numberWithInt:66]];
*2.*Alternatively,you can use the -execute*WithFormat: variant to use NSString-style substitution:
[db executeUpdateWithFormat:#"INSERT INTO mytable VALUES (%d)", 66];
Internally,the -execute*WithFormat: methods are properly boxing things for you.The following percent modifiers are recognized:%#,%c,%s,%d,%D,%i,%u,%U,%hi,%hu,%qi,%qu,%f,%ld,%lu,%lld,and %llu.Using a modifier other than those will have unpredictable results.If,for some reason,you need the % character to appear in your SQL statement,you should use %%.

Resources