DataWeave functions fail when moved to a module - module

I'm having trouble moving functions to a custom Module file.
Using Anypoint Studio v7.11.1. I have this code that works in a Transform Message component:
%dw 2.0
output application/json
var flights = {
"flights": [
{
"airlineName": "Delta",
"availableSeats": 40,
"departureDate": "Apr 11, 2018",
"destination": "LAX",
"flightCode": "A134DS",
"origination": "MUA",
"planeType": "BOEING 777",
"price": "750.00"
},
{
"airlineName": "Delta",
"availableSeats": 18,
"departureDate": "Aug 11, 2018",
"destination": "LAX",
"flightCode": "A1QWER",
"origination": "MUA",
"planeType": "BOEING 747",
"price": "496.00"
},
{
"airlineName": "Delta",
"availableSeats": 10,
"departureDate": "Feb 11, 2018",
"destination": "LAX",
"flightCode": "A1B2C4",
"origination": "MUA",
"planeType": "BOEING 737",
"price": "199.99"
},
{
"flightCode": "rree0001",
"availableSeats": 0,
"destination": "LAX",
"planeType": "Boeing 787",
"price": 541.0,
"origination": "MUA",
"departureDate": "2016-01-20T00:00:00",
"airlineName": "american"
},
{
"flightCode": "ffee0192",
"availableSeats": 0,
"destination": "LAX",
"planeType": "Boeing 777",
"price": 300.0,
"origination": "MUA",
"departureDate": "2016-01-20T00:00:00",
"airlineName": "american"
},
{
"flightCode": "eefd4511",
"availableSeats": 100,
"destination": "LAX",
"planeType": "Boeing 777",
"price": 900.0,
"origination": "MUA",
"departureDate": "2016-01-15T00:00:00",
"airlineName": "american"
},
{
"airlineName": "United",
"availableSeats": 52,
"departureDate": "2015/02/11",
"destination": "LAX",
"flightCode": "ER45if",
"origination": "MUA",
"planeType": "Boeing 737",
"price": 345.99
},
{
"airlineName": "United",
"availableSeats": 12,
"departureDate": "2015/04/11",
"destination": "LAX",
"flightCode": "ER45jd",
"origination": "MUA",
"planeType": "Boeing 777",
"price": 346
},
{
"airlineName": "United",
"availableSeats": 0,
"departureDate": "2015/06/11",
"destination": "LAX",
"flightCode": "ER0945",
"origination": "MUA",
"planeType": "Boeing 707",
"price": 423
}
]
}
import dw::modules::FlightsLibSolution
var keysToDelete = ["openFlightsAirportId", "type", "source"]
//var flights = readUrl("classpath://examples/flightsToLAX.json")
var airportDetailsByIATA = readUrl("classpath://airportInfoTiny.csv", "application/csv") groupBy $.IATA
fun joinAirportDetailsV2(payload :Object, keysToDelete = [], groupedAirportDetails = []) =
flights:{(
payload.flights map ( (flight) -> flight:
//join in the destination airport details with mapObject
flight mapObject (value, key, index) ->
if( lower(key) ~= "destination")
destination: groupedAirportDetails[ flight.destination ][0]
-- keysToDelete
//{(
//airportDetails[ ?($.IATA == flight.destination)]
//groupedAirportDetails[ flight.destination ]
//)}
else (key): value
)
)}
---
joinAirportDetailsV2(flights, keysToDelete, airportDetailsByIATA )
But when I move the function to the dw.modules.FlightsLibSolution.dwl file and I call
---
dw::modules::FlightsLibSolution::joinAirportDetailsV2(flights, keysToDelete, airportDetailsByIATA )
I get the error:
"Too many arguments (3) for function with parameters (payload, keysToDelete).
128| dw::modules::FlightsLibSolution::joinAirportDetailsV2(flights, keysToDelete, airportDetailsByIATA )
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
But if I call this function instead in a module
fun joinAirportDetailsV1(payload :Object,keysToDelete = [], groupedAirportDetails = []) =
flights:
{(
payload.flights map ( (flight) ->
flight:
flight - "destination"
//join in the destination airport details with ++
++ destination:
//{(
groupedAirportDetails[ flight.destination ][0]
//)}
//- "openFlightsAirportId" - "type" - "source"
-- keysToDelete
)
)}
It works.
Also, if I put this function in the Module:
fun joinAirportDetailsV3(payload :Object ) =
flights:{(
payload.flights map ( (flight) -> flight:
//join in the destination airport details with mapObject
flight mapObject (value, key, index) ->
if( lower(key) ~= "destination")
destination: groupedAirportDetails[ flight.destination ][0]
-- keysToDelete
//{(
//airportDetails[ ?($.IATA == flight.destination)]
//groupedAirportDetails[ flight.destination ]
//)}
else (key): value
)
)}
and then I define the two variables used in the function in my Transform Message component:
import dw::modules::FlightsLibSolution
var keysToDelete = ["openFlightsAirportId", "type", "source"]
var airportDetailsByIATA = readUrl("classpath://airportInfoTiny.csv", "application/csv") groupBy $.IATA
var groupedAirportDetails = airportDetailsByIATA
var flights = ...
---
FlightsLibSolution::joinAirportDetailsV3(flights)
I get the error:
output application/json
var flights = {
"flights": [
{
...'. Reason: Unable to resolve reference of: `groupedAirportDetails`.```
Why isn't the `groupedAirportDetails` variable resolved? This is not just a Preview pane error. I get the same error raised then I run the Mule app.

The syntax to import a functions is:
import joinAirportDetailsV3 from dw::modules::FlightsLibSolution
For that to work there has to be file named FlightLibSolution.dwl in the src/main/resources/dw/modules directory.
Alternatively, you can import all functions from the module like this:
import * from dw::modules::FlightLibSolution

Related

Parsing Dynamic response in Karate

I want to verify the value of "RequestedName" in the following response, where the keys for different drugs is dynamic:
{
"requestId": "c826bee1-610e-4dee-b998-1fe4f8c15a1b",
"requestSource": "",
"responseSource": "client",
"status": 200,
"responseCodes": [
{
"code": "S00001",
"message": "Success.",
"params": {
"entity": ""
}
}
],
"context": null,
"payload": {
"0113ccf86ba79b698b8e7a8fb9effc4b": {
"RequestedName": "paracetamol",
"SearchKey": "0113ccf86ba79b698b8e7a8fb9effc4b",
"Name": "Genexa Acetaminophen Extra Strength",
"PrescribableName": "",
"ProductCodes": [
"69676-0059"
],
"DosageForm": "Tablet, coated",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0349fa4ea29da419c46745bc7e2a6c07": {
"RequestedName": "paracetamol",
"SearchKey": "0349fa4ea29da419c46745bc7e2a6c07",
"Name": "Pain Reliever",
"PrescribableName": "",
"ProductCodes": [
"70677-0168"
],
"DosageForm": "Tablet, extended release",
"Route": "Oral",
"Approved": true,
"UnApproved": false,
"Generic": true,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "650",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"060cfbde5d82d947c56aac304c136fd3": {
"RequestedName": "paracetamol",
"SearchKey": "060cfbde5d82d947c56aac304c136fd3",
"Name": "Betr Pain Relief",
"PrescribableName": "Acetaminophen 500 mg Oral Tablet",
"ProductCodes": [
"80267-0484"
],
"DosageForm": "Tablet",
"Route": "Oral",
"Approved": false,
"UnApproved": false,
"Generic": false,
"Allergen": false,
"Vaccine": false,
"Strength": {
"Number": "500",
"Unit": "mg/1"
},
"Purposes": {},
"SideEffects": {}
},
"0950fcbac262c1c1d3a9e6630615a5f9": {
"RequestedName": "paracetamol",
"SearchKey": "0950fcbac262c1c1d3a9e6630615a5f9",
"Name": "Acetaminophen",
I tired this:
* def list = []
* def fun = function(k, v){ karate.appendTo('list', { key: k, val: v } )}
* karate.forEach(response, fun)
* def keys = $list[?(#.val.payload.RequestedName==drugName)].key
but not working, getting error as below:
def keys = $list[?(#.val.payload.RequestedName==drugName)].key
Failed to parse filter: [?(#.val.payload.RequestedName==drugName)], error on position: 32, char: d
testsuite/GetDrugs.feature:20
Here is the approach you can use:
* def response =
"""
{
dynamicKey1: {
fixedKey: 'fixedValue1',
dataKey: 'dataValue2'
},
dynamicKey2: {
fixedKey: 'fixedValue2',
dataKey: 'dataValue2'
}
}
"""
* def keys = []
* def fun = function(k, v){ if (v.fixedKey == 'fixedValue2') keys.push(k) }
* karate.forEach(response, fun)
* match keys == ['dynamicKey2']

AWS IoT rule sql select statement

I am trying to write a SQL select statement for my AWS IoT rule to extract the values 'gateway_id and 'rssi' from the following MQTT message:
{
"end_device_ids": {
"device_id": "imd2",
"application_ids": {
"application_id": "pennal"
},
"dev_eui": "004E3A0DF76DC9E9",
"join_eui": "70B3D57ED003CBE8",
"dev_addr": "260BA9D0"
},
"correlation_ids": [
"as:up:01G30W0J4D65P6D50QH1DN3ZQP",
"gs:conn:01G2ZZ7FT9BH6J93WRYS4ATVDM",
"gs:up:host:01G2ZZ7FTN14103H90QN71Q557",
"gs:uplink:01G30W0HXWMES1Z7X7F2MCFMPF",
"ns:uplink:01G30W0HXXJM5PNGJAD0W01GGH",
"rpc:/ttn.lorawan.v3.GsNs/HandleUplink:01G30W0HXWFR3HNGBZS7XJV15E",
"rpc:/ttn.lorawan.v3.NsAs/HandleUplink:01G30W0J4D18JZW199EM8WERGR"
],
"received_at": "2022-05-14T08:47:25.837680984Z",
"uplink_message": {
"session_key_id": "AYBlRLSz9n83bW3WU3+GfQ==",
"f_port": 1,
"f_cnt": 5013,
"frm_payload": "DiAAAA==",
"decoded_payload": {
"rainmm": 0,
"voltage": 3.616
},
"rx_metadata": [
{
"gateway_ids": {
"gateway_id": "pennal-gw2",
"eui": "AC1F09FFFE057EC6"
},
"time": "2022-05-14T08:47:25.065794944Z",
"timestamp": 114306297,
"rssi": -126,
"channel_rssi": -126,
"snr": -8.25,
"uplink_token": "ChgKFgoKcGVubmFsLWd3MhIIrB8J//4FfsYQ+dnANhoMCJ3Z/ZMGEOPmv6sCIKjZvump7gYqCwid2f2TBhCA568f"
}
],
"settings": {
"data_rate": {
"lora": {
"bandwidth": 125000,
"spreading_factor": 11
}
},
"coding_rate": "4/5",
"frequency": "868100000",
"timestamp": 114306297,
"time": "2022-05-14T08:47:25.065794944Z"
},
"received_at": "2022-05-14T08:47:25.629041670Z",
"confirmed": true,
"consumed_airtime": "0.659456s",
"version_ids": {
"brand_id": "heltec",
"model_id": "cubecell-dev-board-class-a-otaa",
"hardware_version": "_unknown_hw_version_",
"firmware_version": "1.0",
"band_id": "EU_863_870"
},
"network_ids": {
"net_id": "000013",
"tenant_id": "ttn",
"cluster_id": "eu1",
"cluster_address": "eu1.cloud.thethings.network"
}
}
}
I have tried following the documentation here: AWS Documentation but am struggling with the nested part of the message.
my SQL statement at the moment is:
SELECT received_at as datetime, end_device_ids.device_id as device_id,
uplink_message.decoded_payload.rainmm as rainmm, uplink_message.decoded_payload.voltage as
voltage, uplink_message.settings.data_rate.lora.spreading_factor as sprfact,
uplink_message.consumed_airtime as time_on_air ,uplink_message.settings.timestamp as ts,
uplink_message.rx_metadata as rx,(select value gateway_ids from uplink_message.rx_metadata) as gw,
(select value rssi from uplink_message.rx_metadata)as rssi, get((select gateway_id from
uplink_message.rx_metadata),0).gateway_id as gwn FROM 'thethings/lorawan/matt-pennal-ire/uplink'
which returns
{
"datetime": "2022-05-15T12:19:11.947844474Z",
"device_id": "md4",
"rainmm": 5.842001296924288,
"voltage": 3.352,
"sprfact": 8,
"time_on_air": "0.092672s",
"ts": 3262497863,
"rx": [
{
"gateway_ids": {
"gateway_id": "pennal-gw2",
"eui": "AC1F09FFFE057EC6"
},
"time": "2022-05-15T12:19:11.178463935Z",
"timestamp": 3262497863,
"rssi": -125,
"channel_rssi": -125,
"snr": -7.5,
"uplink_token": "ChgKFgoKcGVubmFsLWd3MhIIrB8J//4FfsYQx4jXkwwaDAi/34OUBhCCy9XhAiDY6prg+ckHKgsIv9+DlAYQv8mMVQ=="
}
],
"gw": [
{
"gateway_id": "pennal-gw2",
"eui": "AC1F09FFFE057EC6"
}
],
"rssi": [
-125
]
}
but I would like it to return
{
"datetime": "2022-05-15T12:19:11.947844474Z",
"device_id": "md4",
"rainmm": 5.842001296924288,
"voltage": 3.352,
"sprfact": 8,
"time_on_air": "0.092672s",
"ts": 3262497863,
"gwn":"pennal_gw2"
"rssi":-126
}
Any help to get the values from the nested array would be greatly appreciated!

Karate: I get missing property in path $['data'] while using json filter path

I have gone through karate documentation and questions asked on stack overflow. There are 2 json arrays under resp.response.data. I am trying to retrieve and assert "bId": 81 in below json from the resp.response.data[1] but I get this missing property error while retrieving id value 81. Could you please help if I am missing something ?
* def resp =
"""
{
"response": {
"data": [
{
"aDetails": {
"aId": 15,
"aName": "Test",
"dtype": 2
},
"values": [
{
"bId": 45,
"value": "red"
}
],
"mandatory": false,
"ballId": "1231231414"
},
{
"aDetails": {
"aId": 25,
"aName": "Description",
"dtype": 2
},
"values": [
{
"bId": 46,
"value": "automation"
},
{
"bId": 44,
"value": "NESTED ARRAY"
},
{
"bId": 57,
"value": "sfERjuD"
},
{
"bId": 78,
"value": "zgSyPdg"
},
{
"bId": 79,
"value": "NESTED ARRAY"
},
{
"bId": 80,
"value": "NESTED ARRAY"
},
{
"bId": 81,
"value": "NESTED ARRAY"
}
],
"mandatory": true,
"ballId": "1231231414"
}
],
"corId": "wasdf-242-efkn"
}
}
"""
* def expectedbID=81
* def RespValueId = karate.jsonPath(resp, "$.data[1][?(#.bId == '" + expectedbID + "')]")
* match RespValueId[0] == expectedbID
Maybe you are over-complicating things ?
* match resp.response.data[1].values contains { bId: 81, value: 'NESTED ARRAY' }

React Native Select List Population

I am using this React Native package: https://github.com/gcanti/tcomb-form-native for display and capture form inputs.
And I got questions on display the select list based on custom API response.
{
"response": {
"countries": [
{
"PK_country_id": 132,
"country_code": "MY",
"country_name": "Malaysia"
},
{
"PK_country_id": 196,
"country_code": "SG",
"country_name": "Singapore"
},
{
"PK_country_id": 32,
"country_code": "BN",
"country_name": "Brunei"
},
{
"PK_country_id": 36,
"country_code": "KH",
"country_name": "Cambodia"
}
]
}
}
Well, the documentation did mentioned populating the select list based on enums
const Country = t.enums({
'IT': 'Italy',
'US': 'United States'
}, 'Country');
Any guidance for transforming the custom API response into the enums format provided? Please correct me if I am wrong.
You don't pass function to t.enums. Just the result converted.
For example,
const res = {
"response": {
"countries": [
{
"PK_country_id": 132,
"country_code": "MY",
"country_name": "Malaysia"
},
{
"PK_country_id": 196,
"country_code": "SG",
"country_name": "Singapore"
},
{
"PK_country_id": 32,
"country_code": "BN",
"country_name": "Brunei"
},
{
"PK_country_id": 36,
"country_code": "KH",
"country_name": "Cambodia"
}
]
}
}
By this convert,
let convertedResult = res.response.countries.reduce(function ( result, current ) {
result[ current.country_code ] = current.country_name;
return result;
}, {});
You get
{
'MY': 'Malaysia',
'SG': 'Singapore',
'BN': 'Brunei',
'KH': 'Cambodia'
}
Then pass this to t.enums
const Country = t.enums(convertedResult, 'Country');

lodash filter array using query array

How can I filter an array of objects below using lodash? Here is my query
var query = { "body": ["Hatchback", "Sedan"] };
var objects = [{
"make": "BMW",
"model": "i3",
"maxRange": 81,
"price": "42,400",
"body": "Hatchback"
}, {
"make": "Chevrolet",
"model": "Spark EV",
"maxRange": 82,
"price": "25,120",
"body": "Hatchback"
}, {
"make": "Kia",
"model": "Soul EV",
"maxRange": 90,
"price": "31,950",
"body": "Wagon"
}, {
"make": "Tesla",
"model": "Model S",
"maxRange": 303.2,
"price": "75,000",
"body": "Sedan"
}, {
"make": "Tesla",
"model": "Model X",
"maxRange": 257,
"price": "83,000",
"body": "SUV"
}]
I tried to use _matches but it doesn't seem to match arrays. Here is my attempt
_.filter(objects, _.matches(query))
Ummm, I dont know about how to do with lodash but we can certainly do with vanillaJS in just two lines of code though.
var query = { "body": ["Hatchback", "Sedan"] };
var filteredObjArray = objects.filter(obj => query.body.includes(obj.body)))
Hope that helps :).
You can use JS .filter with .every to check multiple properties. If a query property is an array use .include to compare, if not make a simple comparison:
function multipleFilter(arr, query) {
var queryKeys = Object.keys(query); // create an array of the keys in the query object
return arr.filter(function(item) {
return queryKeys.every(function(key) { // use .every on the keys so if one fails, the item is filtered out
var keyData = item[key]; // get the data of the key from the item
var keyQuery = query[key]; // get the query from query object
return Array.isArray(keyQuery) ? keyQuery.includes(keyData) : keyQuery === keyData; // if the query is an array use include, if not use comparison
});
});
}
var objects = [{
"make": "BMW",
"model": "i3",
"maxRange": 81,
"price": "42,400",
"body": "Hatchback"
}, {
"make": "Chevrolet",
"model": "Spark EV",
"maxRange": 82,
"price": "25,120",
"body": "Hatchback"
}, {
"make": "Kia",
"model": "Soul EV",
"maxRange": 90,
"price": "31,950",
"body": "Wagon"
}, {
"make": "Tesla",
"model": "Model S",
"maxRange": 303.2,
"price": "75,000",
"body": "Sedan"
}, {
"make": "Tesla",
"model": "Model X",
"maxRange": 257,
"price": "83,000",
"body": "SUV"
}];
var query1 = {
"body": ["Hatchback", "Sedan"]
};
var query2 = {
"body": ["Hatchback", "Sedan"],
make: "BMW"
};
console.log('query1', multipleFilter(objects, query1));
console.log('query2', multipleFilter(objects, query2));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.15.0/lodash.min.js"></script>