fragment cannot be spread here as objects of type "Query" - graphql-js

Trying out relay with react and ran into this today. Here is what I've done so far.
Root Query:
query {
tasks {
id
taskName
taskStatus
userId
}
}
React component hierarchy
App
↳--TaskList (props: tasks)
↳--TaskListItem (props: task)
Now due to the principle of colocation I know I have to write fragments in each component to describe their data needs.
TaskListItem.js
const TaskListItemContainer = createFragmentContainer(
TaskListItem,
graphql`
fragment TaskListItem_task on task {
id
taskName
taskDone
authorId
}
`
);
TaskList.js
const TaskListContainer = createFragmentContainer(
TaskList,
graphql`
fragment TaskList_tasks on task {
tasks {
...TaskListItem_task
}
}
`
);
App.js
<QueryRenderer
environment={relayEnvironment}
query={graphql`
query AppQuery {
...TaskList_tasks
}
`
}
When I run the relay compiler I get the following error.
Fragment "TaskList_tasks" cannot be spread here as objects of type "Query" can never be of type "task".
App.js (3:15)
2: query AppQuery {
3: ...TaskList_tasks
^
4: }
Not able to figure out how to organize the structure because of this problem. Should I modify the schema just to facilitate the structure and reuse of fragments on the client side?

A basic Fragment consists of five things:
the fragment keyword
the name of the Fragment
the on keyword
the type the Fragment applies to
the selection set wrapped in a set of curly brackets
The selection set is one or more fields of the type you specify that you want to request when you use the Fragment. Think of the Fragment as a drop in replacement for a single selection set. If I have a query like this:
query {
foo
bar
}
then { foo bar } is the selection set I'm requesting, in this case on the Query type (or whatever your query root operation type is called in your schema). So if I want to use a fragment, I would write:
query {
...QueryFields
}
fragment QueryFields on Query {
foo
bar
}
In your code, you're trying to write a query like:
query {
...TaskList_tasks
}
However, as the error indicates, the type associated with the TaskList_tasks fragment is task. But you're not replacing a selection set for a task type here, you're replacing a selection set for the Query type. So your request is not valid.
TLDR; You need to change the type on your Fragment to Query:
fragment TaskList_tasks on Query {
tasks {
...TaskListItem_task
}
}

Related

OData error when bind to an element in a Master-Detail app

I have developed a Master-Detail app. In the Detail view, I am using a DynamicPage where within content, I am using an IconTabBar Element with 3 items. Each item is a different Fragment with a Smartform.
Master view is loading the data from an EntitySet (MasterEntity)
Detail view with a is using some fields from the Entity MasterEntity
Fragment 1: is using DetailEntitySet
Fragment 2: is using DetailEntitySet
Fragment 3: is using DetailEntitySet
Basically, when Detail View Controller is detecting the RouteMatch, I am receiving the selected line on Master View and I bind it to the View Detail. Once it is done, I am checking if the view was generated and then, calling a method to bind the Expanded entity to the iconTabBar Element which contains the 3 Fragments. The code is as follows:
function _onRoutePatternMatched(event) {
if (event.getParameter("name") === "detail") {
var path = event.getParameter("arguments").contextPath;
if (path !== " ") {
var path2 = "/" + path;
view.bindElement(path2);
if (view) {
this._setBindingToIconTab("Master2Detail");
}
} else {
view.unbindElement();
}
}
}
The _setBindingToIconTab function is as follows:
_setBindingToIconTab: function (sAssociation) {
view.byId("iconTabBar").bindElement(sAssociation);
}
iconTabBar is the ID I have assigned within the Detail view to the IconTabBar Element.
The problem is, when I execute it and it loads the first Fragment, all is ok. With the 2nd and 3rd, I got errors (but the values are displayed...). I am loading the Fragments when they are picked on the screen. If they were not generated, I instantiate and store them in an array. The errors I got are:
Assertion failed: The EDM property "DateFrom" was not found in the "ZZODATA_TEST_SRV.Master" entity type. -
sap.ui.comp.smartfield.ODataControlFactory
It is complaining about Fields from DetailEntitySet are not in MasterEntitySet.
Could you please give me a hand with this?
As there is no XML, running example etc. i can't tell you why this error occurs but..
Best practise is to biind also in the detail view the selected entity with expand to the detail and so on
MasterEntitySet->DetailEntitySet
As bindings are propagated to children there is no need to bind the iconTabBar again. Data is already there. Again i don't know your case, but most services look like this
MasterEntitySet->DetailEntitySet->DataVariantA(ForIconTab1)
->DataVariantB(ForIconTab2)
->DataVariantC(ForIconTab3)
In V4 your detail code looks like this
oView.bindObject({
path: "/MasterEntity(" + this._args.ID + ")",
parameters: {
$expand:`DetailEntityNavPath($expand=DataVariantANavPath()...`
},
events: {
dataReceived: (oEvent) => {...

AWS-CDK Appsync Codefirst input types

To avoid duplication of data structures I wanted to reuse a type definition on an input type like this
export const DeviceStatus = new ObjectType('DeviceStatus', {
definition: {
time: timestamp,
firmwareVersion: string
},
});
export const DeviceStatusInput = new InputType('DeviceStatusInput', {
definition: {
tenantId: id_required,
deviceId: id_required,
// Reuse of DeviceStatus Field definition
status: DeviceStatus.attribute()
}
});
There is no error since the return type of DeviceStatus.attribute() is fine, and this works for ObjectType inheritance.
From my perspective this should work, but deploying results in a nasty "Internal Error creating Schema" error.
Of course I could move the whole definition into an object and reuse it but that seems weird. Is there any good solution on this for the CodeFirst approach
It seem to be invalid to reference object type in input type.
I recommend to view Can you make a graphql type both an input and output type?
Probably best you can do is to create some convenience method which will create you both object and input type from single definition.

How to augment list from one module to another and add leafs YANG

Suppose I have two modules, I would like to extend one list with new leafs.
module A {
list deviceList {
key name;
leaf name{
}
leaf hostname{
}
}
}
and I would like to augment it to another leaf
module B {
list generalInfo{
key customerName;
leaf customerName{
type string;
}
augment moduleA:deviceList {
leaf ipAddress{
}
}
}
I have done it using grouping and container and list inside but this completely changes our existing structure, I would like to ommit container and grouping if thats possible.
It seems that you want to reuse a part of the schema definition, put it in another place in the schema tree and add a node to it.
You cannot do it the way you tried because the augment statement can appear only on the root level or in the uses statement.
You can do that only with a grouping but you can omit the container. Refactor A: define a grouping that's a list. Refer to it in B and augment it.
module A {
grouping devices {
list deviceList {
key name;
leaf name{
}
leaf hostname{
}
}
}
uses devices;
}
module B {
list generalInfo{
key customerName;
leaf customerName{
type string;
}
uses moduleA:devices {
augment "deviceList" {
leaf ipAddress{
}
}
}
}
}
Note that if you use the augment statement in the module B then it means that any device implementing module B has to also implement module A and its root-level list deviceList. See RFC 7950 4.2.8:
When a server implements a module containing an "augment" statement,
that implies that the server's implementation of the augmented module
contains the additional nodes.
I am not sure if this is what you want. If not, then move the grouping definition to a module that contains only grouping definitions (without any "data definition statements") and import it from both A and B.

Yang Model recursive search for must condition

I have a problem with a restriction on my CLI. I've been investigating yang RFC7950 (https://www.rfc-editor.org/rfc/rfc7950) but I've found nothing.
Here is an example.
grouping httpGroup {
list http-list{
key "value";
leaf value {
status current { yexte:preliminary; }
description "value to match";
must "(not(../protocol)) and (not(../network-port)))" {
error-message "Not compatible with protocol or non-TCP ports";
}
type string { length "1..255"; }
}
}
}
This group will be included in several groups with the following structure:
list and {
leaf-list protocol { ..... }
uses A;
list or {
leaf-list protocol { ..... }
uses A;
}
}
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup;
}
I need this must condition included in httpGroup to verify that protocol value has not been configured in any level of the hierarchy.
I've made this be adding more relatives paths to search for this node:
// same level
not(../protocol)
// next level
not(../and/protocol)
not(../or/protocol)
// previous level
not(../../protocol)
not(../../protocol)
//recursively down previous level
not(../../and/protocol)
not(../../or/protocol)
// third level
not(../and/or/protocol)
not(../and/and/protocol)
As you can see, this is not a clean solution at all.
Is there any way it can be done for a whole hierarchy like:
if protocol node exists and http-list exists then error.
Thank you in advance.
Groupings are meant to be reusable. It is a bad practice to attempt to create a grouping that may only be used in specific contexts. This is exactly what happens if you define an XPath expression within a grouping and this expression references nodes that are "outside" this grouping (a not yet known ancestor data node, for example, or even worse - an ancestor with a specific name).
The proper way for you to handle this situation would be to use a refine statement in each different context where this grouping is used. You target the value leaf with it, then refine it by adding a must statement, the expression of which of course depends on usage context. You do not define a must statement within grouping http-list.
Within grouping A:
grouping A {
status{}
leaf-list protocol { ..... }
leaf-list X { ..... }
uses httpGroup {refine "http-list/value" {must "not(../../protocol)";}}
}
As you can see, grouping A is now completely self-sufficient and may be used within any context - the must will not have any problems with it.

In Tritium, is there a way to assign an id based on child number?

I have a table with a series of rows. I want to change them into divs, but maintain (somehow) their positional information. At the moment, this is what I'm doing:
$("./tr[1]") {
add_class("mw_old_row_1")
}
$("./tr[2]") {
add_class("mw_old_row_2")
}
$("./tr") {
name("div")
}
But this isn't ideal because:
It's super-repetitive
I don't know how many rows there are
Is there a way to take the child number and include that in the class I'm assigning?
Yup, you want to make use of the index() function. Below is the example you wrote reworked using index():
$("./tr") {
add_class("mw_old_row_" + index())
name("div")
}
Below is a link with the following example in tritium tester: http://tester.tritium.io/775895b154e8e2ce99e100967299c10d73dbeb91