How to represent lists of blocks in Configgy? - scala

Configgy supports lists of strings as values and blocks of key/value pairs.
But it seems it does not support lists of blocks of key/value pairs as values.
Am I missing something?

I ended up using nested blocks:
contacts {
c1 {
name = "Joe Smith"
email = "jsmith#example.com"
}
c2 {
name = "John Brown"
email = "jbrown#example.com"
}
}

Related

How to edit a value (list of entries) from an api response to use in a request body in Gatling/Scala

I have an issue that I'm hoping someone can help me with. I'm pretty new to coding and Gatling, so I'm not sure how to proceed.
I'm using Gatling (with Scala) to create a performance test scenario that contains two API-calls.
GetInformation
SendInformation
I'm storing some of the values from the GetInformation response so I can use it in the body for the SendInformation request. The problem is that some information from the GetInformation response needs to be edited/removed before it is included in the body for SendInformation.
Extract of the GetInformation response:
{
"parameter": [
{
"name": "ResponseFromGetInfo",
"type": "document",
"total": 3,
"entry": [
{
"fullUrl": "urn:uuid:4ea859d0-daa4-4d2a-8fbc-1571cd7dfdb0",
"resource": {
"resourceType": "Composition"
}
},
{
"fullUrl": "urn:uuid:1b10ed79-333b-4838-93a5-a40d22508f0a",
"resource": {
"resourceType": "Practitioner"
}
},
{
"fullUrl": "urn:uuid:650b8e7a-2cfc-4b0b-a23b-a85d1bf782de",
"resource": {
"resourceType": "Dispense"
}
}
]
}
]
}
What I want is to store the list in "entry" and remove the entries with resourceType = "Dispense" so I can use it in the body for SendInformation.
It would have been ok if the entry list always had the same number of entries and order, but that is not the case. The number of entries can be several hundred and the order of entries varies. The number of entries are equal to the "total" value that is included in the GetInformation response.
I've thought about a few ways to solve it, but now I'm stuck. Some alternatives:
Extract the entire "entry" list using .check(jsonPath("$.parameter[0].entry").saveAs("entryList")) and then iterate through the list to remove the entries with resourceTypes = "Dispense".
But I don't know how to iterate over a value of type io.gatling.core.session.SessionAttribute, or if this is possible. It would have been nice if I could iterate over the entry list and check if parameter[0].entry[0].resourceType = "Dispense", and remove the entry if the statement is true.
I'm also considering If I can use StringBuilder in some way. Maybe if I check one entry at the time using .check(parameter[0].entry[X].resourceType != dispense, and if true then append it to a stringBuilder.
Does someone know how I can do this? Either by one of the alternatives that I listed, or in a different way? All help is appreciated :)
So maybe in the end it will look something like this:
val scn = scenario("getAndSendInformation")
.exec(http("getInformation")
.post("/Information/$getInformation")
.body(ElFileBody("bodies/getInformtion.json"))
// I can save total, så I know the total number of entries in the entry list
.check(jsonPath("$.parameter[0].total").saveAs("total"))
//Store entire entry list
.check(jsonPath("$.parameter[0].entry").saveAs("entryList"))
//Or store all entries separatly and check afterwards who have resourceType = "dispense"? Not sure how to do this..
.check(jsonPath("$.parameter[0].entry[0]").saveAs("entry_0"))
.check(jsonPath("$.parameter[0].entry[1]").saveAs("entry_1"))
//...
.check(jsonPath("$.parameter[0].entry[X]").saveAs("entry_X"))
)
//Alternativ 1
.repeat("${total}", "counter") {
exec(session => {
//Do some magic here
//Check if session("parameter[0]_entry[counter].resourceType") = "Dispense" {
// if yes, remove entry from entry list}
session})}
//Alternativ 2
val entryString = new StringBuilder("")
.repeat("${total}", "counter") {
exec(session => {
//Do some magic here
//Check if session("parameter[0]_entry[counter].resourceType") != "Dispense" {
// if yes, add to StringBuilder}
// entryString.append(session("parameter[0]_entry[counter]").as[String] + ", ")
session})}
.exec(http("sendInformation")
.post("/Information/$sendInformation")
.body(ElFileBody("bodies/sendInformationRequest.json")))
I'm pretty new to coding
I'm using Gatling (with Scala)
Gatling with Java would probably be an easier solution for you.
check(jsonPath("$.parameter[0].entry").saveAs("entryList"))
This is going to capture a String, not a list. In order to be able to iterate, you have to use ofXXX/ofType[], see https://gatling.io/docs/gatling/reference/current/core/check/#jsonpath
Then, in order to generate the next request's body, you could consider a templating engine such as PebbleBody (https://gatling.io/docs/gatling/reference/current/http/request/#pebblestringbody) or indeed use StringBody with a function with a StringBuilder.

Map properties path as function arguments

So i have a function that basically sorts a MAP of MAP's, but it uses different MAP properties for the sort, so i want to sort by age or by name based on the user input.
{
"name": "John",
"other_data:
{
"age": "20",
"nickname": "Doe2020"
}
}
So my idea was to make a generic function to sort this. There is some way where i can send the path of each property as a function argument to sort based on this argument ?
Like "mySortFunction(MapPath: ["other_data"]["age"]);"
or "mySortFunction(MapPath: ["name"]);"
Thanks!
You could try something like this, if your properties are at max two levels:
mySortFunction(Map map, {String firstLevel, String secondLevel}){
if(firstLevel != null){
if(secondLevel != null){
sortMap(map[firstLevel][secondLevel]); // Your sorting logic here
} else {
sortMap(map[firstLevel]); // sorting logic strikes back
}
}
}
You can add more optional variables and increase the if logic for deeper maps

How can I find out if a List of Maps contain a specific value for key?

I'm having trouble understanding how to check if a List of Maps contain a value by a key. Below is the structure of data I have.
[
{
id: 1,
bookTxt: Hereissomebooktext.,
bookAuth: Charles
},
{
id: 3,
bookTxt: Hereissomemorebooktext.,
bookAuth: Roger
},
{
id: 6,
bookTxt: Hereissomeevenmorebooktext.,
bookAuth: Matt
}
]
I'm trying to write something simple or a function to see if this List of Maps contains a certain 'id'. I know that List has the Contains method but in my case I have to find a value within a list of Maps.
For example if I want to see if the List of Maps above contains the id of 3, how would I be able to access that?
Direct way to check
if (list[0].containsKey("id")) {
if (list[0]["id"] == 3) {
// your list of map contains key "id" which has value 3
}
}
And for indirect way you need to iterate through the loop like this:
for (var map in list) {
if (map?.containsKey("id") ?? false) {
if (map!["id"] == 3) {
// your list of map contains key "id" which has value 3
}
}
}
Maybe iterating over the maps in the list, then ask to every map to get key you want, and check the content for what you want.

Comparing two objects in Joi validation (eg. to avoid duplicates)

I'm using Joi to validate a complex form entry. The form asks for two addresses, mainContactAddress and seniorContactAddress. I want to validate them to ensure they aren't the same address.
Each address is an object like this:
{
"line1": "123 Some Street",
"line2": "Some Town",
"county": "Some County",
"postcode": "123 ABC",
"townCity": "City"
}
I initially tried this:
Joi.ukAddress().invalid(Joi.ref('seniorContactAddress'))
(ukAddress() is a custom extension I've created which specifies each of the above fields as a required string.)
This doesn't work, because the equality === comparison between the two objects returns false even when they have the same string values.
I can't see a Joi method to do this. I was hoping to be able to serialise the object (eg. something like Object.values(mainContactAddress).join(',') and then compare the resulting strings) but Joi.ref() only gives, well, a reference to the object, so I can't call functions against it directly.
Any thoughts on how I could achieve this validation/comparison?
I ended up writing a custom rule for my extension:
{
// Enforce a unique address compared to the senior contact
name: 'mainContact',
validate(params, value, state, options) {
// Format addresses into a comparable string,
// making sure we sort them as the stored version
// is in a different order to the form-submitted one.
const serialize = address =>
Object.values(address)
.sort()
.join(',');
const seniorContactAddress = get(
state.parent,
'seniorContactAddress',
[]
);
if (serialize(seniorContactAddress) === serialize(value)) {
return this.createError(
'address.matchesSenior',
{ v: value },
state,
options
);
} else {
return value;
}
}
}
This does feel like an anti-pattern (eg. abusing state to look at other values in the Joi object) but it does what I needed.

Mongodb - How to find string in multiple fields?

Using Pymongo for this scenario.
I have User that has email, first_name, last_name.
I am using this Pymongo snippet:
user_found = users.find({'$or':[
{'email':{'$regex':searchString, '$options':'i'}},
{'first_name':{'$regex':searchString, '$options':'i'}},
{'last_name':{'$regex':searchString, '$options':'i'}}]})
this example works, if I want to find searchString in:
email, or
first_name, or
last_name
now I need to also find searchString in first_name + last_name combined.
how can I do that?
Is there a way in mongo, through the query, to combine the two into a "fullname" then search the fullname?
Easiest way is to add an array field and populate it with all of the variants that you want to search on. Index that array field.
That way you only need one index and your search across all fields is simple and doesn't change when you want to search on some new search variant. You can also normalize the text you put into the search array, for example, lower casing it, removing punctuation etc.
See https://stackoverflow.com/q/8206188/224370
Edit: MongoDB's documentation now covers keyword search and the new full-text search feature.
I had the same problem. I already used regex string search, so my solution was:
generate a helper collection. Here I combine all relevant string, like:
{
search_field: email + " " + first_name + " " + last_name,
ref_id: (id to real object)
}
I then use a regexp to creat what i allow to be looked for:
// logic found here: http://stackoverflow.com/questions/10870372/regex-match-if-string-contain-all-the-words-or-a-condition
var words = query.split(/[ ,]+/);
var regstr = "";
for (var i = 0; i < words.length; ++i) {
var word = words[i];
regstr += "(?=.*?\\b" + word + ")";
}
regstr += "^.*$";
regex = new RegExp(regstr, "i");
This then also gives some flexibility about the order.
Searching is not the fastest, since it still uses regex on all elements, but it is ok for me. (I also index the collection on search_field.
Getting results also becomes a nested call, since first you need to get the _ids you really want, and then you can query for them like so:
connection.find({ "search_field" : regex }, { _id: 0, ref_id: 1 }, { limit: limit, skip: start }).toArray(function (err, docs) {
if (err) throw err;
// map array of documents into simple array of ids
var ids = [];
for (var i = 0; i < docs.length; ++i)
{
var doc = docs[i];
ids.push(doc.ref_id);
}
if (ids.length > 0)
MongooseEmails.find({ "_id": { $in: ids } }, function (err, docres) {
if (err) throw err;
res.send(JSON.stringify(docsres));
});
else
res.send("");
});
This is edited code.. perhaps there is a syntax error, generally, it is working for me.