Giter Club home page Giter Club logo

Comments (5)

epii-1 avatar epii-1 commented on July 20, 2024

@hartig
How, exactly is the @requiredForTarget directive supposed to be handled/used in combination with interfaces? Suppose we hava an interface type I1 and some type Tx such that

type Tx {
   empty: String
}

interface I1 {
   pointer: Tx @requiredForTarget
}

Would the types implementing I1 also have the @requiredForTarget on the pointer field?
For example

type T1 implements I1 {
   pointer: Tx @requiredForTarget
}

type T2 implements I1 {
   pointer: Tx @requiredForTarget
}

If so, what does this actually mean? Would a Tx object then always be required to have both a T1 and a T2 object pointing at it (which is what it actually says currently)?
If instead, this just marks that Tx need at least one object inheriting I1 pointing at it, we will for each @requiredForTarget directive have to check with any potential interface to see if it's inherited or not.
And what if we want to override the inherited field and directive? For example if Tx was also an interface, and we have the types Ty implementing Tx, and (I'm not even sure this is actually allowed. It makes sense in oo, but maybe not in graphql)

type T3 implements I1 {
   pointer: Ty @requiredForTarget
}

How would we ever differ between the directly inherited variants of @requiredForTarget and this override variant? (Might not be a problem as we might not be allowed to do it in graphql, but otherwise a good question)

If T1 and T2 are instead not required to inherit the @requiredForTarget, it feels like we are losing information to present to the user. The directive is not lost, as the interface still has it. It's just not directly clear from just looking at the types that the directive exists.
Would it be an idea to add an additional directive, called something like @inheritedRequiredForTarget? This directive should not be manually applied, but automatically applied to any inherited fields where the inherited interface have @requiredForTarget directives. T1 and T2 would then look like

type T1 implements I1 {
   pointer: Tx @inheritedRequiredForTarget
}

type T2 implements I1 {
   pointer: Tx @inheritedRequiredForTarget
}

This way we can still easily show to the user that there are directives in play on these fields, but it does not cause confusion on whether Tx objects need both T1 and T2 pointers, or just one of them.
At the same time @inheritedRequiredForTarget would serve as a hint for the mediator that a @requiredForTarget exists here, without the need to get check the interface.

Should also point out that other directives currently being implemented does not have any ambiguity of this form.

from woo.sh.

hartig avatar hartig commented on July 20, 2024

Good questions! To answer them I had to look into the details of our paper about the schema definition approach.

The answer to your first question is: no, the constraints of an interface type do not have to be inherited by the object types that implement the interface. This question is related to the notion of "interface consistency" that we define in the paper (see Def.4.3 on page 6).

Consequently, you are right with your observation that "we will for each @requiredForTarget directive have to check with any potential interface to see if it's inherited or not."

Now to your question of overriding of inherited fields or of directives. An inherited field can be overridden. So, your example ...

type T3 implements I1 {
   pointer: Ty @requiredForTarget
}

...is possible. What this type definition would mean is the following: First of all, due to the constraint in the interface I1, every node of some type that implements interface Tx (such as your type Ty) must have at least one incoming pointer edge from a node that is of type T1, T2, or T3 (or any other type that implements I1). Second, due to the additional(!) constraint in T3 now, every node of type Ty must have an incoming pointer edge from a node of type T3. This second constraint is stronger in the sense that every Ty node that satisfies this constraint is guaranteed to also satisfy the first constraint. However, the second constraint does not make the first constraint obsolete because we may have another type that implements interface Tx and the nodes of this type are not affected by the second constraint.

Regarding your proposal of adding a @inheritedRequiredForTarget directive, I like this idea, assuming my understanding of this idea is indeed what you mean. So, let me try to rephrase your idea: This new type of directive is not meant to be used in a DB schema; so, it does not actually represent some new kind of constraints. Instead, this new type of directive will be added only into the generated API schema, where it serves two purposes: First, remind the users that there is a related constraint in the corresponding interface. Second, make it easier for the implementation of the @requiredForTarget constraints in the mediator. Sounds good! I have only a small change to this idea: Instead of @inheritedRequiredForTarget, I would name the directive @_requiredForTarget_AccordingToInterface (notice the underscore in the beginning, and the fact that I do not use the word "inherited" because the constraint is not actually inherited) and the directive should have one mandatory argument that specifies the interface where the constraint is. Hence, in your example this would look as follows.

type T1 implements I1 {
   pointer: Tx @_requiredForTarget_AccordingToInterface(interface: "I1")
}

from woo.sh.

epii-1 avatar epii-1 commented on July 20, 2024

Good! Then we agree.

I do, however, have one more question: There should be no issue with also applying @required directives to the reverse edges in the API schema, right? For example the DB schema

type T {
   pointer: Y @requiredForTarget
}

type Y {
   ...
}

would turn into

type T {
   pointer: Y @requiredForTarget
}

type Y {
   ...
   _pointerFromX: [X] @required
}

in the API schema.

from woo.sh.

hartig avatar hartig commented on July 20, 2024

Yes that's possible.

Notice however that the added field must also be non-nullable. So, it must be:

   _pointerFromX: [X!]! @required

from woo.sh.

hartig avatar hartig commented on July 20, 2024

Addressed in PR #54 and to be followed up in #61 and #62

from woo.sh.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.