How to return a Union type from a GraphQL Mutation - graphql-ruby

I want to use this pattern for returning validation failures from the GraphQL Ruby: https://medium.com/#sachee/200-ok-error-handling-in-graphql-7ec869aec9bc
From my mutation I'd like to be able to return a payload that is a union like this:
class RegistrationPayloadType < Base::Union
possible_types UserType, ValidationFailureType
def self.resolve_type(object, context)
if context.current_user.present?
UserType
else
ValidationFailureType
end
end
end
And my resolve method in the mutation is something like this;
def resolve(input:)
#input = input.to_h
if registration.save
candidate
else
registration.errors
end
end
The client can then call the mutation thus;
mutation UserRegistrationMutation($input: UserRegistrationInput!) {
userRegistration(input: $input) {
__typename
... on User {
id
}
... on ValidationFailure {
path
message
}
}
}
How in GraphQL-ruby can I return a Union as a payload?

The answer to this was actually really simple. If you want to return a different type from the mutation, in my case the RegistrationPayloadType above.
class RegistrationMutation < Base::Mutation
argument :input, Inputs::RegistrationInputType, required: true
payload_type RegistrationPayloadType
...
end
Using the payload_type class method got me what I needed.

This blog(https://www.abhaynikam.me/posts/polymorphic-types-with-graphql-ruby/) covers how you could use union types in GraphQL-ruby for polymorphic types. Here, instead of using payload_type another field Type is returned which resolves the union types.

Related

how to return the sum of a value in a table with where clause in grails 2.5.0

Domain class:
class Transaction {
String roundId
BigDecimal amount
:
}
The SQL we wish to execute the following:
"select sum(t.amount) from transaction t where t.roundId = xxx"
We have been unable to find an example which does not return Transaction rows.
We assume there are two approaches:
Use projections and/or criteria etc? All the examples we have found only return lists of transaction rows, not the sum.
Use raw SQL. How do we call SQL, and get a handle on the BigDecimal it returns?
I tried this:
class bla{
def sessionFactory
def someMethod() {
def SQLsession = sessionFactory.getCurrentSession()
def results = SQLsession.createSQLQuery("select sum(t.credit) from transaction t where t.round_id = :roundId", [roundId: roundId])
But this fails with
groovy.lang.MissingMethodException: No signature of method: org.hibernate.internal.SessionImpl.createSQLQuery() is applicable for argument types: (java.lang.String, java.util.LinkedHashMap)
Also, I have no idea what the return type would be (cant find any documentation). I am guessing it will be a list of something: Arrays? Maps?
==== UPDATE ====
Found one way which works (not very elegant or grails like)
def SQLsession = sessionFactory.getCurrentSession()
final query = "select sum(t.credit) from transaction t where t.round_id = :roundId"
final sqlQuery = SQLsession.createSQLQuery(query)
final results = sqlQuery.with {
setString('roundId', roundId)
list() // what is this for? Is there a better return value?
}
This seems to return an array, not a list as expected, so I can do this:
if (results?.size == 1) {
println results[0] // outputs a big decimal
}
Strangely, results.length fails, but results.size works.
Using Criteria, you can do
Transaction.withCriteria {
eq 'roundId', yourRoundIdValueHere
projections {
sum 'amount'
}
}
https://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/classic/Session.html
Query createSQLQuery(String sql, String[] returnAliases, Class[] returnClasses)
Query createSQLQuery(String sql, String returnAlias, Class returnClass)
The second argument of createSQLQuery is one or more returnAliases and not meant for binding the statement to a value.
Instead of passing your values in the 2nd argument, use the setters of your Query object i.e. setString, setInteger, etc.
results.setInteger('roundId',roundId);

asp.net mvc Type.GetMethod when two action with same name, but get and post

in asp.net mvc 4, I write a custom Exception handler, working as a Attribute named HandleCustomError.
In this handler, I should know which action the current request for, then I can know what kind of return type for this action. I will return different data for "return type view() and json".
But, now I have two action with the same name, but one is for "Get", other is for "Post".The method "GetMethod" return an error: " System.Reflection.AmbiguousMatchException "
public class HandleCustomError : System.Web.Mvc.HandleErrorAttribute
{
public override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
//base.OnException(filterContext);
if (filterContext.ExceptionHandled)
{
return;
}
else
{
//Determine the return type of the action
string actionName = filterContext.RouteData.Values["action"].ToString();
Type controllerType = filterContext.Controller.GetType();
var method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
var returnType = method.ReturnType;
}
....(Omitted)
I also came across this issue that below line was giving Ambigeous issue
controllerType.GetMethod(actionName, BindingFlags.IgnoreCase |
BindingFlags.Public | BindingFlags.Instance);
Reason was that controller has two method with same name one is
[HTTPGET]
and other iis
[HTTPPOST]
.
For to get exact method I use GetMethods and LINQ.
Note: In controller writting [HTTPGet]**on action is not compulsory for get method i.e. on action if HTTpGet is not written the by default .net will consider it as **[HttpGet]. But for post action it is compulsory.
Will use this property for finding the correct method.
Steps
1. Find Type of request
2. Find the action using reflection
Finding Request type:
var actionName =
filterContext.RouteData.Values["action"].ToString();
Type typeOfRequest = filterContext.HttpContext.Request.RequestType.ToLower()
=="get"?typeof(HttpGetAttribute):typeof(HttpPostAttribute);
Finding method:
var cntMethods = controllerType.GetMethods()
.Where(m =>
m.Name == actionName &&
( ( typeOfRequest == typeof(HttpPostAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeOfRequest).Count()>0
)
||
( typeOfRequest == typeof(HttpGetAttribute) &&
m.CustomAttributes.Where(a => a.AttributeType == typeof(HttpPostAttribute)).Count() == 0
)
)
);
MethodInfo actionMethodInfo = actionMethodInfo = cntMethods != null && cntMethods.Count() == 1 ? cntMethods.ElementAt(0):null;
Reference : https://techatfingers.wordpress.com/2016/06/14/session-state-on-action/
As you have mentioned that you have two action with the same name, but one is for "Get", other is for "Post" , You could try out the [HttpGet] to the first action and [HttpPost] to the section action or you can try something like this if your action serves requests from multiple verbs
[HttpGet, HttpPost] or [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
For Example ,
if your function name is GetMethod then try like this
[HttpGet]
Public ActionResult GetMethod()
{
//do something ...
}
[HttpPost]
Public ActionResult GetMethod()
{
//do something ...
}
One approach to solve this issue is to use the GetMethods() method on the System.Type object to return a list of methods on the System.Type object. Use a LINQ query to filter the method list to just those methods that match a specific action name.
Add this approach by replacing the following in your code:
var method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
with the following if condition that checks if multiple methods are found that match the variable actionName from your code. Define a string variable that identifies the action type (i.e. "HttpGet" or "HttpPost") and compare it to the attributes of each method in the filtered list.
System.Reflection.MethodInfo[] matchedMethods = controllerType.GetMethods(
System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public)
.Where(m => m.Name == actionName).ToArray<System.Reflection.MethodInfo>();
if (matchedMethods.Length > 1)
{
string attributeTypeString = "HttpGet"; // Change this to "HttpPut" or the text of any custom attribute filter
foreach (System.Reflection.MethodInfo methodInfo in matchedMethods)
{
if (methodInfo.CustomAttributes.Count() == 0) { continue; }
// An alternative below is to explicitly check against a defined attribute type (e.g. `ca.AttributeType == ...`).
if (methodInfo.CustomAttributes.FirstOrDefault(ca => ca.ToString().IndexOf(attributeTypeString) == 0) !=null)
{
method = methodInfo;
break; // Break out of the 'foreach' loop since a match was found
}
}
}
else
{
method = controllerType.GetMethod(actionName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
}
Code notes
I used strongly-typed variable declarations (versus 'var') so it's easier to follow what the code is doing.
Add using System.Reflection; and using System.Linq at the top of the class file. I listed the full assembly declaration of a variable/type/flag in the code above so that again it's easier to follow (at least for me) in this answer.
The first line of code in the above solution can be broken into separate lines to make it easier to follow:
System.Reflection.MethodInfo[] allMethods = controllerType.GetMethods(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
System.Reflection.MethodInfo[] matchedMethods = allMethods.Where(m => m.Name == actionName).ToArray<System.Reflection.MethodInfo>();
Note the if condition within the foreach loop.
if (methodInfo.CustomAttributes.FirstOrDefault(ca => ca.ToString().IndexOf(attributeTypeString) == 0) !=null)
The if condition doesn't have to convert the custom attribute to a string. An alternative is to explicitly check against a defined attribute type (e.g. ca.AttributeType == ...). If the condition does check against the text of an attribute name then ensure the string comparison method (e.g. IndexOf() used here) satisfies the conditions of your application. For example, I used IndexOf() > -1 to determine if the text of variable attributeTypeString is listed anywhere in a custom attribute because I assumed that there should not be another custom attribute that contains the text 'HttpGet'.

NHibernate Criteria Filtering

I use this code to filter database records
if (!string.IsNullOrEmpty(_searchCriteria.MessageType))
{
var messageType = (AutotransferMessageType)Enum.Parse(typeof(AutotransferMessageType), _searchCriteria.MessageType, true);
if (Enum.IsDefined(typeof(AutotransferMessageType), messageType))
{
criteriaQuery.CreateAlias("AutotransferInputRecord", "AutotransferInputRecord")
.Add(
Restrictions.Eq(
"AutotransferInputRecord." + AutotransferLogSearchCriteria.MessageTypePropertyName,
messageType));
}
else
{
criteriaQuery.Add(Restrictions.IsNull("AutotransferInputRecord"));
}
}
AutotransferMessageType is enumerable type
public enum AutotransferMessageType
{
[DisplayName("MT202")]
[DatabaseName("MT202")]
MT202,
[DisplayName("MT210")]
[DatabaseName("MT210")]
MT210,
//...
}
My filter outputs the results when I enter MT202, for example. (It's the right behavior).
When I input just number, for example, 202, I get no results (It's the right behavior too).
But when I try to input some line, "mt", for example, I get error
Unexpected application error has been occured:
'Requested value 'mt' was not found.'
How to make the filter do not show any results when I input a line?
Your error is coming from the line that parses the enum. Use Enum.TryParse instead:
AutotransferMessageType msgEnum;
var enumPrasedOk = Enum.TryParse(_searchCriteria.MessageType, true, out msgEnum);
if(enumPrasedOk){
//Do something
}else{
//Handle case where enum was not found for some reason (if need be)
}
Also please note that you can not look up the enum this way using it's description (in your case they are the same so it is ok).

Yii framework: Trying to get property of non-object

What I have:
public function beforeValidate() {
$offender = Accounts::model()->find(array('select'=>'id','condition'=>'username=:username','params'=>array(':username'=>$this->offender)));
$informer = Accounts::model()->find(array('select'=>'id','condition'=>'username=:username','params'=>array(':username'=>$this->informer)));
$this->offender = $offender->id;
$this->informer = $informer->id;
return parent::beforeValidate();
}
What I get:
PHP Notice, that says, that i'm trying to get property "id" of non-object $offender and $informer.
But those are 100% objects:
var_dump($offender):
object(Accounts)[46]
var_dump($informer):
object(Accounts)[46]
And it actually sets the right id, but shows that notice anyway. What is wrong?
SOLVED
Can't post it as official answer for six more hours, so i just leave it here:
Actually, the problem was in double beforeValidate() call.
AbuseController.php:
if(isset($_POST['AbuseReport']))
{
$model->attributes=$_POST['AbuseReport'];
if($model->validate())
{
$model->save();
}
}
First time it validates on $model->validate(), and replaces $this->offender and $this->informer with correct ID's. Second time it validates on $model->save();, but model returns null this time, because $this->offender is already ID, but it expects username.
The whole solution to this is to disable second validation: $model->save(false);.
use isset or is_object
if(isset($offender->id) || is_object($offender->id)){
$this->offender = $offender->id;
$this->informer = $informer->id;
}

Why when I call save on an object that I instantiate within the same class does it not return true?

I've created a class method and within that class method I instantiate another object of the same class. While trying to save this object I'm getting false according to my test, but I can't figure out why.
As far as the implementation of deposit. I've tested transaction.credit by itself and it works as intended. The problem is the transaction.save is not returning TRUE. Anding (&&) these two methods together should return true only if both methods evaluate to TRUE.
class Transaction
.
.
.
def self.deposit(account, amount, description, task_description_id)
# create credit transaction
transaction = Transaction.new
transaction.description = description
transaction.task_description_id = task_description_id
transaction.credit(account, amount) && transaction.save
end
.
.
.
end
My test
describe "when performing account deposit" do
before { #flag = Transaction.deposit(#discrete_task.commitment_account, 10000, "transfer", 4) }
it { #discrete_task.commitment_account.balance.to_f.should == 10000 }
it { #flag.should be_true }
end
My test failed due to not fulfilling validation requirements, therefore my object would not save...Thanks to #23tux for helping me to get the error messages I needed to get this figured out.