React Relay: Complex mutation fat query - relayjs

I'm creating a voting applications with polls that can be voted. I'm currently stuck on voting for a poll (essentially, creating a vote).
My schema:
(Long story short: polls are accessible from the main store, but the viewer's polls and votes can be accessed directly by him (as fields). votes also are accessible from the min store, but the poll's votes can be accessed also directly by it.
query {
store {
polls { //poll connection
edges {
node { //poll
votes { //vote connection
...
}
}
}
}
votes { //vote connection
edges {
node { //vote
...
}
}
}
}
viewer {
polls { //poll connection
edges {
node { //poll
votes { //vote connection
...
}
}
}
}
votes { //vote connection
edges {
node { //vote
...
}
}
}
}
}
This complex schema makes me confused about how should I define my fat query, since it should define all that could be changing.
Here's what can change:
A vote is created (so voteEdge in the fat query).
A vote is added to the votes connection under store.
A vote is added to the votes connection under viewer.
A vote is added to the votes connection under some poll in the polls connection under store.
(only if the viewer is also the poll's creator, which is possible): A vote is added to the votes connection under some poll in the polls connection under viewer.
So my question is how should I express this in my fat query, should this be suffice?
getFatQuery() {
return Relay.QL`
fragment on CreateVoteMutation {
voteEdge,
viewer{
polls,
voteCount
votes,
},
store{
polls,
voteCount,
votes,
}
}
`;
}
Or should I somehow include votes under polls?
getFatQuery() {
return Relay.QL`
fragment on CreateVoteMutation {
voteEdge,
viewer{
polls{
edges{
node{
voteCount,
votes
}
}
},
voteCount
votes,
},
store{
polls{
edges{
node{
voteCount,
votes
}
}
},
voteCount,
votes,
}
}
`;
}
Thanks!

Looks like you have the right idea. When defining your FatQuery in Relay, you should keep your return fields as optimal as possible, since that's the benefit of GraphQL (you don't need to return more than you will use in your client). So your FatQuery should look like this:
getFatQuery() {
return Relay.QL`
fragment on CreateVoteMutation {
voteEdge,
viewer{
polls { // this is most likely a GraphQL object type, so you'll need a sub-selection, but you don't necessarily need to return all the Votes again since you do that later
name
timestamp
}
voteCount // scalar integer
votes { // again, here you'll need to return a sub-selection since Votes is a GraphQL object type
name
timestamp
}
},
store{
polls { // this is most likely a GraphQL object type, so you'll need a sub-selection, but you don't necessarily need to return all the Votes again since you do that later
name
timestamp
}
voteCount // scalar integer
votes { // again, here you'll need to return a sub-selection since Votes is a GraphQL object type
name
timestamp
}
}
}
`;
}
The idea is that you could technically return votes again as a sub-selection of polls; however, there's no need to since you return is under viewer already. this will give you the total voteCount and all Votes in your system. If you wanted to filter the Votes and VoteCount by Polls, then you could do the opposite, which would look something like this:
getFatQuery() {
return Relay.QL`
fragment on CreateVoteMutation {
voteEdge,
viewer{
polls { // this is most likely a GraphQL object type, so you'll need a sub-selection, but you don't necessarily need to return all the Votes again since you do that later
name
timestamp
voteCount // scalar integer
votes { // again, here you'll need to return a sub-selection since Votes is a GraphQL object type
name
timestamp
}
}
},
store{
polls { // this is most likely a GraphQL object type, so you'll need a sub-selection, but you don't necessarily need to return all the Votes again since you do that later
name
timestamp
voteCount // scalar integer
votes { // again, here you'll need to return a sub-selection since Votes is a GraphQL object type
name
timestamp
}
}
}
}
`;
}
Hope this helps!

Related

Creating and changing existent Methods for Dart classes

I'm trying to program with Dart on Visual Studio Code and need to understand the Syntax of Dart a bit more to be able to code what is needed.
These are the classes I have coded:
Book (defines book title, isbn, price and availability)
class Book {
// properties
late String _title;
late int _isbn;
late double _price;
bool _isAvailable;
....
}
BookCatalog (imports prior class and defines current list of books + methods to add new books)
class BookCatalog{
// no arrays, everything is a list
List<Book> _books = [];
...
}
Main (imports prior classes and executes wanted input)
What I want to change:
improve addBook Method within BookCatalog Class, to not add a new Book, if it has the same ISBN as a already existing one, which it currently does. (Potentially give out message stating 'false' if user tries to add Book with same ISBN)
// adds a book to the store
void addBook(book) {
_books.add(book);
}
improve printBookCatalog Method within BookCatalog Class, to only print available Books and not all Books added to the Store.
// Print books contained in the catalog
void printBookCatalog() {
print("List of Books:");
for (var book in _books) {
print(book);
}
}
improve getBook Method within BookCatalog Class, to actually get the book by its ID, as it's not working right now.
// Get a book by id
Book getBook(int place) => _books[place];
improve calculateAvgPrice Method within BookCatalog Class, to calculate the average price of Books, it's not working correctly as of now
// NEW, calculates average price of books
Book calculateAvgPrice(double price) {
for(var book in _books) {
sum += book.Price;
}
return sum / _books.length;
}
create a new Method within BookCatalog Class to delete Books from the Catalog
answer could be, but I'm not sure :
// deletes book from the catalog
void deleteBook(book) {
_books.remove(book);
}
Any help, explanations, examples or external sources to read up on Dart would be appreciated!
(Especially examples for my specific cases)
I suggest going through Dart Language Tour first.
(Side note: ISBN has leading zero and hyphen, so it's better to use a String for it instead of int)
In your BookCatalog class, you could use a Map instead of a List:
class BookCatalog {
Map<String, Book> _books = {}; // Map from ISBN to Book
// ...
}
Here I'm assuming that both classes are in the same file, otherwise accessing private members wouldn't work, so you'd have to have public getters available.
/// Adds a book to the store only if the ISBN does NOT exist.
bool addBook(Book book) {
if (_books.containsKey(book._isbn)) {
return false;
}
_books[book._isbn] = book;
return true;
}
Missing the if conditional.
void printBookCatalog() {
print("List of Books:");
for (final book in _books.values) {
if (book._isAvailable) {
print(book);
}
}
}
Assuming that by id you mean, its ISBN. It returns a nullable Book? because the isbn might not exist in the catalog.
// Get a book by id
Book? getBook(String isbn) => _books[isbn];
The function has a return type of double not a Book as it's the average price. You also don't need to provide any argument to this function. And you need to define the sum variable first before using it!
double calculateAvgPrice() {
var sum = 0.0;
for (final book in _books.values) {
sum += book._price;
}
return sum / _books.length;
}
Assuming that you want to remove books by their ISBN:
bool removeBook(String isbn) {
return _books.remove(isbn) != null;
}

Is it possible to access property value inside creatCriteria?

I have three domain classes as follows :
Case {
...
Reserve reserve
...
}
Reserve {
...
Amount amount
...
}
Amount {
...
Double value
String currency
...
}
I have a createcriteria as follows
List<Case> cases = []
cases = Case.createCriteria().list( ) {
/* I want to access currency of each case here */
}
Is it possible to access value of Currency for each Case inside the createCriteria? I am new to grails and I tried looking for documentation for this but couldn't find any.
like #cfrick commented:
def cases = Case.createCriteria().list {
reserve {
amount {
eq('currency', 'EUR')
}
}
}
You can use sqlRestriction() to write native sql query inside createCriteria.
More info here

Purpose of #relay(pattern:true)

New expression #relay(pattern: true) was introduced in change log for relay.js 0.5.
But can't figure out from description nor tests what exactly it does and when I should use it when writing fatQueries.
Some example would be very helpful.
Consider a GraphQL query like the following:
viewer {
friends(first: 10) {
totalCount
edges { node { name } }
pageInfo { hasNextPage }
}
}
When defining a fat query for a Relay mutation, to include the name of a field without specifying any of its subfields tells Relay that any subfield of that field could change as a result of that mutation.
Unfortunately, to omit connection arguments such as find, first, and last on the friends field will cause a validation error on the connection-argument-dependent fields edges and pageInfo:
getFatQuery() {
return Relay.QL`
fragment on AddFriendMutationPayload {
viewer {
friends { edges, pageInfo } # Will throw the validation error below
}
}
`;
}
// Uncaught Error: GraphQL validation/transform error ``You supplied the `pageInfo`
// field on a connection named `friends`, but you did not supply an argument necessary
// to do so. Use either the `find`, `first`, or `last` argument.`` in file
// `/path/to/MyMutation.js`.
You can use the #relay(pattern: true) directive to indicate that want to use the fat query to pattern match against the tracked query, instead of to use it as a fully-fledged query.
getFatQuery() {
return Relay.QL`
fragment on AddFriendMutationPayload #relay(pattern: true) {
viewer {
friends { edges, pageInfo } # Valid!
}
}
`;
}
For more information about mutations see: https://facebook.github.io/relay/docs/guides-mutations.html#content

gorm withCriteria and groping by domain class property

I have the following entities in my app :
class Statistic {
int hour
...
Widget widget
}
class Widget {
String name
...
}
And I also have StatisticObj that is just DTO of Statistics domain
class StatisticObj {
int hour
...
String widgetName
}
I want to make criteria which would count Statistic and group by widgetName (so in the end I have count of Statistic per each widngetName) and then convert result to list of StatisticObj. My Criteria looks like this:
def results = Statistic.withCriteria {
groupProperty('widget.name', 'widgetName')
..... projections { count ...}
}
resultTransformer(Transformers.aliasToBean(StatisticObj.class))
}
but in the end I get result which is not grouped.
What I'm doing wrong? Thanks
For first groupProperty must be in projections. And it take only one property.
projections{
groupProperty('widget.name')
count
}
Try it I think it must resolve problem
.withCriteria {
createAlias('widget', 'w')
...
projections {
groupProperty("w.name", "displayValue")
}
....
}
works now!

GORM Criteria Query: Finding Children with specific properties

Have the following Domain modal:
class TransactionHeader {
static hasMany = [details: TransactionDetail]
}
class TransactionDetail {
static belongsTo = [header: TransactionHeader]
Product product
}
I'm trying to write a criteria query that will return all the TransactionHeader rows that contain TransactionDetails with 2 different Products. This is what I have so far and it isn't doing exactly what I'm after:
def list = TransactionHeader.withCriteria {
details {
and {
eq("product", product1)
eq("product", product2)
}
}
}
What's happening is it is return rows that contain at least 1 detail with 1 of the products. I need rows that have 2 details, each with one of the products.
Feels like you want to move details out of that, so actually
def list = TransactionHeader.withCriteria {
and {
details {
eq("product", product1)
}
details {
eq("product", product2)
}
}
}
Not sure how hibernate / gorm will deal this, though.
Have you tried using the "in" statement in your criteria dsl?
def list = TransactionHeader.withCriteria {
and {
details {
'in'("product", [product1, product2])
}
}
}

Resources