Introspection query for EnumValues as a GraphQL fragment in react-component - react-native

I'm building a React Native application using GraphQL (Hosted on graph.cool) with a Relay Schema.
I have a QueryRenderer in the top-level component, fetching data for the presentational components using fragments, which is working fine.
My problem: I want to do an introspection query to fetch possible enum values as a list, for a specific field in my schema and fetch these alongside the fragments.
My current query with fragments:
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
}
The MainList_items fragment:
fragment AnimalList_items on Viewer {
allAnimalCategories {
edges {
node{
id
...AnimalListRow_item
}
}
}
}
I got the following query working for fetching enumValues via introspection (using: https://www.graph.cool/forum/t/how-to-access-the-possible-values-of-an-enum-type-created-inside-the-console/23/2):
query {
__type(name: "JOURNAL_ENTRY_GENDER") {
enumValues {
name
}
}
}
But i can't seem to find a way to create a fragment that can be added to the top-level query.
I could just paste the introspection directly into the top-level query, but that would kind of work against the relay framework, as far as I understand it. Since doing it this way I would have to explicitly pass the result down as a props, instead of letting the presentational component specify what it needs and supplying that as a fragment to the QueryRenderer at the top-level and letting the relay framework implicitly pass the query result down to the component.

After some tinkering around i found a way to solve it - it leaves two places to maintain the fragments query, but it was the only way I found that solved it. :)
In my component i defined the following fragment:
fragment GenderTile_items on __Type {
enumValues{
name
}
}
Then in my main container, i expanded the query in the QueryRenderer with the following
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
__type(name: "JOURNAL_ENTRY_GENDER"){
...GenderTile_items
}
}
The resulting enum data from the QueryRenderer is then available in the successblock by passing 'props.__type' down to the component with the corresponding fragment and from there accessing props.items.enumValues (As the prop for the data was defined as 'items' in the fragment (e.g GenderTile_items when following the naming convention 'FileName_propName'. (https://facebook.github.io/relay/docs/fragment-container.html#data-dependencies-with-graphql)).
I then ran into the problem where i wanted to fetch more than one type of enums and the query returned an error with duplicate __type assignments. This can be fixed this by using alias' like this:
query ReportingContainerQuery {
viewer {
...MainList_items
...
}
genderEnums: __type(name: "JOURNAL_ENTRY_GENDER"){
...GenderTile_items
}
otherEnums: __type(name: "JOURNAL_ENTRY_OTHER"){
...OtherComponent_items
}
}
The data is then available via props.[alias] (e.g. 'props.genderEnums' and 'props.otherEnums'), which you then pass to the component with the fragment and as above access it via props.items.enumValues.
Hope that made sense for anyone else running into the same problem as me. :D

Related

Can I use TypeOrm's FindOperators inside a base class without getting bad SQL Unknown column '_type' in 'where clause'

I am trying to write a base class for CRUD operations for "typeorm": "~0.2.45" under "#nestjs/typeorm": "~8.0.3" using node v14.19.3.
The base class looks like this:
export class CrudService<T> {
protected repository: Repository<T>;
constructor(repository: Repository<T>) {
this.repository = repository;
}
...
// Minimized code example
async find() {
return this.repository.find({
where: {
created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
}
});
}
}
This generates the following SQL query (which is wrong), it seems to use the Between() object as a literal equality comparison.
query failed: SELECT ... FROM `carts` `CartEntity` WHERE `CartEntity`.`created` = ?
-- PARAMETERS: {
"_type":"between",
"_value":[
"2022-06-21T14:18:00.000Z",
"2022-06-21T14:19:00.000Z"
],
"_useParameter":true,
"_multipleParameters":true
}
If I implement the same code inside the CartsEntity service like this:
#Injectable()
export class CartsService extends CrudService<CartEntity> {
constructor(
#InjectRepository(CartsRepository) repository: CartsRepository
) {
super(repository);
}
...
async find() {
return this.repository.find({
where: {
created: Between("2022-06-21T14:18:00.000Z", "2022-06-21T14:19:00.000Z")
}
});
}
It works fine and retrieves the data with valid SQL using BETWEEN on MySql.
I am wondering what is wrong here since I am using the same instance of repository in both code examples. I tried looking at the TypeOrm FindOperator logic but could not pinpoint it.
It turns out that the problem is a difference in the typeorm npm versions I was using.
The CrudEntity described above is inside a private npm using typeorm 0.2.45 as are my microservices extending CrudEntity like the CartEntity above.
Since #nestjs/typeorm is tagged to typeorm 0.2.34 the type was not the same for FindOperator and thus returned as an object condition instead of a FindOperator generating the proper BETWEEN SQL statement.
Basically, make sure all typeorm versions are the same across all your projects sharing code.

Extracting Nested POJO Object with Rest-Assured

I'm writing some tests using rest-assured and its Kotlin extensions to test some simple Spring MVC endpoints. I'm trying to understand how to extract values.
One endpoint returns a BookDetailsView POJO, the other returns a Page<BookDetailsView> (where Page is an interface provided by Spring for doing paging).
BookDetailsView is a really simple Kotlin data class with a single field:
data class BookDetailsView(val id: UUID)
For the single object endpoint, I have:
#Test
fun `single object`() {
val details = BookDetailsView(UUID.randomUUID())
whenever(bookDetailsService.getBookDetails(details.id)).thenReturn(details)
val result: BookDetailsView = Given {
mockMvc(mockMvc)
} When {
get("/book_details/${details.id}")
} Then {
statusCode(HttpStatus.SC_OK)
} Extract {
`as`(BookDetailsView::class.java)
}
assertEquals(details.id, result.id)
}
This works as expected, but trying to apply the same technique for the Page<BookDetailsView> runs afoul of all sorts of parsing challenges since Page is an interface, and even trying to use PageImpl isn't entirely straightforward. In the end, I don't even really care about the Page object, I just care about the nested list of POJOs inside it.
I've tried various permutations like the code below to just grab the bit I care about:
#Test
fun `extract nested`() {
val page = PageImpl(listOf(
BookDetailsView(UUID.randomUUID())
))
whenever(bookDetailsService.getBookDetailsPaged(any())).thenReturn(page)
val response = Given {
mockMvc(mockMvc)
} When {
get("/book_details")
} Then {
statusCode(HttpStatus.SC_OK)
body("content.size()", `is`(1))
body("content[0].id", equalTo(page.first().id.toString()))
} Extract {
path<List<BookDetailsView>>("content")
}
println(response[0].javaClass)
}
The final println spits out class java.util.LinkedHashMap. If instead I try to actually use the object, I get class java.util.LinkedHashMap cannot be cast to class BookDetailsView. There are lots of questions and answers related to this, and I understand it's ultimately an issue of the underlying JSON parser not knowing what to do, but I'm not clear on:
Why does the "simple" case parse without issue?
Shouldn't the type param passed to the path() function tell it what type to use?
What needs configuring to make the second case work, OR
Is there some other approach for grabbing a nested object that would make more sense?
Digging a bit into the code, it appears that the two cases may actually be using different json parsers/configurations (the former seems to stick to rest-assured JSON parsing, while the latter ends up in JsonPath's?)
I don't know kotlin but here is the thing:
path() doesn't know the Element in your List, so it'll be LinkedHashMap by default instead of BookDetailsView.class
to overcome it, you can provide TypeReference for this.
java example
List<BookDetailsView> response = ....then()
.extract().jsonPath()
.getObject("content", new TypeRef<List<BookDetailsView>>() {});
kotlin example
#Test
fun `extract nested`() {
var response = RestAssured.given().get("http://localhost:8000/req1")
.then()
.extract()
.jsonPath()
.getObject("content", object : TypeRef<List<BookDetailsView?>?>() {});
println(response)
//[{id=1}, {id=2}]
}

Why association resource is not binding

I am using spring data rest. When I try to create a resource using post method with application/json using following object, association resources are not binded although they are already present in db
{
screeName : 'adsaf',
screenType : {
screenTypeId : 1,
screenTypeName : 'Fixed'
}
}
Why? Is there anyother way of accomplishing this task other than separately setting associations? I am asking this question because if I manually receive this form in a controller and use ObjectMapper to deserialize and then save this object, all associations would be set. Then why its not happening in spring data rest
Spring Data REST works with links to resources so you have to change your payload to something like this:
POST http://localhost:8080/api/screens
{
"screenName": "adsaf",
"screenType": "http://localhost:8080/api/screenTypes/1"
}
If you need to save ScreenType when you POST Screen object too, you should turn off the exporting of your ScreenType repository:
#RepositoryRestResource(exported = false)
public interface ScreenTypeRepo extends JpaRepository<ScreenType, ...> {
}
and add cascading (at least PERSIST) to your screenType field in Screen entity:
public class Screen {
//...
#ManyToOne(cascade = CascadeType.PERSIST)
ScreenType screenType;
}
That's mean that ScreenType will be managed by Screen. In this case you would be able to use a payload like this:
POST http://localhost:8080/api/screens
{
"screenName": "adsaf",
"screenType": {
"screenTypeName": "Fixed"
}
}
to create a new ScreenType simultaneously with Screen.
This can be done using Custom HttpMessageConverter. check following thread.
Creating Resource with references using spring data rest

pass data to another route without messing with url

DISCLAIMER: I'm a noob.. sorry
Say I have 2 different components that are siblings:
comp1 and comp2
I wish to route from comp1 to comp2 with a bunch of data. How can I achieve this without getting a fugly url-bar containing everything?
I've tried using a separate class, lets call it DataTransmitter:
data-transmitter.js:
export class DataTransmitter {
constructor() {
this.val= "a";
}
}
comp1.js:
import { DataTransmitter } from './data-transmitter';
#inject(DataTransmitter)
export class comp1{
constructor(DataTransmitter){
this.DataTransmitter = DataTransmitter;
}
someMethod(){
this.DataTransmitter.val = "b";
console.log('comp1: ' + this.DataTransmitter.val);
}
}
comp2.js:
import { DataTransmitter } from './data-transmitter';
#inject(DataTransmitter)
export class comp2{
constructor(DataTransmitter){
this.DataTransmitter = DataTransmitter;
}
someMethod(){
console.log('comp2: ' + this.DataTransmitter.val);
}
}
This gives me the output:
comp1: b
comp2: a
I've also tried messing around with EventAggregator, but no success.
Is there some way of routing with parameters WITHOUT having a url that looks like site/comp2?data=stuff&things=otherstuff&params=values&more=etc?
You absolutely want to use a singleton class and then inject it inside of whatever components you need your data. The link that Gaby posted is definitely what you want to do.
The reason your posted code does not work is because you're attempting to use the inject decorator, but you're not importing it. Please see this working example of what you are trying to do on Gist.run here. I have two components, you can click to route between them and set the value. You'll notice the set value remains when you navigate back and forth.

How to document an web component with jsdoc3

What would be the way to document a web component using jsdoc3
Here is an example of web component registered with x-tag.
xtag.register('x-analytics',
{
lifecycle : {
created : function(){
}
},
accessors : {
code : {
attribute : true
},
domain : {
attribute : true
}
}
});
Since X-Tag is also just JavaScript, you can simply use the corresponding annotations provided by jsdoc. So things like #memberof etc.
However, Web Components syntax can have its own kind of additional meaning. For example you probably want an annotation for #element or #lifecycleCallback and stuff like this. This is not provided by jsdoc and therefore e.g. Polymer uses it's own documentation annotation using core-component-page.
You either use what jsdoc provides and see what annotations fit best for your use case, or you use something like dgeni which lets you build a documentation tool pipe entirely from scratch, so you have full control over your annotations etc.