Apache Camel Bindy Unmarshall vs Marshall is different - apache-camel

I'm working with a piece of fixed length data that is in a weird format. Essentially its 10 characters, but the first one indicates the sign. I was able to unmarshal the data as an integer using the below configuration, but when marshaling back I need to get the data in the original format.
I think the issue is the pattern appears to only be used when unmarshalling, as I changed it to something completely invalid and it doesn't change the marshalled results.
I also tried the following, which add the leading zeros, but I also need the sign character added back.
#field:DataField(pos = 1, length = 10, pattern = "+0", align = 'R', paddingChar='0')
Data
+000000746
#FixedLengthRecord
#Link
data class Row(
#field:DataField(pos = 1, length = 10, pattern = "+0")
val messageBodyLength: Int? = null
)
// All of the routes are direct:
// First unmarshal the data
from(UNMARSHALL_ENDPOINT_URI)
.unmarshal()
.bindy(BindyType.Fixed, Row::class.java)
.to(UNMARSHALL_RESULT_MOCK_ENDPOINT_URI)
sendBody(UNMARSHALL_ENDPOINT_URI, "+000000746")
// returns a Row with messageBodyLength set to 746 as expected.
from(MARSHALL_ENDPOINT_URI)
.marshal()
.bindy(BindyType.Fixed, Row::class.java)
.convertBodyTo(String::class.java)
.to(MARSHALL_RESULT_MOCK_ENDPOINT_URI)
sendBody(MARSHALL_ENDPOINT_URI, Row(messageBodyLength=746))
// Returns " 746"
// Expected "+000000746"
Thanks!

Found the issue. The pattern fields for numbers need to have a locale specified.
camel:
dataformat:
bindy-fixed:
locale: default

Related

How to construct Django enum filter

The following is to get 1 record out of database by matching enum type.
TYPES = (
('ABC_ABC', 'abc abc'),
('XYZ_XYZ', 'xyz xyz'),
)
class Hello(models.Model):
type = models.CharField(max_length=8, choices=TYPES, blank=True)
database:
'1', 'ABC_ABC', 'other data'
Queryset:
qset = Q(type__in=('ABC_ABC'))
hello = models.Hello.objects.filter(qset)
Output:
print('count: {}'.format(hello.count()))
Result is 0. It should be 1. What's wrong?
Try changing your Q filter as follow:
qset = Q(type='ABC_ABC')
Explanations:
When using in lookup, django expects an iterable. As you provided only one value, I suspect, it tried to iterate over the string 'ABC_ABC' which is why you didn't get any hit.
If you really want to use the in lookup, which is useless in this case, you should add a comma in to force creating a 1-tuple.
qset = Q(type__in=('ABC_ABC',))
Further thoughts
As this query is quite basic, using a Q object is superfluous. You can simply call
.filter(type='ABC_ABC')

Convert NUMERIC to VARCHAR using sequelize model

I have this NUMERIC(20) field on mssql and I'm trying do read it as a data type string to get the full number because int limits on javascript
code: {
type: DataTypes.STRING
}
But the returned value is a truncated INT
[ {code: 4216113112911594000 } ]
No matter what kind of data type choose it'll return as truncated int
The original values is 4216113112911594192. This is a java UUID
How can a convert this value to using model.findAll()
This is a already created table for another application and I'm trying to read it using sequelize
Here you go :
code: {
type: Sequelize.INTEGER , // <------ keep is as DB's datatype
get() { // <------ Use getter method to modify the output of query
return this.getDataValue('code').toString();
}
}
I think this might help you
model.findOne({
attributes: [[db.sequelize.literal('cast(`code` as varchar)'), 'code_string']] ,
where : { id : YOUR_ID }
}).then(data => {
console.log(data); // <------ Check your output here
})
I have not fully understood what you are trying to achieve.
Nor my code is tested.
Idea 1 : convert into float.
Idea 2 : Append any string alphabet to originial int value before sending to javascript.
The original values is 4216113112911594192.
So the string become 'A'+'4216113112911594192'='A4216113112911594192'
Now you can play with 'A4216113112911594192'
There are many javascript library to support big integer.
BigInteger
This worked for postgres (thanks Bessonov & vitaly-t!)
Just add this before you initialize sequelize
import pg from 'pg'
// Parse bigints and bigint arrays
pg.types.setTypeParser(20, BigInt) // Type Id 20 = BIGINT | BIGSERIAL
const parseBigIntArray = pg.types.getTypeParser(1016) // 1016 = Type Id for arrays of BigInt values
pg.types.setTypeParser(1016, (a) => parseBigIntArray(a).map(BigInt))
A little background:
I didn't want Sequelize to parse bigint columns as strings, so I added pg.defaults.parseInt8 = true. That made pg start parsing bigints as regular numbers, but it truncated numbers that were too big. I ended up going with the above solution.

Regex to match the last value in given data

I get data from a URL, and am working on the data to check for a few conditions. The data from the URL look like this:
1528190345":100,"1528190346":100,"1528190368":100,"1528190414":100,"1528190439":99,"1528190440":99,"1528190463":100,"1528190485":100,"1528190508":100,"1528190550":100,"1528190575":100,"1528190576":100,"1528190599":100,"1528190600":100,"1528190622":100,"1528190667":100,"1528190688":100,"1528190689":100,"1528190712":100,"1528190736":100,"1528190762":100,"1528190785":100,"1528190786":100,"1528190807":100,"1528190828":100,"1528190853":100,"1528190877":100,"1528190901":100,"1528190925":100,"1528190948":100,"1528190968":100,"1528190991":100}}]
====
I have converted that too JSON
{"metric"=>"Insta_real-unique_value", "tags"=>{"host"=>"letme.quickly.com", "tier"=>"2", "device"=>"tester1", "dc"=>"xxx"}, "aggregateTags"=>["device_name", "device_ip"], "dps"=>{"1526972408"=>100, "1526972424"=>100, "1526972440"=>100, "1526972456"=>100, "1526972472"=>100, "1526972488"=>100, "1526972504"=>100, "1526972520"=>100, "1526972536"=>100, "1526972552"=>100, "1526972568"=>100, "1526972569"=>100, "1526972584"=>100, "1526972585"=>100, "1526972601"=>100, "1526972617"=>100, "1526972633"=>100, "1526972649"=>100, "1526972665"=>100, "1526972681"=>100}}
I want to extract the value that corresponds to 100. When I do this:
url = "#{URL}"
uri = URI(url)
response = Net::HTTP.get(uri)
value = response[-6..-4]
puts value
I get the last value, but when the last value changes to 99/9/0, it prints :99 or ":9.
Is there a way to get the exact value as is?
When dealing with JSON data, it's almost always better to parse the data properly rather than using regex against the string.
In this case, we can do:
JSON.parse(response)['dps'].values.last #=> 100
If the response is a json response, you must use a json parser else if is not a json response, you can use a regex expression with a Regex Object.
In case of a json response, assuming that the object is something like is declared into the variable response of the next code, you can parse it into a JObject. (using Newtonsoft.Json available from nuget repository).
See the next example :
string response = "[{\"response\":{\"1528190345\":100,\"1528190346\":100,\"1528190368\":100,\"1528190414\":100,\"1528190439\":99,\"1528190440\":99,\"1528190463\":100,\"1528190485\":100,\"1528190508\":100,\"1528190550\":100,\"1528190575\":100,\"1528190576\":100,\"1528190599\":100,\"1528190600\":100,\"1528190622\":100,\"1528190667\":100,\"1528190688\":100,\"1528190689\":100,\"1528190712\":100,\"1528190736\":100,\"1528190762\":100,\"1528190785\":100,\"1528190786\":100,\"1528190807\":100,\"1528190828\":100,\"1528190853\":100,\"1528190877\":100,\"1528190901\":100,\"1528190925\":100,\"1528190948\":100,\"1528190968\":100,\"1528190991\":100}}]";
List<Dictionary<string, Dictionary<string, int>>> values = JsonConvert.DeserializeObject<List<Dictionary<string, Dictionary<string, int>>>>(response);
Dictionary<string, Dictionary<string, int>> firstLevel = values[0]; // Access to the first object of the list closed with ']'
Dictionary<string, int> secondLevel = firstLevel["response"]; // Access to the first object response and get's it's object context of first '}' starting from the end of response
/** This is an option, if you ever knows the name of the element (1528190991) */
int thirdLevel = secondLevel["1528190991"]; // Access to the last element of the object by it's name, context of second '}' starting from the end of response.
Console.WriteLine(thirdLevel);
/** This is another option if you doesn't know the name of the element and wants ever the last element. */
List<int> listOfValues = secondLevel.Values.ToList();
Console.WriteLine(listOfValues[listOfValues.Count-1]);
Note that i've chenged a little bit your response adding [{\"response\":{\" at the start to become a json response.
If is not a json response you can use this pattern with regular expression :
:(.{2,6})}}\]$
Hope will help!

resolving string (read from database) to list python

I have a list stored in database as varchar. When I read the list value, it is read as string. I'm trying to convert string to a valid list
Here are 2 example lists I have
str_db_bins = [10,20,30,40] (This is string)
The desired output is
str_db_bins_list = [10,20,30,40] (This is list)
I want to convert this to list. When I use split method I get [[,1,0...]] which is not the desired output
2nd situtation is
str_db_lov = ['id','num','val'].
When I use split method, again I get weird output
The desired output is to read this as list
str_db_lov_list = ['id', 'num', 'val']
How do I deal with these situations
Thanks
Pari
str_db_bins_list = eval(str_db_bins)
str_db_lov_list = eval(str_db_lov)

Bindy paddingChar

In my Bindy model I would like to set a paddingChar on one field. I saw in the documentation that with a #Fixed-length record I can add a paddingChar attribute but with a #CsvRecord it seems not to be the possible ?
This code doesn't pad field mandant with "0":
#CsvRecord(separator = ";", generateHeaderColumns=true)
public class Unity{
#DataField(pos = 1, length = 3, paddingChar = '0') String mandant;
...
According to the Camel documentation, you could use the pattern attribute for Double, Integer, Float, Short, Long, and BigDecimal fields. The format is defined according to java.text.DecimalFormat:
#DataField(pos = 1, pattern = "000")
Float mandant;
EDIT:
pattern is ignored (at least for Camel 2.13.1), if the locale is not set (a kind of a bug or at least an undocumented feature...). Thus, do the following:
final BindyCsvDataFormat bindy = new BindyCsvDataFormat(Unity.class);
bindy.setLocale(Locale.US.getISO3Country());
EDIT:
I opened a Jira issue as I think this should be fixed: CAMEL-7578
EDIT:
CAMEL-7578 is fixed for Camel versions 2.12.5, 2.13.3, and 2.14.0.

Resources