Check if one list contains element from the other in groovy - groovy

i have 2 list
List<Car> cars
List<Car> filteredCars
and in cars
{
{
"uuid":"1234",
"name": "A"
},
{
"uuid":"2222",
"name": "B"
}
}
and in filteredCars
{
{
"uuid":"1234",
"name": "A"
},
{
"uuid":"3333",
"name": "C"
}
}
Now i want to add add filteredCars in cars by and then car should contains there object only (A,B,C)
i am try to implement this using groovy closure
filteredCars.each {
if (!cars.contains(it)) {
cars.add(it)
}
}
and but by using this it added the duplicate objects
Any efficeent way to implement this in groovy without using two nested loops?

Depending on your list objects/maps there your approach would only work if the objects themself are compareable (which they are most likely not). So it might be easier to just build an index of the known items for a quick lookup. E.g.
def knownCarsIds = cars*.uuid.toSet()
Then only add if such an id ist not known:
...
if (!knownCarIds.contains(it.uuid)
...

Related

GraphiQL on Orchard-Core: "where" and "filter" does not work

I am trying to understand how to query with GraphiQL on Orchard-Core and I am facing some problems which I cannot fix:
I am trying to implement an extremelly simple query:
query MyQuery ($myDesc: String) {
product (where: {description: $myDesc}) {
description
}
}
When I try to play the query I receive the following error:
{
"errors": [
{
"message": "Argument \"where\" has invalid value {description: $myDesc}.\nIn field \"description\": Unknown field.",
"locations": [
{
"line": 17,
"column": 11
}
],
"extensions": {
"code": "5.3.3.1"
}
}
]
}
It says that 'Field "description" is not defined by type "productWhereInput"'
I need to apply to the products a bunch of filters to give me the result I want, but none of them are working.
I have also tried to use "filter" instead of "where", but then I get another error:
'Unknown argument "filter" on field "Query.product".'
Looking to some documentations it doesn't seem to be so hard to use GraphiQL, but when I try to write the code in the way I find it on the docs it give me errors after errors here on Orchard-Core.
There are only limited number of default implemented where filters. By the error you get you didn't implement WhereInputObjectGraphType for your part.
One way is to create yessql MapIndex on fields you want to be able to query.
I'll assume Description is TextField.
So first create ProductPartIndex class as YesSQL MapIndex, that will map Description of every ContentItem with ProductPart.
After that you need to connect index with GraphQL WhereInputObjectType.
public class ProductInputObjectType : WhereInputObjectGraphType<ProductPart>
{
public ProductInputObjectType(IStringLocalizer<ProductInputObjectType> S)
{
AddScalarFilterFields<StringGraphType>("description", S["product description"]);
}
}
public class ProductPartIndexAliasProvider : IIndexAliasProvider
{
private static readonly IndexAlias[] _aliases = new[]
{
new IndexAlias
{
Alias = "ProductPart",
Index = nameof(ProductPartIndex),
IndexType = typeof(ProductPartIndex)
}
};
public IEnumerable<IndexAlias> GetAliases()
{
return _aliases;
}
}
[RequireFeatures("OrchardCore.Apis.GraphQL")]
public class Startup : StartupBase
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddInputObjectGraphType<ProductPart, ProductInputObjectType>();
services.AddTransient<IIndexAliasProvider, ProductPartIndexAliasProvider>();
services.AddWhereInputIndexPropertyProvider<ProductPartIndex>();
}
}
This is adhoc code, didn't test it. Everything in here is altered version of AliasPart from source code.

Is there a way to validate a schema against a groovy map?

My use case is Jenkins specific but this is a general Groovy question
I have a map I want to apply a schema to. If this map is missing fields or some fields are of the wrong type (string/int/list/map/etc) I want to throw a clear error message that explains where the map doesn't match the schema.
I pass a map in my Jenkinsfile to a function in my shared library like this, so mypipeline would need to include the schema validation piece:
#Jenkinsfile
#Library('my-shared-lib') _
mypipeline ([
'validate-this-map': [
// manditory-param-one must exist and be a list
'manditory-param-one': ["aaa","bbb","ccc"]
// manditory-param-two must exist and be a map
'manditory-param-two': [
"manditory-one": "111", // must include this field and be a string
"manditory-two": "222", // must include this field and be a string
"optional": "33",
]
// manditory-param-three must exist and be a list of maps that have specific fields
'manditory-param-three': [
"manditory-one": [
// all maps in this list must have these two fields
"aaa": true // validate bool
"bbb": "sdfsfdsd" //validate string
]
]
'optional-param': "sdfsdfs" // ignore this. dont fail if this is here
]
])
What I have done in the past is things like translate the language specific construct (in this case a groovy Map) to json and apply a jsonschema which supports advanced features like recursion, etc. That can be wonky though and I want to know if this is possible in an idiomatic groovy way.
I don't want to make validate-this-map a class because that would complicate the Jenkinsfile config I think. Is there a way I can have groovy translate a map into a class and have groovy validate the class properties or something?
You can use Groovy's named parameter in constructor facility and create object hierarchies automagically.
Then you can sprinkle it with simple validation, I used Groovy Truth down bellow for simplicity.
The code (after some clean-up of JSON keys) could look like:
import groovy.transform.*
// your classes
#ToString
class A {
List<String> manditoryParamOne
ManditoryParamTwo manditoryParamTwo
ManditoryParamThree manditoryParamThree
String optionalParam
boolean asBoolean() {
manditoryParamOne && manditoryParamTwo && manditoryParamThree
}
}
#ToString
class ManditoryParamTwo {
String manditoryOne, manditoryTwo, optional
boolean asBoolean() {
manditoryOne && manditoryTwo
}
}
#ToString
class ManditoryParamThree {
ManditoryOne manditoryOne
boolean asBoolean() {
manditoryOne
}
}
#ToString
class ManditoryOne{
Boolean aaa
String bbb
boolean asBoolean() {
null != aaa && bbb
}
}
// some test code, pay attention to map keys
def mapValid = [
// manditory-param-one must exist and be a list
'manditoryParamOne': ["aaa","bbb","ccc"],
// manditory-param-two must exist and be a map
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
// all maps in this list must have these two fields
"aaa": true, // validate bool
"bbb": "sdfsfdsd" //validate string
]
],
'optionalParam': "sdfsdfs" // ignore this. dont fail if this is here
]
A a = new A( mapValid )
assert a.toString() == 'A([aaa, bbb, ccc], ManditoryParamTwo(111, 222, 33), ManditoryParamThree(ManditoryOne(true, sdfsfdsd)), sdfsdfs)'
assert true == !!a
assert true == !!a.manditoryParamOne
assert true == !!a.manditoryParamTwo
def mapInvalid = [
'manditoryParamTwo': [
"manditoryOne": "111", // must include this field and be a string
"manditoryTwo": "222", // must include this field and be a string
"optional": "33",
],
// manditory-param-three must exist and be a list of maps that have specific fields
'manditoryParamThree': [
"manditoryOne": [
"bbb": "sdfsfdsd" //validate string
]
]
]
A aa = new A( mapInvalid )
assert false == !!aa
assert true == !!aa.manditoryParamTwo
assert false == !!aa.manditoryParamThree

Issue in giving plurals in Bixby dialogs

I had a question regarding plurals in dialog.
Let's say I have a structure
structure (MyStructure) {
property (MyConcept) {
type {EnumConcept} max (Many)
}
}
And a Value dialog for it:
dialog (Value) {
match: MyConcept(this)
if (this == 'ABC') {
switch(plural(this)) {
case (One) { template("single1") }
default { template ("plural1") }
}
}
if (this == 'DEF') {
switch(plural(this)) {
case (One) { template("single2") }
default { template ("plural2") }
}
}
}
By using
Code:
#{value(myStructure.myConcept.plural('Many'))}
I am able to get "plural1" or "plural2" when myStructure has below values and size of myConcept is 1:
myStructure = [
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: ABC }
]
When size of myConcept is 2 and myStructure has below values,
myStructure = [
{ myConcept: ABC },
{ myConcept: ABC },
{ myConcept: DEF },
{ myConcept: DEF }
]
using the Code:
#{value(myStructure.myConcept.plural('Many'))}
is giving NLG as
"single1 and single2"
What I want in the NLG:
"plural1 and plural2"
Can someone please help us in giving proper plural NLG for each element of the unique "myConcept" present in the list of "myStructure"?
What I want is to apply plurality to each individual value of an array.
size(myStructure.myConcept) = 2.
I want to apply plural to both the values of myConcept.
I do not think in dialogs we have an for-each kind of thing available.
It's a little hard to tell what's going on in the code above. If this answer isn't helpful, consider sharing the full source code somewhere for live debugging.
You can try something like
#{value(myStructure.myConcept.plural(plural(myStructure.myConcept))}
The docs has an example like:
#{concept(restaurantStyle.plural(plural(restaurant)))}
Source: https://bixbydevelopers.com/dev/docs/reference/ref-topics/el-ref#node-evaluation-functions in the plural(node) section.

How do I pass Javascript Object to Bixby's Action Output?

I am building an app that search for anime quotes. So, I have the following data, which is 331 Objects (which I call them 'Quote Cards') long and so it will also be updated in future as I add more and more quotes. The problem I having is in creating concepts for JS's array items such as keywords, and imageTag. and also the the character names which are listed as property. I am also willing to change the output as long as I can keep category, and keywords array items. Those are necessary for my quote cards
[
{
$id: "Cold_Souls_1",
animeTitle: "Fullmetal Alchemist Brotherhood",
animePoster:{
referenceImage: 'https://qph.fs.quoracdn.net/main-qimg-da58c837c7197acf364cb2ada34fc5fb.webp',
imageTags: ["Grey","Yellow","Blue","Metal Body","Machine", "Robot","Yellow Hair Boy"],
},
animeCharacters:{
"Edward Elric": [
{
quote: "A lesson without pain is meaningless. For you cannot gain something without sacrificing something else in return. But once you have recovered it and made it your own... You will gain an irreplaceable Fullmetal heart.",
keywords: ["lesson", "pain", "return", "meaningless", "gain","sacrificing", "recover"],
category: "Life Lesson"
}
]
}
},....................
]
In Bixby, you would model a structure that represents the JSON response.
structure (Anime) {
description (The output of your action)
property (title) {
type(viv.core.Text)
visibility (Private)
}
property (poster){
type(AnimePoster)
visibility (Private)
}
property (characters) {
type (AnimeCharacter)
max (Many)
visibility (Private)
}
}
structure (AnimePoster) {
property (referenceImage) {
type (viv.core.Text)
visibility (Private)
}
property (imageTags) {
type (viv.core.Text)
max (Many)
visibility (Private)
}
}
structure (AnimeCharacter) {
property (name) {
type (viv.core.Text)
visibility (Private)
}
property (quote) {
type (viv.core.Text)
visibility (Private)
}
property (keywords) {
type (viv.core.Text)
max (Many)
visibility (Private)
}
property (category) {
type (viv.core.Text)
visibility (Private)
}
}
In your javascript file, you process the JSON structure of animes
// listOfAnimes is the JSON object described in the question
var animes = [];
listOfAnimes.forEach((anime) => {
var characterNames = Object.keys(anime.animeCharacters);
var characters = [];
Object.keys(anime.animeCharacters).forEach((key) => {
characters.push({
name: key,
quote: anime.animeCharacters[key][0].quote, // * warning, can be many
category: anime.animeCharacters[key][0].category// * warning, can be many
});
});
animes.push( {
$id: anime.$id,
title: anime.title,
characters: characters,
poster: {
referenceImage: anime.animePoster.referenceImage,
imageTags: anime.animePoster.imageTags
},
});
});

Need to get the values of the objects (JSON) which have been created dynamically

How to get the top object value in PentahoDI? I have got the other elements like Category, Subcategory, section from the following example of Json file. However, I need to capture the first root object which is x#chapter#e50de0196d77495d9b50fc05567b4a4b and x#e50de0196d77495d9b50fc05567b4a4b
{
"x#chapter#e50de0196d77495d9b50fc05567b4a4b": {
"Category": "chapter",
"SubCategory": [
"x#4eb9072cf36f4d6fa1e98717e6bb54f7",
"x#d85849fbde324690b6067f3b18c4258d",
"x#3edff1a1864f41fe8b212df2bc96bf13"
],
"Section": {
"display_name": "Week 1 Section"
}
},
"x#e50de0196d77495d9b50fc05567b4a4b": {
"category": "course",
"Subcategory": [
"x#e50de0196d77495d9b50fc05567b4a4b"
],
"Section": {
"advanced_modules": [
"google-document"
],
}
}
}
In the Fields tab of the Json Input step I have given the Names and Paths as: Category --> $..Category, Subcategory --> $..Subcategory, Section --> $..Section.
However, I am unable to get the root element as it is crucial information for us to work on it. ex (x#chapter#e50de0196d77495d9b50fc05567b4a4b and x#e50de0196d77495d9b50fc05567b4a4b)
I have used the following code to get the values of the dynamic objects but it didnt work. The following is the code I used it.
var obj = JSON.parse (JBlock) //Jblock is the one which holds the entire string.
var keys = Object.name( obj);
JSONPath is not able to get the keys of a JSON structure. This is one of my main issues with JSONPath, and I wish Pentaho had included other JSON parsing engines.
This JavaScript to be used in Modified Java Script Value works for me. Add a value in the fields editor like this:
And then a script like this:
var obj = JSON.parse(JBlock);
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
    var row = createRowCopy(getOutputRowMeta().size());
    var idx = getInputRowMeta().size();
row[idx++] = keys[i];
putRow(row);
}
trans_Status = SKIP_TRANSFORMATION;

Resources