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

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.

Related

Missing element in SOAP API request using Python's Zeep, but the element is in the request dictionary

i'm using Zeep to interact with Workday's SOAP API to edit a someone's Workday username. Here is the following request body to the Human Resources WSDL, v37.2
request_dict = {
"Workday_Account_for_Worker_Update": {
"Worker_Reference": {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
},
"Workday_Account_for_Worker_Data": {
"User_Name": username
}
}
}
response = client.service.Update_Workday_Account(request_dict)
The error message i receive is
zeep.exceptions.ValidationError: Missing element Workday_Account_for_Worker_Data (Workday_Account_for_Worker_Update.Workday_Account_for_Worker_Data), but the element is clearly there. Anyone have any idea what I'm doing wrong?
You are not using the correct method signature to perform the call.
If you do a:
python -mzeep https://community.workday.com/sites/default/files/file-hosting/productionapi/Human_Resources/v37.2/Human_Resources.wsdl > output.txt
and you look inside the produced output.txt file, you will see that Update_Workday_Account has this signature:
Update_Workday_Account(
Worker_Reference: ns0:Worker_ReferenceType,
Non_Worker_Reference: ns0:RoleObjectType,
Workday_Account_for_Worker_Data: ns0:Workday_Account_for_Worker_DataType,
version: xsd:string,
_soapheaders={header: ns0:Workday_Common_HeaderType}
) -> None
so your code should probably be something like this:
worker_reference = {
"Employee_Reference": {
"Integration_ID_Reference": {
"ID": {
"type": "WD-EMPLID",
"_value_1": user_id
}
}
}
}
workday_account_for_worker_data = {
"User_Name": username
}
client.service.Update_Workday_Account(worker_reference, None, workday_account_for_worker_data)
I can't really test the call from my side so you should substitute appropriate parameters on your side before making the request.

Check if one list contains element from the other in 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)
...

coordinates does not exist in type 'GeometryDataType'

This is a follow up on this question. Now I am using the point object correctly however I get this error:
src/actions/collectGpsData.ts:22:43 - error TS2322: Type '{ type: string; coordinates: any[]; }' is not assignable to type 'GeometryDataType'.
Object literal may only specify known properties, and '"coordinates"' does not exist in type 'GeometryDataType'.
22 place.location = { "type": "Point", "coordinates": [point.latitude, point.longitude] };
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Found 1 error.
import { Action } from "actionhero"; // No GeometryDataType sequelize.js definition
import { Place } from "../models/Place";
export class CollectGpsData extends Action {
constructor() {
super();
this.name = "collectGpsData";
this.description = "Collects GPS data and inserts it into the database";
this.outputExample = {};
this.inputs = {
gpsdata: {
required:true
}
}
}
async run(data) {
var GPSdata = data.params.gpsdata;
GPSdata.forEach(point => {
var place = new Place();
place.deviceimei = point.deviceimei;
place.location = { "type": "Point", "coordinates": [point.latitude, point.longitude] }; //error line
});
}
}
Why am I getting this error? and how can I avoid this error in the future?
I've answered it in your GitHub issue:
Hello #krlicmuhamed!
As #nainkunal933 noted, please include a complete code sample next time. The code you posted does not show how User is defined, for example. Please use a sequelize-sscce.
That said, I took the time to look into what's happening and tried to figure it out.
So, first of all, this issue is typescript-only. The code works fine in runtime. Please include this information directly next time.
I ventured into your stackoverflow question and comments and found this:
https://gist.github.com/krlicmuhamed/199c0bc3560a08718b553f3f609acbcd#file-places-ts-L22
Did you find any documentation instructing you to use this specific type explicitly here? If yes, please post the link so I can fix it. Regardless, I don't blame you because we really should have a set of recommended types to apply on each data type. It turns out GeometryDataType is not the correct type to use in this case.
The solution is to install #types/geojson:
npm install --save-dev #types/geojson
Then, import Geometry:
import type { Geometry } from '#types/geojson'
And then replace that line of code in which you put GeometryDataType with Geometry:
#AllowNull(false)
#Column(DataTypes.GEOMETRY)
- location: GeometryDataType;
+ location: Geometry;

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
},
});
});

Resources