CriteriaQuery order by FIND_IN_SET - mysql

I am using JPA Specification Queries where we follow the common Architecture as below for the Queries
#Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
// Create a new predicate list
List<Predicate> predicates = new ArrayList<>();
// Add criteria to predicates
for (SearchCriteria criteria : list) {
switch (criteria.getOperation()) {
case EQUAL:
predicates.add((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
? builder.equal(root.get(criteria.getKey()), criteria.getValue())
: builder.equal(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey()),
criteria.getValue()));
break;
case MATCH:
predicates.add((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
? builder.like(builder.lower(root.get(criteria.getKey())),
"%" + criteria.getValue().toString().toLowerCase() + "%")
: builder.like(
builder.lower(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())),
"%" + criteria.getValue().toString().toLowerCase() + "%"));
break;
case SORT_ASC:
query.orderBy((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
? builder.asc(root.get(criteria.getKey()))
: builder.asc(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())));
break;
case SORT_DESC:
query.orderBy((Objects.isNull(criteria.getJoinMap()) || criteria.getJoinMap().isEmpty())
? builder.desc(root.get(criteria.getKey()))
: builder.desc(getOrCreateJoins(root, criteria.getJoinMap()).get(criteria.getKey())));
default:
break;
}
}
return isSearchOperationOr ? builder.or(predicates.toArray(new Predicate[0]))
: builder.and(predicates.toArray(new Predicate[0]));
}
In this we have key and value/values which are being processed but I want the order of Ids which I provide in IN Query to be same in order while the results are being fetched.
Already gone through the FIND_IN_SET term as from mysql it is possible but any idea how to configure here in the above code?

Related

How to use avro data with old and new namespace

I am facing a problem where I have updated the namespace in my avsc schema file. Since we were using common processor created in Java to parse the XML to avro and were using the avsc file.
We have separated the interfaces and created 2 different namespaces and now having 2 avsc schemas which are identical just the namespace is different.
Since we have data which was generated using old namespace, I am unable to query this data with new data generated with new namespace.
Here is example of my schemas -
Old schema - "type" : "record",
"name" : "Message",
"namespace" : "com.myfirstavsc",
"fields" : [ {
"name" : "Header",.....**other fields**
New schema - "type" : "record",
"name" : "Message",
"namespace" : "com.mysecondavsc",
"fields" : [ {
"name" : "Header",.....**other fields**
When I query my hive table I get below exception
Failed with exception java.io.IOException:org.apache.avro.AvroTypeException: Found com.myfirstavsc.Property, expecting union
I am not sure how you are trying to read your data but use GenericDatumReader should solve your issue, after that you can convert the generic record to your specific records. I found something similar here
http://apache-avro.679487.n3.nabble.com/Deserialize-with-different-schema-td4032782.html
http://apache-avro.679487.n3.nabble.com/Deserialize-with-different-schema-td4032782.html
The link mentioned above is not work anymore, so add an explanation here.
We got the same error in a project named Hudi, so raised an issue about it: https://github.com/apache/hudi/issues/7284
After trouble shooting, the root cause of this exception org.apache.avro.AvroTypeException: Found hoodie.test_mor_tab.test_mor_tab_record.new_test_col.fixed, expecting union is Avro schema generator rule, it can't accept the change of namespace when handling UNION type.
According to Avro Schema Resolution doc, it can accept schema evolution if either schema is a union in reader or writer schema in GenericDatumReader(Schema writer, Schema reader). But it didn't mention there is another restriction about it: the full name of schema must be the same if the type is RECORD or ENUM or FIXED.
Code reference:
ResolvingGrammarGenerator#bestBranch
public class ResolvingGrammarGenerator extends ValidatingGrammarGenerator {
...
private int bestBranch(Schema r, Schema w, Map<LitS, Symbol> seen) throws IOException {
Schema.Type vt = w.getType();
// first scan for exact match
int j = 0;
int structureMatch = -1;
for (Schema b : r.getTypes()) {
if (vt == b.getType())
if (vt == Schema.Type.RECORD || vt == Schema.Type.ENUM ||
vt == Schema.Type.FIXED) {
String vname = w.getFullName();
String bname = b.getFullName();
// return immediately if the name matches exactly according to spec
if (vname != null && vname.equals(bname))
return j;
if (vt == Schema.Type.RECORD &&
!hasMatchError(resolveRecords(w, b, seen))) {
String vShortName = w.getName();
String bShortName = b.getName();
// use the first structure match or one where the name matches
if ((structureMatch < 0) ||
(vShortName != null && vShortName.equals(bShortName))) {
structureMatch = j;
}
}
} else
return j;
j++;
}
// if there is a record structure match, return it
if (structureMatch >= 0)
return structureMatch;
// then scan match via numeric promotion
j = 0;
for (Schema b : r.getTypes()) {
switch (vt) {
case INT:
switch (b.getType()) {
case LONG: case DOUBLE:
return j;
}
break;
case LONG:
case FLOAT:
switch (b.getType()) {
case DOUBLE:
return j;
}
break;
case STRING:
switch (b.getType()) {
case BYTES:
return j;
}
break;
case BYTES:
switch (b.getType()) {
case STRING:
return j;
}
break;
}
j++;
}
return -1;
}
...
}

Function with 3 arguments: Return result after applying operator i.e. (5, 7, '+') = 35

Hopefully my title explains it but I need a function that will take 3 arguments (two numbers and an operator [*, +, /, -]), then compute the result.
Something like this:
function evaluateExpression (firstNum, secondNum, operator) {
...
return ...;
}
evaluateExpression (35, 7, '/'); // should return 5
Pseudocode:
evaluateExpression( first, second, op ) :
if op == "+" :
return first + second
else if op == "*" :
return first * second
... etc
else :
return error
One way:
if (operator === "+") { return firstNum + secondNum };
if (operator === "-") { return firstNum - secondNum };
if (operator === "/") { return firstNum / secondNum };
if (operator === "*") { return firstNum * secondNum };
if (operator === "%") { return firstNum % secondNum };
Another way:
switch (operator) {
case "+" : return firstNum + secondNum;
case "-" : return firstNum - secondNum;
case "/" : return firstNum / secondNum;
case "*" : return firstNum * secondNum;
case "%" : return firstNum % secondNum;
}
If you are using javascript, this could be another way:
eval(firstNum + operator + secondNum);
Even in python, you can use the eval method. Just convert the operands to strings and call the function.
evaluateExpression( first, second, op ) :
return eval(str(first) + op + str(second))

string to int inside linq2sql lambda expression

I have a lambda expression that returns the sum of two fields in a table. The problem is that the field (ExpectedQuantity) is a string, while QtyExpected is an int. I thought I would be able to use int.Parse in my lambda expression, but I get an error saying that SQL cannot translate it.
return new QuantitiesDashboardAggregate()
{
QtyExpected = query.Sum(x => int.Parse(x.ExpectedQuantity)),
QtyReceived = query.Sum(x => int.Parse(x.ReceivedQuantity)),
};
Can someone help?
Here is how I defined the query variable:
IQueryable<Data.POProduct> query = this.Database.POProducts;
// Apply date range
DateRange dateRange = new DateRange(args.DateRangeFilter, args.DateRangeCriteria);
switch (dateRange.DateRangeFilter)
{
case DateRangeFilter.Date:
query = query.Where(po => po.PurchaseOrder.FiscalDate.Date == dateRange.Date);
break;
case DateRangeFilter.FiscalWeek:
query = query.Where(po => (po.PurchaseOrder.FiscalDate.Year == dateRange.Year) &&
(po.PurchaseOrder.FiscalDate.WeekYear == dateRange.Number));
break;
case DateRangeFilter.FiscalPeriod:
query = query.Where(po => (po.PurchaseOrder.FiscalDate.Year == dateRange.Year) &&
(po.PurchaseOrder.FiscalDate.Period == dateRange.Number));
break;
case DateRangeFilter.FiscalYear:
query = query.Where(po => po.PurchaseOrder.FiscalDate.Year == dateRange.Year);
break;
default:
break;
}
Basically Linq to SQL cannot translate your expression, so you should call .ToList() (or .AsEnumerable()) on your query, it will fetch data drom db, and than you can use your expression with int.Parse

instanceof String not behaving as expected in Google Apps Script

I wanted to check whether a variable in an Apps Script was a String, but found that instanceof wasn't returning true when the variable was in fact a string. The following test:
function test_instanceof() {
var a = "a";
Logger.log('"a" is ' + ((a instanceof String) ? '' : 'not ') + 'a String');
var b = String("b");
Logger.log('String("b") is ' + ((b instanceof String) ? '' : 'not ') + 'a String');
}
Logs these two messages:
"a" is not a String
String("b") is not a String
The docs aren't clear on the subset of ECMAScript that is supported, though apparently instanceof is a valid operator and String is a valid type, judging from the fact that
the code executed without an exception.
What is the appropriate way to check the type of a variable?
It's standard EcmaScript 3.
Your code is doing what JavaScript expects: see here for the equivalent JavaScript running in your browser.
Instanceof checks for a matching constructor in the prototype chain. That's good for objects created via 'new' but not very helpful for strings. What you actually want for String is typeof, as shown in this example in your browser or the equivalent Apps Script code:
function test_instanceof() {
var a = "a";
Logger.log('"a" is ' + ((typeof a == 'string') ? '' : 'not ') + 'a String');
var b = String("b");
Logger.log('String("b") is ' + ((typeof b == 'string') ? '' : 'not ') + 'a String');
}

How to call a setter method with arguments dynamically in flash AS3

This AS3 function works for normal methods and getter methods:
public function MyClassTestAPI(functionName:String, ...rest):* {
var value:*;
try {
switch(rest.length) {
case 0:
value = myObj[functionName];
break;
case 1:
value = myObj[functionName].call(functionName, rest[0]);
break;
case 2:
value = myObj[functionName].call(functionName, rest[0],rest[1]);
break;
default:
throw("Cannot pass more than 2 parameters (passed " + rest.length + ")");
}
}
return value;
}
Sample usage:
this.MyClassTestAPI("Foo", "arg1"); // tests function Foo(arg1:String):String
this.MyClassTestAPI("MyProperty"); // tests function get MyProperty():String
this.MyClassTestAPI("MyProperty", "new value");// tests function set MyProperty(val:String):void
The third call does not work (throws exception).
How can I make it work for setter methods as well?
Thanks!
edit:
This is a version that works, except with getter and setter that have additional parameters.
It is ok for my needs:
public function MyClassTestAPI(functionName:String, ...rest):* {
var value:*;
try {
if (typeof(this.mediaPlayer[functionName]) == 'function') {
switch(rest.length) {
case 0:
value = myObj[functionName].call(functionName);
break;
case 1:
value = myObj[functionName].call(functionName, rest[0]);
break;
case 2:
value = myObj[functionName].call(functionName, rest[0],rest[1]);
break;
default:
throw("Cannot pass more than 2 parameters (passed " + rest.length + ")");
}
} else {
switch(rest.length) {
case 0:
value = myObj[functionName];
break;
case 1:
myObj[functionName] = rest[0];
break;
default:
throw("Cannot pass parameter to getter or more than one parameter to setter (passed " + rest.length + ")");
}
}
}
return value;
}
Setter functions works as variables, so you can't use it in this way:
myProperty.call( "new value" );
Your function for variables is pointless, because you just have to do a value assignment:
myProperty = "new value";
By the way you can include it in your function in two ways:
create a third parameter what tells your function it is a function or variable
create the value assignment in the catch section
You are currently passing only one string with value "new value"
This should do the trick:
this.MyClassTestAPI("MyProperty", "new","value");
For more information on this matter check the Adobe LiveDocs at:
http://livedocs.adobe.com/flex/3/html/help.html?content=03_Language_and_Syntax_19.html
Cheers