access content of parent's field in graphene python - graphql

I am using graphene in python.
Let's say I have the following schema:
extends type Query {
a(search:String):A
}
type A {
b:B
important_info:ID
}
type B {
fieldone: String
fieldtwo: String
}
Now I'd like to query:
query {
a(search:"search string") {
b {
fieldone
}
}
}
however fieldone is based on important_info.
My class B looks like this:
class B(graphene.ObjectType):
fieldone = graphene.String()
fieldtwo = graphene.String()
def resolve_fieldone(self,info):
# Here I want access to important_info, but I don't know how ...
return "something based on important_info"
How can I access important info from within the resolver of fieldone?

It seems there is no obvious or documented solution for this requirement.
I solved it by adding the root object to info.context within the outermost type:
class B(ObjectType):
c = String()
def resolve_c(parent, info):
return 'foo' if info.context['z'] == '' else 'bar'
class A(ObjectType):
b = Field(B)
def resolve_b(parent, info):
return parent.b
class Query(ObjectType):
a = Field(A)
z = String()
def resolve_a(parent, info):
return some_function_to_get_a()
def resolve_z(parent, info):
z = some_function_to_get_z()
info.context['z'] = z
return z

Related

Replacing for loops for searching list in kotlin

I am trying to convert my code as clean as possible using the Kotlin's built-in functions. I have done some part of the code using for loops. But I want to know the efficient built-in functions to be used for this application
I have two array lists accounts and cards.
My goal is to search a specific card with the help of its card-number, in the array list named cards.
Then I have to validate the pin. If the pin is correct, by getting that gift card's customerId I have to search the account in the array list named accounts. Then I have to update the balance of the account.
These are the class which I have used
class Account{
constructor( )
var id : String = generateAccountNumber()
var name: String? = null
set(name) = if (name != null) field = name.toUpperCase() else { field = "Unknown User"; println("invalid details\nAccount is not Created");}
var balance : Double = 0.0
set(balance) = if (balance >= 0) field = balance else { field = 0.0 }
constructor(id: String = generateAccountNumber(), name: String?,balance: Double) {
this.id = id
this.balance = balance
this.name = name
}
}
class GiftCard {
constructor( )
var cardNumber : String = generateCardNumber()
var pin: String? = null
set(pin) = if (pin != null) field = pin else { field = "Unknown User"; println("Please set the pin\nCard is not Created");}
var customerId : String = ""
set(customerId) = if (customerId != "") field = customerId else { field = "" }
var cardBalance : Double = 0.0
set(cardBalance) = if (cardBalance > 0) field = cardBalance else { field = 0.0; println("Card is created with zero balance\nPlease deposit") }
var status = Status.ACTIVE
constructor(cardNumber: String = generateCardNumber(),
pin: String,
customerId: String,
cardBalance: Double = 0.0,
status: Status = Status.ACTIVE){
this.cardNumber = cardNumber
this.pin = pin
this.customerId = customerId
this.cardBalance = cardBalance
this.status = status
}
}
This is the part of code, I have to be changed :
override fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
for (giftcard in giftcards) {
if (giftcard.cardNumber == cardNumber) {
if (giftcard.pin == pin) {
giftcard.status = Status.CLOSED
for (account in accounts)
account.balance = account.balance + giftcard.cardBalance
giftcard.cardBalance = 0.0
return Pair(true,true)
}
\\invalid pin
return Pair(true,false)
}
}
\\card is not present
return Pair(false,false)
}
Both classes are not very idiomatic. The primary constructor of a Kotlin class is implicit and does not need to be defined, however, you explicitly define a constructor and thus you add another one that is empty.
// good
class C
// bad
class C {
constructor()
}
Going further, Kotlin has named arguments and default values, so make use of them.
class Account(
val id: String = generateAccountNumber(),
val name: String = "Unknown User",
val balance: Double = 0.0
)
Double is a very bad choice for basically anything due to its shortcomings, see for instance https://www.floating-point-gui.de/ Choosing Int, Long, heck even BigDecimal would be better. It also seems that you don’t want the balance to ever go beneath zero, in that case consider UInt and ULong.
Last but not least is the mutability of your class. This can make sense but it also might be dangerous. It is up to you to decide upon your needs and requirements.
enum class Status {
CLOSED
}
#ExperimentalUnsignedTypes
class Account(private var _balance: UInt) {
val balance get() = _balance
operator fun plusAssign(other: UInt) {
_balance += other
}
}
#ExperimentalUnsignedTypes
class GiftCard(
val number: String,
val pin: String,
private var _status: Status,
private var _balance: UInt
) {
val status get() = _status
val balance get() = _balance
fun close() {
_status = Status.CLOSED
_balance = 0u
}
}
#ExperimentalUnsignedTypes
class Main(val accounts: List<Account>, val giftCards: List<GiftCard>) {
fun closeCard(cardNumber: String, pin: String) =
giftCards.find { it.number == cardNumber }?.let {
(it.pin == pin).andAlso {
accounts.forEach { a -> a += it.balance }
it.close()
}
}
}
inline fun Boolean.andAlso(action: () -> Unit): Boolean {
if (this) action()
return this
}
We change the return type from Pair<Boolean, Boolean> to a more idiomatic Boolean? where Null means that we did not find anything (literally the true meaning of Null), false that the PIN did not match, and true that the gift card was closed. We are not creating a pair anymore and thus avoid the additional object allocation.
The Boolean.andAlso() is a handy extension function that I generally keep handy, it is like Any.also() from Kotlin’s STD but only executes the action if the Boolean is actually true.
There's probably a million different ways to do this, but here's one that at least has some language features I feel are worthy to share:
fun closeCard(cardNumber: String, pin: String): Pair<Boolean, Boolean> {
val giftCard = giftcards.find { it.cardNumber == cardNumber }
?: return Pair(false, false)
return if (giftCard.pin == pin) {
giftCard.status = Status.CLOSED
accounts.forEach {
it.balance += giftCard.cardBalance
}
Pair(true, true)
} else
Pair(true, false)
}
The first thing to notice if the Elvis operator - ?: - which evaluates the right side of the expression if the left side is null. In this case, if find returns null, which is equivalent to not finding a card number that matches the desired one, we'll immediately return Pair(false, false). This is the last step in your code.
From there one it's pretty straight forward. If the pins match, you loop through the accounts list with a forEach and close the card. If the pins don't match, then we'll go straight to the else branch. In kotlin, if can be used as an expression, therefore we can simply put the return statement before the if and let it return the result of the last expression on each branch.
PS: I won't say this is more efficient than your way. It's just one way that uses built-in functions - find and forEach - like you asked, as well as other language features.
PPS: I would highly recommend to try and find another way to update the lists without mutating the objects. I don't know your use cases, but this doesn't feel too thread-safe. I didn't post any solution for this, because it's outside the scope of this question.

How to resolve graphene.Union Type?

I want to create a UnionType(graphene.Union) of two existing types (FirstType and SecondType) and be able to resolve the query of this union type.
Schema
class FirstType(DjangoObjectType):
class Meta:
model = FirstModel
class SecondType(DjangoObjectType):
class Meta:
model = SecondModel
class UnionType(graphene.Union):
class Meta:
types = (FirstType, SecondType)
So with this schema I want to query all objects from FirstType and SecondType with pk in some list [pks]
query {
all_items(pks: [1,2,5,7]){
... on FirstType{
pk,
color,
}
... on SecondType{
pk,
size,
}
}
}
PKs from FirstType are normally not in the SecondType.
I tried like one below
def resolve_items(root, info, ids):
queryset1 = FirstModel.objects.filter(id__in=pks)
queryset2 = SecondModel.objects.filter(id__in=pks)
return queryset1 | queryset2
but it gives an error: 'Cannot combine queries on two different base models.'
I expect the following response from query:
{ 'data':
{'all_items':[
{'pk': 1,
'color': blue
},
{'pk': 2,
'size': 50.0
},
...
]}
}
So how the resolver should look like?
The graphene Documentation on union types is very sparse. Here is a working example of how to do it correctly:
from graphene import ObjectType, Field, List, String, Int, Union
mock_data = {
"episode": 3,
"characters": [
{
"type": "Droid",
"name": "R2-D2",
"primaryFunction": "Astromech"
},
{
"type": "Human",
"name": "Luke Skywalker",
"homePlanet": "Tatooine"
},
{
"type": "Starship",
"name": "Millennium Falcon",
"length": 35
}
]
}
class Human(ObjectType):
name = String()
homePlanet = String()
class Droid(ObjectType):
name = String()
primaryFunction = String()
class Starship(ObjectType):
name = String()
length = Int()
class Character(Union):
class Meta:
types = (Human, Droid, Starship)
#classmethod
def resolve_type(cls, instance, info):
if instance["type"] == "Human":
return Human
if instance["type"] == "Droid":
return Droid
if instance["type"] == "Starship":
return Starship
class RootQuery(ObjectType):
result = Field(SearchResult)
def resolve_result(_, info):
return mock_data
Then, for a query like
query Humans {
result {
episode
characters {
... on Droid {
name
}
... on Starship {
name
}
... on Human {
name
}
}
}
}
it returns the correct result.
Okay, so I was too concentrated on merging query sets and I didn't notice that I can simply return a list.
So here is solution which gives me the response I was looking for:
def resolve_items(root, info, ids):
items = []
queryset1 = FirstModel.objects.filter(id__in=pks)
items.extend(queryset1)
queryset2 = SecondModel.objects.filter(id__in=pks)
items.extend(queryset2)
return items

Compare value objects using a custom comparator

I want to compare value objects in a way that null properties are ignored.
More specifically, I only want to include those properties of a value object in the comparison which are not-null on the right side.
E.g.
class Person {
String name;
String surname;
}
Person personLeft = new Person();
personLeft.name = "John";
personLeft.surname = "Doe";
Person personRight = new Person();
personRight.name="John"
// this should NOT yield any changes
javers.compare(personLeft, personRight);
// that comparison however, will show that surname has changed
javers.compare(personRight, personLeft);
I though I could tackle this problem by writing a custom comparator and registering it for Person.
Unfortunately this comparator is never called.
Stumbling upon that post, I fear that this is not possible using a custom comparator for the Person class.
Instead I would have to register custom comparators for all containing value types of the Person class, i.e. String.
Is that the intended use of javers or are there any alternatives to that approach?
What is important here is that CustomValueComparator can be used only for Value types. So you have 2 options:
Map Person as Value and then you implement diff algorithm for
Person. It works but is awkward because Person is more like an
Entity.
Register a CustomValueComparator for Strings (all Strings), and then you can use Person as Entity. That's the option that I would choose.
See how it works (groovy):
class Entity {
#Id int id
Person person
}
class Person {
String name
}
def "should use CustomValueComparator for Person when Person is mapped as Value"(){
given:
def javers = JaversBuilder.javers().registerValue(Person,
{ l, r -> if (r.name == null) return true
else return r.name.equals(l.name)
}).build()
def personLeft = new Person(name: "john")
def personRight = new Person()
def eLeft = new Entity(id:1, person: personLeft)
def eRight = new Entity(id:1, person: personRight)
expect:
javers.compare(eLeft, eRight).changes.size() == 0
javers.compare(eRight, eLeft).changes.size() == 1
javers.getTypeMapping(Person) instanceof ValueType
}
def "should used CustomValueComparator for Strings"(){
given:
def javers = JaversBuilder.javers().registerValue(String,
{ l, r -> if (r == null) return true
else return r.equals(l)
}).build()
def personLeft = new Person(name: "john")
def personRight = new Person()
expect:
javers.compare(personLeft, personRight).changes.size() == 0
javers.compare(personRight, personLeft).changes.size() == 1
javers.getTypeMapping(Person) instanceof ValueObjectType
}

Filtering multiple times on one dictionary

I currently run this code:
searchterm = "test"
results = resultsArray.filter { $0.description.contains (searchterm!) }
My question is how do I search in company_name or place or any other field in my model and add it to the results.
Do I need to use filters together and then append the results to a new variable instance of my model?
EDIT:
If "test" is in company_name, place and description. I want all three results returned. However, if "test" is only in place, I need only place to be returned.
EDIT2:
This is an example of my model return. Is this a dictionary or an array? I'm sorry I dont 100% percent know the difference. I know ' "this": is ' what a dictionary looks like, however because there were [] brackets around them, I thought that made it an array...
struct GraphData {
var description: String
var company_name: String
var places: String
init(description: String, company_name: String, places: String){
self.description = description
self.company_name = company_name
self.places = places
}
func toAnyObject() -> Any {
print("return")
return [
"description": description,
"company_name": company_name,
"places": places,
]
}
The easiest way to do this would be to create a custom contains method in your model which can you can use to match the search term against any property in the model:
class YourModel {
var company_name: String
var description: String
var place: String
// ...
func contains(_ searchTerm: String) -> Bool {
return self.company_name.contains(searchTerm)
|| self.description.contains(searchTerm)
|| self.place.contains(searchTerm)
}
}
You can then simply filter using your custom method:
let searchTerm = "test"
let results = resultsArray.filter { $0.contains(searchTerm) }
Is this resultsArray a dictionary or an array?
You can do something like this
let searchTerm = "test"
let filter = resultsArray.filter{ $0.company_name!.contains(searchTerm) || $0.place!.contains(searchTerm) }
Edit
class TestClass: NSObject {
var place: String?
var company_name: String?
func contain(searchTerm: String) -> [String] {
var result = [String]()
if let placeVal = place, placeVal.contains(searchTerm) {
result.append(placeVal)
}
if let companyVal = company_name, companyVal.contains(searchTerm) {
result.append(companyVal)
}
return result
}
}
let searchTerm = "test"
let filter = resultsArray.map { $0.contain(searchTerm: searchTerm) }

annotation macro that rewrites and impls a trait, generics not processed correctly

I am writing a macro that needs to create a class that rewrites a trait, having the same methods/args of the trait but different return type.
So say we got:
trait MyTrait[T]
{
def x(t1: T)(t2: T): T
}
#AnnProxy
class MyClass[T] extends MyTrait[T]
MyClass will be rewritten to:
class MyClass[T] {
def x(t1: T)(t2: T): R[T]
}
(so x will now return R[T] instead of T)
I wrote the macro and debugging it, it produces this code:
Expr[Any](class MyClass[T] extends scala.AnyRef {
def <init>() = {
super.<init>();
()
};
def x(t1: T)(t2: T): macrotests.R[T] = $qmark$qmark$qmark
})
#AnnProxy
As you see the signature seems ok. But when trying to use the macro, I get a compilation error:
val my = new MyClass[Int]
my.x(5)(6)
Error:(14, 7) type mismatch;
found : Int(5)
required: T
x.x(5)(6)
^
So it seems the method's generic T is not the same as the class [T]. Any ideas how to fix?
This is my macro so far. I am not any good with macros (coin'd this up with a lot of help from stackoverflow), but this is the current state:
#compileTimeOnly("enable macro paradise to expand macro annotations")
class AnnProxy extends StaticAnnotation
{
def macroTransform(annottees: Any*): Any = macro IdentityMacro.impl
}
trait R[T]
object IdentityMacro
{
private val SDKClasses = Set("java.lang.Object", "scala.Any")
def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
def showInfo(s: String) = c.info(c.enclosingPosition, s.split("\n").mkString("\n |---macro info---\n |", "\n |", ""), true)
val classDef = annottees.map(_.tree).head.asInstanceOf[ClassDef]
val clazz = c.typecheck(classDef).symbol.asClass
val tparams = clazz.typeParams
val baseClasses = clazz.baseClasses.tail.filter(clz => !SDKClasses(clz.fullName))
val methods = baseClasses.flatMap {
base =>
base.info.decls.filter(d => d.isMethod && d.isPublic).map { decl =>
val termName = decl.name.toTermName
val method = decl.asMethod
val params = method.paramLists.map(_.map {
s =>
val vd = internal.valDef(s)
val f = tparams.find(_.name == vd.tpt.symbol.name)
val sym = if (f.nonEmpty) f.get else vd.tpt.symbol
q"val ${vd.name} : $sym "
})
val paramVars = method.paramLists.flatMap(_.map(_.name))
q""" def $termName (...$params)(timeout:scala.concurrent.duration.FiniteDuration) : macrotests.R[${method.returnType}] = {
???
}"""
}
}
val cde = c.Expr[Any] {
q"""
class ${classDef.name} [..${classDef.tparams}] {
..$methods
}
"""
}
showInfo(show(cde))
cde
}
}
EDIT: I managed to work around by building the class as a string and then using c.parse to compile it. Feels like a hack but it works. There must be a better way by manipulating the tree.
package macrotests
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox
#compileTimeOnly("enable macro paradise to expand macro annotations")
class AnnProxy extends StaticAnnotation
{
def macroTransform(annottees: Any*): Any = macro AnnProxyMacro.impl
}
trait R[T]
trait Remote[T]
object AnnProxyMacro
{
private val SDKClasses = Set("java.lang.Object", "scala.Any")
def impl(c: whitebox.Context)(annottees: c.Expr[Any]*): c.Expr[Any] = {
import c.universe._
val classDef = annottees.map(_.tree).head.asInstanceOf[ClassDef]
val clazz = c.typecheck(classDef).symbol.asClass
val baseClasses = clazz.baseClasses.tail.filter(clz => !SDKClasses(clz.fullName))
val methods = baseClasses.flatMap {
base =>
base.info.decls.filter(d => d.isMethod && d.isPublic).map { decl =>
val termName = decl.name.toTermName
val method = decl.asMethod
val params = method.paramLists.map(_.map {
s =>
val vd = internal.valDef(s)
val tq = vd.tpt
s"${vd.name} : $tq"
})
val paramVars = method.paramLists.flatMap(_.map(_.name))
val paramVarsArray = paramVars.mkString("Array(", ",", ")")
val paramsStr = params.map(_.mkString("(", ",", ")")).mkString(" ")
val retTpe = method.returnType.typeArgs.mkString("-unexpected-")
s""" def $termName $paramsStr (timeout:scala.concurrent.duration.FiniteDuration) : macrotests.Remote[$retTpe] = {
println($paramVarsArray.toList)
new macrotests.Remote[$retTpe] {}
}"""
}
}
val tparams = clazz.typeParams.map(_.name)
val tparamsStr = if (tparams.isEmpty) "" else tparams.mkString("[", ",", "]")
val code =
s"""
|class ${classDef.name}$tparamsStr (x:Int) {
|${methods.mkString("\n")}
|}
""".stripMargin
// print(code)
val cde = c.Expr[Any](c.parse(code))
cde
}
}
the code is very long , you can look at the github: https://github.com/1178615156/scala-macro-example/blob/master/stackoverflow/src/main/scala/so/AnnotationWithTrait.scala
import scala.annotation.StaticAnnotation
import scala.language.experimental.macros
import scala.reflect.macros.blackbox.Context
/**
* Created by yu jie shui on 2015/12/2.
*/
class AnnotationWithTrait extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro AnnotationWithTraitImpl.apply
}
class AnnotationWithTraitImpl(val c: Context) {
import c.universe._
val SDKClasses = Set("java.lang.Object", "scala.Any")
def showInfo(s: String) = c.info(c.enclosingPosition, s.split("\n").mkString("\n |---macro info---\n |", "\n |", ""), true)
def apply(annottees: c.Expr[Any]*) = {
val classDef = annottees.map(_.tree).head.asInstanceOf[ClassDef]
val superClassSymbol= c.typecheck(classDef).symbol.asClass.baseClasses.tail
.filterNot(e => SDKClasses.contains(e.fullName)).reverse
val superClassTree= classDef match {
case q"$mod class $name[..$t](..$params) extends ..$superClass { ..$body }" =>
(superClass: List[Tree]).filterNot(e =>
typeOf[Object].members.exists(_.name == e.children.head.toString())
)
}
showInfo(show(superClassSymbol))
showInfo(show(superClassTree))
val impl = q"private[this] object ${TermName("impl")} extends ..${superClassTree}"
//
//get super class all can call method
val methods = superClassSymbol.map(_.info.members
.filterNot(_.isConstructor)
.filterNot(e => typeOf[Object].members.exists(_.name == e.name)).map(_.asMethod)).toList
case class ReplaceTypeParams(from: String, to: String)
type ClassReplace = List[ReplaceTypeParams]
//trait a[A]
//class b[B] extends a[B]
//need replace type params A to B
val classReplaceList: List[ClassReplace] = superClassTree zip superClassSymbol map {
case (superClassTree, superClassSymbol) =>
superClassSymbol.asClass.typeParams.map(_.name) zip superClassTree.children.tail map
(e => ReplaceTypeParams(e._1.toString, e._2.toString()))
}
val out = classReplaceList zip methods map {
case (classReplace, func) =>
func map { e => {
val funcName = e.name
val funcTypeParams = e.typeParams.map(_.name.toString).map(name => {
TypeDef(Modifiers(Flag.PARAM), TypeName(name), List(), TypeBoundsTree(EmptyTree, EmptyTree))
})
val funcParams = e.paramLists.map(_.map(e => q"${e.name.toTermName}:${
TypeName(
classReplace.find(_.from == e.info.toString).map(_.to).getOrElse(e.info.toString)
)} "))
val funcResultType = TypeName(
classReplace.find(_.from == e.returnType.toString).map(_.to).getOrElse(e.info.toString)
)
q"""
def ${funcName}[..${funcTypeParams}](...$funcParams):${funcResultType}=
impl.${funcName}[..${funcTypeParams}](...$funcParams)
"""
}
}
}
showInfo(show(out))
q"""
class ${classDef.name}[..${classDef.tparams}]{
$impl
..${out.flatten}
}
"""
}
}
test
trait MyTrait[MT1] {
def x(t1: MT1)(t2: MT1): MT1 = t1
}
trait MyTrait2[MT2] {
def t(t2: MT2): MT2 = t2
}
#AnnotationWithTrait
class MyClass[MCT1, MCT2] extends MyTrait[MCT1] with MyTrait2[MCT2]
object AnnotationWithTraitUsing extends App {
assert(new MyClass[Int, String].x(1)(2) == 1)
assert(new MyClass[Int, String].t("aaa") == "aaa")
}

Resources